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