Serenity Operating System
at portability 361 lines 11 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/Assertions.h> 28#include <AK/BufferStream.h> 29#include <AK/Optional.h> 30#include <AK/String.h> 31#include <LibGfx/Color.h> 32#include <LibGfx/SystemTheme.h> 33#include <ctype.h> 34#include <stdio.h> 35 36namespace Gfx { 37 38Color::Color(NamedColor named) 39{ 40 struct { 41 u8 r; 42 u8 g; 43 u8 b; 44 } rgb; 45 46 switch (named) { 47 case Black: 48 rgb = { 0, 0, 0 }; 49 break; 50 case White: 51 rgb = { 255, 255, 255 }; 52 break; 53 case Red: 54 rgb = { 255, 0, 0 }; 55 break; 56 case Green: 57 rgb = { 0, 255, 0 }; 58 break; 59 case Cyan: 60 rgb = { 0, 255, 255 }; 61 break; 62 case DarkCyan: 63 rgb = { 0, 127, 127 }; 64 break; 65 case MidCyan: 66 rgb = { 0, 192, 192 }; 67 break; 68 case Blue: 69 rgb = { 0, 0, 255 }; 70 break; 71 case Yellow: 72 rgb = { 255, 255, 0 }; 73 break; 74 case Magenta: 75 rgb = { 255, 0, 255 }; 76 break; 77 case DarkGray: 78 rgb = { 64, 64, 64 }; 79 break; 80 case MidGray: 81 rgb = { 127, 127, 127 }; 82 break; 83 case LightGray: 84 rgb = { 192, 192, 192 }; 85 break; 86 case MidGreen: 87 rgb = { 0, 192, 0 }; 88 break; 89 case MidBlue: 90 rgb = { 0, 0, 192 }; 91 break; 92 case MidRed: 93 rgb = { 192, 0, 0 }; 94 break; 95 case MidMagenta: 96 rgb = { 192, 0, 192 }; 97 break; 98 case DarkGreen: 99 rgb = { 0, 128, 0 }; 100 break; 101 case DarkBlue: 102 rgb = { 0, 0, 128 }; 103 break; 104 case DarkRed: 105 rgb = { 128, 0, 0 }; 106 break; 107 case WarmGray: 108 rgb = { 212, 208, 200 }; 109 break; 110 default: 111 ASSERT_NOT_REACHED(); 112 break; 113 } 114 115 m_value = 0xff000000 | (rgb.r << 16) | (rgb.g << 8) | rgb.b; 116} 117 118String Color::to_string() const 119{ 120 return String::format("#%b%b%b%b", red(), green(), blue(), alpha()); 121} 122 123Optional<Color> Color::from_string(const StringView& string) 124{ 125 if (string.is_empty()) 126 return {}; 127 128 struct ColorAndWebName { 129 RGBA32 color; 130 const char* name; 131 }; 132 133 const ColorAndWebName web_colors[] = { 134 // CSS Level 1 135 { 0x000000, "black" }, 136 { 0xc0c0c0, "silver" }, 137 { 0x808080, "gray" }, 138 { 0xffffff, "white" }, 139 { 0x800000, "maroon" }, 140 { 0xff0000, "red" }, 141 { 0x800080, "purple" }, 142 { 0xff00ff, "fuchsia" }, 143 { 0x008000, "green" }, 144 { 0x00ff00, "lime" }, 145 { 0x808000, "olive" }, 146 { 0xffff00, "yellow" }, 147 { 0x000080, "navy" }, 148 { 0x0000ff, "blue" }, 149 { 0x008080, "teal" }, 150 { 0x00ffff, "aqua" }, 151 // CSS Level 2 (Revision 1) 152 { 0xffa500, "orange" }, 153 // CSS Color Module Level 3 154 { 0xf0f8ff, "aliceblue" }, 155 { 0xfaebd7, "antiquewhite" }, 156 { 0x7fffd4, "aquamarine" }, 157 { 0xf0ffff, "azure" }, 158 { 0xf5f5dc, "beige" }, 159 { 0xffe4c4, "bisque" }, 160 { 0xffebcd, "blanchedalmond" }, 161 { 0x8a2be2, "blueviolet" }, 162 { 0xa52a2a, "brown" }, 163 { 0xdeb887, "burlywood" }, 164 { 0x5f9ea0, "cadetblue" }, 165 { 0x7fff00, "chartreuse" }, 166 { 0xd2691e, "chocolate" }, 167 { 0xff7f50, "coral" }, 168 { 0x6495ed, "cornflowerblue" }, 169 { 0xfff8dc, "cornsilk" }, 170 { 0xdc143c, "crimson" }, 171 { 0x00ffff, "cyan" }, 172 { 0x00008b, "darkblue" }, 173 { 0x008b8b, "darkcyan" }, 174 { 0xb8860b, "darkgoldenrod" }, 175 { 0xa9a9a9, "darkgray" }, 176 { 0x006400, "darkgreen" }, 177 { 0xa9a9a9, "darkgrey" }, 178 { 0xbdb76b, "darkkhaki" }, 179 { 0x8b008b, "darkmagenta" }, 180 { 0x556b2f, "darkolivegreen" }, 181 { 0xff8c00, "darkorange" }, 182 { 0x9932cc, "darkorchid" }, 183 { 0x8b0000, "darkred" }, 184 { 0xe9967a, "darksalmon" }, 185 { 0x8fbc8f, "darkseagreen" }, 186 { 0x483d8b, "darkslateblue" }, 187 { 0x2f4f4f, "darkslategray" }, 188 { 0x2f4f4f, "darkslategrey" }, 189 { 0x00ced1, "darkturquoise" }, 190 { 0x9400d3, "darkviolet" }, 191 { 0xff1493, "deeppink" }, 192 { 0x00bfff, "deepskyblue" }, 193 { 0x696969, "dimgray" }, 194 { 0x696969, "dimgrey" }, 195 { 0x1e90ff, "dodgerblue" }, 196 { 0xb22222, "firebrick" }, 197 { 0xfffaf0, "floralwhite" }, 198 { 0x228b22, "forestgreen" }, 199 { 0xdcdcdc, "gainsboro" }, 200 { 0xf8f8ff, "ghostwhite" }, 201 { 0xffd700, "gold" }, 202 { 0xdaa520, "goldenrod" }, 203 { 0xadff2f, "greenyellow" }, 204 { 0x808080, "grey" }, 205 { 0xf0fff0, "honeydew" }, 206 { 0xff69b4, "hotpink" }, 207 { 0xcd5c5c, "indianred" }, 208 { 0x4b0082, "indigo" }, 209 { 0xfffff0, "ivory" }, 210 { 0xf0e68c, "khaki" }, 211 { 0xe6e6fa, "lavender" }, 212 { 0xfff0f5, "lavenderblush" }, 213 { 0x7cfc00, "lawngreen" }, 214 { 0xfffacd, "lemonchiffon" }, 215 { 0xadd8e6, "lightblue" }, 216 { 0xf08080, "lightcoral" }, 217 { 0xe0ffff, "lightcyan" }, 218 { 0xfafad2, "lightgoldenrody" }, 219 { 0xd3d3d3, "lightgray" }, 220 { 0x90ee90, "lightgreen" }, 221 { 0xd3d3d3, "lightgrey" }, 222 { 0xffb6c1, "lightpink" }, 223 { 0xffa07a, "lightsalmon" }, 224 { 0x20b2aa, "lightseagreen" }, 225 { 0x87cefa, "lightskyblue" }, 226 { 0x778899, "lightslategray" }, 227 { 0x778899, "lightslategrey" }, 228 { 0xb0c4de, "lightsteelblue" }, 229 { 0xffffe0, "lightyellow" }, 230 { 0x32cd32, "limegreen" }, 231 { 0xfaf0e6, "linen" }, 232 { 0xff00ff, "magenta" }, 233 { 0x66cdaa, "mediumaquamarin" }, 234 { 0x0000cd, "mediumblue" }, 235 { 0xba55d3, "mediumorchid" }, 236 { 0x9370db, "mediumpurple" }, 237 { 0x3cb371, "mediumseagreen" }, 238 { 0x7b68ee, "mediumslateblue" }, 239 { 0x00fa9a, "mediumspringgre" }, 240 { 0x48d1cc, "mediumturquoise" }, 241 { 0xc71585, "mediumvioletred" }, 242 { 0x191970, "midnightblue" }, 243 { 0xf5fffa, "mintcream" }, 244 { 0xffe4e1, "mistyrose" }, 245 { 0xffe4b5, "moccasin" }, 246 { 0xffdead, "navajowhite" }, 247 { 0xfdf5e6, "oldlace" }, 248 { 0x6b8e23, "olivedrab" }, 249 { 0xff4500, "orangered" }, 250 { 0xda70d6, "orchid" }, 251 { 0xeee8aa, "palegoldenrod" }, 252 { 0x98fb98, "palegreen" }, 253 { 0xafeeee, "paleturquoise" }, 254 { 0xdb7093, "palevioletred" }, 255 { 0xffefd5, "papayawhip" }, 256 { 0xffdab9, "peachpuff" }, 257 { 0xcd853f, "peru" }, 258 { 0xffc0cb, "pink" }, 259 { 0xdda0dd, "plum" }, 260 { 0xb0e0e6, "powderblue" }, 261 { 0xbc8f8f, "rosybrown" }, 262 { 0x4169e1, "royalblue" }, 263 { 0x8b4513, "saddlebrown" }, 264 { 0xfa8072, "salmon" }, 265 { 0xf4a460, "sandybrown" }, 266 { 0x2e8b57, "seagreen" }, 267 { 0xfff5ee, "seashell" }, 268 { 0xa0522d, "sienna" }, 269 { 0x87ceeb, "skyblue" }, 270 { 0x6a5acd, "slateblue" }, 271 { 0x708090, "slategray" }, 272 { 0x708090, "slategrey" }, 273 { 0xfffafa, "snow" }, 274 { 0x00ff7f, "springgreen" }, 275 { 0x4682b4, "steelblue" }, 276 { 0xd2b48c, "tan" }, 277 { 0xd8bfd8, "thistle" }, 278 { 0xff6347, "tomato" }, 279 { 0x40e0d0, "turquoise" }, 280 { 0xee82ee, "violet" }, 281 { 0xf5deb3, "wheat" }, 282 { 0xf5f5f5, "whitesmoke" }, 283 { 0x9acd32, "yellowgreen" }, 284 // CSS Color Module Level 4 285 { 0x663399, "rebeccapurple" }, 286 // (Fallback) 287 { 0x000000, nullptr } 288 }; 289 290 for (size_t i = 0; web_colors[i].name; ++i) { 291 if (string == web_colors[i].name) 292 return Color::from_rgb(web_colors[i].color); 293 } 294 295 if (string[0] != '#') 296 return {}; 297 298 auto hex_nibble_to_u8 = [](char nibble) -> Optional<u8> { 299 if (!isxdigit(nibble)) 300 return {}; 301 if (nibble >= '0' && nibble <= '9') 302 return nibble - '0'; 303 return 10 + (tolower(nibble) - 'a'); 304 }; 305 306 if (string.length() == 4) { 307 Optional<u8> r = hex_nibble_to_u8(string[1]); 308 Optional<u8> g = hex_nibble_to_u8(string[2]); 309 Optional<u8> b = hex_nibble_to_u8(string[3]); 310 if (!r.has_value() || !g.has_value() || !b.has_value()) 311 return {}; 312 return Color(r.value() * 17, g.value() * 17, b.value() * 17); 313 } 314 315 if (string.length() == 5) { 316 Optional<u8> r = hex_nibble_to_u8(string[1]); 317 Optional<u8> g = hex_nibble_to_u8(string[2]); 318 Optional<u8> b = hex_nibble_to_u8(string[3]); 319 Optional<u8> a = hex_nibble_to_u8(string[4]); 320 if (!r.has_value() || !g.has_value() || !b.has_value() || !a.has_value()) 321 return {}; 322 return Color(r.value() * 17, g.value() * 17, b.value() * 17, a.value() * 17); 323 } 324 325 if (string.length() != 7 && string.length() != 9) 326 return {}; 327 328 auto to_hex = [&](char c1, char c2) -> Optional<u8> { 329 auto nib1 = hex_nibble_to_u8(c1); 330 auto nib2 = hex_nibble_to_u8(c2); 331 if (!nib1.has_value() || !nib2.has_value()) 332 return {}; 333 return nib1.value() << 4 | nib2.value(); 334 }; 335 336 Optional<u8> r = to_hex(string[1], string[2]); 337 Optional<u8> g = to_hex(string[3], string[4]); 338 Optional<u8> b = to_hex(string[5], string[6]); 339 Optional<u8> a = string.length() == 9 ? to_hex(string[7], string[8]) : Optional<u8>(255); 340 341 if (!r.has_value() || !g.has_value() || !b.has_value() || !a.has_value()) 342 return {}; 343 344 return Color(r.value(), g.value(), b.value(), a.value()); 345} 346} 347 348const LogStream& operator<<(const LogStream& stream, Color value) 349{ 350 return stream << value.to_string(); 351} 352 353bool IPC::decode(BufferStream& stream, Color& color) 354{ 355 u32 rgba = 0; 356 stream >> rgba; 357 if (stream.handle_read_failure()) 358 return false; 359 color = Color::from_rgba(rgba); 360 return true; 361}