1 /* AbiSource Program Utilities
2 * Copyright (C) 1998 AbiSource, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <ctype.h>
25
26 #include "ut_color.h"
27 #include "ut_assert.h"
28 #include "ut_string.h"
29 #include "ut_debugmsg.h"
30
31 #include <limits.h>
32
33 /*****************************************************************/
34 /*****************************************************************/
35
36 /* These are the colors defined in the SVG standard (I haven't checked the final recommendation for changes)
37 */
38 struct colorToRGBMapping
39 {
40 const char * m_name;
41
42 unsigned char m_red;
43 unsigned char m_green;
44 unsigned char m_blue;
45 };
46
47 static struct colorToRGBMapping s_Colors[] =
48 {
49 { "aliceblue", 240, 248, 255 },
50 { "antiquewhite", 250, 235, 215 },
51 { "aqua", 0, 255, 255 },
52 { "aquamarine", 127, 255, 212 },
53 { "azure", 240, 255, 255 },
54 { "beige", 245, 245, 220 },
55 { "bisque", 255, 228, 196 },
56 { "black", 0, 0, 0 },
57 { "blanchedalmond", 255, 235, 205 },
58 { "blue", 0, 0, 255 },
59 { "blueviolet", 138, 43, 226 },
60 { "brown", 165, 42, 42 },
61 { "burlywood", 222, 184, 135 },
62 { "cadetblue", 95, 158, 160 },
63 { "chartreuse", 127, 255, 0 },
64 { "chocolate", 210, 105, 30 },
65 { "coral", 255, 127, 80 },
66 { "cornflowerblue", 100, 149, 237 },
67 { "cornsilk", 255, 248, 220 },
68 { "crimson", 220, 20, 60 },
69 { "cyan", 0, 255, 255 },
70 { "darkblue", 0, 0, 139 },
71 { "darkcyan", 0, 139, 139 },
72 { "darkgoldenrod", 184, 134, 11 },
73 { "darkgray", 169, 169, 169 },
74 { "darkgreen", 0, 100, 0 },
75 { "darkgrey", 169, 169, 169 },
76 { "darkkhaki", 189, 183, 107 },
77 { "darkmagenta", 139, 0, 139 },
78 { "darkolivegreen", 85, 107, 47 },
79 { "darkorange", 255, 140, 0 },
80 { "darkorchid", 153, 50, 204 },
81 { "darkred", 139, 0, 0 },
82 { "darksalmon", 233, 150, 122 },
83 { "darkseagreen", 143, 188, 143 },
84 { "darkslateblue", 72, 61, 139 },
85 { "darkslategray", 47, 79, 79 },
86 { "darkslategrey", 47, 79, 79 },
87 { "darkturquoise", 0, 206, 209 },
88 { "darkviolet", 148, 0, 211 },
89 { "deeppink", 255, 20, 147 },
90 { "deepskyblue", 0, 191, 255 },
91 { "dimgray", 105, 105, 105 },
92 { "dimgrey", 105, 105, 105 },
93 { "dodgerblue", 30, 144, 255 },
94 { "firebrick", 178, 34, 34 },
95 { "floralwhite", 255, 250, 240 },
96 { "forestgreen", 34, 139, 34 },
97 { "fuchsia", 255, 0, 255 },
98 { "gainsboro", 220, 220, 220 },
99 { "ghostwhite", 248, 248, 255 },
100 { "gold", 255, 215, 0 },
101 { "goldenrod", 218, 165, 32 },
102 { "gray", 128, 128, 128 },
103 { "grey", 128, 128, 128 },
104 { "green", 0, 128, 0 },
105 { "greenyellow", 173, 255, 47 },
106 { "honeydew", 240, 255, 240 },
107 { "hotpink", 255, 105, 180 },
108 { "indianred", 205, 92, 92 },
109 { "indigo", 75, 0, 130 },
110 { "ivory", 255, 255, 240 },
111 { "khaki", 240, 230, 140 },
112 { "lavender", 230, 230, 250 },
113 { "lavenderblush", 255, 240, 245 },
114 { "lawngreen", 124, 252, 0 },
115 { "lemonchiffon", 255, 250, 205 },
116 { "lightblue", 173, 216, 230 },
117 { "lightcoral", 240, 128, 128 },
118 { "lightcyan", 224, 255, 255 },
119 { "lightgoldenrodyellow", 250, 250, 210 },
120 { "lightgray", 211, 211, 211 },
121 { "lightgreen", 144, 238, 144 },
122 { "lightgrey", 211, 211, 211 },
123 { "lightpink", 255, 182, 193 },
124 { "lightsalmon", 255, 160, 122 },
125 { "lightseagreen", 32, 178, 170 },
126 { "lightskyblue", 135, 206, 250 },
127 { "lightslategray", 119, 136, 153 },
128 { "lightslategrey", 119, 136, 153 },
129 { "lightsteelblue", 176, 196, 222 },
130 { "lightyellow", 255, 255, 224 },
131 { "lime", 0, 255, 0 },
132 { "limegreen", 50, 205, 50 },
133 { "linen", 250, 240, 230 },
134 { "magenta", 255, 0, 255 },
135 { "maroon", 128, 0, 0 },
136 { "mediumaquamarine", 102, 205, 170 },
137 { "mediumblue", 0, 0, 205 },
138 { "mediumorchid", 186, 85, 211 },
139 { "mediumpurple", 147, 112, 219 },
140 { "mediumseagreen", 60, 179, 113 },
141 { "mediumslateblue", 123, 104, 238 },
142 { "mediumspringgreen", 0, 250, 154 },
143 { "mediumturquoise", 72, 209, 204 },
144 { "mediumvioletred", 199, 21, 133 },
145 { "midnightblue", 25, 25, 112 },
146 { "mintcream", 245, 255, 250 },
147 { "mistyrose", 255, 228, 225 },
148 { "moccasin", 255, 228, 181 },
149 { "navajowhite", 255, 222, 173 },
150 { "navy", 0, 0, 128 },
151 { "oldlace", 253, 245, 230 },
152 { "olive", 128, 128, 0 },
153 { "olivedrab", 107, 142, 35 },
154 { "orange", 255, 165, 0 },
155 { "orangered", 255, 69, 0 },
156 { "orchid", 218, 112, 214 },
157 { "palegoldenrod", 238, 232, 170 },
158 { "palegreen", 152, 251, 152 },
159 { "paleturquoise", 175, 238, 238 },
160 { "palevioletred", 219, 112, 147 },
161 { "papayawhip", 255, 239, 213 },
162 { "peachpuff", 255, 218, 185 },
163 { "peru", 205, 133, 63 },
164 { "pink", 255, 192, 203 },
165 { "plum", 221, 160, 221 },
166 { "powderblue", 176, 224, 230 },
167 { "purple", 128, 0, 128 },
168 { "red", 255, 0, 0 },
169 { "rosybrown", 188, 143, 143 },
170 { "royalblue", 65, 105, 225 },
171 { "saddlebrown", 139, 69, 19 },
172 { "salmon", 250, 128, 114 },
173 { "sandybrown", 244, 164, 96 },
174 { "seagreen", 46, 139, 87 },
175 { "seashell", 255, 245, 238 },
176 { "sienna", 160, 82, 45 },
177 { "silver", 192, 192, 192 },
178 { "skyblue", 135, 206, 235 },
179 { "slateblue", 106, 90, 205 },
180 { "slategray", 112, 128, 144 },
181 { "slategrey", 112, 128, 144 },
182 { "snow", 255, 250, 250 },
183 { "springgreen", 0, 255, 127 },
184 { "steelblue", 70, 130, 180 },
185 { "tan", 210, 180, 140 },
186 { "teal", 0, 128, 128 },
187 { "thistle", 216, 191, 216 },
188 { "tomato", 255, 99, 71 },
189 { "turquoise", 64, 224, 208 },
190 { "violet", 238, 130, 238 },
191 { "wheat", 245, 222, 179 },
192 { "white", 255, 255, 255 },
193 { "whitesmoke", 245, 245, 245 },
194 { "yellow", 255, 255, 0 },
195 { "yellowgreen", 154, 205, 50 }
196 };
197
198
color_compare(const void * a,const void * b)199 static int color_compare (const void * a, const void * b)
200 {
201 const char * name = static_cast<const char *>(a);
202 const colorToRGBMapping * id = static_cast<const colorToRGBMapping *>(b);
203
204 return g_ascii_strcasecmp (name, id->m_name);
205 }
206
207
x_hexDigit(char c)208 static int x_hexDigit(char c)
209 {
210 if ((c>='0') && (c<='9'))
211 {
212 return c-'0';
213 }
214
215 if ((c>='a') && (c<='f'))
216 {
217 return c - 'a' + 10;
218 }
219
220 if ((c>='A') && (c<='F'))
221 {
222 return c - 'A' + 10;
223 }
224
225 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
226
227 return 0;
228 }
229
UT_HashColor()230 UT_HashColor::UT_HashColor ()
231 {
232 m_colorBuffer[0] = 0;
233 }
234
~UT_HashColor()235 UT_HashColor::~UT_HashColor ()
236 {
237 //
238 }
239
setColor(const char * color)240 const char * UT_HashColor::setColor (const char * color)
241 {
242 m_colorBuffer[0] = 0;
243 if (color == 0) return 0;
244
245 if (color[0] == '#') return setHashIfValid (color + 1);
246
247 return lookupNamedColor (color);
248 }
249
setColor(unsigned char r,unsigned char g,unsigned char b)250 const char * UT_HashColor::setColor (unsigned char r, unsigned char g, unsigned char b)
251 {
252 static const char hexval[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
253
254 m_colorBuffer[0] = '#';
255 m_colorBuffer[1] = hexval[(r >> 4) & 0x0f];
256 m_colorBuffer[2] = hexval[ r & 0x0f];
257 m_colorBuffer[3] = hexval[(g >> 4) & 0x0f];
258 m_colorBuffer[4] = hexval[ g & 0x0f];
259 m_colorBuffer[5] = hexval[(b >> 4) & 0x0f];
260 m_colorBuffer[6] = hexval[ b & 0x0f];
261 m_colorBuffer[7] = 0;
262
263 return static_cast<const char *>(m_colorBuffer);
264 }
265
lookupNamedColor(const char * color_name)266 const char * UT_HashColor::lookupNamedColor (const char * color_name)
267 {
268 m_colorBuffer[0] = 0;
269 if (color_name == 0) return 0;
270
271 size_t length = sizeof (s_Colors) / sizeof (s_Colors[0]);
272
273 colorToRGBMapping * id = 0;
274 id = static_cast<colorToRGBMapping *>(bsearch (color_name, s_Colors, static_cast<int>(length), sizeof (colorToRGBMapping), color_compare));
275
276 if (id == 0) return 0;
277
278 return setColor (id->m_red, id->m_green, id->m_blue);
279 }
280
setHashIfValid(const char * color_hash)281 const char * UT_HashColor::setHashIfValid (const char * color_hash)
282 {
283 m_colorBuffer[0] = 0;
284 if (color_hash == 0) return 0;
285
286 bool isValid = true;
287 for (int i = 0; i < 6; i++)
288 {
289 switch (color_hash[i])
290 {
291 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
292 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
293 m_colorBuffer[i+1] = color_hash[i];
294 break;
295 case 'A': m_colorBuffer[i+1] = 'a'; break;
296 case 'B': m_colorBuffer[i+1] = 'b'; break;
297 case 'C': m_colorBuffer[i+1] = 'c'; break;
298 case 'D': m_colorBuffer[i+1] = 'd'; break;
299 case 'E': m_colorBuffer[i+1] = 'e'; break;
300 case 'F': m_colorBuffer[i+1] = 'f'; break;
301 default:
302 isValid = false;
303 break;
304 }
305 if (!isValid) break;
306 }
307 if (!isValid) return 0;
308
309 m_colorBuffer[0] = '#';
310 m_colorBuffer[7] = 0;
311
312 return static_cast<const char *>(m_colorBuffer);
313 }
314
rgb()315 const UT_RGBColor UT_HashColor::rgb ()
316 {
317 unsigned char r = 0;
318 unsigned char g = 0;
319 unsigned char b = 0;
320
321 if (m_colorBuffer[0])
322 {
323 r = static_cast<unsigned char>(x_hexDigit (m_colorBuffer[1]) << 4) | static_cast<unsigned char>(x_hexDigit (m_colorBuffer[2]));
324 g = static_cast<unsigned char>(x_hexDigit (m_colorBuffer[3]) << 4) | static_cast<unsigned char>(x_hexDigit (m_colorBuffer[4]));
325 b = static_cast<unsigned char>(x_hexDigit (m_colorBuffer[5]) << 4) | static_cast<unsigned char>(x_hexDigit (m_colorBuffer[6]));
326 }
327
328 return UT_RGBColor (r, g, b);
329 }
330
parseColorToNextDelim(const char * p,UT_uint32 & index)331 static int parseColorToNextDelim ( const char * p, UT_uint32 & index )
332 {
333 char buffer[7] = "" ;
334 index = 0 ;
335
336 while (isdigit(*p))
337 {
338 buffer[index++] = *p++;
339 }
340 buffer[index] = 0;
341 return atoi(buffer);
342 }
343
UT_parseGrayColor(const char * p,UT_RGBColor & c)344 static void UT_parseGrayColor(const char *p, UT_RGBColor& c)
345 {
346 UT_DEBUGMSG(("DOM: parsing gray value\n"));
347
348 int grayVal = 0 ;
349
350 p+=5; // go past gray(
351
352 UT_uint32 index = 0;
353 grayVal= parseColorToNextDelim ( p, index ) ;
354
355 c.m_red = grayVal;
356 c.m_grn = grayVal;
357 c.m_blu = grayVal;
358 }
359
UT_parseCMYKColor(const char * p,UT_RGBColor & c)360 static void UT_parseCMYKColor(const char *p, UT_RGBColor& c)
361 {
362 // yes, i know that CMYK->RGB is lossy... DAL
363 // WARNING: !!!!UNTESTED!!!!
364
365 UT_DEBUGMSG(("DOM: parsing CMYK value!!\n"));
366
367 int cyanVal = 0;
368 int magentaVal = 0;
369 int yellowVal = 0;
370 int kVal = 0;
371
372 p += 5; // advance past "CMYK("
373
374 UT_uint32 index = 0;
375
376 cyanVal = parseColorToNextDelim ( p, index ) ;
377 p+=(index+1); index = 0;
378
379 magentaVal = parseColorToNextDelim ( p, index ) ;
380 p+=(index+1); index = 0;
381
382 yellowVal = parseColorToNextDelim ( p, index ) ;
383 p+=(index+1); index = 0;
384
385 kVal = parseColorToNextDelim ( p, index ) ;
386
387 int cPlusK = cyanVal + kVal;
388 int mPlusK = magentaVal + kVal;
389 int yPlusK = yellowVal + kVal;
390
391 if (cPlusK < 255)
392 c.m_red = 255 - cPlusK;
393
394 if (mPlusK < 255)
395 c.m_grn = 255 - mPlusK;
396
397 if (yPlusK < 255)
398 c.m_blu = 255 - yPlusK;
399
400 UT_DEBUGMSG(("DOM: CMYK (%d %d %d %d) -> RGB (%d %d %d)!!\n",
401 cyanVal, magentaVal, yellowVal, kVal,
402 c.m_red, c.m_grn, c.m_blu));
403 }
404
405
~UT_ColorPatImpl()406 UT_ColorPatImpl::~UT_ColorPatImpl()
407 {
408 }
409
410
UT_RGBColor()411 UT_RGBColor::UT_RGBColor()
412 : m_patImpl(NULL)
413 {
414 m_red = 0;
415 m_grn = 0;
416 m_blu = 0;
417 m_bIsTransparent = false;
418 }
419
UT_RGBColor(unsigned char red,unsigned char grn,unsigned char blu,bool bTransparent)420 UT_RGBColor::UT_RGBColor(unsigned char red, unsigned char grn, unsigned char blu, bool bTransparent)
421 : m_patImpl(NULL)
422 {
423 m_red = red;
424 m_grn = grn;
425 m_blu = blu;
426 m_bIsTransparent = bTransparent;
427 }
428
UT_RGBColor(const UT_RGBColor & c)429 UT_RGBColor::UT_RGBColor(const UT_RGBColor &c)
430 {
431 m_red = c.m_red;
432 m_grn = c.m_grn;
433 m_blu = c.m_blu;
434 m_bIsTransparent = c.m_bIsTransparent;
435 m_patImpl = ( c.m_patImpl ? c.m_patImpl->clone() : NULL );
436 }
437
UT_RGBColor(const UT_ColorPatImpl * pat)438 UT_RGBColor::UT_RGBColor(const UT_ColorPatImpl * pat)
439 : m_red(0)
440 , m_grn(0)
441 , m_blu(0)
442 , m_bIsTransparent(false)
443 , m_patImpl(pat)
444 {
445 }
446
447
~UT_RGBColor()448 UT_RGBColor::~UT_RGBColor()
449 {
450 DELETEP(m_patImpl);
451 }
452
453
operator =(const UT_RGBColor & c)454 UT_RGBColor & UT_RGBColor::operator=(const UT_RGBColor &c)
455 {
456 m_red = c.m_red;
457 m_grn = c.m_grn;
458 m_blu = c.m_blu;
459 m_bIsTransparent = c.m_bIsTransparent;
460 if(m_patImpl) {
461 delete m_patImpl;
462 }
463 m_patImpl = ( c.m_patImpl ? c.m_patImpl->clone() : NULL );
464
465 return *this;
466 }
467
468
setColor(const char * pszColor)469 bool UT_RGBColor::setColor(const char * pszColor)
470 {
471 unsigned char r = m_red, g = m_grn, b = m_blu;
472
473 if(!pszColor || !strcmp(pszColor,"transparent") /* || !strcmp(pszColor,"ffffff") */)
474 {
475 m_red = m_grn = m_blu = 255;
476 m_bIsTransparent = true;
477 }
478 else
479 {
480 UT_parseColor(pszColor, *this);
481 m_bIsTransparent = false;
482 }
483
484 return (r != m_red || g != m_grn || b != m_blu);
485 }
486
487
UT_setColor(UT_RGBColor & col,unsigned char r,unsigned char g,unsigned char b,bool bTransparent)488 void UT_setColor(UT_RGBColor & col, unsigned char r, unsigned char g, unsigned char b, bool bTransparent)
489 {
490 col.m_red = r;
491 col.m_grn = g;
492 col.m_blu = b;
493 col.m_bIsTransparent = bTransparent;
494 }
495
UT_parseColor(const char * p,UT_RGBColor & c)496 void UT_parseColor(const char *p, UT_RGBColor& c)
497 {
498 UT_uint32 len = strlen (p);
499
500 if ( len > 7 && strncmp ( p, "cmyk(", 5 ) == 0 )
501 {
502 // CMYK color. parse that out
503 UT_parseCMYKColor ( p, c ) ;
504 return;
505 }
506
507 if ( len > 6 && strncmp ( p, "gray(", 5 ) == 0 )
508 {
509 // grayscale color. parse that out
510 UT_parseGrayColor ( p, c ) ;
511 return ;
512 }
513
514
515 if(!strcmp(p,"transparent") /* || !strcmp(p,"ffffff") */)
516 {
517 c.m_red = c.m_grn = c.m_blu = 255;
518 c.m_bIsTransparent = true;
519 return;
520 }
521
522 UT_HashColor hash;
523
524 if (hash.setColor (p))
525 {
526 c = hash.rgb ();
527 }
528 else if (hash.setHashIfValid (p))
529 {
530 c = hash.rgb ();
531 }
532 else
533 {
534 UT_DEBUGMSG(("String = %s \n",p));
535 UT_ASSERT(UT_NOT_IMPLEMENTED);
536 }
537
538 }
539
540 /*! This function takes in a color string of any form (e.g. "red", "CMYK()",
541 "#000000", "000000", etc.) and returns an RGB hexadecimal string.
542 \param szColor The incoming string to parse
543 \param bPrefix The return string will be prefixed with a '#'
544 if bPrefix is true. Defaults to false.
545 \return An RGB hexadecimal string or an empty string if szColor is empty
546
547 WARNING: Will return 000000 or #000000 if an invalid color is passed in
548 */
549
UT_colorToHex(const char * szColor,bool bPrefix)550 std::string UT_colorToHex(const char * szColor, bool bPrefix)
551 {
552 std::string sColor;
553 UT_return_val_if_fail(szColor && *szColor, sColor);
554
555 // This initialization will cause black to be returned if an invalid
556 // color is passed in. TODO: make UT_parseColor() return a bool to
557 // make this unnecessary?
558 UT_RGBColor color(0,0,0);
559 UT_HashColor hashColor;
560
561 UT_parseColor(szColor, color);
562 sColor = hashColor.setColor(color.m_red, color.m_grn, color.m_blu);
563
564 if(!bPrefix)
565 sColor.erase(0, 1);
566
567 return sColor;
568 }
569
570