home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / evbl0627.zip / everblue_20010627.zip / x11 / Xcms_CvCols.c < prev    next >
C/C++ Source or Header  |  1999-11-02  |  29KB  |  1,059 lines

  1. /* $XConsortium: CvCols.c,v 1.12 93/09/07 21:30:32 rws Exp $" */
  2.  
  3. /*
  4.  * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
  5.  *     All Rights Reserved
  6.  * 
  7.  * This file is a component of an X Window System-specific implementation
  8.  * of Xcms based on the TekColor Color Management System.  Permission is
  9.  * hereby granted to use, copy, modify, sell, and otherwise distribute this
  10.  * software and its documentation for any purpose and without fee, provided
  11.  * that this copyright, permission, and disclaimer notice is reproduced in
  12.  * all copies of this software and in supporting documentation.  TekColor
  13.  * is a trademark of Tektronix, Inc.
  14.  * 
  15.  * Tektronix makes no representation about the suitability of this software
  16.  * for any purpose.  It is provided "as is" and with all faults.
  17.  * 
  18.  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
  19.  * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  20.  * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
  21.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  22.  * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
  23.  * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  24.  * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
  25.  *
  26.  *
  27.  *    NAME
  28.  *        XcmsCvCols.c
  29.  *
  30.  *    DESCRIPTION
  31.  *        Xcms API routine that converts between the
  32.  *        device-independent color spaces.
  33.  *
  34.  *
  35.  */
  36.  
  37. #include "Xlib_private.h"
  38. #include "Xcmsint.h"
  39.  
  40. /*
  41.  *      EXTERNS
  42.  *              External declarations required locally to this package
  43.  *              that are not already declared in any of the included header
  44.  *        files (external includes or internal includes).
  45.  */
  46. extern XcmsRegColorSpaceEntry _XcmsRegColorSpaces[];
  47. extern XcmsColorSpace **_XcmsDIColorSpaces;
  48. extern XcmsColorSpace **_XcmsDDColorSpaces;
  49.  
  50. /*
  51.  *      LOCAL DEFINES
  52.  */
  53. #define    DD_FORMAT    0x01
  54. #define    DI_FORMAT    0x02
  55. #define    MIX_FORMAT    0x04
  56. #ifndef MAX
  57. #  define MAX(x,y) ((x) > (y) ? (x) : (y))
  58. #endif
  59.  
  60. /*
  61.  *      FORWARD DECLARATIONS
  62.  */
  63. Status _XcmsDIConvertColors();
  64. Status _XcmsDDConvertColors();
  65.  
  66.  
  67. /************************************************************************
  68.  *                                    *
  69.  *             PRIVATE ROUTINES                *
  70.  *                                    *
  71.  ************************************************************************/
  72.  
  73. /*
  74.  *    NAME
  75.  *        EqualCIEXYZ
  76.  *
  77.  *    SYNOPSIS
  78.  */
  79. static int
  80. EqualCIEXYZ(p1, p2)
  81.     XcmsColor *p1, *p2;
  82. /*
  83.  *    DESCRIPTION
  84.  *        Compares two XcmsColor structures that are in XcmsCIEXYZFormat
  85.  *
  86.  *    RETURNS
  87.  *        Returns 1 if equal; 0 otherwise.
  88.  *
  89.  */
  90. {
  91.     DBUG_ENTER("EqualCIEXYZ")
  92.     if (p1->format != XcmsCIEXYZFormat || p2->format != XcmsCIEXYZFormat) {
  93.     DBUG_RETURN(0);
  94.     }
  95.     if ((p1->spec.CIEXYZ.X != p2->spec.CIEXYZ.X)
  96.         || (p1->spec.CIEXYZ.Y != p2->spec.CIEXYZ.Y)
  97.         || (p1->spec.CIEXYZ.Z != p2->spec.CIEXYZ.Z)) {
  98.     DBUG_RETURN(0);
  99.     }
  100.     DBUG_RETURN(1);
  101. }
  102.  
  103.  
  104. /*
  105.  *    NAME
  106.  *        XcmsColorSpace
  107.  *
  108.  *    SYNOPSIS
  109.  */
  110. static XcmsColorSpace *
  111. ColorSpaceOfID(ccc, id)
  112.     XcmsCCC ccc;
  113.     XcmsColorFormat    id;
  114. /*
  115.  *    DESCRIPTION
  116.  *        Returns a pointer to the color space structure
  117.  *        (XcmsColorSpace) associated with the specified color space
  118.  *        ID.
  119.  *
  120.  *    RETURNS
  121.  *        Pointer to matching XcmsColorSpace structure if found;
  122.  *        otherwise NULL.
  123.  */
  124. {
  125.     DBUG_ENTER("ColorSpaceOfID")
  126.     XcmsColorSpace    **papColorSpaces;
  127.  
  128.     if (ccc == NULL) {
  129.     DBUG_RETURN(NULL);
  130.     }
  131.  
  132.     /*
  133.      * First try Device-Independent color spaces
  134.      */
  135.     papColorSpaces = _XcmsDIColorSpaces;
  136.     if (papColorSpaces != NULL) {
  137.     while (*papColorSpaces != NULL) {
  138.         if ((*papColorSpaces)->id == id) {
  139.         DBUG_RETURN(*papColorSpaces);
  140.         }
  141.         papColorSpaces++;
  142.     }
  143.     }
  144.  
  145.     /*
  146.      * Next try Device-Dependent color spaces
  147.      */
  148.     papColorSpaces = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
  149.     if (papColorSpaces != NULL) {
  150.     while (*papColorSpaces != NULL) {
  151.         if ((*papColorSpaces)->id == id) {
  152.         DBUG_RETURN(*papColorSpaces);
  153.         }
  154.         papColorSpaces++;
  155.     }
  156.     }
  157.  
  158.     DBUG_RETURN(NULL);
  159. }
  160.  
  161.  
  162. /*
  163.  *    NAME
  164.  *        ValidDIColorSpaceID
  165.  *
  166.  *    SYNOPSIS
  167.  */
  168. static int
  169. ValidDIColorSpaceID(id)
  170.     XcmsColorFormat id;
  171. /*
  172.  *    DESCRIPTION
  173.  *        Determines if the specified color space ID is a valid
  174.  *        Device-Independent color space in the specified Color
  175.  *        Conversion Context.
  176.  *
  177.  *    RETURNS
  178.  *        Returns zero if not valid; otherwise non-zero.
  179.  */
  180. {
  181.     DBUG_ENTER("ValidDIColorSpaceID")
  182.     XcmsColorSpace **papRec;
  183.     papRec = _XcmsDIColorSpaces;
  184.     if (papRec != NULL) {
  185.     while (*papRec != NULL) {
  186.         if ((*papRec)->id == id) {
  187.         DBUG_RETURN(1);
  188.         }
  189.         papRec++;
  190.     }
  191.     }
  192.     DBUG_RETURN(0);
  193. }
  194.  
  195.  
  196. /*
  197.  *    NAME
  198.  *        ValidDDColorSpaceID
  199.  *
  200.  *    SYNOPSIS
  201.  */
  202. static int
  203. ValidDDColorSpaceID(ccc, id)
  204.     XcmsCCC ccc;
  205.     XcmsColorFormat id;
  206. /*
  207.  *    DESCRIPTION
  208.  *        Determines if the specified color space ID is a valid
  209.  *        Device-Dependent color space in the specified Color
  210.  *        Conversion Context.
  211.  *
  212.  *    RETURNS
  213.  *        Returns zero if not valid; otherwise non-zero.
  214.  */
  215. {
  216.     DBUG_ENTER("ValidDDColorSpaceID")
  217.     XcmsColorSpace **papRec;
  218.  
  219.     if (ccc->pPerScrnInfo->state != XcmsInitNone) {
  220.     papRec = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces;
  221.     while (*papRec != NULL) {
  222.         if ((*papRec)->id == id) {
  223.         DBUG_RETURN(1);
  224.         }
  225.         papRec++;
  226.     }
  227.     }
  228.     DBUG_RETURN(0);
  229. }
  230.  
  231.  
  232. /*
  233.  *    NAME
  234.  *        ConvertMixedColors - Convert XcmsColor structures
  235.  *
  236.  *    SYNOPSIS
  237.  */
  238. static Status
  239. ConvertMixedColors(ccc, pColors_in_out, pWhitePt, nColors,
  240.     targetFormat, format_flag)
  241.     XcmsCCC ccc;
  242.     XcmsColor *pColors_in_out;
  243.     XcmsColor *pWhitePt;
  244.     unsigned int nColors;
  245.     XcmsColorFormat targetFormat;
  246.     unsigned char format_flag;
  247. /*
  248.  *    DESCRIPTION
  249.  *        This routine will only convert the following types of
  250.  *        batches:
  251.  *            DI to DI
  252.  *            DD to DD
  253.  *            DD to CIEXYZ
  254.  *        In other words, it will not convert the following types of
  255.  *        batches:
  256.  *            DI to DD
  257.  *            DD to DI(not CIEXYZ)
  258.  *        
  259.  *        format_flag:
  260.  *            0x01 : convert Device-Dependent only specifications to the
  261.  *            target format.
  262.  *            0x02 : convert Device-Independent only specifications to the
  263.  *            target format.
  264.  *            0x03 : convert all specifications to the target format.
  265.  *
  266.  *    RETURNS
  267.  *        XcmsFailure if failed,
  268.  *        XcmsSuccess if none of the color specifications were
  269.  *            compressed in the conversion process
  270.  *        XcmsSuccessWithCompression if at least one of the
  271.  *            color specifications were compressed in the
  272.  *            conversion process.
  273.  *
  274.  */
  275. {
  276.     DBUG_ENTER("ConvertMixedColors")
  277.     XcmsColor *pColor, *pColors_start;
  278.     XcmsColorFormat format;
  279.     Status retval_tmp;
  280.     Status retval = XcmsSuccess;
  281.     unsigned int iColors;
  282.     unsigned int nBatch;
  283.  
  284.     /*
  285.      * Convert array of mixed color specifications in batches of
  286.      * contiguous formats to the target format
  287.      */
  288.     iColors = 0;
  289.     while (iColors < nColors) {
  290.     /*
  291.      * Find contiguous array of color specifications with the
  292.      * same format
  293.      */
  294.     pColor = pColors_start = pColors_in_out + iColors;
  295.     format = pColors_start->format;
  296.     nBatch = 0;
  297.     while (iColors < nColors && pColor->format == format) {
  298.         pColor++;
  299.         nBatch++;
  300.         iColors++;
  301.     }
  302.     if (format != targetFormat) {
  303.         /*
  304.          * Need to convert this batch from current format to target format.
  305.          */
  306.         if (XCMS_DI_ID(format) && (format_flag & DI_FORMAT) &&
  307.         XCMS_DI_ID(targetFormat)) {
  308.         /*
  309.          * DI->DI
  310.          *
  311.          * Format of interest is Device-Independent,
  312.          * This batch contains Device-Independent specifications, and
  313.          * the Target format is Device-Independent.
  314.          */
  315.         retval_tmp = _XcmsDIConvertColors(ccc, pColors_start, pWhitePt,
  316.             nBatch, targetFormat);
  317.         } else if (XCMS_DD_ID(format) && (format_flag & DD_FORMAT) &&
  318.             (targetFormat == XcmsCIEXYZFormat)) {
  319.         /*
  320.          * DD->CIEXYZ
  321.          *
  322.          * Format of interest is Device-Dependent,
  323.          * This batch contains Device-Dependent specifications, and
  324.          * the Target format is CIEXYZ.
  325.          *
  326.          * Since DD->CIEXYZ we can use NULL instead of pCompressed.
  327.          */
  328.         if ((ccc->whitePtAdjProc != NULL) && !_XcmsEqualWhitePts(ccc,
  329.             pWhitePt, ScreenWhitePointOfCCC(ccc))) {
  330.             /*
  331.              * Need to call WhiteAdjustProc (Screen White Point to
  332.              *   White Point).
  333.              */
  334.             retval_tmp = (*ccc->whitePtAdjProc)(ccc,
  335.                 ScreenWhitePointOfCCC(ccc), pWhitePt,
  336.                 XcmsCIEXYZFormat, pColors_start, nBatch,
  337.                 (Bool *)NULL);
  338.         } else {
  339.             retval_tmp = _XcmsDDConvertColors(ccc, pColors_start,
  340.                 nBatch, XcmsCIEXYZFormat, (Bool *)NULL);
  341.         }
  342.         } else if (XCMS_DD_ID(format) && (format_flag & DD_FORMAT) &&
  343.             XCMS_DD_ID(targetFormat)) {
  344.         /*
  345.          * DD->DD(not CIEXYZ)
  346.          *
  347.          * Format of interest is Device-Dependent,
  348.          * This batch contains Device-Dependent specifications, and
  349.          * the Target format is Device-Dependent and not CIEXYZ.
  350.          */
  351.         retval_tmp = _XcmsDDConvertColors(ccc, pColors_start, nBatch,
  352.             targetFormat, (Bool *)NULL);
  353.         } else {
  354.         /*
  355.          * This routine is called for the wrong reason.
  356.          */
  357.         DBUG_RETURN(XcmsFailure);
  358.         }
  359.         if (retval_tmp == XcmsFailure) {
  360.         DBUG_RETURN(XcmsFailure);
  361.         }
  362.         retval = MAX(retval, retval_tmp);
  363.     }
  364.     }
  365.     DBUG_RETURN(retval);
  366. }
  367.  
  368.  
  369. /************************************************************************
  370.  *                                    *
  371.  *             API PRIVATE ROUTINES                *
  372.  *                                    *
  373.  ************************************************************************/
  374.  
  375. /*
  376.  *    NAME
  377.  *        _XcmsEqualWhitePts
  378.  *
  379.  *    SYNOPSIS
  380.  */
  381. int
  382. _XcmsEqualWhitePts(ccc, pWhitePt1, pWhitePt2)
  383.     XcmsCCC ccc;
  384.     XcmsColor *pWhitePt1, *pWhitePt2;
  385. /*
  386.  *    DESCRIPTION
  387.  *
  388.  *    RETURNS
  389.  *        Returns 0 if not equal; otherwise 1.
  390.  *
  391.  */
  392. {
  393.     DBUG_ENTER("_XcmsEqualWhitePts")
  394.     XcmsColor tmp1, tmp2;
  395.  
  396.     memcpy((char *)&tmp1, (char *)pWhitePt1, sizeof(XcmsColor));
  397.     memcpy((char *)&tmp2, (char *)pWhitePt2, sizeof(XcmsColor));
  398.  
  399.     if (tmp1.format != XcmsCIEXYZFormat) {
  400.     if (_XcmsDIConvertColors(ccc, &tmp1, (XcmsColor *) NULL, 1,
  401.         XcmsCIEXYZFormat)==0) {
  402.         DBUG_RETURN(0);
  403.     }
  404.     }
  405.  
  406.     if (tmp2.format != XcmsCIEXYZFormat) {
  407.     if (_XcmsDIConvertColors(ccc, &tmp2, (XcmsColor *) NULL, 1,
  408.         XcmsCIEXYZFormat)==0) {
  409.         DBUG_RETURN(0);
  410.     }
  411.     }
  412.  
  413.     DBUG_RETURN(EqualCIEXYZ(&tmp1, &tmp2));
  414. }
  415.  
  416.  
  417. /*
  418.  *    NAME
  419.  *        _XcmsDIConvertColors - Convert XcmsColor structures
  420.  *
  421.  *    SYNOPSIS
  422.  */
  423. Status
  424. _XcmsDIConvertColors(ccc, pColors_in_out, pWhitePt, nColors,
  425.     newFormat)
  426.     XcmsCCC ccc;
  427.     XcmsColor *pColors_in_out;
  428.     XcmsColor *pWhitePt;
  429.     unsigned int nColors;
  430.     XcmsColorFormat newFormat;
  431. /*
  432.  *    DESCRIPTION
  433.  *        Convert XcmsColor structures to another Device-Independent
  434.  *        form.
  435.  *
  436.  *        Here are some assumptions that this routine makes:
  437.  *        1. The calling routine has already checked if
  438.  *            pColors_in_out->format == newFormat, therefore
  439.  *            there is no need to check again here.
  440.  *        2. The calling routine has already checked nColors,
  441.  *            therefore this routine assumes nColors > 0.
  442.  *        3. The calling routine may want to convert only between
  443.  *            CIExyY <-> CIEXYZ <-> CIEuvY
  444.  *            therefore, this routine allows pWhitePt to equal NULL.
  445.  *        
  446.  *
  447.  *    RETURNS
  448.  *        XcmsFailure if failed,
  449.  *        XcmsSuccess if succeeded.
  450.  *
  451.  */
  452. {
  453.     DBUG_ENTER("_XcmsDIConvertColors")
  454.     XcmsColorSpace *pFrom, *pTo;
  455.     XcmsConversionProc *src_to_CIEXYZ, *src_from_CIEXYZ;
  456.     XcmsConversionProc *dest_to_CIEXYZ, *dest_from_CIEXYZ;
  457.     XcmsConversionProc *to_CIEXYZ_stop, *from_CIEXYZ_start;
  458.     XcmsConversionProc *tmp;
  459.  
  460.     /*
  461.      * Allow pWhitePt to equal NULL.  This appropriate when converting
  462.      *    anywhere between:
  463.      *        CIExyY <-> CIEXYZ <-> CIEuvY
  464.      */
  465.  
  466.     if (pColors_in_out == NULL ||
  467.         !ValidDIColorSpaceID(pColors_in_out->format) ||
  468.         !ValidDIColorSpaceID(newFormat)) {
  469.     DBUG_RETURN(XcmsFailure);
  470.     }
  471.  
  472.     /*
  473.      * Get a handle on the function list for the current specification format
  474.      */
  475.     if ((pFrom = ColorSpaceOfID(ccc, pColors_in_out->format))
  476.         == NULL) {
  477.     DBUG_RETURN(XcmsFailure);
  478.     }
  479.  
  480.     /*
  481.      * Get a handle on the function list for the new specification format
  482.      */
  483.     if ((pTo = ColorSpaceOfID(ccc, newFormat)) == NULL) {
  484.     DBUG_RETURN(XcmsFailure);
  485.     }
  486.  
  487.     src_to_CIEXYZ = pFrom->to_CIEXYZ;
  488.     src_from_CIEXYZ = pFrom->from_CIEXYZ;
  489.     dest_to_CIEXYZ = pTo->to_CIEXYZ;
  490.     dest_from_CIEXYZ = pTo->from_CIEXYZ;
  491.  
  492.     if (pTo->inverse_flag && pFrom->inverse_flag) {
  493.     /*
  494.      * Find common function pointers
  495.      */
  496.     for (to_CIEXYZ_stop = src_to_CIEXYZ; *to_CIEXYZ_stop; to_CIEXYZ_stop++){
  497.         for (tmp = dest_to_CIEXYZ; *tmp; tmp++) {
  498.         if (*to_CIEXYZ_stop == *tmp) {
  499.             goto Continue;
  500.         }
  501.         }
  502.     }
  503.  
  504. Continue:
  505.  
  506.     /*
  507.      * Execute the functions to CIEXYZ, stopping short as necessary
  508.      */
  509.     while (src_to_CIEXYZ != to_CIEXYZ_stop) {
  510.         if ((*src_to_CIEXYZ++)(ccc, pWhitePt, pColors_in_out,
  511.             nColors) == XcmsFailure) {
  512.         DBUG_RETURN(XcmsFailure);
  513.         }
  514.     }
  515.  
  516.     /*
  517.      * Determine where to start on the from_CIEXYZ path.
  518.      */
  519.     from_CIEXYZ_start = dest_from_CIEXYZ;
  520.     tmp = src_from_CIEXYZ;
  521.     while ((*from_CIEXYZ_start == *tmp) && (*from_CIEXYZ_start != NULL)) {
  522.         from_CIEXYZ_start++;
  523.         tmp++;
  524.     }
  525.  
  526.     } else {
  527.     /*
  528.      * The function in at least one of the Color Spaces are not
  529.      * complementary, i.e.,
  530.      *    for an i, 0 <= i < n elements
  531.      *    from_CIEXYZ[i] is not the inverse of to_CIEXYZ[i]
  532.      *    
  533.      * Execute the functions all the way to CIEXYZ
  534.      */
  535.     while (*src_to_CIEXYZ) {
  536.         if ((*src_to_CIEXYZ++)(ccc, pWhitePt, pColors_in_out,
  537.             nColors) == XcmsFailure) {
  538.         DBUG_RETURN(XcmsFailure);
  539.         }
  540.     }
  541.  
  542.     /*
  543.      * Determine where to start on the from_CIEXYZ path.
  544.      */
  545.     from_CIEXYZ_start = dest_from_CIEXYZ;
  546.     }
  547.  
  548.  
  549.     /*
  550.      * Execute the functions from CIEXYZ.
  551.      */
  552.     while (*from_CIEXYZ_start) {
  553.     if ((*from_CIEXYZ_start++)(ccc, pWhitePt, pColors_in_out,
  554.         nColors) == XcmsFailure) {
  555.         DBUG_RETURN(XcmsFailure);
  556.     }
  557.     }
  558.  
  559.     DBUG_RETURN(XcmsSuccess);
  560. }
  561.  
  562.  
  563. /*
  564.  *    NAME
  565.  *        _XcmsDDConvertColors - Convert XcmsColor structures
  566.  *
  567.  *    SYNOPSIS
  568.  */
  569. Status
  570. _XcmsDDConvertColors(ccc, pColors_in_out, nColors, newFormat,
  571.     pCompressed)
  572.     XcmsCCC ccc;
  573.     XcmsColor *pColors_in_out;
  574.     unsigned int nColors;
  575.     XcmsColorFormat newFormat;
  576.     Bool *pCompressed;
  577. /*
  578.  *    DESCRIPTION
  579.  *        Convert XcmsColor structures:
  580.  *
  581.  *        1. From CIEXYZ to Device-Dependent formats (typically RGB and
  582.  *            RGBi),
  583.  *            or
  584.  *        2. Between Device-Dependent formats (typically RGB and RGBi).
  585.  *
  586.  *        Assumes that these specifications have already been white point
  587.  *        adjusted if necessary from Client White Point to Screen
  588.  *        White Point.  Therefore, the white point now associated
  589.  *        with the specifications is the Screen White Point.
  590.  *
  591.  *        pCompressed may be NULL.  If so this indicates that the
  592.  *        calling routine is not interested in knowing exactly which
  593.  *        color was compressed, if any.
  594.  *
  595.  *
  596.  *    RETURNS
  597.  *        XcmsFailure if failed,
  598.  *        XcmsSuccess if none of the color specifications were
  599.  *            compressed in the conversion process
  600.  *        XcmsSuccessWithCompression if at least one of the
  601.  *            color specifications were compressed in the
  602.  *            conversion process.
  603.  *
  604.  */
  605. {
  606.     DBUG_ENTER("_XcmsDDConvertColors")
  607.     XcmsColorSpace *pFrom, *pTo;
  608.     XcmsConversionProc *src_to_CIEXYZ, *src_from_CIEXYZ;
  609.     XcmsConversionProc *dest_to_CIEXYZ, *dest_from_CIEXYZ;
  610.     XcmsConversionProc *from_CIEXYZ_start, *to_CIEXYZ_stop;
  611.     XcmsConversionProc *tmp;
  612.     int    retval;
  613.     int hasCompressed = 0;
  614.  
  615.     if (ccc == NULL || pColors_in_out == NULL) {
  616.     DBUG_RETURN(XcmsFailure);
  617.     }
  618.  
  619.     if (nColors == 0 || pColors_in_out->format == newFormat) {
  620.     /* do nothing */
  621.     DBUG_RETURN(XcmsSuccess);
  622.     }
  623.  
  624.     if (((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet) == NULL) {
  625.     DBUG_RETURN(XcmsFailure);    /* hmm, an internal error? */
  626.     }
  627.  
  628.     /*
  629.      * Its ok if pColors_in_out->format == XcmsCIEXYZFormat
  630.      *    or 
  631.      * if newFormat == XcmsCIEXYZFormat
  632.      */
  633.     if ( !( ValidDDColorSpaceID(ccc, pColors_in_out->format)
  634.         ||
  635.         (pColors_in_out->format == XcmsCIEXYZFormat))
  636.      ||
  637.      !(ValidDDColorSpaceID(ccc, newFormat)
  638.         ||
  639.         newFormat == XcmsCIEXYZFormat)) {
  640.     DBUG_RETURN(XcmsFailure);
  641.     }
  642.  
  643.     if ((pFrom = ColorSpaceOfID(ccc, pColors_in_out->format)) == NULL){
  644.     DBUG_RETURN(XcmsFailure);
  645.     }
  646.  
  647.     if ((pTo = ColorSpaceOfID(ccc, newFormat)) == NULL) {
  648.     DBUG_RETURN(XcmsFailure);
  649.     }
  650.  
  651.     src_to_CIEXYZ = pFrom->to_CIEXYZ;
  652.     src_from_CIEXYZ = pFrom->from_CIEXYZ;
  653.     dest_to_CIEXYZ = pTo->to_CIEXYZ;
  654.     dest_from_CIEXYZ = pTo->from_CIEXYZ;
  655.  
  656.     if (pTo->inverse_flag && pFrom->inverse_flag) {
  657.     /*
  658.      * Find common function pointers
  659.      */
  660.     for (to_CIEXYZ_stop = src_to_CIEXYZ; *to_CIEXYZ_stop; to_CIEXYZ_stop++){
  661.         for (tmp = dest_to_CIEXYZ; *tmp; tmp++) {
  662.         if (*to_CIEXYZ_stop == *tmp) {
  663.             goto Continue;
  664.         }
  665.         }
  666.     }
  667. Continue:
  668.  
  669.     /*
  670.      * Execute the functions
  671.      */
  672.     while (src_to_CIEXYZ != to_CIEXYZ_stop) {
  673.         retval = (*src_to_CIEXYZ++)(ccc, pColors_in_out, nColors,
  674.             pCompressed);
  675.         if (retval == XcmsFailure) {
  676.         DBUG_RETURN(XcmsFailure);
  677.         }
  678.         hasCompressed |= (retval == XcmsSuccessWithCompression);
  679.     }
  680.  
  681.     /*
  682.      * Determine where to start on the from_CIEXYZ path.
  683.      */
  684.     from_CIEXYZ_start = dest_from_CIEXYZ;
  685.     tmp = src_from_CIEXYZ;
  686.     while ((*from_CIEXYZ_start == *tmp) && (*from_CIEXYZ_start != NULL)) {
  687.         from_CIEXYZ_start++;
  688.         tmp++;
  689.     }
  690.  
  691.     } else {
  692.     /*
  693.      * The function in at least one of the Color Spaces are not
  694.      * complementary, i.e.,
  695.      *    for an i, 0 <= i < n elements
  696.      *    from_CIEXYZ[i] is not the inverse of to_CIEXYZ[i]
  697.      *    
  698.      * Execute the functions all the way to CIEXYZ
  699.      */
  700.     while (*src_to_CIEXYZ) {
  701.         retval = (*src_to_CIEXYZ++)(ccc, pColors_in_out, nColors,
  702.             pCompressed);
  703.         if (retval == XcmsFailure) {
  704.         DBUG_RETURN(XcmsFailure);
  705.         }
  706.         hasCompressed |= (retval == XcmsSuccessWithCompression);
  707.     }
  708.  
  709.     /*
  710.      * Determine where to start on the from_CIEXYZ path.
  711.      */
  712.     from_CIEXYZ_start = dest_from_CIEXYZ;
  713.     }
  714.  
  715.     while (*from_CIEXYZ_start) {
  716.     retval = (*from_CIEXYZ_start++)(ccc, pColors_in_out, nColors,
  717.         pCompressed);
  718.     if (retval == XcmsFailure) {
  719.         DBUG_RETURN(XcmsFailure);
  720.     }
  721.     hasCompressed |= (retval == XcmsSuccessWithCompression);
  722.     }
  723.  
  724.     DBUG_RETURN(hasCompressed ? XcmsSuccessWithCompression : XcmsSuccess);
  725. }
  726.  
  727.  
  728. /************************************************************************
  729.  *                                    *
  730.  *             PUBLIC ROUTINES                *
  731.  *                                    *
  732.  ************************************************************************/
  733.  
  734. /*
  735.  *    NAME
  736.  *        XcmsConvertColors - Convert XcmsColor structures
  737.  *
  738.  *    SYNOPSIS
  739.  */
  740. Status
  741. XcmsConvertColors(ccc, pColors_in_out, nColors, targetFormat, pCompressed)
  742.     XcmsCCC ccc;
  743.     XcmsColor *pColors_in_out;
  744.     unsigned int nColors;
  745.     XcmsColorFormat targetFormat;
  746.     Bool *pCompressed;
  747. /*
  748.  *    DESCRIPTION
  749.  *        Convert XcmsColor structures to another format
  750.  *
  751.  *    RETURNS
  752.  *        XcmsFailure if failed,
  753.  *        XcmsSuccess if succeeded without gamut compression,
  754.  *        XcmsSuccessWithCompression if succeeded with gamut
  755.  *            compression.
  756.  *
  757.  */
  758. {
  759.     DBUG_ENTER("XcmsConvertColors")
  760.     XcmsColor clientWhitePt;
  761.     XcmsColor Color1;
  762.     XcmsColor *pColors_tmp;
  763.     int callWhiteAdjustProc = 0;
  764.     XcmsColorFormat format;
  765.     Status retval;
  766.     unsigned char contents_flag = 0x00;
  767.     unsigned int iColors;
  768.  
  769.     if (ccc == NULL || pColors_in_out == NULL ||
  770.         !(ValidDIColorSpaceID(targetFormat) ||
  771.         ValidDDColorSpaceID(ccc, targetFormat))) {
  772.     DBUG_RETURN(XcmsFailure);
  773.     }
  774.  
  775.     /*
  776.      * Check formats in color specification array
  777.      */
  778.     format = pColors_in_out->format;
  779.     for (pColors_tmp = pColors_in_out, iColors = nColors; iColors; pColors_tmp++, iColors--) {
  780.     if (!(ValidDIColorSpaceID(pColors_tmp->format) ||
  781.         ValidDDColorSpaceID(ccc, pColors_tmp->format))) {
  782.         DBUG_RETURN(XcmsFailure);
  783.     }
  784.     if (XCMS_DI_ID(pColors_tmp->format)) {
  785.         contents_flag |= DI_FORMAT;
  786.     } else {
  787.         contents_flag |= DD_FORMAT;
  788.     }
  789.     if (pColors_tmp->format != format) {
  790.         contents_flag |= MIX_FORMAT;
  791.     }
  792.     }
  793.  
  794.     /*
  795.      * Check if we need the Client White Point.
  796.      */
  797.     if ((contents_flag & DI_FORMAT) || XCMS_DI_ID(targetFormat)) {
  798.     /* To proceed, we need to get the Client White Point */
  799.     memcpy((char *)&clientWhitePt, (char *)&ccc->clientWhitePt,
  800.            sizeof(XcmsColor));
  801.     if (clientWhitePt.format == XcmsUndefinedFormat) {
  802.         /*
  803.          * Client White Point is undefined, therefore set to the Screen
  804.          *   White Point.
  805.          * Since Client White Point == Screen White Point, WhiteAdjustProc
  806.          *   is not called.
  807.          */
  808.         memcpy((char *)&clientWhitePt,
  809.            (char *)&ccc->pPerScrnInfo->screenWhitePt,
  810.            sizeof(XcmsColor));
  811.     } else if ((ccc->whitePtAdjProc != NULL) && !_XcmsEqualWhitePts(ccc,
  812.         &clientWhitePt, ScreenWhitePointOfCCC(ccc))) {
  813.         /*
  814.          * Client White Point != Screen White Point, and WhiteAdjustProc
  815.          *   is not NULL, therefore, will need to call it when
  816.          *   converting between DI and DD specifications.
  817.          */
  818.         callWhiteAdjustProc = 1;
  819.     }
  820.     }
  821.  
  822.     /*
  823.      * Make copy of array of color specifications
  824.      */
  825.     if (nColors > 1) {
  826.     pColors_tmp = (XcmsColor *) Xmalloc(nColors * sizeof(XcmsColor));
  827.     } else {
  828.     pColors_tmp = &Color1;
  829.     }
  830.     memcpy((char *)pColors_tmp, (char *)pColors_in_out,
  831.        nColors * sizeof(XcmsColor));
  832.  
  833.     /*
  834.      * zero out pCompressed
  835.      */
  836.     if (pCompressed) {
  837.     bzero((char *)pCompressed, nColors * sizeof(Bool));
  838.     }
  839.  
  840.     if (contents_flag == DD_FORMAT || contents_flag == DI_FORMAT) {
  841.     /*
  842.      * ENTIRE ARRAY IS IN ONE FORMAT.
  843.      */
  844.     if (XCMS_DI_ID(format) && XCMS_DI_ID(targetFormat)) {
  845.         /*
  846.          * DI-to-DI only conversion
  847.          */
  848.         retval = _XcmsDIConvertColors(ccc, pColors_tmp,
  849.             &clientWhitePt, nColors, targetFormat);
  850.     } else if (XCMS_DD_ID(format) && XCMS_DD_ID(targetFormat)) {
  851.         /*
  852.          * DD-to-DD only conversion
  853.          *   Since DD->DD there will be no compressed thus we can
  854.          *   pass NULL instead of pCompressed.
  855.          */
  856.         retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
  857.             targetFormat, (Bool *)NULL);
  858.     } else {
  859.         /*
  860.          * Otherwise we have:
  861.          *    1. Device-Independent to Device-Dependent Conversion
  862.          *        OR
  863.          *    2. Device-Dependent to Device-Independent Conversion
  864.          *
  865.          *  We need to go from oldFormat -> CIEXYZ -> targetFormat
  866.          *    adjusting for white points as necessary.
  867.          */
  868.  
  869.         if (XCMS_DI_ID(format)) {
  870.         /*
  871.          *    1. Device-Independent to Device-Dependent Conversion
  872.          */
  873.         if (callWhiteAdjustProc) {
  874.             /*
  875.              * White Point Adjustment
  876.              *        Client White Point to Screen White Point
  877.              */
  878.             retval = (*ccc->whitePtAdjProc)(ccc, &clientWhitePt,
  879.                 ScreenWhitePointOfCCC(ccc), targetFormat,
  880.                 pColors_tmp, nColors, pCompressed);
  881.         } else {
  882.             if (_XcmsDIConvertColors(ccc, pColors_tmp,
  883.                 &clientWhitePt, nColors, XcmsCIEXYZFormat)
  884.                 == XcmsFailure) {
  885.             goto Failure;
  886.             }
  887.             retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
  888.                 targetFormat, pCompressed);
  889.         }
  890.         } else {
  891.         /*
  892.          *    2. Device-Dependent to Device-Independent Conversion
  893.          */
  894.         if (callWhiteAdjustProc) {
  895.             /*
  896.              * White Point Adjustment
  897.              *        Screen White Point to Client White Point
  898.              */
  899.             retval = (*ccc->whitePtAdjProc)(ccc,
  900.                 ScreenWhitePointOfCCC(ccc), &clientWhitePt,
  901.                 targetFormat, pColors_tmp, nColors, pCompressed);
  902.         } else {
  903.             /*
  904.              * Since DD->CIEXYZ, no compression takes place therefore
  905.              * we can pass NULL instead of pCompressed.
  906.              */
  907.             if (_XcmsDDConvertColors(ccc, pColors_tmp, nColors,
  908.                 XcmsCIEXYZFormat, (Bool *)NULL) == XcmsFailure) {
  909.             goto Failure;
  910.             }
  911.             retval = _XcmsDIConvertColors(ccc, pColors_tmp,
  912.                 &clientWhitePt, nColors, targetFormat);
  913.         }
  914.         }
  915.     }
  916.     } else {
  917.     /*
  918.      * ARRAY HAS MIXED FORMATS.
  919.      */
  920.     if ((contents_flag == (DI_FORMAT | MIX_FORMAT)) &&
  921.         XCMS_DI_ID(targetFormat)) {
  922.         /*
  923.          * Convert from DI to DI in batches of contiguous formats
  924.          *
  925.          * Because DI->DI, WhiteAdjustProc not called.
  926.          */
  927.         retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
  928.             nColors, targetFormat, (unsigned char)DI_FORMAT);
  929.     } else if ((contents_flag == (DD_FORMAT | MIX_FORMAT)) &&
  930.         XCMS_DD_ID(targetFormat)) {
  931.         /*
  932.          * Convert from DD to DD in batches of contiguous formats
  933.          *
  934.          * Because DD->DD, WhiteAdjustProc not called.
  935.          */
  936.         retval = ConvertMixedColors(ccc, pColors_tmp,
  937.             (XcmsColor *)NULL, nColors, targetFormat,
  938.             (unsigned char)DD_FORMAT);
  939.     } else if (XCMS_DI_ID(targetFormat)) {
  940.         /*
  941.          * We need to convert from DI-to-DI and DD-to-DI, therefore
  942.          *   1. convert DD specifications to CIEXYZ, then
  943.          *   2. convert all in batches to the target DI format.
  944.          *
  945.          * Note that ConvertMixedColors will call WhiteAdjustProc
  946.          * as necessary.
  947.          */
  948.  
  949.         /*
  950.          * Convert only DD specifications in batches of contiguous formats
  951.          * to CIEXYZ
  952.          *
  953.          * Since DD->CIEXYZ, ConvertMixedColors will apply WhiteAdjustProc
  954.          * if required.
  955.          */
  956.         retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
  957.             nColors, XcmsCIEXYZFormat, (unsigned char)DD_FORMAT);
  958.  
  959.         /*
  960.          * Because at this point we may have a mix of DI formats
  961.          * (e.g., CIEXYZ, CIELuv) we must convert the specs to the
  962.          * target DI format in batches of contiguous source formats.
  963.          */
  964.         retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
  965.             nColors, targetFormat, (unsigned char)DI_FORMAT);
  966.     } else {
  967.         /*
  968.          * We need to convert from DI-to-DD and DD-to-DD, therefore
  969.          *   1. convert DI specifications to CIEXYZ, then
  970.          *   2. convert all to the DD target format.
  971.          *
  972.          *   This allows white point adjustment and gamut compression
  973.          *     to be applied to all the color specifications in one
  974.          *   swoop if those functions do in fact modify the entire
  975.          *   group of color specifications.
  976.          */
  977.  
  978.         /*
  979.          * Convert in batches to CIEXYZ
  980.          *
  981.          * If DD->CIEXYZ, ConvertMixedColors will apply WhiteAdjustProc
  982.          * if required.
  983.          */
  984.         if ((retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt,
  985.             nColors, XcmsCIEXYZFormat,
  986.             (unsigned char)(DI_FORMAT | DD_FORMAT))) == XcmsFailure) {
  987.         goto Failure;
  988.         }
  989.  
  990.         /*
  991.          * Convert all specifications (now in CIEXYZ format) to
  992.          * the target DD format.
  993.          * Since CIEXYZ->DD, compression MAY take place therefore
  994.          * we must pass pCompressed.
  995.          * Note that WhiteAdjustProc must be used if necessary.
  996.          */
  997.         if (callWhiteAdjustProc) {
  998.         /*
  999.          * White Point Adjustment
  1000.          *    Client White Point to Screen White Point
  1001.          */
  1002.         retval = (*ccc->whitePtAdjProc)(ccc,
  1003.             &clientWhitePt, ScreenWhitePointOfCCC(ccc),
  1004.             targetFormat, pColors_tmp, nColors, pCompressed);
  1005.         } else {
  1006.         retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors,
  1007.             targetFormat, pCompressed);
  1008.         }
  1009.     }
  1010.     }
  1011.  
  1012.     if (retval != XcmsFailure) {
  1013.     memcpy((char *)pColors_in_out, (char *)pColors_tmp,
  1014.            nColors * sizeof(XcmsColor));
  1015.     }
  1016.     if (nColors > 1) {
  1017.     Xfree((char *)pColors_tmp);
  1018.     }
  1019.     DBUG_RETURN(retval);
  1020.  
  1021. Failure:
  1022.     if (nColors > 1) {
  1023.     Xfree((char *)pColors_tmp);
  1024.     }
  1025.     DBUG_RETURN(XcmsFailure);
  1026. }
  1027.  
  1028.  
  1029. /*
  1030.  *    NAME
  1031.  *        XcmsRegFormatOfPrefix
  1032.  *
  1033.  *    SYNOPSIS
  1034.  */
  1035. XcmsColorFormat
  1036. _XcmsRegFormatOfPrefix(prefix)
  1037.     char *prefix;
  1038. /*
  1039.  *    DESCRIPTION
  1040.  *        Returns a color space ID associated with the specified
  1041.  *        X Consortium registered color space prefix.
  1042.  *
  1043.  *    RETURNS
  1044.  *        The color space ID if found;
  1045.  *        otherwise NULL.
  1046.  */
  1047. {
  1048.     DBUG_ENTER("_XcmsRegFormatOfPrefix")
  1049.     XcmsRegColorSpaceEntry *pEntry = _XcmsRegColorSpaces;
  1050.  
  1051.     while (pEntry->prefix != NULL) {
  1052.     if (strcmp(prefix, pEntry->prefix) == 0) {
  1053.         DBUG_RETURN(pEntry->id);
  1054.     }
  1055.     pEntry++;
  1056.     }
  1057.     DBUG_RETURN(XcmsUndefinedFormat);
  1058. }
  1059.