update for HEAD-2003050101
[reactos.git] / subsys / win32k / eng / xlate.c
index da83776..00a4f63 100644 (file)
@@ -17,7 +17,7 @@
 #include <include/object.h>
 #include "handle.h"
 
-//#define NDEBUG
+#define NDEBUG
 #include <win32k/debug1.h>
 
 ULONG CCMLastSourceColor = 0, CCMLastColorMatch = 0;
@@ -32,17 +32,43 @@ ULONG BGRtoULONG(BYTE Blue, BYTE Green, BYTE Red)
   return ((Blue & 0xff) << 16) | ((Green & 0xff) << 8) | (Red & 0xff);
 }
 
+static ULONG ShiftAndMask(XLATEGDI *XlateGDI, ULONG Color)
+{
+  ULONG TranslatedColor;
+
+  TranslatedColor = 0;
+  if (XlateGDI->RedShift < 0)
+  {
+    TranslatedColor = (Color >> -(XlateGDI->RedShift)) & XlateGDI->RedMask;
+  } else
+    TranslatedColor = (Color << XlateGDI->RedShift) & XlateGDI->RedMask;
+  if (XlateGDI->GreenShift < 0)
+  {
+    TranslatedColor |= (Color >> -(XlateGDI->GreenShift)) & XlateGDI->GreenMask;
+  } else
+    TranslatedColor |= (Color << XlateGDI->GreenShift) & XlateGDI->GreenMask;
+  if (XlateGDI->BlueShift < 0)
+  {
+    TranslatedColor |= (Color >> -(XlateGDI->BlueShift)) & XlateGDI->BlueMask;
+  } else
+    TranslatedColor |= (Color << XlateGDI->BlueShift) & XlateGDI->BlueMask;
+
+  return TranslatedColor;
+}
+
 
 // FIXME: If the caller knows that the destinations are indexed and not RGB
 // then we should cache more than one value. Same with the source.
 
 // Takes indexed palette and a
-ULONG ClosestColorMatch(ULONG SourceColor, ULONG *DestColors,
+ULONG ClosestColorMatch(XLATEGDI *XlateGDI, ULONG SourceColor, ULONG *DestColors,
                         ULONG NumColors)
 {
   PVIDEO_CLUTDATA cSourceColor;
   PVIDEO_CLUTDATA cDestColors;
   LONG idx = 0, i, rt;
+  ULONG SourceRGB;
+  ULONG SourceRed, SourceGreen, SourceBlue;
   ULONG cxRed, cxGreen, cxBlue, BestMatch = 16777215;
 
   // Simple cache -- only one value because we don't want to waste time
@@ -53,16 +79,33 @@ ULONG ClosestColorMatch(ULONG SourceColor, ULONG *DestColors,
     return CCMLastColorMatch;
   }
 
-  cSourceColor = (PVIDEO_CLUTDATA)&SourceColor;
+  if (PAL_BITFIELDS == XlateGDI->XlateObj.iSrcType)
+    {
+    /* FIXME: must use bitfields */
+    SourceRGB = ShiftAndMask(XlateGDI, SourceColor);
+    cSourceColor = (PVIDEO_CLUTDATA) &SourceRGB;
+/*
+    SourceRed = (SourceColor >> 7) & 0xff;
+    SourceGreen = (SourceColor >> 2) & 0xff;
+    SourceBlue = (SourceColor << 3) & 0xff;
+*/
+    }
+  else
+    {
+    cSourceColor = (PVIDEO_CLUTDATA)&SourceColor;
+    } 
+  SourceRed = cSourceColor->Red;
+  SourceGreen = cSourceColor->Green;
+  SourceBlue = cSourceColor->Blue;
   for (i=0; i<NumColors; i++)
   {
     cDestColors = (PVIDEO_CLUTDATA)&DestColors[i];
 
-    cxRed = (cSourceColor->Red - cDestColors->Red);
+    cxRed = (SourceRed - cDestColors->Red);
        cxRed *= cxRed;  //compute cxRed squared
-    cxGreen = (cSourceColor->Green - cDestColors->Green);
+    cxGreen = (SourceGreen - cDestColors->Green);
        cxGreen *= cxGreen;
-    cxBlue = (cSourceColor->Blue - cDestColors->Blue);
+    cxBlue = (SourceBlue - cDestColors->Blue);
        cxBlue *= cxBlue;
 
     rt = /* sqrt */ (cxRed + cxGreen + cxBlue);
@@ -80,19 +123,60 @@ ULONG ClosestColorMatch(ULONG SourceColor, ULONG *DestColors,
   return idx;
 }
 
-VOID IndexedToIndexedTranslationTable(ULONG *TranslationTable,
+VOID IndexedToIndexedTranslationTable(XLATEGDI *XlateGDI, ULONG *TranslationTable,
                                       PALGDI *PalDest, PALGDI *PalSource)
 {
   ULONG i;
 
   for(i=0; i<PalSource->NumColors; i++)
   {
-    TranslationTable[i] = ClosestColorMatch(PalSource->IndexedColors[i], PalDest->IndexedColors, PalDest->NumColors);
+    TranslationTable[i] = ClosestColorMatch(XlateGDI, PalSource->IndexedColors[i], PalDest->IndexedColors, PalDest->NumColors);
   }
 }
 
-XLATEOBJ *EngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
-                         HPALETTE PaletteDest, HPALETTE PaletteSource)
+static VOID BitMasksFromPal(USHORT PalType, PPALGDI Palette,
+                            PULONG RedMask, PULONG BlueMask, PULONG GreenMask)
+{
+  switch(PalType)
+  {
+    case PAL_RGB:
+      *RedMask = RGB(255, 0, 0);
+      *GreenMask = RGB(0, 255, 0);
+      *BlueMask = RGB(0, 0, 255);
+      break;
+    case PAL_BGR:
+      *RedMask = RGB(0, 0, 255);
+      *GreenMask = RGB(0, 255, 0);
+      *BlueMask = RGB(255, 0, 0);
+      break;
+    case PAL_BITFIELDS:
+      *RedMask = Palette->RedMask;
+      *BlueMask = Palette->BlueMask;
+      *GreenMask = Palette->GreenMask;
+      break;
+  }
+}
+
+/*
+ * Calculate the number of bits Mask must be shift to the left to get a
+ * 1 in the most significant bit position
+ */
+static INT CalculateShift(ULONG Mask)
+{
+   INT Shift = 0;
+   ULONG LeftmostBit = 1 << (8 * sizeof(ULONG) - 1);
+
+   while (0 == (Mask & LeftmostBit) && Shift < 8 * sizeof(ULONG))
+     {
+     Mask = Mask << 1;
+     Shift++;
+     }
+
+   return Shift;
+}
+
+XLATEOBJ *IntEngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
+                            HPALETTE PaletteDest, HPALETTE PaletteSource)
 {
   // FIXME: Add support for BGR conversions
 
@@ -101,20 +185,27 @@ XLATEOBJ *EngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
   XLATEGDI *XlateGDI;
   PALGDI   *SourcePalGDI, *DestPalGDI;
   ULONG    IndexedColors;
+  ULONG    SourceRedMask, SourceGreenMask, SourceBlueMask;
+  ULONG    DestRedMask, DestGreenMask, DestBlueMask;
+  UINT     i;
 
   NewXlate = (HPALETTE)CreateGDIHandle(sizeof( XLATEGDI ), sizeof( XLATEOBJ ));
   if( !ValidEngHandle( NewXlate ) )
        return NULL;
 
-  XlateObj = (XLATEOBJ*) AccessUserObject( NewXlate );
-  XlateGDI = (XLATEGDI*) AccessInternalObject( NewXlate );
+  XlateObj = (XLATEOBJ*) AccessUserObject( (ULONG) NewXlate );
+  XlateGDI = (XLATEGDI*) AccessInternalObject( (ULONG) NewXlate );
   ASSERT( XlateObj );
   ASSERT( XlateGDI );
 
-  if(SourcePalType == PAL_INDEXED)
+  if (NULL != PaletteSource)
+  {
     SourcePalGDI = (PALGDI*)AccessInternalObject((ULONG)PaletteSource);
-  if(DestPalType == PAL_INDEXED)
+  }
+  if (NULL != PaletteDest)
+  {
     DestPalGDI = (PALGDI*)AccessInternalObject((ULONG)PaletteDest);
+  }
 
   XlateObj->iSrcType = SourcePalType;
   XlateObj->iDstType = DestPalType;
@@ -125,6 +216,23 @@ XLATEOBJ *EngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
 
   XlateObj->flXlate = 0;
 
+  XlateGDI->UseShiftAndMask = FALSE;
+
+  /* Compute bit fiddeling constants unless both palettes are indexed, then we don't need them */
+  if (PAL_INDEXED != SourcePalType || PAL_INDEXED != DestPalType)
+  {
+    BitMasksFromPal(PAL_INDEXED == SourcePalType ? PAL_RGB : SourcePalType,
+                    SourcePalGDI, &SourceRedMask, &SourceBlueMask, &SourceGreenMask);
+    BitMasksFromPal(PAL_INDEXED == DestPalType ? PAL_RGB : DestPalType,
+                    DestPalGDI, &DestRedMask, &DestBlueMask, &DestGreenMask);
+    XlateGDI->RedShift = CalculateShift(SourceRedMask) - CalculateShift(DestRedMask);
+    XlateGDI->RedMask = DestRedMask;
+    XlateGDI->GreenShift = CalculateShift(SourceGreenMask) - CalculateShift(DestGreenMask);
+    XlateGDI->GreenMask = DestGreenMask;
+    XlateGDI->BlueShift = CalculateShift(SourceBlueMask) - CalculateShift(DestBlueMask);
+    XlateGDI->BlueMask = DestBlueMask;
+  }
+
   // If source and destination palettes are the same or if they're RGB/BGR
   if( (PaletteDest == PaletteSource) ||
       ((DestPalType == PAL_RGB) && (SourcePalType == PAL_RGB)) ||
@@ -134,6 +242,20 @@ XLATEOBJ *EngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
     return XlateObj;
   }
 
+  /* If source and destination are bitfield based (RGB and BGR are just special bitfields) */
+  if ((PAL_RGB == DestPalType || PAL_BGR == DestPalType || PAL_BITFIELDS == DestPalType) &&
+      (PAL_RGB == SourcePalType || PAL_BGR == SourcePalType || PAL_BITFIELDS == SourcePalType))
+  {
+    if (SourceRedMask == DestRedMask &&
+        SourceBlueMask == DestBlueMask &&
+        SourceGreenMask == DestGreenMask)
+      {
+      XlateObj->flXlate |= XO_TRIVIAL;
+      }
+    XlateGDI->UseShiftAndMask = TRUE;
+    return XlateObj;
+  }
+
   // Prepare the translation table
   if( (SourcePalType == PAL_INDEXED) || (SourcePalType == PAL_RGB) )
   {
@@ -158,9 +280,9 @@ XLATEOBJ *EngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
     if(XlateObj->iDstType == PAL_INDEXED)
     {
       // Converting from indexed to indexed
-      IndexedToIndexedTranslationTable(XlateGDI->translationTable, DestPalGDI, SourcePalGDI);
+      IndexedToIndexedTranslationTable(XlateGDI, XlateGDI->translationTable, DestPalGDI, SourcePalGDI);
     } else
-      if(XlateObj->iDstType == PAL_RGB)
+      if (PAL_RGB == XlateObj->iDstType || PAL_BITFIELDS == XlateObj->iDstType )
       {
         // FIXME: Is this necessary? I think the driver has to call this
         // function anyways if pulXlate is NULL and Source is PAL_INDEXED
@@ -170,6 +292,13 @@ XLATEOBJ *EngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
         XLATEOBJ_cGetPalette(XlateObj, XO_SRCPALETTE,
                              SourcePalGDI->NumColors,
                              XlateGDI->translationTable);
+       if (PAL_BITFIELDS == XlateObj->iDstType)
+       {
+         for (i = 0; i < SourcePalGDI->NumColors; i++)
+         {
+         XlateGDI->translationTable[i] = ShiftAndMask(XlateGDI, XlateGDI->translationTable[i]);
+         }
+       }
       }
 
     XlateObj->pulXlate = XlateGDI->translationTable;
@@ -232,7 +361,11 @@ XLATEOBJ_iXlate(XLATEOBJ *XlateObj,
   {
     return Color;
   } else
-  if(XlateObj->iSrcType == PAL_RGB)
+  if(XlateGDI->UseShiftAndMask)
+  {
+    return ShiftAndMask(XlateGDI, Color);
+  } else
+  if(PAL_RGB == XlateObj->iSrcType || PAL_BITFIELDS == XlateObj->iSrcType)
   {
     // FIXME: should we cache colors used often?
     // FIXME: won't work if destination isn't indexed
@@ -240,8 +373,8 @@ XLATEOBJ_iXlate(XLATEOBJ *XlateObj,
     // Extract the destination palette
     PalGDI = (PALGDI*)AccessInternalObject((ULONG)XlateGDI->DestPal);
 
-    // Return closest match for the given RGB color
-    return ClosestColorMatch(Color, PalGDI->IndexedColors, PalGDI->NumColors);
+    // Return closest match for the given color
+    return ClosestColorMatch(XlateGDI, Color, PalGDI->IndexedColors, PalGDI->NumColors);
   } else
   if(XlateObj->iSrcType == PAL_INDEXED)
   {