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