Color.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Assertions.h>
  7. #include <AK/DeprecatedString.h>
  8. #include <AK/FloatingPointStringConversions.h>
  9. #include <AK/Optional.h>
  10. #include <AK/Vector.h>
  11. #include <LibGfx/Color.h>
  12. #include <LibGfx/SystemTheme.h>
  13. #include <LibIPC/Decoder.h>
  14. #include <LibIPC/Encoder.h>
  15. #include <ctype.h>
  16. namespace Gfx {
  17. DeprecatedString Color::to_deprecated_string() const
  18. {
  19. return DeprecatedString::formatted("#{:02x}{:02x}{:02x}{:02x}", red(), green(), blue(), alpha());
  20. }
  21. DeprecatedString Color::to_deprecated_string_without_alpha() const
  22. {
  23. return DeprecatedString::formatted("#{:02x}{:02x}{:02x}", red(), green(), blue());
  24. }
  25. static Optional<Color> parse_rgb_color(StringView string)
  26. {
  27. VERIFY(string.starts_with("rgb("sv, CaseSensitivity::CaseInsensitive));
  28. VERIFY(string.ends_with(')'));
  29. auto substring = string.substring_view(4, string.length() - 5);
  30. auto parts = substring.split_view(',');
  31. if (parts.size() != 3)
  32. return {};
  33. auto r = parts[0].to_uint().value_or(256);
  34. auto g = parts[1].to_uint().value_or(256);
  35. auto b = parts[2].to_uint().value_or(256);
  36. if (r > 255 || g > 255 || b > 255)
  37. return {};
  38. return Color(r, g, b);
  39. }
  40. static Optional<Color> parse_rgba_color(StringView string)
  41. {
  42. VERIFY(string.starts_with("rgba("sv, CaseSensitivity::CaseInsensitive));
  43. VERIFY(string.ends_with(')'));
  44. auto substring = string.substring_view(5, string.length() - 6);
  45. auto parts = substring.split_view(',');
  46. if (parts.size() != 4)
  47. return {};
  48. auto r = parts[0].to_int().value_or(256);
  49. auto g = parts[1].to_int().value_or(256);
  50. auto b = parts[2].to_int().value_or(256);
  51. double alpha = 0;
  52. char const* start = parts[3].characters_without_null_termination();
  53. auto alpha_result = parse_first_floating_point(start, start + parts[3].length());
  54. if (alpha_result.parsed_value())
  55. alpha = alpha_result.value;
  56. unsigned a = alpha * 255;
  57. if (r > 255 || g > 255 || b > 255 || a > 255)
  58. return {};
  59. return Color(r, g, b, a);
  60. }
  61. Optional<Color> Color::from_string(StringView string)
  62. {
  63. if (string.is_empty())
  64. return {};
  65. struct ColorAndWebName {
  66. constexpr ColorAndWebName(ARGB32 c, char const* n)
  67. : color(c)
  68. , name(n != nullptr ? StringView { n, __builtin_strlen(n) } : StringView {})
  69. {
  70. }
  71. ARGB32 color;
  72. StringView name;
  73. };
  74. constexpr ColorAndWebName web_colors[] = {
  75. // CSS Level 1
  76. { 0x000000, "black" },
  77. { 0xc0c0c0, "silver" },
  78. { 0x808080, "gray" },
  79. { 0xffffff, "white" },
  80. { 0x800000, "maroon" },
  81. { 0xff0000, "red" },
  82. { 0x800080, "purple" },
  83. { 0xff00ff, "fuchsia" },
  84. { 0x008000, "green" },
  85. { 0x00ff00, "lime" },
  86. { 0x808000, "olive" },
  87. { 0xffff00, "yellow" },
  88. { 0x000080, "navy" },
  89. { 0x0000ff, "blue" },
  90. { 0x008080, "teal" },
  91. { 0x00ffff, "aqua" },
  92. // CSS Level 2 (Revision 1)
  93. { 0xffa500, "orange" },
  94. // CSS Color Module Level 3
  95. { 0xf0f8ff, "aliceblue" },
  96. { 0xfaebd7, "antiquewhite" },
  97. { 0x7fffd4, "aquamarine" },
  98. { 0xf0ffff, "azure" },
  99. { 0xf5f5dc, "beige" },
  100. { 0xffe4c4, "bisque" },
  101. { 0xffebcd, "blanchedalmond" },
  102. { 0x8a2be2, "blueviolet" },
  103. { 0xa52a2a, "brown" },
  104. { 0xdeb887, "burlywood" },
  105. { 0x5f9ea0, "cadetblue" },
  106. { 0x7fff00, "chartreuse" },
  107. { 0xd2691e, "chocolate" },
  108. { 0xff7f50, "coral" },
  109. { 0x6495ed, "cornflowerblue" },
  110. { 0xfff8dc, "cornsilk" },
  111. { 0xdc143c, "crimson" },
  112. { 0x00ffff, "cyan" },
  113. { 0x00008b, "darkblue" },
  114. { 0x008b8b, "darkcyan" },
  115. { 0xb8860b, "darkgoldenrod" },
  116. { 0xa9a9a9, "darkgray" },
  117. { 0x006400, "darkgreen" },
  118. { 0xa9a9a9, "darkgrey" },
  119. { 0xbdb76b, "darkkhaki" },
  120. { 0x8b008b, "darkmagenta" },
  121. { 0x556b2f, "darkolivegreen" },
  122. { 0xff8c00, "darkorange" },
  123. { 0x9932cc, "darkorchid" },
  124. { 0x8b0000, "darkred" },
  125. { 0xe9967a, "darksalmon" },
  126. { 0x8fbc8f, "darkseagreen" },
  127. { 0x483d8b, "darkslateblue" },
  128. { 0x2f4f4f, "darkslategray" },
  129. { 0x2f4f4f, "darkslategrey" },
  130. { 0x00ced1, "darkturquoise" },
  131. { 0x9400d3, "darkviolet" },
  132. { 0xff1493, "deeppink" },
  133. { 0x00bfff, "deepskyblue" },
  134. { 0x696969, "dimgray" },
  135. { 0x696969, "dimgrey" },
  136. { 0x1e90ff, "dodgerblue" },
  137. { 0xb22222, "firebrick" },
  138. { 0xfffaf0, "floralwhite" },
  139. { 0x228b22, "forestgreen" },
  140. { 0xdcdcdc, "gainsboro" },
  141. { 0xf8f8ff, "ghostwhite" },
  142. { 0xffd700, "gold" },
  143. { 0xdaa520, "goldenrod" },
  144. { 0xadff2f, "greenyellow" },
  145. { 0x808080, "grey" },
  146. { 0xf0fff0, "honeydew" },
  147. { 0xff69b4, "hotpink" },
  148. { 0xcd5c5c, "indianred" },
  149. { 0x4b0082, "indigo" },
  150. { 0xfffff0, "ivory" },
  151. { 0xf0e68c, "khaki" },
  152. { 0xe6e6fa, "lavender" },
  153. { 0xfff0f5, "lavenderblush" },
  154. { 0x7cfc00, "lawngreen" },
  155. { 0xfffacd, "lemonchiffon" },
  156. { 0xadd8e6, "lightblue" },
  157. { 0xf08080, "lightcoral" },
  158. { 0xe0ffff, "lightcyan" },
  159. { 0xfafad2, "lightgoldenrodyellow" },
  160. { 0xd3d3d3, "lightgray" },
  161. { 0x90ee90, "lightgreen" },
  162. { 0xd3d3d3, "lightgrey" },
  163. { 0xffb6c1, "lightpink" },
  164. { 0xffa07a, "lightsalmon" },
  165. { 0x20b2aa, "lightseagreen" },
  166. { 0x87cefa, "lightskyblue" },
  167. { 0x778899, "lightslategray" },
  168. { 0x778899, "lightslategrey" },
  169. { 0xb0c4de, "lightsteelblue" },
  170. { 0xffffe0, "lightyellow" },
  171. { 0x32cd32, "limegreen" },
  172. { 0xfaf0e6, "linen" },
  173. { 0xff00ff, "magenta" },
  174. { 0x66cdaa, "mediumaquamarine" },
  175. { 0x0000cd, "mediumblue" },
  176. { 0xba55d3, "mediumorchid" },
  177. { 0x9370db, "mediumpurple" },
  178. { 0x3cb371, "mediumseagreen" },
  179. { 0x7b68ee, "mediumslateblue" },
  180. { 0x00fa9a, "mediumspringgreen" },
  181. { 0x48d1cc, "mediumturquoise" },
  182. { 0xc71585, "mediumvioletred" },
  183. { 0x191970, "midnightblue" },
  184. { 0xf5fffa, "mintcream" },
  185. { 0xffe4e1, "mistyrose" },
  186. { 0xffe4b5, "moccasin" },
  187. { 0xffdead, "navajowhite" },
  188. { 0xfdf5e6, "oldlace" },
  189. { 0x6b8e23, "olivedrab" },
  190. { 0xff4500, "orangered" },
  191. { 0xda70d6, "orchid" },
  192. { 0xeee8aa, "palegoldenrod" },
  193. { 0x98fb98, "palegreen" },
  194. { 0xafeeee, "paleturquoise" },
  195. { 0xdb7093, "palevioletred" },
  196. { 0xffefd5, "papayawhip" },
  197. { 0xffdab9, "peachpuff" },
  198. { 0xcd853f, "peru" },
  199. { 0xffc0cb, "pink" },
  200. { 0xdda0dd, "plum" },
  201. { 0xb0e0e6, "powderblue" },
  202. { 0xbc8f8f, "rosybrown" },
  203. { 0x4169e1, "royalblue" },
  204. { 0x8b4513, "saddlebrown" },
  205. { 0xfa8072, "salmon" },
  206. { 0xf4a460, "sandybrown" },
  207. { 0x2e8b57, "seagreen" },
  208. { 0xfff5ee, "seashell" },
  209. { 0xa0522d, "sienna" },
  210. { 0x87ceeb, "skyblue" },
  211. { 0x6a5acd, "slateblue" },
  212. { 0x708090, "slategray" },
  213. { 0x708090, "slategrey" },
  214. { 0xfffafa, "snow" },
  215. { 0x00ff7f, "springgreen" },
  216. { 0x4682b4, "steelblue" },
  217. { 0xd2b48c, "tan" },
  218. { 0xd8bfd8, "thistle" },
  219. { 0xff6347, "tomato" },
  220. { 0x40e0d0, "turquoise" },
  221. { 0xee82ee, "violet" },
  222. { 0xf5deb3, "wheat" },
  223. { 0xf5f5f5, "whitesmoke" },
  224. { 0x9acd32, "yellowgreen" },
  225. // CSS Color Module Level 4
  226. { 0x663399, "rebeccapurple" },
  227. // (Fallback)
  228. { 0x000000, nullptr }
  229. };
  230. if (string.equals_ignoring_case("transparent"sv))
  231. return Color::from_argb(0x00000000);
  232. for (size_t i = 0; !web_colors[i].name.is_null(); ++i) {
  233. if (string.equals_ignoring_case(web_colors[i].name))
  234. return Color::from_rgb(web_colors[i].color);
  235. }
  236. if (string.starts_with("rgb("sv, CaseSensitivity::CaseInsensitive) && string.ends_with(')'))
  237. return parse_rgb_color(string);
  238. if (string.starts_with("rgba("sv, CaseSensitivity::CaseInsensitive) && string.ends_with(')'))
  239. return parse_rgba_color(string);
  240. if (string[0] != '#')
  241. return {};
  242. auto hex_nibble_to_u8 = [](char nibble) -> Optional<u8> {
  243. if (!isxdigit(nibble))
  244. return {};
  245. if (nibble >= '0' && nibble <= '9')
  246. return nibble - '0';
  247. return 10 + (tolower(nibble) - 'a');
  248. };
  249. if (string.length() == 4) {
  250. Optional<u8> r = hex_nibble_to_u8(string[1]);
  251. Optional<u8> g = hex_nibble_to_u8(string[2]);
  252. Optional<u8> b = hex_nibble_to_u8(string[3]);
  253. if (!r.has_value() || !g.has_value() || !b.has_value())
  254. return {};
  255. return Color(r.value() * 17, g.value() * 17, b.value() * 17);
  256. }
  257. if (string.length() == 5) {
  258. Optional<u8> r = hex_nibble_to_u8(string[1]);
  259. Optional<u8> g = hex_nibble_to_u8(string[2]);
  260. Optional<u8> b = hex_nibble_to_u8(string[3]);
  261. Optional<u8> a = hex_nibble_to_u8(string[4]);
  262. if (!r.has_value() || !g.has_value() || !b.has_value() || !a.has_value())
  263. return {};
  264. return Color(r.value() * 17, g.value() * 17, b.value() * 17, a.value() * 17);
  265. }
  266. if (string.length() != 7 && string.length() != 9)
  267. return {};
  268. auto to_hex = [&](char c1, char c2) -> Optional<u8> {
  269. auto nib1 = hex_nibble_to_u8(c1);
  270. auto nib2 = hex_nibble_to_u8(c2);
  271. if (!nib1.has_value() || !nib2.has_value())
  272. return {};
  273. return nib1.value() << 4 | nib2.value();
  274. };
  275. Optional<u8> r = to_hex(string[1], string[2]);
  276. Optional<u8> g = to_hex(string[3], string[4]);
  277. Optional<u8> b = to_hex(string[5], string[6]);
  278. Optional<u8> a = string.length() == 9 ? to_hex(string[7], string[8]) : Optional<u8>(255);
  279. if (!r.has_value() || !g.has_value() || !b.has_value() || !a.has_value())
  280. return {};
  281. return Color(r.value(), g.value(), b.value(), a.value());
  282. }
  283. Color Color::mixed_with(Color other, float weight) const
  284. {
  285. if (alpha() == other.alpha() || with_alpha(0) == other.with_alpha(0)) {
  286. return Gfx::Color {
  287. round_to<u8>(mix<float>(red(), other.red(), weight)),
  288. round_to<u8>(mix<float>(green(), other.green(), weight)),
  289. round_to<u8>(mix<float>(blue(), other.blue(), weight)),
  290. round_to<u8>(mix<float>(alpha(), other.alpha(), weight)),
  291. };
  292. }
  293. // Fallback to slower, but more visually pleasing premultiplied alpha mix.
  294. // This is needed for linear-gradient()s in LibWeb.
  295. auto mixed_alpha = mix<float>(alpha(), other.alpha(), weight);
  296. auto premultiplied_mix_channel = [&](float channel, float other_channel, float weight) {
  297. return round_to<u8>(mix<float>(channel * alpha(), other_channel * other.alpha(), weight) / mixed_alpha);
  298. };
  299. return Gfx::Color {
  300. premultiplied_mix_channel(red(), other.red(), weight),
  301. premultiplied_mix_channel(green(), other.green(), weight),
  302. premultiplied_mix_channel(blue(), other.blue(), weight),
  303. round_to<u8>(mixed_alpha),
  304. };
  305. }
  306. Vector<Color> Color::shades(u32 steps, float max) const
  307. {
  308. float shade = 1.f;
  309. float step = max / steps;
  310. Vector<Color> shades;
  311. for (u32 i = 0; i < steps; i++) {
  312. shade -= step;
  313. shades.append(this->darkened(shade));
  314. }
  315. return shades;
  316. }
  317. Vector<Color> Color::tints(u32 steps, float max) const
  318. {
  319. float shade = 1.f;
  320. float step = max / steps;
  321. Vector<Color> tints;
  322. for (u32 i = 0; i < steps; i++) {
  323. shade += step;
  324. tints.append(this->lightened(shade));
  325. }
  326. return tints;
  327. }
  328. }
  329. template<>
  330. ErrorOr<void> IPC::encode(Encoder& encoder, Color const& color)
  331. {
  332. return encoder.encode(color.value());
  333. }
  334. template<>
  335. ErrorOr<Gfx::Color> IPC::decode(Decoder& decoder)
  336. {
  337. auto rgba = TRY(decoder.decode<u32>());
  338. return Gfx::Color::from_argb(rgba);
  339. }
  340. ErrorOr<void> AK::Formatter<Gfx::Color>::format(FormatBuilder& builder, Gfx::Color value)
  341. {
  342. return Formatter<StringView>::format(builder, value.to_deprecated_string());
  343. }