Color.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. #include <AK/Assertions.h>
  2. #include <LibDraw/Color.h>
  3. #include <LibDraw/SystemTheme.h>
  4. #include <ctype.h>
  5. #include <stdio.h>
  6. Color::Color(SystemColor system_color)
  7. {
  8. auto& theme = current_system_theme();
  9. switch (system_color) {
  10. case SystemColor::Window:
  11. m_value = theme.window.value();
  12. break;
  13. case SystemColor::WindowText:
  14. m_value = theme.window_text.value();
  15. break;
  16. case SystemColor::Base:
  17. m_value = theme.base.value();
  18. break;
  19. case SystemColor::ThreedShadow1:
  20. m_value = theme.threed_shadow1.value();
  21. break;
  22. case SystemColor::ThreedShadow2:
  23. m_value = theme.threed_shadow2.value();
  24. break;
  25. case SystemColor::ThreedHighlight:
  26. m_value = theme.threed_highlight.value();
  27. break;
  28. case SystemColor::Button:
  29. m_value = theme.button.value();
  30. break;
  31. case SystemColor::ButtonText:
  32. m_value = theme.button_text.value();
  33. break;
  34. case SystemColor::HoverHighlight:
  35. m_value = theme.hover_highlight.value();
  36. break;
  37. case SystemColor::DesktopBackground:
  38. m_value = theme.desktop_background.value();
  39. break;
  40. case SystemColor::ActiveWindowBorder1:
  41. m_value = theme.active_window_border1.value();
  42. break;
  43. case SystemColor::ActiveWindowBorder2:
  44. m_value = theme.active_window_border2.value();
  45. break;
  46. case SystemColor::ActiveWindowTitle:
  47. m_value = theme.active_window_title.value();
  48. break;
  49. case SystemColor::InactiveWindowBorder1:
  50. m_value = theme.inactive_window_border1.value();
  51. break;
  52. case SystemColor::InactiveWindowBorder2:
  53. m_value = theme.inactive_window_border2.value();
  54. break;
  55. case SystemColor::InactiveWindowTitle:
  56. m_value = theme.inactive_window_title.value();
  57. break;
  58. case SystemColor::MovingWindowBorder1:
  59. m_value = theme.moving_window_border1.value();
  60. break;
  61. case SystemColor::MovingWindowBorder2:
  62. m_value = theme.moving_window_border2.value();
  63. break;
  64. case SystemColor::MovingWindowTitle:
  65. m_value = theme.moving_window_title.value();
  66. break;
  67. case SystemColor::HighlightWindowBorder1:
  68. m_value = theme.highlight_window_border1.value();
  69. break;
  70. case SystemColor::HighlightWindowBorder2:
  71. m_value = theme.highlight_window_border2.value();
  72. break;
  73. case SystemColor::HighlightWindowTitle:
  74. m_value = theme.highlight_window_title.value();
  75. break;
  76. case SystemColor::MenuStripe:
  77. m_value = theme.menu_stripe.value();
  78. break;
  79. case SystemColor::MenuBase:
  80. m_value = theme.menu_base.value();
  81. break;
  82. case SystemColor::MenuSelection:
  83. m_value = theme.menu_selection.value();
  84. break;
  85. }
  86. }
  87. Color::Color(NamedColor named)
  88. {
  89. struct {
  90. u8 r;
  91. u8 g;
  92. u8 b;
  93. } rgb;
  94. switch (named) {
  95. case Black:
  96. rgb = { 0, 0, 0 };
  97. break;
  98. case White:
  99. rgb = { 255, 255, 255 };
  100. break;
  101. case Red:
  102. rgb = { 255, 0, 0 };
  103. break;
  104. case Green:
  105. rgb = { 0, 255, 0 };
  106. break;
  107. case Cyan:
  108. rgb = { 0, 255, 255 };
  109. break;
  110. case DarkCyan:
  111. rgb = { 0, 127, 127 };
  112. break;
  113. case MidCyan:
  114. rgb = { 0, 192, 192 };
  115. break;
  116. case Blue:
  117. rgb = { 0, 0, 255 };
  118. break;
  119. case Yellow:
  120. rgb = { 255, 255, 0 };
  121. break;
  122. case Magenta:
  123. rgb = { 255, 0, 255 };
  124. break;
  125. case DarkGray:
  126. rgb = { 64, 64, 64 };
  127. break;
  128. case MidGray:
  129. rgb = { 127, 127, 127 };
  130. break;
  131. case LightGray:
  132. rgb = { 192, 192, 192 };
  133. break;
  134. case MidGreen:
  135. rgb = { 0, 192, 0 };
  136. break;
  137. case MidBlue:
  138. rgb = { 0, 0, 192 };
  139. break;
  140. case MidRed:
  141. rgb = { 192, 0, 0 };
  142. break;
  143. case MidMagenta:
  144. rgb = { 192, 0, 192 };
  145. break;
  146. case DarkGreen:
  147. rgb = { 0, 128, 0 };
  148. break;
  149. case DarkBlue:
  150. rgb = { 0, 0, 128 };
  151. break;
  152. case DarkRed:
  153. rgb = { 128, 0, 0 };
  154. break;
  155. case WarmGray:
  156. rgb = { 212, 208, 200 };
  157. break;
  158. default:
  159. ASSERT_NOT_REACHED();
  160. break;
  161. }
  162. m_value = 0xff000000 | (rgb.r << 16) | (rgb.g << 8) | rgb.b;
  163. }
  164. String Color::to_string() const
  165. {
  166. return String::format("#%b%b%b%b", red(), green(), blue(), alpha());
  167. }
  168. Optional<Color> Color::from_string(const StringView& string)
  169. {
  170. if (string.is_empty())
  171. return {};
  172. struct ColorAndWebName {
  173. RGBA32 color;
  174. const char* name;
  175. };
  176. const ColorAndWebName web_colors[] = {
  177. // CSS Level 1
  178. { 0x000000, "black" },
  179. { 0xc0c0c0, "silver" },
  180. { 0x808080, "gray" },
  181. { 0xffffff, "white" },
  182. { 0x800000, "maroon" },
  183. { 0xff0000, "red" },
  184. { 0x800080, "purple" },
  185. { 0xff00ff, "fuchsia" },
  186. { 0x008000, "green" },
  187. { 0x00ff00, "lime" },
  188. { 0x808000, "olive" },
  189. { 0xffff00, "yellow" },
  190. { 0x000080, "navy" },
  191. { 0x0000ff, "blue" },
  192. { 0x008080, "teal" },
  193. { 0x00ffff, "aqua" },
  194. // CSS Level 2 (Revision 1)
  195. { 0xffa500, "orange" },
  196. // CSS Color Module Level 3
  197. { 0xf0f8ff, "aliceblue" },
  198. { 0xfaebd7, "antiquewhite" },
  199. { 0x7fffd4, "aquamarine" },
  200. { 0xf0ffff, "azure" },
  201. { 0xf5f5dc, "beige" },
  202. { 0xffe4c4, "bisque" },
  203. { 0xffebcd, "blanchedalmond" },
  204. { 0x8a2be2, "blueviolet" },
  205. { 0xa52a2a, "brown" },
  206. { 0xdeb887, "burlywood" },
  207. { 0x5f9ea0, "cadetblue" },
  208. { 0x7fff00, "chartreuse" },
  209. { 0xd2691e, "chocolate" },
  210. { 0xff7f50, "coral" },
  211. { 0x6495ed, "cornflowerblue" },
  212. { 0xfff8dc, "cornsilk" },
  213. { 0xdc143c, "crimson" },
  214. { 0x00ffff, "cyan" },
  215. { 0x00008b, "darkblue" },
  216. { 0x008b8b, "darkcyan" },
  217. { 0xb8860b, "darkgoldenrod" },
  218. { 0xa9a9a9, "darkgray" },
  219. { 0x006400, "darkgreen" },
  220. { 0xa9a9a9, "darkgrey" },
  221. { 0xbdb76b, "darkkhaki" },
  222. { 0x8b008b, "darkmagenta" },
  223. { 0x556b2f, "darkolivegreen" },
  224. { 0xff8c00, "darkorange" },
  225. { 0x9932cc, "darkorchid" },
  226. { 0x8b0000, "darkred" },
  227. { 0xe9967a, "darksalmon" },
  228. { 0x8fbc8f, "darkseagreen" },
  229. { 0x483d8b, "darkslateblue" },
  230. { 0x2f4f4f, "darkslategray" },
  231. { 0x2f4f4f, "darkslategrey" },
  232. { 0x00ced1, "darkturquoise" },
  233. { 0x9400d3, "darkviolet" },
  234. { 0xff1493, "deeppink" },
  235. { 0x00bfff, "deepskyblue" },
  236. { 0x696969, "dimgray" },
  237. { 0x696969, "dimgrey" },
  238. { 0x1e90ff, "dodgerblue" },
  239. { 0xb22222, "firebrick" },
  240. { 0xfffaf0, "floralwhite" },
  241. { 0x228b22, "forestgreen" },
  242. { 0xdcdcdc, "gainsboro" },
  243. { 0xf8f8ff, "ghostwhite" },
  244. { 0xffd700, "gold" },
  245. { 0xdaa520, "goldenrod" },
  246. { 0xadff2f, "greenyellow" },
  247. { 0x808080, "grey" },
  248. { 0xf0fff0, "honeydew" },
  249. { 0xff69b4, "hotpink" },
  250. { 0xcd5c5c, "indianred" },
  251. { 0x4b0082, "indigo" },
  252. { 0xfffff0, "ivory" },
  253. { 0xf0e68c, "khaki" },
  254. { 0xe6e6fa, "lavender" },
  255. { 0xfff0f5, "lavenderblush" },
  256. { 0x7cfc00, "lawngreen" },
  257. { 0xfffacd, "lemonchiffon" },
  258. { 0xadd8e6, "lightblue" },
  259. { 0xf08080, "lightcoral" },
  260. { 0xe0ffff, "lightcyan" },
  261. { 0xfafad2, "lightgoldenrody" },
  262. { 0xd3d3d3, "lightgray" },
  263. { 0x90ee90, "lightgreen" },
  264. { 0xd3d3d3, "lightgrey" },
  265. { 0xffb6c1, "lightpink" },
  266. { 0xffa07a, "lightsalmon" },
  267. { 0x20b2aa, "lightseagreen" },
  268. { 0x87cefa, "lightskyblue" },
  269. { 0x778899, "lightslategray" },
  270. { 0x778899, "lightslategrey" },
  271. { 0xb0c4de, "lightsteelblue" },
  272. { 0xffffe0, "lightyellow" },
  273. { 0x32cd32, "limegreen" },
  274. { 0xfaf0e6, "linen" },
  275. { 0xff00ff, "magenta" },
  276. { 0x66cdaa, "mediumaquamarin" },
  277. { 0x0000cd, "mediumblue" },
  278. { 0xba55d3, "mediumorchid" },
  279. { 0x9370db, "mediumpurple" },
  280. { 0x3cb371, "mediumseagreen" },
  281. { 0x7b68ee, "mediumslateblue" },
  282. { 0x00fa9a, "mediumspringgre" },
  283. { 0x48d1cc, "mediumturquoise" },
  284. { 0xc71585, "mediumvioletred" },
  285. { 0x191970, "midnightblue" },
  286. { 0xf5fffa, "mintcream" },
  287. { 0xffe4e1, "mistyrose" },
  288. { 0xffe4b5, "moccasin" },
  289. { 0xffdead, "navajowhite" },
  290. { 0xfdf5e6, "oldlace" },
  291. { 0x6b8e23, "olivedrab" },
  292. { 0xff4500, "orangered" },
  293. { 0xda70d6, "orchid" },
  294. { 0xeee8aa, "palegoldenrod" },
  295. { 0x98fb98, "palegreen" },
  296. { 0xafeeee, "paleturquoise" },
  297. { 0xdb7093, "palevioletred" },
  298. { 0xffefd5, "papayawhip" },
  299. { 0xffdab9, "peachpuff" },
  300. { 0xcd853f, "peru" },
  301. { 0xffc0cb, "pink" },
  302. { 0xdda0dd, "plum" },
  303. { 0xb0e0e6, "powderblue" },
  304. { 0xbc8f8f, "rosybrown" },
  305. { 0x4169e1, "royalblue" },
  306. { 0x8b4513, "saddlebrown" },
  307. { 0xfa8072, "salmon" },
  308. { 0xf4a460, "sandybrown" },
  309. { 0x2e8b57, "seagreen" },
  310. { 0xfff5ee, "seashell" },
  311. { 0xa0522d, "sienna" },
  312. { 0x87ceeb, "skyblue" },
  313. { 0x6a5acd, "slateblue" },
  314. { 0x708090, "slategray" },
  315. { 0x708090, "slategrey" },
  316. { 0xfffafa, "snow" },
  317. { 0x00ff7f, "springgreen" },
  318. { 0x4682b4, "steelblue" },
  319. { 0xd2b48c, "tan" },
  320. { 0xd8bfd8, "thistle" },
  321. { 0xff6347, "tomato" },
  322. { 0x40e0d0, "turquoise" },
  323. { 0xee82ee, "violet" },
  324. { 0xf5deb3, "wheat" },
  325. { 0xf5f5f5, "whitesmoke" },
  326. { 0x9acd32, "yellowgreen" },
  327. // CSS Color Module Level 4
  328. { 0x663399, "rebeccapurple" },
  329. // (Fallback)
  330. { 0x000000, nullptr }
  331. };
  332. for (size_t i = 0; web_colors[i].name; ++i) {
  333. if (string == web_colors[i].name)
  334. return Color::from_rgb(web_colors[i].color);
  335. }
  336. if (string[0] != '#')
  337. return {};
  338. auto hex_nibble_to_u8 = [](char nibble) -> Optional<u8> {
  339. if (!isxdigit(nibble))
  340. return {};
  341. if (nibble >= '0' && nibble <= '9')
  342. return nibble - '0';
  343. return 10 + (tolower(nibble) - 'a');
  344. };
  345. if (string.length() == 4) {
  346. Optional<u8> r = hex_nibble_to_u8(string[1]);
  347. Optional<u8> g = hex_nibble_to_u8(string[2]);
  348. Optional<u8> b = hex_nibble_to_u8(string[3]);
  349. if (!r.has_value() || !g.has_value() || !b.has_value())
  350. return {};
  351. return Color(r.value() * 17, g.value() * 17, b.value() * 17);
  352. }
  353. if (string.length() != 7 && string.length() != 9)
  354. return {};
  355. auto to_hex = [&](char c1, char c2) -> Optional<u8> {
  356. auto nib1 = hex_nibble_to_u8(c1);
  357. auto nib2 = hex_nibble_to_u8(c2);
  358. if (!nib1.has_value() || !nib2.has_value())
  359. return {};
  360. return nib1.value() << 4 | nib2.value();
  361. };
  362. Optional<u8> r = to_hex(string[1], string[2]);
  363. Optional<u8> g = to_hex(string[3], string[4]);
  364. Optional<u8> b = to_hex(string[5], string[6]);
  365. Optional<u8> a = string.length() == 9 ? to_hex(string[7], string[8]) : Optional<u8>(255);
  366. if (!r.has_value() || !g.has_value() || !b.has_value() || !a.has_value())
  367. return {};
  368. return Color(r.value(), g.value(), b.value(), a.value());
  369. }