1
2 /*
3 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
4 * All Rights Reserved
5 *
6 * This file is a component of an X Window System-specific implementation
7 * of Xcms based on the TekColor Color Management System. Permission is
8 * hereby granted to use, copy, modify, sell, and otherwise distribute this
9 * software and its documentation for any purpose and without fee, provided
10 * that this copyright, permission, and disclaimer notice is reproduced in
11 * all copies of this software and in supporting documentation. TekColor
12 * is a trademark of Tektronix, Inc.
13 *
14 * Tektronix makes no representation about the suitability of this software
15 * for any purpose. It is provided "as is" and with all faults.
16 *
17 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
18 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
20 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
22 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
24 *
25 * NAME
26 * XcmsColNm.c
27 *
28 * DESCRIPTION
29 * Source for _XcmsLookupColorName().
30 *
31 *
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 #include "Xlibint.h"
38 #include "Xcmsint.h"
39 #include <X11/Xos.h>
40 #include <sys/stat.h>
41 #include <stdio.h>
42 #include <ctype.h>
43 #include <limits.h>
44 #define XK_LATIN1
45 #include <X11/keysymdef.h>
46 #include "Cv.h"
47
48 /* forwards/locals */
49 static Status LoadColornameDB(void);
50
51
52 /*
53 * LOCAL DEFINES
54 * #define declarations local to this package.
55 */
56 #ifndef XCMSDB
57 #define XCMSDB XCMSDIR "/Xcms.txt"
58 #endif
59
60 #ifndef isgraph
61 # define isgraph(c) (isprint((c)) && !isspace((c)))
62 #endif
63
64 #ifndef XCMSDB_MAXLINELEN
65 # define XCMSDB_MAXLINELEN 256
66 #endif
67
68 #define FORMAT_VERSION "0.1"
69 #define START_TOKEN "XCMS_COLORDB_START"
70 #define END_TOKEN "XCMS_COLORDB_END"
71 #define DELIM_CHAR '\t'
72
73 #define NOT_VISITED 0x0
74 #define VISITED 0x1
75 #define CYCLE 0xFFFF
76 #define XcmsDbInitNone -1
77 #define XcmsDbInitFailure 0
78 #define XcmsDbInitSuccess 1
79
80 /*
81 * LOCAL TYPEDEFS
82 */
83 typedef struct _XcmsPair {
84 const char *first;
85 const char *second;
86 int flag;
87 } XcmsPair;
88
89 /*
90 * LOCAL VARIABLES
91 */
92 static int XcmsColorDbState = XcmsDbInitNone;
93 static int nEntries;
94 static char *strings;
95 static XcmsPair *pairs;
96 static const char whitePtStr[] = "WhitePoint";
97
98
99 /************************************************************************
100 * *
101 * PRIVATE ROUTINES *
102 * *
103 ************************************************************************/
104
105 /*
106 * NAME
107 * _XcmsColorSpaceOfString
108 *
109 * SYNOPSIS
110 */
111 static XcmsColorSpace *
_XcmsColorSpaceOfString(XcmsCCC ccc,const char * color_string)112 _XcmsColorSpaceOfString(
113 XcmsCCC ccc,
114 const char *color_string)
115 /*
116 * DESCRIPTION
117 * Returns a pointer to the color space structure
118 * (XcmsColorSpace) associated with the specified color string.
119 *
120 * RETURNS
121 * Pointer to matching XcmsColorSpace structure if found;
122 * otherwise NULL.
123 *
124 * CAVEATS
125 *
126 */
127 {
128 XcmsColorSpace **papColorSpaces;
129 size_t n;
130 char *pchar;
131
132 if ((pchar = strchr(color_string, ':')) == NULL) {
133 return(XcmsFailure);
134 }
135 n = (size_t)(pchar - color_string);
136
137 if (ccc == NULL) {
138 return(NULL);
139 }
140
141 /*
142 * First try Device-Independent color spaces
143 */
144 papColorSpaces = _XcmsDIColorSpaces;
145 if (papColorSpaces != NULL) {
146 while (*papColorSpaces != NULL) {
147 if (strncmp((*papColorSpaces)->prefix, color_string, n) == 0 &&
148 !((*papColorSpaces)->prefix)[n]) {
149 return(*papColorSpaces);
150 }
151 papColorSpaces++;
152 }
153 }
154
155 /*
156 * Next try Device-Dependent color spaces
157 */
158 papColorSpaces = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
159 if (papColorSpaces != NULL) {
160 while (*papColorSpaces != NULL) {
161 if (strncmp((*papColorSpaces)->prefix, color_string, n) == 0 &&
162 !((*papColorSpaces)->prefix)[n]) {
163 return(*papColorSpaces);
164 }
165 papColorSpaces++;
166 }
167 }
168
169 return(NULL);
170 }
171
172
173 /*
174 * NAME
175 * _XcmsParseColorString
176 *
177 * SYNOPSIS
178 */
179 static int
_XcmsParseColorString(XcmsCCC ccc,const char * color_string,XcmsColor * pColor)180 _XcmsParseColorString(
181 XcmsCCC ccc,
182 const char *color_string,
183 XcmsColor *pColor)
184 /*
185 * DESCRIPTION
186 * Assuming color_string contains a numerical string color
187 * specification, attempts to parse a string into an
188 * XcmsColor structure.
189 *
190 * RETURNS
191 * 0 if failed; otherwise non-zero.
192 *
193 * CAVEATS
194 * A color string containing a numerical color specification
195 * must be in ISO Latin-1 encoding!
196 */
197 {
198 XcmsColorSpace *pColorSpace;
199 char string_buf[64];
200 char *string_lowered;
201 size_t len;
202 int res;
203
204 if (ccc == NULL) {
205 return(0);
206 }
207
208 /*
209 * While copying color_string to string_lowered, convert to lowercase
210 */
211 if ((len = strlen(color_string)) >= sizeof(string_buf)) {
212 string_lowered = Xmalloc(len+1);
213 if (string_lowered == NULL)
214 return(XcmsFailure);
215 } else {
216 string_lowered = string_buf;
217 }
218
219 _XcmsCopyISOLatin1Lowered(string_lowered, color_string);
220
221 if (*string_lowered == '#') {
222 if ((pColorSpace = _XcmsColorSpaceOfString(ccc, "rgb:")) != NULL) {
223 res = (*pColorSpace->parseString)(string_lowered, pColor);
224 if (len >= sizeof(string_buf)) Xfree(string_lowered);
225 return res;
226 }
227 }
228
229 if ((pColorSpace = _XcmsColorSpaceOfString(ccc, string_lowered)) != NULL) {
230 res = (*pColorSpace->parseString)(string_lowered, pColor);
231 if (len >= sizeof(string_buf)) Xfree(string_lowered);
232 return res;
233 }
234
235 if (len >= sizeof(string_buf)) Xfree(string_lowered);
236 return(0);
237 }
238
239
240 /*
241 * NAME
242 * FirstCmp - Compare color names of pair recs
243 *
244 * SYNOPSIS
245 */
246 static int
FirstCmp(const void * p1,const void * p2)247 FirstCmp(const void *p1, const void *p2)
248 /*
249 * DESCRIPTION
250 * Compares the color names of XcmsColorTuples.
251 * This routine is public to allow access from qsort???.
252 *
253 * RETURNS
254 * 0 if equal;
255 * < 0 if first precedes second,
256 * > 0 if first succeeds second.
257 *
258 */
259 {
260 return(strcmp(((const XcmsPair *)p1)->first, ((const XcmsPair *)p2)->first));
261 }
262
263
264
265 /*
266 * NAME
267 * stringSectionSize - determine memory needed for strings
268 *
269 * SYNOPSIS
270 */
271 static void
SetNoVisit(void)272 SetNoVisit(void)
273 /*
274 * DESCRIPTION
275 *
276 * RETURNS
277 * void
278 *
279 */
280 {
281 int i;
282 XcmsPair *pair = pairs;
283
284 for (i = 0; i < nEntries; i++, pair++) {
285 if (pair->flag != CYCLE) {
286 pair->flag = NOT_VISITED;
287 }
288 }
289 }
290
291
292
293
294 /*
295 * NAME
296 * field2 - extract two fields
297 *
298 * SYNOPSIS
299 */
300 static int
field2(char * pBuf,char delim,char ** p1,char ** p2)301 field2(
302 char *pBuf,
303 char delim, /* in: field delimiter */
304 char **p1, /* in/out: pointer to pointer to field 1 */
305 char **p2) /* in/out: pointer to pointer to field 2 */
306 /*
307 * DESCRIPTION
308 * Extracts two fields from a "record".
309 *
310 * RETURNS
311 * XcmsSuccess if succeeded, otherwise XcmsFailure.
312 *
313 */
314 {
315 *p1 = *p2 = NULL;
316
317 /* Find Field 1 */
318 while (!isgraph(*pBuf)) {
319 if ((*pBuf == '\n') || (*pBuf == '\0')) {
320 return(XcmsFailure);
321 }
322 if (isspace(*pBuf) || (*pBuf == delim)) {
323 pBuf++;
324 }
325 }
326 *p1 = pBuf;
327
328 /* Find end of Field 2 */
329 while (isprint(*pBuf) && (*pBuf != delim)) {
330 pBuf++;
331 }
332 if ((*pBuf == '\n') || (*pBuf == '\0')) {
333 return(XcmsFailure);
334 }
335 if ((*pBuf == ' ') || (*pBuf == delim)) {
336 *pBuf++ = '\0'; /* stuff end of string character */
337 } else {
338 return(XcmsFailure);
339 }
340
341 /* Find Field 2 */
342 while (!isgraph(*pBuf)) {
343 if ((*pBuf == '\n') || (*pBuf == '\0')) {
344 return(XcmsFailure);
345 }
346 if (isspace(*pBuf) || (*pBuf == delim)) {
347 pBuf++;
348 }
349 }
350 *p2 = pBuf;
351
352 /* Find end of Field 2 */
353 while (isprint(*pBuf) && (*pBuf != delim)) {
354 pBuf++;
355 }
356 if (*pBuf != '\0') {
357 *pBuf = '\0'; /* stuff end of string character */
358 }
359
360 return(XcmsSuccess);
361 }
362
363
364 /*
365 * NAME
366 * _XcmsLookupColorName - Lookup DB entry for a color name
367 *
368 * SYNOPSIS
369 */
370 static Status
_XcmsLookupColorName(XcmsCCC ccc,const char ** name,XcmsColor * pColor)371 _XcmsLookupColorName(
372 XcmsCCC ccc,
373 const char **name,
374 XcmsColor *pColor)
375 /*
376 * DESCRIPTION
377 * Searches for an entry in the Device-Independent Color Name
378 * Database for the specified string.
379 *
380 * RETURNS
381 * XcmsFailure if failed to find a matching entry in
382 * the database.
383 * XcmsSuccess if succeeded in converting color name to
384 * XcmsColor.
385 * _XCMS_NEWNAME if succeeded in converting color string (which
386 * is a color name to yet another color name. Note
387 * that the new name is passed back via 'name'.
388 */
389 {
390 Status retval = 0;
391 char name_lowered_64[64];
392 char *name_lowered;
393 register int i, j, left, right;
394 int len;
395 const char *tmpName;
396 XcmsPair *pair = NULL;
397
398 /*
399 * Check state of Database:
400 * XcmsDbInitNone
401 * XcmsDbInitSuccess
402 * XcmsDbInitFailure
403 */
404 if (XcmsColorDbState == XcmsDbInitFailure) {
405 return(XcmsFailure);
406 }
407 if (XcmsColorDbState == XcmsDbInitNone) {
408 if (!LoadColornameDB()) {
409 return(XcmsFailure);
410 }
411 }
412
413 SetNoVisit();
414
415 /*
416 * While copying name to name_lowered, convert to lowercase
417 */
418
419 tmpName = *name;
420
421 Retry:
422 if ((len = (int)strlen(tmpName)) > 63) {
423 name_lowered = Xmalloc(len+1);
424 if (name_lowered == NULL)
425 return(XcmsFailure);
426 } else {
427 name_lowered = name_lowered_64;
428 }
429
430 _XcmsCopyISOLatin1Lowered(name_lowered, tmpName);
431
432 /*
433 * Now, remove spaces.
434 */
435 for (i = 0, j = 0; j < len; j++) {
436 if (!isspace(name_lowered[j])) {
437 name_lowered[i++] = name_lowered[j];
438 }
439 }
440 name_lowered[i] = '\0';
441
442 left = 0;
443 right = nEntries - 1;
444 while (left <= right) {
445 i = (left + right) >> 1;
446 pair = &pairs[i];
447 j = strcmp(name_lowered, pair->first);
448 if (j < 0)
449 right = i - 1;
450 else if (j > 0)
451 left = i + 1;
452 else {
453 break;
454 }
455 }
456 if (len > 63) Xfree(name_lowered);
457
458 if (left > right) {
459 if (retval == 2) {
460 if (*name != tmpName) {
461 *name = tmpName;
462 }
463 return(_XCMS_NEWNAME);
464 }
465 return(XcmsFailure);
466 }
467
468 if (pair->flag == CYCLE) {
469 return(XcmsFailure);
470 }
471 if (pair->flag == VISITED) {
472 pair->flag = CYCLE;
473 return(XcmsFailure);
474 }
475
476 if (_XcmsParseColorString(ccc, pair->second, pColor) == XcmsSuccess) {
477 /* f2 contains a numerical string specification */
478 return(XcmsSuccess);
479 } else {
480 /* f2 does not contain a numerical string specification */
481 tmpName = pair->second;
482 pair->flag = VISITED;
483 retval = 2;
484 goto Retry;
485 }
486 }
487
488
489 /*
490 * NAME
491 * RemoveSpaces
492 *
493 * SYNOPSIS
494 */
495 static int
RemoveSpaces(char * pString)496 RemoveSpaces(
497 char *pString)
498 /*
499 * DESCRIPTION
500 * Removes spaces from string.
501 *
502 * RETURNS
503 * Void
504 *
505 */
506 {
507 int i, count = 0;
508 char *cptr;
509
510 /* REMOVE SPACES */
511 cptr = pString;
512 for (i = (int)strlen(pString); i; i--, cptr++) {
513 if (!isspace(*cptr)) {
514 *pString++ = *cptr;
515 count++;
516 }
517 }
518 *pString = '\0';
519 return(count);
520 }
521
522
523 /*
524 * NAME
525 * stringSectionSize - determine memory needed for strings
526 *
527 * SYNOPSIS
528 */
529 static int
stringSectionSize(FILE * stream,int * pNumEntries,int * pSectionSize)530 stringSectionSize(
531 FILE *stream,
532 int *pNumEntries,
533 int *pSectionSize)
534 /*
535 * DESCRIPTION
536 * Determines the amount of memory required to store the
537 * color name strings and also the number of strings.
538 *
539 * RETURNS
540 * XcmsSuccess if succeeded, otherwise XcmsFailure.
541 *
542 */
543 {
544 char buf[XCMSDB_MAXLINELEN];
545 char token[XCMSDB_MAXLINELEN];
546 char token2[XCMSDB_MAXLINELEN];
547 char *pBuf;
548 char *f1;
549 char *f2;
550 size_t i;
551
552 unsigned int numEntries = 0;
553 unsigned int sectionSize = 0;
554
555 *pNumEntries = 0;
556 *pSectionSize = 0;
557
558 /*
559 * Advance to START_TOKEN
560 * Anything before is just considered as comments.
561 */
562
563 while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
564 if ((sscanf(buf, "%s %s", token, token2))
565 && (strcmp(token, START_TOKEN) == 0)) {
566 if (strcmp(token2, FORMAT_VERSION) != 0) {
567 /* text file not in the right format */
568 return(XcmsFailure);
569 }
570 break;
571 } /* else it was just a blank line or comment */
572 }
573
574 if (pBuf == NULL) {
575 return(XcmsFailure);
576 }
577
578 while((fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
579 if ((sscanf(buf, "%s", token)) && (strcmp(token, END_TOKEN) == 0)) {
580 break;
581 }
582
583 if (field2(buf, DELIM_CHAR, &f1, &f2) != XcmsSuccess) {
584 return(XcmsFailure);
585 }
586
587 numEntries++;
588 if (numEntries >= INT_MAX)
589 return(XcmsFailure);
590
591 i = strlen(f1);
592 if (i >= INT_MAX - sectionSize)
593 return(XcmsFailure);
594 sectionSize += i + 1;
595 for (; i; i--, f1++) {
596 /* REMOVE SPACES FROM COUNT */
597 if (isspace(*f1)) {
598 sectionSize--;
599 }
600 }
601
602 i = strlen(f2);
603 if (i >= INT_MAX - sectionSize)
604 return(XcmsFailure);
605 sectionSize += i + 1;
606 for (; i; i--, f2++) {
607 /* REMOVE SPACES FROM COUNT */
608 if (isspace(*f2)) {
609 sectionSize--;
610 }
611 }
612
613 }
614
615 *pNumEntries = (int) numEntries;
616 *pSectionSize = (int) sectionSize;
617
618 return(XcmsSuccess);
619 }
620
621
622 /*
623 * NAME
624 * ReadColornameDB - Read the Color Name Database
625 *
626 * SYNOPSIS
627 */
628 static Status
ReadColornameDB(FILE * stream,XcmsPair * pRec,char * pString)629 ReadColornameDB(
630 FILE *stream,
631 XcmsPair *pRec,
632 char *pString)
633 /*
634 * DESCRIPTION
635 * Loads the Color Name Database from a text file.
636 *
637 * RETURNS
638 * XcmsSuccess if succeeded, otherwise XcmsFailure.
639 *
640 */
641 {
642 char buf[XCMSDB_MAXLINELEN];
643 char token[XCMSDB_MAXLINELEN];
644 char token2[XCMSDB_MAXLINELEN];
645 char *f1;
646 char *f2;
647 char *pBuf;
648
649 /*
650 * Advance to START_TOKEN
651 * Anything before is just considered as comments.
652 */
653
654 while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
655 if ((sscanf(buf, "%s %s", token, token2))
656 && (strcmp(token, START_TOKEN) == 0)) {
657 if (strcmp(token2, FORMAT_VERSION) != 0) {
658 /* text file not in the right format */
659 return(XcmsFailure);
660 }
661 break;
662 } /* else it was just a blank line or comment */
663 }
664
665 if (pBuf == NULL) {
666 return(XcmsFailure);
667 }
668
669 /*
670 * Process lines between START_TOKEN to END_TOKEN
671 */
672
673 while ((fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) {
674 if ((sscanf(buf, "%s", token)) && (strcmp(token, END_TOKEN) == 0)) {
675 /*
676 * Found END_TOKEN so break out of for loop
677 */
678 break;
679 }
680
681 /*
682 * Get pairs
683 */
684 if (field2(buf, DELIM_CHAR, &f1, &f2) != XcmsSuccess) {
685 /* Invalid line */
686 continue;
687 }
688
689 /*
690 * Add strings
691 */
692
693 /* Left String */
694 pRec->first = pString;
695 _XcmsCopyISOLatin1Lowered(pString, f1);
696 pString += (1 + RemoveSpaces(pString));
697 pRec->second = pString;
698 /* Right String */
699 _XcmsCopyISOLatin1Lowered(pString, f2);
700 pString += RemoveSpaces(pString) + 1;
701 pRec++;
702
703 }
704
705 return(XcmsSuccess);
706 }
707
708
709 /*
710 * NAME
711 * LoadColornameDB - Load the Color Name Database
712 *
713 * SYNOPSIS
714 */
715 static Status
LoadColornameDB(void)716 LoadColornameDB(void)
717 /*
718 * DESCRIPTION
719 * Loads the Color Name Database from a text file.
720 *
721 * RETURNS
722 * XcmsSuccess if succeeded, otherwise XcmsFailure.
723 *
724 */
725 {
726 int size;
727 FILE *stream;
728 const char *pathname;
729 struct stat txt;
730 int length;
731
732 /* use and name of this env var is not part of the standard */
733 /* implementation-dependent feature */
734 if ((pathname = getenv("XCMSDB")) == NULL) {
735 pathname = XCMSDB;
736 }
737 #ifdef __UNIXOS2__
738 pathname = __XOS2RedirRoot(pathname);
739 #endif
740
741 length = (int)strlen(pathname);
742 if ((length == 0) || (length >= (BUFSIZ - 5))){
743 XcmsColorDbState = XcmsDbInitFailure;
744 return(XcmsFailure);
745 }
746
747 if (stat(pathname, &txt)) {
748 /* can't stat file */
749 XcmsColorDbState = XcmsDbInitFailure;
750 return(XcmsFailure);
751 }
752
753 if ((stream = _XFopenFile (pathname, "r")) == NULL) {
754 /* can't open file */
755 XcmsColorDbState = XcmsDbInitFailure;
756 return(XcmsFailure);
757 }
758
759 if (stringSectionSize(stream, &nEntries, &size) != XcmsSuccess ||
760 nEntries == 0) {
761 (void) fclose(stream);
762 XcmsColorDbState = XcmsDbInitFailure;
763 return(XcmsFailure);
764 }
765 rewind(stream);
766
767 strings = Xmalloc(size);
768 pairs = Xcalloc(nEntries, sizeof(XcmsPair));
769 if (strings == NULL || pairs == NULL) {
770 free(strings);
771 free(pairs);
772 (void) fclose(stream);
773 XcmsColorDbState = XcmsDbInitFailure;
774 return(XcmsFailure);
775 }
776
777 ReadColornameDB(stream, pairs, strings);
778 (void) fclose(stream);
779
780 /*
781 * sort the pair recs
782 */
783 qsort((char *)pairs, nEntries, sizeof(XcmsPair), FirstCmp);
784
785 XcmsColorDbState = XcmsDbInitSuccess;
786 return(XcmsSuccess);
787 }
788
789
790 /************************************************************************
791 * *
792 * API PRIVATE ROUTINES *
793 * *
794 ************************************************************************/
795
796 /*
797 * NAME
798 * _XcmsCopyISOLatin1Lowered
799 *
800 * SYNOPSIS
801 */
802 void
_XcmsCopyISOLatin1Lowered(char * dst,const char * src)803 _XcmsCopyISOLatin1Lowered(
804 char *dst,
805 const char *src)
806 /*
807 * DESCRIPTION
808 * ISO Latin-1 case conversion routine
809 * Identical to XmuCopyISOLatin1Lowered() but provided here
810 * to eliminate need to link with libXmu.a.
811 *
812 * IMPLEMENTORS NOTE:
813 * This routine is also used in XcmsFormatOfPrefix.
814 *
815 * RETURNS
816 * Void
817 *
818 */
819 {
820 register unsigned char *dest;
821 register const unsigned char *source;
822
823 for (dest = (unsigned char *)dst, source = (const unsigned char *)src;
824 *source;
825 source++, dest++)
826 {
827 if ((*source >= XK_A) && (*source <= XK_Z))
828 *dest = *source + (XK_a - XK_A);
829 else if ((*source >= XK_Agrave) && (*source <= XK_Odiaeresis))
830 *dest = *source + (XK_agrave - XK_Agrave);
831 else if ((*source >= XK_Ooblique) && (*source <= XK_Thorn))
832 *dest = *source + (XK_oslash - XK_Ooblique);
833 else
834 *dest = *source;
835 }
836 *dest = '\0';
837 }
838
839
840 /*
841 * NAME
842 * _XcmsResolveColorString -
843 *
844 * SYNOPSIS
845 */
846 Status
_XcmsResolveColorString(XcmsCCC ccc,const char ** color_string,XcmsColor * pColor_exact_return,XcmsColorFormat result_format)847 _XcmsResolveColorString (
848 XcmsCCC ccc,
849 const char **color_string,
850 XcmsColor *pColor_exact_return,
851 XcmsColorFormat result_format)
852 /*
853 * DESCRIPTION
854 * The XcmsLookupColor function finds the color specification
855 * associated with a color name in the Device-Independent Color
856 * Name Database.
857 * RETURNS
858 * XcmsFailure if failed to convert valid color string.
859 * XcmsSuccess if succeeded in converting color string to
860 * XcmsColor.
861 * _XCMS_NEWNAME if failed to parse the string or find it in
862 * the database, or if succeeded in looking it up and
863 * found another name which is not in the database.
864 * Note that the new name is returned in color_string.
865 *
866 * This function returns both the color specification found in the
867 * database (db specification) and the color specification for the
868 * color displayable by the specified screen (screen
869 * specification). The calling routine sets the format for these
870 * returned specifications in the XcmsColor format component.
871 * If XcmsUndefinedFormat, the specification is returned in the
872 * format used to store the color in the database.
873 */
874 {
875 XcmsColor dbWhitePt; /* whitePt associated with pColor_exact_return*/
876 /* the screen's white point */
877 XcmsColor *pClientWhitePt;
878 int retval;
879 const char *strptr = whitePtStr;
880
881 /*
882 * 0. Check for invalid arguments.
883 */
884 if (ccc == NULL || (*color_string)[0] == '\0' || pColor_exact_return == NULL) {
885 return(XcmsFailure);
886 }
887
888 /*
889 * 1. First attempt to parse the string
890 * If successful, then convert the specification to the target format
891 * and return.
892 */
893 if (_XcmsParseColorString(ccc, *color_string, pColor_exact_return)
894 == 1) {
895 if (result_format != XcmsUndefinedFormat
896 && pColor_exact_return->format != result_format) {
897 /* need to be converted to the target format */
898 return(XcmsConvertColors(ccc, pColor_exact_return, 1,
899 result_format, (Bool *)NULL));
900 } else {
901 return(XcmsSuccess);
902 }
903 }
904
905 /*
906 * 2. Attempt to find it in the DI Color Name Database
907 */
908
909 /*
910 * a. Convert String into a XcmsColor structure
911 * Attempt to extract the specification for color_string from the
912 * DI Database (pColor_exact_return). If the DI Database does not
913 * have this entry, then return failure.
914 */
915 retval = _XcmsLookupColorName(ccc, color_string, pColor_exact_return);
916
917 if (retval != XcmsSuccess) {
918 /* color_string replaced with a color name, or not found */
919 return(_XCMS_NEWNAME);
920 }
921
922 if (pColor_exact_return->format == XcmsUndefinedFormat) {
923 return(XcmsFailure);
924 }
925
926 /*
927 * b. If result_format not defined, then assume target format
928 * is the exact format.
929 */
930 if (result_format == XcmsUndefinedFormat) {
931 result_format = pColor_exact_return->format;
932 }
933
934 if ((ClientWhitePointOfCCC(ccc))->format == XcmsUndefinedFormat) {
935 pClientWhitePt = ScreenWhitePointOfCCC(ccc);
936 } else {
937 pClientWhitePt = ClientWhitePointOfCCC(ccc);
938 }
939
940 /*
941 * c. Convert to the target format, making adjustments for white
942 * point differences as necessary.
943 */
944 if (XCMS_DD_ID(pColor_exact_return->format)) {
945 /*
946 * The spec format is Device-Dependent, therefore assume the
947 * its white point is the Screen White Point.
948 */
949 if (XCMS_DD_ID(result_format)) {
950 /*
951 * Target format is Device-Dependent
952 * Therefore, DD --> DD conversion
953 */
954 return(_XcmsDDConvertColors(ccc, pColor_exact_return,
955 1, result_format, (Bool *) NULL));
956 } else {
957 /*
958 * Target format is Device-Independent
959 * Therefore, DD --> DI conversion
960 */
961 if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
962 pClientWhitePt, ScreenWhitePointOfCCC(ccc))) {
963 return((*ccc->whitePtAdjProc)(ccc, ScreenWhitePointOfCCC(ccc),
964 pClientWhitePt, result_format,
965 pColor_exact_return, 1, (Bool *) NULL));
966 } else {
967 if (_XcmsDDConvertColors(ccc, pColor_exact_return, 1,
968 XcmsCIEXYZFormat, (Bool *) NULL) == XcmsFailure) {
969 return(XcmsFailure);
970 }
971 return(_XcmsDIConvertColors(ccc, pColor_exact_return,
972 pClientWhitePt, 1, result_format));
973 }
974 }
975 } else {
976 /*
977 * The spec format is Device-Independent, therefore attempt
978 * to find a database white point.
979 *
980 * If the Database does not have a white point, then assume the
981 * database white point is the same as the Screen White Point.
982 */
983
984 if (_XcmsLookupColorName(ccc, &strptr, &dbWhitePt) != 1) {
985 memcpy((char *)&dbWhitePt,
986 (char *)&ccc->pPerScrnInfo->screenWhitePt,
987 sizeof(XcmsColor));
988 }
989 if (XCMS_DD_ID(result_format)) {
990 /*
991 * Target format is Device-Dependent
992 * Therefore, DI --> DD conversion
993 */
994 if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
995 &dbWhitePt, ScreenWhitePointOfCCC(ccc))) {
996 return((*ccc->whitePtAdjProc)(ccc, &dbWhitePt,
997 ScreenWhitePointOfCCC(ccc), result_format,
998 pColor_exact_return, 1, (Bool *)NULL));
999 } else {
1000 if (pColor_exact_return->format != XcmsCIEXYZFormat) {
1001 if (_XcmsDIConvertColors(ccc, pColor_exact_return,
1002 &dbWhitePt, 1, XcmsCIEXYZFormat) == XcmsFailure) {
1003 return(XcmsFailure);
1004 }
1005 }
1006 return (_XcmsDDConvertColors(ccc, pColor_exact_return, 1,
1007 result_format, (Bool *)NULL));
1008 }
1009 } else {
1010 /*
1011 * Target format is Device-Independent
1012 * Therefore, DI --> DI conversion
1013 */
1014 if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc,
1015 &dbWhitePt, pClientWhitePt)) {
1016 /*
1017 * The calling routine wants to resolve this color
1018 * in terms if it's white point (i.e. Client White Point).
1019 * Therefore, apply white adjustment for the displacement
1020 * between dbWhitePt to clientWhitePt.
1021 */
1022 return((*ccc->whitePtAdjProc)(ccc, &dbWhitePt,
1023 pClientWhitePt, result_format,
1024 pColor_exact_return, 1, (Bool *)NULL));
1025 } else if (_XcmsEqualWhitePts(ccc,
1026 &dbWhitePt, pClientWhitePt)) {
1027 /*
1028 * Can use either dbWhitePt or pClientWhitePt to
1029 * convert to the result_format.
1030 */
1031 if (pColor_exact_return->format == result_format) {
1032 return(XcmsSuccess);
1033 } else {
1034 return (_XcmsDIConvertColors(ccc, pColor_exact_return,
1035 &dbWhitePt, 1, result_format));
1036 }
1037 } else {
1038 /*
1039 * Need to convert to a white point independent color
1040 * space (let's choose CIEXYZ) then convert to the
1041 * target color space. Why? Lets assume that
1042 * pColor_exact_return->format and result format
1043 * are white point dependent format (e.g., CIELUV, CIELAB,
1044 * TekHVC ... same or any combination). If so, we'll
1045 * need to convert the color with dbWhitePt to an absolute
1046 * spec (i.e. non-white point dependent) then convert that
1047 * absolute value with clientWhitePt to the result_format.
1048 */
1049 if (pColor_exact_return->format != XcmsCIEXYZFormat) {
1050 if (_XcmsDIConvertColors(ccc, pColor_exact_return,
1051 &dbWhitePt, 1, XcmsCIEXYZFormat) == XcmsFailure) {
1052 return(XcmsFailure);
1053 }
1054 }
1055 if (result_format == XcmsCIEXYZFormat) {
1056 return(XcmsSuccess);
1057 } else {
1058 return(_XcmsDIConvertColors(ccc, pColor_exact_return,
1059 pClientWhitePt, 1, result_format));
1060 }
1061 }
1062 }
1063 }
1064 }
1065