2009-11-08 Chris Toshok <toshok@ximian.com>
[moon.git] / src / color.cpp
blob193e6396d13ff6df56708b0faf73a6dc7bb8a7d9
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * color.cpp: Colors
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include <config.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <math.h>
20 #include "color.h"
21 #include "utils.h"
23 // match System.Windows.Media.Colors properties
24 typedef struct {
25 const char *name;
26 const unsigned int color;
27 } named_colors_t;
29 named_colors_t named_colors [] = {
30 // NOTE: samples shows that XAML supports more than the colors defined in System.Windows.Media.Colors
31 // in fact tests shows that all System.Drawing.Color seems to be available
32 { "transparent", 0x00FFFFFF },
33 { "aliceblue", 0xFFF7FBFF },
34 { "antiquewhite", 0xFFFAEBD7 },
35 { "aqua", 0xFF00FFFF },
36 { "aquamarine", 0xFF7FFFD4 },
37 { "azure", 0xFFF7FFFF },
38 { "beige", 0xFFF5F5DC },
39 { "bisque", 0xFFFFE4C4 },
40 { "black", 0xFF000000 },
41 { "blanchedalmond", 0xFFFFEBCD },
42 { "blue", 0xFF0000FF },
43 { "blueviolet", 0xFF8A2BE2 },
44 { "brown", 0xFFA52A2A },
45 { "burlywood", 0xFFDEB887 },
46 { "cadetblue", 0xFF5F9EA0 },
47 { "chartreuse", 0xFF7FFF00 },
48 { "chocolate", 0xFFD2691E },
49 { "coral", 0xFFFF7F50 },
50 { "cornflowerblue", 0xFF6495ED },
51 { "cornsilk", 0xFFFFF8DC },
52 { "crimson", 0xFFDC143C },
53 { "cyan", 0xFF00FFFF },
54 { "darkblue", 0xFF00008B },
55 { "darkcyan", 0xFF008B8B },
56 { "darkgoldenrod", 0xFFB8860B },
57 { "darkgray", 0xFFA9A9A9 },
58 { "darkgreen", 0xFF006400 },
59 { "darkkhaki", 0xFFBDB76B },
60 { "darkmagenta", 0xFF8B008B },
61 { "darkolivegreen", 0xFF556B2F },
62 { "darkorange", 0xFFFF8C00 },
63 { "darkorchid", 0xFF9932CC },
64 { "darkred", 0xFF8B0000 },
65 { "darksalmon", 0xFFE9967A },
66 { "darkseagreen", 0xFF8FBC8B },
67 { "darkslateblue", 0xFF483D8B },
68 { "darkslategray", 0xFF2F4F4F },
69 { "darkturquoise", 0xFF00CED1 },
70 { "darkviolet", 0xFF9400D3 },
71 { "deeppink", 0xFFFF1493 },
72 { "deepskyblue", 0xFF00BFFF },
73 { "dimgray", 0xFF696969 },
74 { "dodgerblue", 0xFF1E90FF },
75 { "firebrick", 0xFFB22222 },
76 { "floralwhite", 0xFFFFFBF7 },
77 { "forestgreen", 0xFF228B22 },
78 { "fuchsia", 0xFFFF00FF },
79 { "gainsboro", 0xFFDCDCDC },
80 { "ghostwhite", 0xFFF8F8FF },
81 { "gold", 0xFFFFD700 },
82 { "goldenrod", 0xFFDAA520 },
83 { "gray", 0xFF808080 },
84 { "green", 0xFF008000 },
85 { "greenyellow", 0xFFADFF2F },
86 { "honeydew", 0xFFF0FFF0 },
87 { "hotpink", 0xFFFF69B4 },
88 { "indianred", 0xFFCD5C5C },
89 { "indigo", 0xFF4B0082 },
90 { "ivory", 0xFFFFFFF7 },
91 { "khaki", 0xFFF0E68C },
92 { "lavender", 0xFFE6E6FA },
93 { "lavenderblush", 0xFFFFF0F5 },
94 { "lawngreen", 0xFF7CFC00 },
95 { "lemonchiffon", 0xFFFFFACD },
96 { "lightblue", 0xFFADD8E6 },
97 { "lightcoral", 0xFFF08080 },
98 { "lightcyan", 0xFFE0FFFF },
99 { "lightgoldenrodyellow", 0xFFFAFAD2 },
100 { "lightgreen", 0xFF90EE90 },
101 { "lightgray", 0xFFD3D3D3 },
102 { "lightpink", 0xFFFFB6C1 },
103 { "lightsalmon", 0xFFFFA07A },
104 { "lightseagreen", 0xFF20B2AA },
105 { "lightskyblue", 0xFF87CEFA },
106 { "lightslategray", 0xFF778899 },
107 { "lightsteelblue", 0xFFB0C4DE },
108 { "lightyellow", 0xFFFFFFE0 },
109 { "lime", 0xFF00FF00 },
110 { "limegreen", 0xFF32CD32 },
111 { "linen", 0xFFFAF0E6 },
112 { "magenta", 0xFFFF00FF },
113 { "maroon", 0xFF800000 },
114 { "mediumaquamarine", 0xFF66CDAA },
115 { "mediumblue", 0xFF0000CD },
116 { "mediumorchid", 0xFFBA55D3 },
117 { "mediumpurple", 0xFF9370DB },
118 { "mediumseagreen", 0xFF3CB371 },
119 { "mediumslateblue", 0xFF7B68EE },
120 { "mediumspringgreen", 0xFF00FA9A },
121 { "mediumturquoise", 0xFF48D1CC },
122 { "mediumvioletred", 0xFFC71585 },
123 { "midnightblue", 0xFF191970 },
124 { "mintcream", 0xFFF7FFFF },
125 { "mistyrose", 0xFFFFE4E1 },
126 { "moccasin", 0xFFFFE4B5 },
127 { "navajowhite", 0xFFFFDEAD },
128 { "navy", 0xFF000080 },
129 { "oldlace", 0xFFFDF5E6 },
130 { "olive", 0xFF808000 },
131 { "olivedrab", 0xFF6B8E23 },
132 { "orange", 0xFFFFA500 },
133 { "orangered", 0xFFFF4500 },
134 { "orchid", 0xFFDA70D6 },
135 { "palegoldenrod", 0xFFEEE8AA },
136 { "palegreen", 0xFF98FB98 },
137 { "paleturquoise", 0xFFAFEEEE },
138 { "palevioletred", 0xFFDB7093 },
139 { "papayawhip", 0xFFFFEFD5 },
140 { "peachpuff", 0xFFFFDAB9 },
141 { "peru", 0xFFCD853F },
142 { "pink", 0xFFFFC0CB },
143 { "plum", 0xFFDDA0DD },
144 { "powderblue", 0xFFB0E0E6 },
145 { "purple", 0xFF800080 },
146 { "red", 0xFFFF0000 },
147 { "rosybrown", 0xFFBC8F8F },
148 { "royalblue", 0xFF4169E1 },
149 { "saddlebrown", 0xFF8B4513 },
150 { "salmon", 0xFFFA8072 },
151 { "sandybrown", 0xFFF4A460 },
152 { "seagreen", 0xFF2E8B57 },
153 { "seashell", 0xFFFFF5EE },
154 { "sienna", 0xFFA0522D },
155 { "silver", 0xFFC0C0C0 },
156 { "skyblue", 0xFF87CEEB },
157 { "slateblue", 0xFF6A5ACD },
158 { "slategray", 0xFF708090 },
159 { "snow", 0xFFFFFAFA },
160 { "springgreen", 0xFF00FF7F },
161 { "steelblue", 0xFF4682B4 },
162 { "tan", 0xFFD2B48C },
163 { "teal", 0xFF008080 },
164 { "thistle", 0xFFD8BFD8 },
165 { "tomato", 0xFFFF6347 },
166 { "turquoise", 0xFF40E0D0 },
167 { "violet", 0xFFEE82EE },
168 { "wheat", 0xFFF5DEB3 },
169 { "white", 0xFFFFFFFF },
170 { "whitesmoke", 0xFFF5F5F5 },
171 { "yellow", 0xFFFFFF00 },
172 { "yellowgreen", 0xFF9ACD32 },
173 { NULL, 0 }
177 * see: http://msdn2.microsoft.com/en-us/library/system.windows.media.solidcolorbrush.aspx
179 * If no color is found, NULL is returned.
181 Color *
182 color_from_str (const char *name)
184 size_t len;
186 if (!name)
187 return new Color (0x00FFFFFF);
189 if ((len = strlen (name)) == 0)
190 return new Color (0x00000000);
192 if (name [0] == '#') {
193 char a [3] = "FF";
194 char r [3] = "FF";
195 char g [3] = "FF";
196 char b [3] = "FF";
198 // Relaxed parsing with some it's-the-web-and-it's-broken
199 // "error tolerance"
200 int real_len = len - 1;
201 if (real_len >= 8) {
202 // aarrggbb
203 a [0] = name [1]; a [1] = name [2];
204 r [0] = name [3]; r [1] = name [4];
205 g [0] = name [5]; g [1] = name [6];
206 b [0] = name [7]; b [1] = name [8];
207 } else if (real_len >= 6) {
208 // rrggbb
209 r [0] = name [1]; r [1] = name [2];
210 g [0] = name [3]; g [1] = name [4];
211 b [0] = name [5]; b [1] = name [6];
212 } else if (real_len >= 4) {
213 // argb
214 a [1] = a [0] = name [1];
215 r [1] = r [0] = name [2];
216 g [1] = g [0] = name [3];
217 b [1] = b [0] = name [4];
218 } else if (real_len == 3) {
219 // rgb
220 r [1] = r [0] = name [1];
221 g [1] = g [0] = name [2];
222 b [1] = b [0] = name [3];
225 return new Color (strtol (r, NULL, 16) / 255.0F, strtol (g, NULL, 16) / 255.0F,
226 strtol (b, NULL, 16) / 255.0F, strtol (a, NULL, 16) / 255.0F);
229 if (name [0] == 's' && name [1] == 'c' && name [2] == '#') {
230 char *iter = (char *) name + 3;
231 double a = 1.0, r = 1.0, g = 1.0, b = 1.0;
232 GArray *channels = double_garray_from_str (iter, 0);
234 if (channels != NULL) {
235 int i = 0;
236 if (channels->len >= 4) {
237 a = g_array_index (channels, double, 0);
238 i++;
241 if (channels->len >= 3) {
242 r = g_array_index (channels, double, 0 + i);
243 g = g_array_index (channels, double, 1 + i);
244 b = g_array_index (channels, double, 2 + i);
247 g_array_free (channels, TRUE);
250 /* Clamp values. scRGB theoretically supports negative numbers
251 * ('darker than black') as a refference to another source but here
252 * it doesn't make too much sense. */
253 r = MIN (1.0, r); r = MAX (0.0, r);
254 g = MIN (1.0, g); g = MAX (0.0, g);
255 b = MIN (1.0, b); b = MAX (0.0, b);
256 a = MIN (1.0, a); a = MAX (0.0, a);
258 /* NOTE: This is not a fully accurate scRGB -> sRGB conversion.
259 * The real stuff has slightly different/more complex band shaping.
260 * But I'd call it "good enough" for now. */
261 r = powf (r, 0.4545);
262 g = powf (g, 0.46);
263 b = powf (b, 0.4545);
265 return new Color (r, g, b, a);
268 if (name[0] >= '0' && name[0] <= '9') {
269 guint32 color = strtoul (name, NULL, 10);
271 return new Color (color);
274 for (int i = 0; named_colors [i].name; i++) {
275 if (!g_ascii_strcasecmp (named_colors [i].name, name))
276 return new Color (named_colors [i].color);
279 return NULL;
283 const char *
284 color_to_string (Color *color)
286 static char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
287 static char buf[10];
288 guint8 v;
290 buf[0] = '#';
292 v = (guint8) (color->r * 255);
293 buf[1] = hex[(v >> 4) & 0x0f];
294 buf[2] = hex[v & 0x0f];
296 v = (guint8) (color->g * 255);
297 buf[3] = hex[(v >> 4) & 0x0f];
298 buf[4] = hex[v & 0x0f];
300 v = (guint8) (color->b * 255);
301 buf[5] = hex[(v >> 4) & 0x0f];
302 buf[6] = hex[v & 0x0f];
304 v = (guint8) (color->a * 255);
305 if (v > 0) {
306 buf[7] = hex[(v >> 4) & 0x0f];
307 buf[8] = hex[v & 0x0f];
308 } else {
309 buf[7] = '\0';
310 buf[8] = '\0';
313 buf[9] = '\0';
315 return buf;