cmsColNm.c revision 258a0ebe
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 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 */ 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 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 */ 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(((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 */ 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 = 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 */ 495static int 496RemoveSpaces( 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 = 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 */ 529static int 530stringSectionSize( 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 */ 628static Status 629ReadColornameDB( 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 */ 715static Status 716LoadColornameDB(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 = 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 */ 802void 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 */ 846Status 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