/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = COLORTAB.C
 *
 * DESCRIPTIVE NAME = Contains color table code.
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION This file contains PostScript driver color table code.
 *
 *
 * FUNCTIONS     = prdc_RGB_to_Solid
 *                 PrintColorTable
 *                 prdc_GetColor()
 *                 prdc_RgbToGray()
 *                 prdc_RgbToNearestRgb()
 *                 prdc_CreateLogColorTable()
 *                 prdc_QueryRGBColor()
 *                 prdc_QueryColorData()
 *                 prdc_QueryNearestColor()
 *                  ColorDistance()
 *                 prdc_QueryColorIndex()
 *                 prdc_QueryRealColors()
 *                 prdc_QueryLogColorTable()
 *
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define  INCL_GPILOGCOLORTABLE
#include "inc\prdinclt.h"
#include "inc\prdgextf.h"
#include "inc\prdcextf.h"
#include "inc\utl.h"
#include "inc\prdmath.h"
#include "inc\prdtcone.h"
#include "inc\pspagtun.h"              /* V2.174057   Page Tuning */
#define  INCL_GENPLIB_ERROR
#include <genplib.h>

#define  RED_WEIGHT    25
#define  GREEN_WEIGHT  60
#define  BLUE_WEIGHT   15
#define  NORMAL_WEIGHT 100
#define  OD_MEMORY 8L

/*
** The RGB values for black and white.
*/
#define  _BLACK        0x000000L
#define  _WHITE        0x0ffffffL
#define  _MAGENTA      0x0ff00ffL
#define  _CYAN         0x000ffffL
#define  _YELLOW       0x0ffff00L

/*
** Forward definitions for functions in this module.
*/
LONG   prdc_RgbToNearestRgb(PDDC,LONG);
extern PDDC EnterDriver(PDDC);
extern VOID ExitDriver(PDDC);
FIXED   prdc_RgbToGray(PDDC,LONG);
int   ColorDistance(PDDC,LONG,LONG);

/*
** Table containing the RGB values for the system colors.
*/
ULONG aulSysColors[N_SYSCOLORS] =
{
//@V3.084698 -- switch black and white
//_WHITE,                              /* CLR_FALSE                         */
//_BLACK,                              /* CLR_TRUE                          */
  _BLACK,                              /* CLR_FALSE                         */
  _WHITE,                              /* CLR_TRUE                          */
  _BLACK,                              /* CLR_DEFAULT                       */
  _WHITE,                              /* CLR_WHITE                         */
  _BLACK,                              /* CLR_BLACK                         */
} ;

/*
** Table containing the RGB values for the standard colors.
*/
ULONG aulStdColors[N_STDCOLORS] =
{
  0x00FFFFFFL,                         /*  0 CLR_BACKGROUND = white          */
  0x000000FFL,                         /*  1 CLR_BLUE = blue                 */
  0x00FF0000L,                         /*  2 CLR_RED = red                   */
  0x00FF00FFL,                         /*  3 CLR_PINK = pink (magenta)       */
  0x0000FF00L,                         /*  4 CLR_GREEN = green               */
  0x0000FFFFL,                         /*  5 CLR_CYAN = turquoise (cyan)     */
  0x00FFFF00L,                         /*  6 CLR_YELLOW = yellow             */
  0x00000000L,                         /*  7 CLR_NEUTRAL = black             */
  0x00404040L,                         /*  8 CLR_DARKGRAY = dark gray        */
  0x00000080L,                         /*  9 CLR_PALEBLUE = dark blue        */
  0x00800000L,                         /* 10 CLR_PALERED = dark red          */
  0x00800080L,                         /* 11 CLR_PALEPINK = purple           */
  0x00008000L,                         /* 13 CLR_DARKGREEN = dark green      */
  0x00008080L,                         /* 13 CLR_DARKCYAN = dark turquoise   */
  0x00808000L,                         /* 14 CLR_BROWN = mustard             */
  0x00808080L                          /* 15 CLR_PALEGRAY = gray             */
} ;

/*
** Table containing the index and RGB values for the REAL (solid) colors.
*/
#define  TOTAL_SOLID_COLORS 5

ULONG aulRealColors[ TOTAL_SOLID_COLORS * 2 ] =
{ /* Index  Solid Color */
     0,     _WHITE,
     7,     _BLACK,
/*** 5, *** _MAGENTA,             This was the old list */
/*** 6, *** _CYAN, **************************************/
/*** 3, *** _YELLOW *************************************/
     3,     _MAGENTA,
     5,     _CYAN,
     6,     _YELLOW
} ;


/*
** ************************************* Private Function ************
*/
/***************************************************************************
 *
 * FUNCTION NAME = prdc_RGB_to_Solid
 *
 *
 * DESCRIPTION   = This function returns a solid color for that device.
 *
 *
 * INPUT         = pddc, lColor
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prdc_RGB_to_Solid( PDDC pddc, ULONG lColor )
  /* ULONG lColor;                         RGB value */
{
  ULONG newlColor;
  int   newdiff, i;
  int   olddiff = 256;                   /* Defect 55631 max dist is 255 */

  if (lColor == CLR_NOINDEX)
  {
    return( lColor );
  }

  if (pddc->pdv->jobProperties.fIsColorDevice)
  {
    for (i = 0 ; i < TOTAL_SOLID_COLORS ; i++)
    {
      newdiff = ColorDistance( pddc, lColor, aulRealColors[(i * 2) + 1] );

      if (newdiff < olddiff)
      {
        newlColor = aulRealColors[(i * 2) + 1];
        olddiff = newdiff;
      }
    }
    lColor = newlColor;
  }
  /*
  ** B/W printer
  */
  else if (lColor != _WHITE)
  {
    lColor = _BLACK;
  }
  return( lColor );
}

void   PrintColorTable( PDDC );
/***************************************************************************
 *
 * FUNCTION NAME = PrintColorTable
 *
 * DESCRIPTION   = Print color table
 *
 * INPUT         = pddc
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void  PrintColorTable( PDDC pddc )
{
  int   i;
  LONG  lColor;
  FIXED fxGray;

  /*
  ** !!!CR This is a debugging function that dumps the color table
  ** !!!CR to the log file.
  */
  for (i = 0 ; i < pddc->pddcb->color.nColors ; ++i)
  {
    lColor = (LONG) pddc->pddcb->color.aulColors[i];
    fxGray = prdc_RgbToGray( pddc, lColor );
    PrintLog( (PSZ)"%d %08lx %f\n", i-5, lColor, fxGray );
  }
  PrintLog( (PSZ)"\n" );
}

/*
** *************************************** Global Function **************
*/
/***************************************************************************
 *
 * FUNCTION NAME = prdc_GetColor()
 *
 * DESCRIPTION   = This function does a color table look-up to convert
 *                 an engine color value into an RGB color.
 *
 * INPUT         = (pddc,lColor)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LONG prdc_GetColor( PDDC pddc, long lColor )
{

  #if      DEBUG
    LogCall(  "prdc_GetColor(%lp, 0x%08lx)", ((PB)&pddc)+sizeof(pddc) );
  #endif                                 /* DEBUG */

  PrintLog( (PSZ)"pddc->pddcb->color.ulFormat = %ld\n",
            pddc->pddcb->color.ulFormat );
  PrintLog( (PSZ)"pddc->pddcb->color.nColors = %d\n",
            pddc->pddcb->color.nColors );

  /*
  ** Default colors are a special case. If the color parameter we
  ** encounter here is a flag signifying default foreground or
  ** background color, then make sure we get the proper default
  ** color selected, regardless of current logical color table mode.
  */
  if (lColor == DEFAULT_FOREGROUND_COL)
  {
    if (pddc->pddcb->color.ulFormat == LCOLF_RGB)
    {
      lColor = _BLACK;
    }
    else
    {
      lColor = CLR_NEUTRAL;
    }
  }
  else if (lColor == DEFAULT_BACKGROUND_COL)
  {
    if (pddc->pddcb->color.ulFormat == LCOLF_RGB)
    {
      lColor = _WHITE;
    }
    else
    {
      lColor = CLR_BACKGROUND;
    }
  }

  /*
  ** If index mode is in effect or if one of the system colors is
  ** selected, then look up the color value in the color table.
  */
  if ((pddc->pddcb->color.ulFormat != LCOLF_RGB) || (lColor < 0))
  {
    /*
    ** Color mode = indexed.
    */
    lColor += N_SYSCOLORS;

    if ((lColor < 0) || (lColor > pddc->pddcb->color.nColors))
    {
      RIP( "GetColor: Color out of range." );
      PrintLog( (PSZ)"Color out of range %ld\n", lColor );
      lColor = _BLACK;
    }
    else
    {
      PrintLog( (PSZ)"Indexing into color table\n" );
      lColor = pddc->pddcb->color.aulColors[lColor];
    }
  }
  PrintLog( (PSZ)"lColorOutput = %08lx\n", lColor );
  PrintLog( (PSZ)"\n" );
  return( lColor );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdc_RgbToGray()
 *
 * DESCRIPTION   = This function converts an RGB color to the a gray
 *                 shade value wich ranges from 0.0 to 1.0 (fixed point).
 *
 * INPUT         = (pddc,lColor)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

FIXED prdc_RgbToGray( PDDC pddc, LONG lColor )
  /* LONG lColor;                          The color to convert              */
{
  FIXED fxRed, fxGreen, fxBlue;
  LONG  fxTmp;

#if 0
//#define  FX_15PERCENT  0X02666L        /* 0.15                              */
//#define  FX_25PERCENT  0x04000L        /* 0.25                              */
//#define  FX_60PERCENT  0x0999AL        /* 0.60                              */
#endif

  /*
  ** @V3.084696
  ** Changed the weighted values.  These values are modified in the
  ** following.
  */
  #define  FX_11PERCENT  0X01C28L      /* 0.11 Blue weight   @84696 */
  #define  FX_30PERCENT  0x04CCCL      /* 0.30 Red weight    */
  #define  FX_59PERCENT  0x0970AL      /* 0.59 Green weight  */

  fxTmp = (lColor & 0x000000ff) << 16;
  fxBlue = frmul( fxTmp, FX_11PERCENT );
  fxTmp = (lColor & 0x0000ff00) << 8;
  fxGreen = frmul( fxTmp, FX_59PERCENT );
  fxTmp = (lColor & 0x00ff0000 );
  fxRed = frmul( fxTmp, FX_30PERCENT );

#if 0
//fxTmp = (lColor & 0x000000ff) << 16;
//fxBlue = frmul( fxTmp, FX_15PERCENT );
//fxTmp = (lColor & 0x0000ff00) << 8;
//fxGreen = frmul( fxTmp, FX_60PERCENT );
//fxTmp = (lColor & 0x00ff0000 );
//fxRed = frmul( fxTmp, FX_25PERCENT );
#endif

  /*
  ** The gray value is computed as a normalized average of the
  ** three color components.  The resultant gray level should
  ** range from 0.0 to 1.0
  */
  return( frdiv( (fxRed + fxGreen + fxBlue), (255L * FX_ONE)) );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdc_RgbToNearestRgb()
 *
 *                 This function converts an RGB color to the nearest color
 * DESCRIPTION   = available on the output device.  For black-and-white
 *                 printers, this will will one of the half-tone gray shades.
 *
 * INPUT         = (pddc,lColor)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (lColor)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LONG prdc_RgbToNearestRgb( PDDC pddc, LONG lColor )
{
  LONG lGray, lRed, lGreen, lBlue;

  /*
  ** If an invalid color is passed in, then just return the
  ** same value because it is a NULL entry in the color
  ** table.
  **
  ** If this is a color printer, then just return the color
  ** value because no grayscale conversion is required.
  */
  if (lColor & 0xff000000L)
  {
    return( lColor );
  }
  lBlue = (lColor) & 0x0ff;
  lGreen = (lColor >> 8) & 0x0ff;
  lRed = (lColor >> 16) & 0x0ff;

  if (pddc->pdv->jobProperties.fIsColorDevice)
  {
    lRed = (lRed * (LONG)pddc->pdv->canvas.nGrayShades) / 255;
    lRed = (lRed * 255L) / pddc->pdv->canvas.nGrayShades;
    lGreen = (lGreen * (LONG)pddc->pdv->canvas.nGrayShades) / 255;
    lGreen = (lGreen * 255L) / pddc->pdv->canvas.nGrayShades;
    lBlue = (lBlue * (LONG)pddc->pdv->canvas.nGrayShades) / 255;
    lBlue = (lBlue * 255L)/pddc->pdv->canvas.nGrayShades;
    lColor = (lRed) << 16 | (lGreen) << 8 | lBlue;
  }
  else
  {
    lGray = (lRed * RED_WEIGHT + lGreen * GREEN_WEIGHT + lBlue * BLUE_WEIGHT) /
       NORMAL_WEIGHT;

    lGray = (lGray * (LONG)pddc->pdv->canvas.nGrayShades) / 255;
    lGray = (lGray * 255L) / pddc->pdv->canvas.nGrayShades;
    lColor = (lGray << 16) | (lGray) << 8 | (lGray );
  }
  return( lColor );
}

/*
**  ********************************** Engine Entry Point ***********
*/
/***************************************************************************
 *
 * FUNCTION NAME = prdc_CreateLogColorTable()
 *
 * DESCRIPTION   = This function creates the driver's color table.
 *
 * INPUT         = prdc_CreateLogColorTable(hdc,ulOptions,ulFormat,iFirstIndex,
 *                 nInput,plInput,pddc,ifn)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prdc_CreateLogColorTable( HDC hdc, ULONG ulOptions, ULONG ulFormat,
                                LONG iFirstIndex, LONG nInput,
                                LONG *plInput, PDDC pddc, ULONG ulFunN )

  /*  HDC hdc;                              The display context handle        */
  /*  ULONG ulOptions;                      The option bits.                  */
  /*  ULONG ulFormat;                       Format descriptor                 */
  /*  LONG iFirstIndex;                     Index of the first element        */
  /*  LONG nInput;                          Number of elements in the table   */
  /*  LONG  *plInput;                       Ptr to the table of values        */
  /*  PDDC pddc;                            Ptr to the DC instance data       */
  /*  ULONG ifn;                            The Gre function number           */

{
  int     nColors;                   /* The number of color table entries */
  int     nbTable;                   /* The number of bytes in the color
                                        table                             */
  int     i;                         /* A loop counter                    */
  ULONG   ulColor;                   /* The RGB color                     */
  int     iIndex;                    /* The color table index             */
  int     iMaxIndex;                 /* The maximum color table index     */
  ERRORID idError;
  ULONG   ulRet;

  EnterDriver( pddc );

  if (pddc->iType == OD_MEMORY)
  {
    ulRet = InnerGreCreateLogColorTable (pddc->hdcMemory, ulOptions,
                                         ulFormat, iFirstIndex, nInput,
                                         plInput, ulFunN );
    ExitDriver( pddc );
    return(ulRet );
  }

  #if      DEBUG
    LogCall(  "prdc_InstallColorTable(%ld, %ld, %ld, %lp, %b, %lp)\n", ((PB)
     &ulFormat)+sizeof(ulFormat) );
  #endif                                 /* DEBUG */
  PrintLog( (PSZ)"pddc->pddcb->color.nColors = %d\n",
            pddc->pddcb->color.nColors );
  PrintLog( (PSZ)"pddc->pddcb->color.aulColors = %lp\n",
            pddc->pddcb->color.aulColors );
  PrintLog( (PSZ)"pddc->hHeap = %lp\n", pddc->hHeap );
  PrintLog( (PSZ)"pddc->pdv->canvas.nGrayShades = %d\n",
            pddc->pdv->canvas.nGrayShades );

  /*
  ** If we're switching from RGB mode or starting fresh, force a reset.
  */
  if (((pddc->pddcb->color.ulFormat == LCOLF_RGB) && (ulFormat != LCOLF_RGB))
     || (pddc->pddcb->color.nColors <= 0))
  {
    ulOptions |= LCOL_RESET;
  }

  /*
  ** set the pure color flag in our ddc
  */
  if (ulOptions&LCOL_PURECOLOR)
  {
    pddc->pddcb->color.fUsePureColor = TRUE;
  }
  pddc->pddcb->color.ulFormat = ulFormat;

  /*
  ** Calculate the color table size for each of the different formats
  */
  switch ((SHORT) ulFormat)
  {
  case LCOLF_DEFAULT:
       PrintLog( (PSZ)"ulFormat = LCOLF_DEFAULT\n" );
       nColors = N_STDCOLORS + N_SYSCOLORS;
       break;

  case LCOLF_INDRGB:
       PrintLog( (PSZ)"ulFormat = LCOLF_INDRGB\n" );

       /*
       ** If the color table format is indexed RGB, then scan
       ** the index values to determine the largest index so that
       ** the driver knows how large the table is.
       */
       iFirstIndex = 0;
       iMaxIndex = -1;

       for (i = 0; i < (int)nInput; i += 2)
       {
         if (plInput[i] < iFirstIndex)
         {
           iFirstIndex = plInput[i];
         }

         if (plInput[i] > iMaxIndex)
         {
           iMaxIndex = (int)plInput[i];
         }
       }

       /*             */
       /*
       ** The number of color entries = N_SYSCOLORS + FirstIndex +
       **                               Number of colors supplied.
       **                             = N_SYSCOLORS + MaxIndex + 1.
       ** nColors = iMaxIndex + 1;
       */
       nColors = N_SYSCOLORS + iMaxIndex + 1;

       /*
       ** Check to see if there is an attempt to redefine
       ** the system colors.
       */
       if (iFirstIndex < 0)
       {
         PrintLog( (PSZ)"Invalid color range. FAILURE\n" );
         GplErrSetError( PMERR_INV_COLOR_INDEX );
         ExitDriver( pddc );
         return( FAILURE );
       }
       PrintLog( (PSZ)"LCOLF_INDRGB: nColors = %d\n", nColors );
       break;

  case LCOLF_CONSECRGB:
       PrintLog( (PSZ)"ulFormat = LCOLF_CONSECRGB\n" );
//@V3.084698
//     pddc->pddcb->color.ulFormat = LCOLF_INDRGB;
       pddc->pddcb->color.ulFormat = LCOLF_DEFAULT;

       if (iFirstIndex < 0)
       {
         PrintLog( (PSZ)"Attempt to change system colors: FAILURE\n" );
         GplErrSetError( PMERR_INV_COLOR_INDEX );
         ExitDriver( pddc );
         return( FAILURE );
       }

       /*             */
       /*
       ** The number of color entries = N_SYSCOLORS + FirstIndex +
       **                               Number of colors supplied.
       **                             = N_SYSCOLORS + MaxIndex + 1.
       ** nColors = (int) iFirstIndex + (int) nInput + 1;
       */
       nColors = N_SYSCOLORS + (int) iFirstIndex + (int) nInput;
       PrintLog( (PSZ)"LCOLF_CONSECRGB: nColors = %d\n", nColors );
       break;

  case LCOLF_RGB:
       nColors = N_SYSCOLORS;
       PrintLog( (PSZ)"ulFormat = LCOLF_RGB\n" );
       PrintLog( (PSZ)"LCOLF_RGB: nColors = %d\n", nColors );
       break;

  default:
      PrintLog( (PSZ)"ulFormat = default(FAILURE)\n" );
      GplErrSetError(  PMERR_INV_COLOR_FORMAT );
      ExitDriver( pddc );
      return( FAILURE );
      break;
  }

  /*             */
  /*
  ** Do a bounds check to make sure that the color table
  ** doesn't overflow.
  */
  if (nColors > N_MAXCOLORS)
  {
    nColors = N_MAXCOLORS;
  }

  /*
  ** Save the color count in the DC instance data.
  */
  pddc->pddcb->color.nColors = nColors;

  if (ulOptions&LCOL_RESET)
  {
    /*
    ** If the color table is an indexed format, the base color table
    ** consists of entries for the system colors, and standard colors.
    */
    if (ulFormat != LCOLF_RGB)
    {
      /*
      ** Ensure that the default colors are present.
      */
      if (nColors < (N_SYSCOLORS+N_STDCOLORS))
      {
        nColors = (N_SYSCOLORS+N_STDCOLORS );
      }

      /*
      ** Do a bounds check to make sure that the color table
      ** doesn't overflow.
      */
      if (nColors > N_MAXCOLORS)
      {
        nColors = N_MAXCOLORS;
      }
    }

    /*
    ** Fill the color table with invalid color values so that
    ** its possible to detect values that weren't initialized
    ** in a sparse table.
    */
    for (i = 0 ; i < N_MAXCOLORS ; ++i)
    {
      pddc->pddcb->color.aulColors[i] = 0xffffffffL;
    }
    PrintLog( (PSZ)"nColors = %d\n", nColors );

    /*
    ** Save the color count in the DC instance data.
    */
    pddc->pddcb->color.nColors = nColors;

    /*
    ** The color table contains entries for the five system colors
    ** regardless of the format.  The RGB values for these colors
    ** are loaded into the color table at this point.
    */
    for (i = 0; i < N_SYSCOLORS; ++i)
    {
      pddc->pddcb->color.aulColors[i] = aulSysColors[i];
    }
    nColors -= N_SYSCOLORS;

    /*
    ** For all color table formats except RGB, load a default
    ** color table consisting of entries for the system colors and
    ** standard colors.
    */
    if (ulFormat != LCOLF_RGB)
    {
      PrintLog( (PSZ)"Initialize standard colors\n" );

      for (i = 0 ; i < N_STDCOLORS ; ++i)
      {
        pddc->pddcb->color.aulColors[N_SYSCOLORS + i] = aulStdColors[i];
      }
    }
  }                                    /* end color table reset */

  /*
  ** At this point, the color table values passed in as input
  ** can be overlayed on the default table that has been set
  ** up.
  */
  if (ulFormat == LCOLF_INDRGB)
  {
    for (i = 0 ; i < (int) (nInput / 2) ;  ++i)
    {
      iIndex = (int) plInput[2 * i];

      /*
      ** Check to make sure a valid color index is being used
      */
      if (iIndex > (N_MAXCOLORS - N_SYSCOLORS))
      {
        GplErrSetError( PMERR_INV_COLOR_INDEX );
        ExitDriver( pddc );
        return( FAILURE );
      }
      pddc->pddcb->color.aulColors[iIndex + N_SYSCOLORS] = plInput[2 * i + 1];
    }
  }
  else if (ulFormat == LCOLF_CONSECRGB)
  {
    if ((iFirstIndex + nInput) > (N_MAXCOLORS - N_SYSCOLORS))
    {
      GplErrSetError( PMERR_INV_COLOR_INDEX );
      ExitDriver( pddc );
      return( FAILURE );
    }

    for (i = 0; i < (int)nInput;  ++ i)
    {
      pddc->pddcb->color.aulColors[i + iFirstIndex + N_SYSCOLORS] = plInput[i];
    }
  }

  /*
  ** if we only want pure colors, now is the time to convert.
  */
  if ((ulOptions & LCOL_PURECOLOR) && (ulFormat != LCOLF_RGB))
  {
    /*            */
    /*
    ** for(i=0;i<(pddc->pddcb->color.nColors );i ++ )
    */

    for (i = 0 ; i < (pddc->pddcb->color.nColors - N_SYSCOLORS ) ; i ++ )
    {
      pddc->pddcb->color.aulColors[i + N_SYSCOLORS] = prdc_RGB_to_Solid(pddc,
         pddc->pddcb->color.aulColors[i + N_SYSCOLORS] );
    }
  }
  ExitDriver( pddc );
  return( SUCCESS );
}

/*
** ************************************ Engine Entry Point ***********
*/
/***************************************************************************
 *
 * FUNCTION NAME = prdc_QueryRGBColor()
 *
 * DESCRIPTION   = This function allows the application to determine the
 *                 RGB color values are in the color table.
 *
 * INPUT         = (hdc,ulOptions,lColor,pddc,ifn)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prdc_QueryRGBColor( HDC hdc, ULONG ulOptions, LONG lColor,
                          PDDC pddc, ULONG ulFunN )
  /*  HDC hdc;                              The display context handle        */
{
  ULONG ulRet;

  EnterDriver( pddc );

  #if      DEBUG
    LogCall( "prdc_QueryRGBColor(%lp, %08lx, %08lx, %lp, %lp)\n", ((PB)&hdc) +
             sizeof(hdc) );
  #endif                                 /* DEBUG */

  PrintLog( (PSZ)"lColor input = %08lx  (%ld)\n", lColor, lColor );

  if (pddc->iType == OD_MEMORY)
  {
     ulRet = InnerGreQueryRGBColor (pddc->hdcMemory, ulOptions,
                                    lColor, ulFunN );
     ExitDriver( pddc );
     return(ulRet );
  }

  if (pddc->pddcb->color.ulFormat == LCOLF_RGB)
  {

    if (lColor & 0xff000000L)
    {
      PrintLog( (PSZ)"FAILURE: Invalid RGB color\n" );
      GplErrSetError( PMERR_INV_COLOR_DATA );
      ExitDriver( pddc );
      return( FAILURE );
    }
  }
  else
  {
    lColor  += N_SYSCOLORS;

    if ((lColor < 0) || (lColor >= pddc->pddcb->color.nColors))
    {
      PrintLog( (PSZ)"FAILURE: Color index out of range\n" );
      GplErrSetError(  PMERR_INV_COLOR_INDEX );
      ExitDriver( pddc );
      return( FAILURE );
    }

    /*
    ** Use the color index to get the RGB value out of
    ** the color table.
    */
    lColor = pddc->pddcb->color.aulColors[lColor];
  }
  PrintLog( (PSZ)"lColor RGB = %08lx\n", lColor );

  if (ulOptions&BIT1)
  {
    lColor = prdc_RgbToNearestRgb( pddc, lColor );
  }
  PrintLog( (PSZ)"lColor output = %08lx\n", lColor );
  ExitDriver( pddc );
  return( lColor );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdc_QueryColorData()
 *
 * DESCRIPTION   = This function allows the application to determine the
 *                          format and size of the color table.
 *
 * INPUT         = (hdc,nOutput,pulOutput,pddc,ifn)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (SUCCESS)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prdc_QueryColorData( HDC hdc, LONG nOutput, ULONG *pulOutput,
                           PDDC pddc, ULONG ulFunN )
{
  int   i;
  ULONG ulRet;

  EnterDriver( pddc );

  #if      DEBUG
    LogCall( "prdc_QueryColorData(%lp, %ld, %lp, %lp, %lp)", ((PB)&hdc) + sizeof
             (hdc) );
  #endif                                 /* DEBUG */

  if (pddc->iType == OD_MEMORY)
  {
     ulRet = InnerGreQueryColorData (pddc->hdcMemory, nOutput,
                                     pulOutput, ulFunN );
     ExitDriver( pddc );
     return( ulRet );
  }

  /*
  ** Loop for each element in the output array and fill
  ** it in with the appropriate values.
  */
  for (i = 0 ; i < (int) nOutput ; i ++)
  {
    /*
    ** select the current item to be returned
    */
    switch (i)
    {
    case 0:                         /* Color Table format                */
         pulOutput[0] = pddc->pddcb->color.ulFormat;
         break;

    case 1:                         /* Smallest color table index        */
         pulOutput[1] = 0L;
         break;

    case 2:                         /* largest color table index         */
         /*             */
         /*
         ** If nColors == N_SYSCOLORS, then
         ** the HIINDEX should be -1 to indicate that there are no more
         ** colors than the system colors. But the engine returns 0
         ** which will lead to that one entry is in the color table after
         ** the system colors.
         ** Hence, the driver also returns 0.
         */
         if (pddc->pddcb->color.nColors > N_SYSCOLORS)
         {
           pulOutput[2] = pddc->pddcb->color.nColors - N_SYSCOLORS - 1L;
         }
         else
         {
           pulOutput[2] = 0L;
         }
         break;

    default:                       /* Zero the remainder of the array   */
         pulOutput[i] = 0L;
         break;
    }
  }
  ExitDriver( pddc );
  return( SUCCESS );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdc_QueryNearestColor()
 *
 * DESCRIPTION   = This function takes an RGB color value as input and
 *                 returns the closest RGB color value that can be
 *                 drawn on the device.  Since PostScript does shades of
 *                 gray, this will be an RGB triplet with each of the
 *                 components set to equal values.
 *
 * INPUT         = (hdc,ulOptions,lColor,pddc,ifn)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = prdc_RgbToNearestRgb(pddc, lColor)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prdc_QueryNearestColor( HDC hdc, ULONG ulOptions, LONG lColor,
                              PDDC pddc, ULONG ulFunN )
{
  ULONG ulRet;

  EnterDriver( pddc );

  #if      DEBUG
    LogCall( "prdc_QueryNearestColor(%lp, %08lx, %08lx, %lp, %lp)\n", ((PB)&hdc) +
             sizeof(hdc) );
  #endif                                 /* DEBUG */

  if (pddc->iType == OD_MEMORY)
  {
    ulRet = InnerGreQueryNearestColor( pddc->hdcMemory, ulOptions,
                                       lColor, ulFunN );
  }
  else
  {
     ulRet = prdc_RgbToNearestRgb( pddc, lColor );
  }

  ExitDriver( pddc );

  return( ulRet );
}

/***************************************************************************
 *
 * FUNCTION NAME =  ColorDistance()
 *
 * DESCRIPTION   =  Compute the distance between two RGB color values.
 *                  The distance is the average of the absolute values
 *                  if the differences between each of the primary color
 *                  values.  The difference ranges from 0 to 255.
 *                  If the device is a gray-scale printer, the color
 *                  differences are weighted according to the response of
 *                  the human eye to the primary color.
 *
 * INPUT         = (pddc,lColor1,lColor2)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (iColorDelta)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

int ColorDistance( PDDC pddc, LONG lColor1, LONG lColor2)
{
  int iColorDelta, iDeltaRed, iDeltaGreen, iDeltaBlue;

  /*
  ** Compute the difference between each of the primary colors
  */
  iDeltaBlue = (((int) lColor1) & 0x0ff) - (((int) lColor2) & 0x0ff );
  lColor1 >>= 8;
  lColor2 >>= 8;
  iDeltaGreen = (((int) lColor1) & 0x0ff) - (((int) lColor2) & 0x0ff );
  lColor1 >>= 8;
  lColor2 >>= 8;
  iDeltaRed = (((int) lColor1) & 0x0ff) - (((int) lColor2) & 0x0ff );
  iDeltaRed = abs( iDeltaRed );
  iDeltaGreen = abs( iDeltaGreen );
  iDeltaBlue = abs( iDeltaBlue );

  if (pddc->pdv->jobProperties.fIsColorDevice)
  {
    iColorDelta = (iDeltaRed + iDeltaGreen + iDeltaBlue)/3;
  }
  else
  {
    iColorDelta = (iDeltaRed * RED_WEIGHT + iDeltaGreen * GREEN_WEIGHT + iDeltaBlue
       * BLUE_WEIGHT) / (3 * NORMAL_WEIGHT );
  }

  return( iColorDelta );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdc_QueryColorIndex()
 *
 * DESCRIPTION   = This function searches the color table for an RGB value
 *                 and returns the color table index of the closest color.
 *
 * INPUT         = (hdc,ulOptions,lColor,pddc,ifn)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = ((LONG)iClosestColor-N_SYSCOLORS)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LONG prdc_QueryColorIndex( HDC hdc, ULONG ulOptions, LONG lColor,
                           PDDC pddc, ULONG ulFunN )

  /*  LONG lColor;                         The RGB color to convert          */
{
  int   i;
  int   iDistance;
  int   iDistanceTemp;
  int   iClosestColor;
  ULONG ulRet;

  EnterDriver( pddc );

  #if      DEBUG
    LogCall( "prdc_QueryColorIndex(%lp, %08lx, %08lx, %lp, %lp)\n", ((PB)&hdc) +
             sizeof(hdc) );
  #endif                                 /* DEBUG */

  if (pddc->iType == OD_MEMORY)
  {
     ulRet = InnerGreQueryColorIndex (pddc->hdcMemory, ulOptions,
                                      lColor, ulFunN );
     ExitDriver( pddc );
     return( ulRet );
  }

  /*
  ** If the only entries in the color table are for the
  ** system colors, then the table is in RGB mode and an
  ** error is returned.
  */
  if (pddc->pddcb->color.nColors <= N_SYSCOLORS)
  {
    ExitDriver( pddc );
    return( -1L );
  }

  /*
  ** Assume that the nearest color is the first color
  ** value past the system colors.  Also compute the
  ** gray-scale distance of this color from the actual
  ** color in the color table.
  */
  iClosestColor = N_SYSCOLORS;
  iDistance = ColorDistance( pddc, lColor, pddc->pddcb->color.aulColors [N_SYSCOLORS] );

  /*
  ** Loop for each color in the color table searching for
  ** the color with the smallest gray-scale distance from
  ** the requested color.
  */
  for (i = N_SYSCOLORS + 1 ; (i < pddc->pddcb->color.nColors) &&
       (iDistance != 0) ; ++i)
  {

    /*
    ** Skip uninitialized entries in the color table.
    */
    if (pddc->pddcb->color.aulColors[i] == 0xffffffffL)
    {
      continue;
    }

    /*
    ** Compute the distance from the specified color and
    ** an RGB value in the color table.
    */
    iDistanceTemp = ColorDistance(pddc, lColor, pddc->pddcb->color.aulColors[i] );

    if (iDistanceTemp < iDistance)
    {
      iDistance = iDistanceTemp;
      iClosestColor = i;
    }
  }
  ExitDriver( pddc );
  return( (LONG)iClosestColor - N_SYSCOLORS );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdc_QueryRealColors()
 *
 *
 * DESCRIPTION   = This function allows the application to determine the
 *                 RGB color values are in the color table as they are
 *                 realized on the device.
 *
 * INPUT         = (hdc,ulOptions,iFirst,nEntries,pulDst,pddc
 *                              ,ifn)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (nEntries)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LONG prdc_QueryRealColors( HDC hdc, ULONG ulOptions, LONG iFirst,
                           LONG nEntries, ULONG *pulDst,
                           PDDC pddc, ULONG ulFunN )
{
  int   nColors = 2;            /* number of real colors supported by device */
  int   i, j;
  ULONG ulRet ;

  EnterDriver( pddc );

  #if      DEBUG
    LogCall( "prdc_QueryRealColors(%lp, %08lx, %ld, %ld, %lp, %lp, %lp)\n",
             ((PB) &hdc) + sizeof(hdc) );
  #endif                                 /* DEBUG */

  if (pddc->iType == OD_MEMORY)
  {
     ulRet = InnerGreQueryRealColors (pddc->hdcMemory, ulOptions,
                                      iFirst, nEntries, pulDst, ulFunN );
     ExitDriver( pddc );
     return( ulRet );
  }

  /*
  ** If this is a color printer, add cyan, magenta, and yellow.
  */
  if (pddc->pdv->jobProperties.fIsColorDevice)
  {
    nColors  += 3;
  }

  /*
  ** Check to make sure that the requested color indicies start
  ** at a valid location.
  */
  if ((iFirst < 0) || (iFirst >= nColors))
  {
    ExitDriver( pddc );
    return( -1 );
  }

  /*
  ** If LCOLOPT_INDEX is on, then the driver will return pairs
  ** of (index, color) values so the output entry count is
  ** divided in half.
  */
  if (ulOptions&LCOLOPT_INDEX)
  {
    nEntries = nEntries / 2;
  }

  /*
  ** Start off at the first color.
  */
  nEntries = (ULONG) min( nColors, (int) nEntries );

  for (i = (int) iFirst, j = 0 ; j < (int) nEntries ;  ++i,  ++j)
  {
    /*
    ** Store the color value into the output color table.
    ** The output can be organized as either pairs of values
    ** (index, RGBcolor) or as an array of RGB color values.
    */
    if (ulOptions & LCOLOPT_INDEX)
    {
      if (pddc->pddcb->color.ulFormat == LCOLF_RGB)
      {
        pulDst[j * 2] = CLR_NOINDEX;
      }
      else
      {
        pulDst[j * 2] = aulRealColors[i * 2];
      }
      pulDst[j * 2 + 1] = aulRealColors[i * 2 + 1];
    }
    else
    {
      pulDst[j] = aulRealColors[i * 2 + 1];
    }
  }

  /*
  ** nEntries -= iFirst; leave what user asked for
  ** The count returned is the number of long words in
  ** the table.
  */
  if (ulOptions & LCOLOPT_INDEX)
  {
    nEntries = nEntries * 2;
  }
  ExitDriver( pddc );
  return( nEntries );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdc_QueryLogColorTable()
 *
 * DESCRIPTION   = This function returns the RGB color values stored in
 *                 the logical color table with no conversion.
 *
 * INPUT         = (hdc,ulOptions,iFirst,nEntries,pulDst, pddc,ifn)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (nEntries)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LONG prdc_QueryLogColorTable( HDC hdc, ULONG ulOptions, LONG iFirst,
                              LONG nEntries, ULONG *pulDst,
                              PDDC pddc, ULONG ulFunN )
{
  int   i;
  ULONG ulRet;

  EnterDriver( pddc );

  #if      DEBUG
    LogCall( "prdc_QueryLogColorTable(%lp, %ld, %ld, %ld, %lp, %lp, %lp)\n",
             ((PB )&hdc) + sizeof(hdc) );
  #endif                                 /* DEBUG */

  if (pddc->iType == OD_MEMORY)
  {
     ulRet = InnerGreQueryLogColorTable( pddc->hdcMemory, ulOptions,
                                         iFirst,nEntries, pulDst, ulFunN );
     ExitDriver( pddc );
     return( ulRet );
  }

  /*
  ** Skip the entries at the beginning of the color table that
  ** are reserved for the system colors.
  */
//@V3.084698 -- add conditional statement
  if (pddc->pddcb->color.nColors > N_SYSCOLORS)
    iFirst += N_SYSCOLORS;

  /*
  ** Check to make sure that the requested color indicies start
  ** at a valid location.
  */
  if ((iFirst < 0) || (iFirst >= pddc->pddcb->color.nColors))
  {
    ExitDriver( pddc );
    return( -1 );
  }

  /*
  ** If LCOLOPT_INDEX is on, then the driver will return pairs
  ** of (index, color) values so the output entry count is
  ** divided in half.
  */
  if (ulOptions & LCOLOPT_INDEX)
  {
    nEntries = nEntries / 2;
  }

  /*
  ** Limit the number of entries to the size of the driver's
  ** color table.
  ** !!!CR What should be done with the entries not filled in?
  */
  if ((iFirst + nEntries) > pddc->pddcb->color.nColors)
  {
    nEntries = pddc->pddcb->color.nColors-iFirst;
  }


  /*
  ** Loop to fill in each of the output values.
  */
  for (i = 0; i < (int) nEntries;  ++i)
  {
    if (ulOptions&LCOLOPT_INDEX)
    {
      pulDst[i * 2] = i;
      pulDst[i * 2 + 1] = pddc->pddcb->color.aulColors[iFirst];
    }
    else
    {
      pulDst[i] = pddc->pddcb->color.aulColors[iFirst];
    }
     ++iFirst;                          /* Increment source index            */
  }

  /*
  ** The count returned is the number of long words in
  ** the table.
  */
  if (ulOptions & LCOLOPT_INDEX)
  {
    nEntries = nEntries * 2;
  }

  #if      0
    PrintColorTable( pddc );
  #endif

  ExitDriver( pddc );
  return( nEntries );
}
