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