Code

excise never-used code and stale comments
[inkscape.git] / src / svg / svg-color.cpp
1 #define __SP_SVG_COLOR_C__
3 /**
4  * \file
5  * Reading \& writing of SVG/CSS colors.
6  */
7 /*
8  * Authors:
9  *   Lauris Kaplinski <lauris@kaplinski.com>
10  *
11  * Copyright (C) 1999-2002 Lauris Kaplinski
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
20 #include "svg-color.h"
21 #include <cassert>
22 #include <math.h>
23 #include <glib/gmessages.h>
24 #include <glib/gstrfuncs.h>
25 #include <glib/ghash.h>
26 #include <glib/gutils.h>
27 #include <cstdio> // sprintf
28 #include "strneq.h"
29 using std::sprintf;
31 struct SPSVGColor {
32     unsigned long rgb;
33     char const *name;
34 };
36 /*
37  * These are the colors defined in the SVG standard
38  */
39 static SPSVGColor const sp_svg_color_named[] = {
40     { 0xF0F8FF, "aliceblue" },
41     { 0xFAEBD7, "antiquewhite" },
42     { 0x00FFFF, "aqua" },
43     { 0x7FFFD4, "aquamarine" },
44     { 0xF0FFFF, "azure" },
45     { 0xF5F5DC, "beige" },
46     { 0xFFE4C4, "bisque" },
47     { 0x000000, "black" },
48     { 0xFFEBCD, "blanchedalmond" },
49     { 0x0000FF, "blue" },
50     { 0x8A2BE2, "blueviolet" },
51     { 0xA52A2A, "brown" },
52     { 0xDEB887, "burlywood" },
53     { 0x5F9EA0, "cadetblue" },
54     { 0x7FFF00, "chartreuse" },
55     { 0xD2691E, "chocolate" },
56     { 0xFF7F50, "coral" },
57     { 0x6495ED, "cornflowerblue" },
58     { 0xFFF8DC, "cornsilk" },
59     { 0xDC143C, "crimson" },
60     { 0x00FFFF, "cyan" },
61     { 0x00008B, "darkblue" },
62     { 0x008B8B, "darkcyan" },
63     { 0xB8860B, "darkgoldenrod" },
64     { 0xA9A9A9, "darkgray" },
65     { 0x006400, "darkgreen" },
66     { 0xA9A9A9, "darkgrey" },
67     { 0xBDB76B, "darkkhaki" },
68     { 0x8B008B, "darkmagenta" },
69     { 0x556B2F, "darkolivegreen" },
70     { 0xFF8C00, "darkorange" },
71     { 0x9932CC, "darkorchid" },
72     { 0x8B0000, "darkred" },
73     { 0xE9967A, "darksalmon" },
74     { 0x8FBC8F, "darkseagreen" },
75     { 0x483D8B, "darkslateblue" },
76     { 0x2F4F4F, "darkslategray" },
77     { 0x2F4F4F, "darkslategrey" },
78     { 0x00CED1, "darkturquoise" },
79     { 0x9400D3, "darkviolet" },
80     { 0xFF1493, "deeppink" },
81     { 0x00BFFF, "deepskyblue" },
82     { 0x696969, "dimgray" },
83     { 0x696969, "dimgrey" },
84     { 0x1E90FF, "dodgerblue" },
85     { 0xB22222, "firebrick" },
86     { 0xFFFAF0, "floralwhite" },
87     { 0x228B22, "forestgreen" },
88     { 0xFF00FF, "fuchsia" },
89     { 0xDCDCDC, "gainsboro" },
90     { 0xF8F8FF, "ghostwhite" },
91     { 0xFFD700, "gold" },
92     { 0xDAA520, "goldenrod" },
93     { 0x808080, "gray" },
94     { 0x808080, "grey" },
95     { 0x008000, "green" },
96     { 0xADFF2F, "greenyellow" },
97     { 0xF0FFF0, "honeydew" },
98     { 0xFF69B4, "hotpink" },
99     { 0xCD5C5C, "indianred" },
100     { 0x4B0082, "indigo" },
101     { 0xFFFFF0, "ivory" },
102     { 0xF0E68C, "khaki" },
103     { 0xE6E6FA, "lavender" },
104     { 0xFFF0F5, "lavenderblush" },
105     { 0x7CFC00, "lawngreen" },
106     { 0xFFFACD, "lemonchiffon" },
107     { 0xADD8E6, "lightblue" },
108     { 0xF08080, "lightcoral" },
109     { 0xE0FFFF, "lightcyan" },
110     { 0xFAFAD2, "lightgoldenrodyellow" },
111     { 0xD3D3D3, "lightgray" },
112     { 0x90EE90, "lightgreen" },
113     { 0xD3D3D3, "lightgrey" },
114     { 0xFFB6C1, "lightpink" },
115     { 0xFFA07A, "lightsalmon" },
116     { 0x20B2AA, "lightseagreen" },
117     { 0x87CEFA, "lightskyblue" },
118     { 0x778899, "lightslategray" },
119     { 0x778899, "lightslategrey" },
120     { 0xB0C4DE, "lightsteelblue" },
121     { 0xFFFFE0, "lightyellow" },
122     { 0x00FF00, "lime" },
123     { 0x32CD32, "limegreen" },
124     { 0xFAF0E6, "linen" },
125     { 0xFF00FF, "magenta" },
126     { 0x800000, "maroon" },
127     { 0x66CDAA, "mediumaquamarine" },
128     { 0x0000CD, "mediumblue" },
129     { 0xBA55D3, "mediumorchid" },
130     { 0x9370DB, "mediumpurple" },
131     { 0x3CB371, "mediumseagreen" },
132     { 0x7B68EE, "mediumslateblue" },
133     { 0x00FA9A, "mediumspringgreen" },
134     { 0x48D1CC, "mediumturquoise" },
135     { 0xC71585, "mediumvioletred" },
136     { 0x191970, "midnightblue" },
137     { 0xF5FFFA, "mintcream" },
138     { 0xFFE4E1, "mistyrose" },
139     { 0xFFE4B5, "moccasin" },
140     { 0xFFDEAD, "navajowhite" },
141     { 0x000080, "navy" },
142     { 0xFDF5E6, "oldlace" },
143     { 0x808000, "olive" },
144     { 0x6B8E23, "olivedrab" },
145     { 0xFFA500, "orange" },
146     { 0xFF4500, "orangered" },
147     { 0xDA70D6, "orchid" },
148     { 0xEEE8AA, "palegoldenrod" },
149     { 0x98FB98, "palegreen" },
150     { 0xAFEEEE, "paleturquoise" },
151     { 0xDB7093, "palevioletred" },
152     { 0xFFEFD5, "papayawhip" },
153     { 0xFFDAB9, "peachpuff" },
154     { 0xCD853F, "peru" },
155     { 0xFFC0CB, "pink" },
156     { 0xDDA0DD, "plum" },
157     { 0xB0E0E6, "powderblue" },
158     { 0x800080, "purple" },
159     { 0xFF0000, "red" },
160     { 0xBC8F8F, "rosybrown" },
161     { 0x4169E1, "royalblue" },
162     { 0x8B4513, "saddlebrown" },
163     { 0xFA8072, "salmon" },
164     { 0xF4A460, "sandybrown" },
165     { 0x2E8B57, "seagreen" },
166     { 0xFFF5EE, "seashell" },
167     { 0xA0522D, "sienna" },
168     { 0xC0C0C0, "silver" },
169     { 0x87CEEB, "skyblue" },
170     { 0x6A5ACD, "slateblue" },
171     { 0x708090, "slategray" },
172     { 0x708090, "slategrey" },
173     { 0xFFFAFA, "snow" },
174     { 0x00FF7F, "springgreen" },
175     { 0x4682B4, "steelblue" },
176     { 0xD2B48C, "tan" },
177     { 0x008080, "teal" },
178     { 0xD8BFD8, "thistle" },
179     { 0xFF6347, "tomato" },
180     { 0x40E0D0, "turquoise" },
181     { 0xEE82EE, "violet" },
182     { 0xF5DEB3, "wheat" },
183     { 0xFFFFFF, "white" },
184     { 0xF5F5F5, "whitesmoke" },
185     { 0xFFFF00, "yellow" },
186     { 0x9ACD32, "yellowgreen" }
187 };
189 static GHashTable *sp_svg_create_color_hash();
191 guint32
192 sp_svg_read_color(gchar const *str, guint32 def)
194     static GHashTable *colors = NULL;
195     gchar c[32];
196     guint32 val = 0;
198     if (str == NULL) return def;
199     while ((*str <= ' ') && *str) str++;
200     if (!*str) return def;
202     if (str[0] == '#') {
203         gint i;
204         for (i = 1; str[i]; i++) {
205             int hexval;
206             if (str[i] >= '0' && str[i] <= '9')
207                 hexval = str[i] - '0';
208             else if (str[i] >= 'A' && str[i] <= 'F')
209                 hexval = str[i] - 'A' + 10;
210             else if (str[i] >= 'a' && str[i] <= 'f')
211                 hexval = str[i] - 'a' + 10;
212             else
213                 break;
214             val = (val << 4) + hexval;
215         }
216         /* handle #rgb case */
217         if (i == 1 + 3) {
218             val = ((val & 0xf00) << 8) |
219                 ((val & 0x0f0) << 4) |
220                 (val & 0x00f);
221             val |= val << 4;
222         } else if (i != 1 + 6) {
223             /* must be either 3 or 6 digits. */
224             return def;
225         }
226     } else if (strneq(str, "rgb(", 4)) {
227         gboolean hasp, hasd;
228         gchar *s, *e;
229         gdouble r, g, b;
231         s = (gchar *) str + 4;
232         hasp = FALSE;
233         hasd = FALSE;
235         r = g_ascii_strtod(s, &e);
236         if (s == e) return def;
237         s = e;
238         if (*s == '%') {
239             hasp = TRUE;
240             s += 1;
241         } else {
242             hasd = TRUE;
243         }
244         while (*s && g_ascii_isspace(*s)) s += 1;
245         if (*s != ',') return def;
246         s += 1;
247         while (*s && g_ascii_isspace(*s)) s += 1;
248         g = g_ascii_strtod(s, &e);
249         if (s == e) return def;
250         s = e;
251         if (*s == '%') {
252             hasp = TRUE;
253             s += 1;
254         } else {
255             hasd = TRUE;
256         }
257         while (*s && g_ascii_isspace(*s)) s += 1;
258         if (*s != ',') return def;
259         s += 1;
260         while (*s && g_ascii_isspace(*s)) s += 1;
261         b = g_ascii_strtod(s, &e);
262         if (s == e) return def;
263         s = e;
264         if (*s == '%') {
265             hasp = TRUE;
266         } else {
267             hasd = TRUE;
268         }
269         if (hasp && hasd) return def;
270         if (hasp) {
271             val = (guint) floor(CLAMP(r, 0.0, 100.0) * 2.559999) << 24;
272             val |= ((guint) floor(CLAMP(g, 0.0, 100.0) * 2.559999) << 16);
273             val |= ((guint) floor(CLAMP(b, 0.0, 100.0) * 2.559999) << 8);
274         } else {
275             val = (guint) CLAMP(r, 0, 255) << 24;
276             val |= ((guint) CLAMP(g, 0, 255) << 16);
277             val |= ((guint) CLAMP(b, 0, 255) << 8);
278         }
279         return val;
280     } else {
281         gint i;
282         if (!colors) {
283             colors = sp_svg_create_color_hash();
284         }
285         for (i = 0; i < 31; i++) {
286             if (str[i] == ';') {
287                 c[i] = '\0';
288                 break;
289             }
290             c[i] = g_ascii_tolower(str[i]);
291             if (!str[i]) break;
292         }
293         c[31] = '\0';
295         gpointer const rgb_ptr = g_hash_table_lookup(colors, c);
296         if (rgb_ptr) {
297             val = *(static_cast<unsigned long *>(rgb_ptr));
298         } else {
299             return def;
300         }
301     }
303     return (val << 8);
306 /**
307  * Converts an RGB colour expressed in form 0x00rrggbb to a CSS/SVG representation of that colour.
308  * The result is valid even in SVG Tiny or non-SVG CSS.
309  */
310 static void
311 rgb24_to_css(char *const buf, unsigned const rgb24)
313     assert(rgb24 < (1u << 24));
315     /* SVG 1.1 Full allows additional colour names not supported by SVG Tiny, but we don't bother
316      * with them: it's good for these colours to be copyable to non-SVG CSS stylesheets and for
317      * documents to be more viewable in SVG Tiny/Basic viewers; and some of the SVG Full names are
318      * less meaningful than hex equivalents anyway.  And it's easier for a person to map from the
319      * restricted set because the only component values are {00,80,ff}, other than silver 0xc0c0c0.
320      */
322     char const *src = NULL;
323     switch (rgb24) {
324         /* Extracted mechanically from the table at
325          * http://www.w3.org/TR/REC-html40/types.html#h-6.5 .*/
326         case 0x000000: src = "black"; break;            
327         case 0xc0c0c0: src = "silver"; break;           
328         case 0x808080: src = "gray"; break;             
329         case 0xffffff: src = "white"; break;            
330         case 0x800000: src = "maroon"; break;           
331         case 0xff0000: src = "red"; break;              
332         case 0x800080: src = "purple"; break;           
333         case 0xff00ff: src = "fuchsia"; break;          
334         case 0x008000: src = "green"; break; 
335         case 0x00ff00: src = "lime"; break;  
336         case 0x808000: src = "olive"; break; 
337         case 0xffff00: src = "yellow"; break;
338         case 0x000080: src = "navy"; break;  
339         case 0x0000ff: src = "blue"; break;  
340         case 0x008080: src = "teal"; break;  
341         case 0x00ffff: src = "aqua"; break;  
343         default: {
344             if ((rgb24 & 0xf0f0f) * 0x11 == rgb24) {
345                 /* Can use the shorter three-digit form #rgb instead of #rrggbb. */
346                 sprintf(buf, "#%x%x%x",
347                         (rgb24 >> 16) & 0xf,
348                         (rgb24 >> 8) & 0xf,
349                         rgb24 & 0xf);
350             } else {
351                 sprintf(buf, "#%06x", rgb24);
352             }
353             break;
354         }
355     }
356     if (src) {
357         strcpy(buf, src);
358     }
360     assert(sp_svg_read_color(buf, 0xff) == (rgb24 << 8));
363 /**
364  * Converts an RGBA32 colour to a CSS/SVG representation of the RGB portion of that colour.  The
365  * result is valid even in SVG Tiny or non-SVG CSS.
366  *
367  * \param rgba32 Colour expressed in form 0xrrggbbaa.
368  * \pre buflen \>= 8.
369  */
370 void
371 sp_svg_write_color(gchar *buf, unsigned const buflen, guint32 const rgba32)
373     g_assert(8 <= buflen);
375     unsigned const rgb24 = rgba32 >> 8;
376     rgb24_to_css(buf, rgb24);
379 static GHashTable *
380 sp_svg_create_color_hash()
382     GHashTable *colors = g_hash_table_new(g_str_hash, g_str_equal);
384     for (unsigned i = 0 ; i < G_N_ELEMENTS(sp_svg_color_named) ; i++) {
385         g_hash_table_insert(colors,
386                             (gpointer)(sp_svg_color_named[i].name),
387                             (gpointer)(&sp_svg_color_named[i].rgb));
388     }
390     return colors;
393 /*
394   Local Variables:
395   mode:c++
396   c-file-style:"stroustrup"
397   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
398   indent-tabs-mode:nil
399   fill-column:99
400   End:
401 */
402 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :