2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Color Translation Functions
5 * FILE: subsys/win32k/eng/xlate.c
6 * PROGRAMER: Jason Filby
11 // TODO: Cache XLATEOBJs that are created by EngCreateXlate by checking if the given palettes match a cached list
13 #include <ddk/ntddk.h>
14 #include <ddk/winddi.h>
15 #include <ddk/ntddvid.h>
17 #include <include/object.h>
21 #include <win32k/debug1.h>
23 ULONG CCMLastSourceColor = 0, CCMLastColorMatch = 0;
25 ULONG RGBtoULONG(BYTE Red, BYTE Green, BYTE Blue)
27 return ((Red & 0xff) << 16) | ((Green & 0xff) << 8) | (Blue & 0xff);
30 ULONG BGRtoULONG(BYTE Blue, BYTE Green, BYTE Red)
32 return ((Blue & 0xff) << 16) | ((Green & 0xff) << 8) | (Red & 0xff);
35 static ULONG ShiftAndMask(XLATEGDI *XlateGDI, ULONG Color)
37 ULONG TranslatedColor;
40 if (XlateGDI->RedShift < 0)
42 TranslatedColor = (Color >> -(XlateGDI->RedShift)) & XlateGDI->RedMask;
44 TranslatedColor = (Color << XlateGDI->RedShift) & XlateGDI->RedMask;
45 if (XlateGDI->GreenShift < 0)
47 TranslatedColor |= (Color >> -(XlateGDI->GreenShift)) & XlateGDI->GreenMask;
49 TranslatedColor |= (Color << XlateGDI->GreenShift) & XlateGDI->GreenMask;
50 if (XlateGDI->BlueShift < 0)
52 TranslatedColor |= (Color >> -(XlateGDI->BlueShift)) & XlateGDI->BlueMask;
54 TranslatedColor |= (Color << XlateGDI->BlueShift) & XlateGDI->BlueMask;
56 return TranslatedColor;
60 // FIXME: If the caller knows that the destinations are indexed and not RGB
61 // then we should cache more than one value. Same with the source.
63 // Takes indexed palette and a
64 ULONG ClosestColorMatch(XLATEGDI *XlateGDI, ULONG SourceColor, ULONG *DestColors,
67 PVIDEO_CLUTDATA cSourceColor;
68 PVIDEO_CLUTDATA cDestColors;
71 ULONG SourceRed, SourceGreen, SourceBlue;
72 ULONG cxRed, cxGreen, cxBlue, BestMatch = 16777215;
74 // Simple cache -- only one value because we don't want to waste time
75 // if the colors aren't very sequential
77 if(SourceColor == CCMLastSourceColor)
79 return CCMLastColorMatch;
82 if (PAL_BITFIELDS == XlateGDI->XlateObj.iSrcType)
84 /* FIXME: must use bitfields */
85 SourceRGB = ShiftAndMask(XlateGDI, SourceColor);
86 cSourceColor = (PVIDEO_CLUTDATA) &SourceRGB;
88 SourceRed = (SourceColor >> 7) & 0xff;
89 SourceGreen = (SourceColor >> 2) & 0xff;
90 SourceBlue = (SourceColor << 3) & 0xff;
95 cSourceColor = (PVIDEO_CLUTDATA)&SourceColor;
97 SourceRed = cSourceColor->Red;
98 SourceGreen = cSourceColor->Green;
99 SourceBlue = cSourceColor->Blue;
100 for (i=0; i<NumColors; i++)
102 cDestColors = (PVIDEO_CLUTDATA)&DestColors[i];
104 cxRed = (SourceRed - cDestColors->Red);
105 cxRed *= cxRed; //compute cxRed squared
106 cxGreen = (SourceGreen - cDestColors->Green);
108 cxBlue = (SourceBlue - cDestColors->Blue);
111 rt = /* sqrt */ (cxRed + cxGreen + cxBlue);
120 CCMLastSourceColor = SourceColor;
121 CCMLastColorMatch = idx;
126 VOID IndexedToIndexedTranslationTable(XLATEGDI *XlateGDI, ULONG *TranslationTable,
127 PALGDI *PalDest, PALGDI *PalSource)
131 for(i=0; i<PalSource->NumColors; i++)
133 TranslationTable[i] = ClosestColorMatch(XlateGDI, PalSource->IndexedColors[i], PalDest->IndexedColors, PalDest->NumColors);
137 static VOID BitMasksFromPal(USHORT PalType, PPALGDI Palette,
138 PULONG RedMask, PULONG BlueMask, PULONG GreenMask)
143 *RedMask = RGB(255, 0, 0);
144 *GreenMask = RGB(0, 255, 0);
145 *BlueMask = RGB(0, 0, 255);
148 *RedMask = RGB(0, 0, 255);
149 *GreenMask = RGB(0, 255, 0);
150 *BlueMask = RGB(255, 0, 0);
153 *RedMask = Palette->RedMask;
154 *BlueMask = Palette->BlueMask;
155 *GreenMask = Palette->GreenMask;
161 * Calculate the number of bits Mask must be shift to the left to get a
162 * 1 in the most significant bit position
164 static INT CalculateShift(ULONG Mask)
167 ULONG LeftmostBit = 1 << (8 * sizeof(ULONG) - 1);
169 while (0 == (Mask & LeftmostBit) && Shift < 8 * sizeof(ULONG))
178 XLATEOBJ *IntEngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
179 HPALETTE PaletteDest, HPALETTE PaletteSource)
181 // FIXME: Add support for BGR conversions
186 PALGDI *SourcePalGDI, *DestPalGDI;
188 ULONG SourceRedMask, SourceGreenMask, SourceBlueMask;
189 ULONG DestRedMask, DestGreenMask, DestBlueMask;
192 NewXlate = (HPALETTE)CreateGDIHandle(sizeof( XLATEGDI ), sizeof( XLATEOBJ ));
193 if( !ValidEngHandle( NewXlate ) )
196 XlateObj = (XLATEOBJ*) AccessUserObject( (ULONG) NewXlate );
197 XlateGDI = (XLATEGDI*) AccessInternalObject( (ULONG) NewXlate );
201 if (NULL != PaletteSource)
203 SourcePalGDI = (PALGDI*)AccessInternalObject((ULONG)PaletteSource);
205 if (NULL != PaletteDest)
207 DestPalGDI = (PALGDI*)AccessInternalObject((ULONG)PaletteDest);
210 XlateObj->iSrcType = SourcePalType;
211 XlateObj->iDstType = DestPalType;
213 // Store handles of palettes in internal Xlate GDI object (or NULLs)
214 XlateGDI->DestPal = PaletteDest;
215 XlateGDI->SourcePal = PaletteSource;
217 XlateObj->flXlate = 0;
219 XlateGDI->UseShiftAndMask = FALSE;
221 /* Compute bit fiddeling constants unless both palettes are indexed, then we don't need them */
222 if (PAL_INDEXED != SourcePalType || PAL_INDEXED != DestPalType)
224 BitMasksFromPal(PAL_INDEXED == SourcePalType ? PAL_RGB : SourcePalType,
225 SourcePalGDI, &SourceRedMask, &SourceBlueMask, &SourceGreenMask);
226 BitMasksFromPal(PAL_INDEXED == DestPalType ? PAL_RGB : DestPalType,
227 DestPalGDI, &DestRedMask, &DestBlueMask, &DestGreenMask);
228 XlateGDI->RedShift = CalculateShift(SourceRedMask) - CalculateShift(DestRedMask);
229 XlateGDI->RedMask = DestRedMask;
230 XlateGDI->GreenShift = CalculateShift(SourceGreenMask) - CalculateShift(DestGreenMask);
231 XlateGDI->GreenMask = DestGreenMask;
232 XlateGDI->BlueShift = CalculateShift(SourceBlueMask) - CalculateShift(DestBlueMask);
233 XlateGDI->BlueMask = DestBlueMask;
236 // If source and destination palettes are the same or if they're RGB/BGR
237 if( (PaletteDest == PaletteSource) ||
238 ((DestPalType == PAL_RGB) && (SourcePalType == PAL_RGB)) ||
239 ((DestPalType == PAL_BGR) && (SourcePalType == PAL_BGR)) )
241 XlateObj->flXlate |= XO_TRIVIAL;
245 /* If source and destination are bitfield based (RGB and BGR are just special bitfields) */
246 if ((PAL_RGB == DestPalType || PAL_BGR == DestPalType || PAL_BITFIELDS == DestPalType) &&
247 (PAL_RGB == SourcePalType || PAL_BGR == SourcePalType || PAL_BITFIELDS == SourcePalType))
249 if (SourceRedMask == DestRedMask &&
250 SourceBlueMask == DestBlueMask &&
251 SourceGreenMask == DestGreenMask)
253 XlateObj->flXlate |= XO_TRIVIAL;
255 XlateGDI->UseShiftAndMask = TRUE;
259 // Prepare the translation table
260 if( (SourcePalType == PAL_INDEXED) || (SourcePalType == PAL_RGB) )
262 XlateObj->flXlate |= XO_TABLE;
263 if ((SourcePalType == PAL_INDEXED) && (DestPalType == PAL_INDEXED))
265 if(SourcePalGDI->NumColors > DestPalGDI->NumColors)
267 IndexedColors = SourcePalGDI->NumColors;
269 IndexedColors = DestPalGDI->NumColors;
271 else if (SourcePalType == PAL_INDEXED) { IndexedColors = SourcePalGDI->NumColors; }
272 else if (DestPalType == PAL_INDEXED) { IndexedColors = DestPalGDI->NumColors; }
274 XlateGDI->translationTable = EngAllocMem(FL_ZERO_MEMORY, sizeof(ULONG)*IndexedColors, 0);
277 // Source palette is indexed
278 if(XlateObj->iSrcType == PAL_INDEXED)
280 if(XlateObj->iDstType == PAL_INDEXED)
282 // Converting from indexed to indexed
283 IndexedToIndexedTranslationTable(XlateGDI, XlateGDI->translationTable, DestPalGDI, SourcePalGDI);
285 if (PAL_RGB == XlateObj->iDstType || PAL_BITFIELDS == XlateObj->iDstType )
287 // FIXME: Is this necessary? I think the driver has to call this
288 // function anyways if pulXlate is NULL and Source is PAL_INDEXED
290 // Converting from indexed to RGB
292 XLATEOBJ_cGetPalette(XlateObj, XO_SRCPALETTE,
293 SourcePalGDI->NumColors,
294 XlateGDI->translationTable);
295 if (PAL_BITFIELDS == XlateObj->iDstType)
297 for (i = 0; i < SourcePalGDI->NumColors; i++)
299 XlateGDI->translationTable[i] = ShiftAndMask(XlateGDI, XlateGDI->translationTable[i]);
304 XlateObj->pulXlate = XlateGDI->translationTable;
307 // Source palette is RGB
308 if(XlateObj->iSrcType == PAL_RGB)
310 if(XlateObj->iDstType == PAL_INDEXED)
312 // FIXME: Is this necessary? I think the driver has to call this
313 // function anyways if pulXlate is NULL and Dest is PAL_INDEXED
315 // Converting from RGB to indexed
316 XLATEOBJ_cGetPalette(XlateObj, XO_DESTPALETTE, DestPalGDI->NumColors, XlateGDI->translationTable);
320 // FIXME: Add support for XO_TO_MONO
324 VOID EngDeleteXlate(XLATEOBJ *XlateObj)
326 HPALETTE HXlate = (HPALETTE)AccessHandleFromUserObject(XlateObj);
327 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObject((ULONG)HXlate);
329 if(XlateGDI->translationTable!=NULL)
331 EngFreeMem(XlateGDI->translationTable);
334 FreeGDIHandle((ULONG)HXlate);
338 XLATEOBJ_piVector(XLATEOBJ *XlateObj)
340 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
342 if(XlateObj->iSrcType == PAL_INDEXED)
344 return XlateGDI->translationTable;
351 XLATEOBJ_iXlate(XLATEOBJ *XlateObj,
355 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
357 // Return the original color if there's no color translation object
358 if(!XlateObj) return Color;
360 if(XlateObj->flXlate & XO_TRIVIAL)
364 if(XlateGDI->UseShiftAndMask)
366 return ShiftAndMask(XlateGDI, Color);
368 if(PAL_RGB == XlateObj->iSrcType || PAL_BITFIELDS == XlateObj->iSrcType)
370 // FIXME: should we cache colors used often?
371 // FIXME: won't work if destination isn't indexed
373 // Extract the destination palette
374 PalGDI = (PALGDI*)AccessInternalObject((ULONG)XlateGDI->DestPal);
376 // Return closest match for the given color
377 return ClosestColorMatch(XlateGDI, Color, PalGDI->IndexedColors, PalGDI->NumColors);
379 if(XlateObj->iSrcType == PAL_INDEXED)
381 return XlateGDI->translationTable[Color];
388 XLATEOBJ_cGetPalette(XLATEOBJ *XlateObj,
398 XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
400 if(PalOutType == XO_SRCPALETTE)
402 HPal = XlateGDI->SourcePal;
404 if(PalOutType == XO_DESTPALETTE)
406 HPal = XlateGDI->DestPal;
409 PalGDI = (PALGDI*)AccessInternalObject((ULONG)HPal);
410 RtlCopyMemory(OutPal, PalGDI->IndexedColors, sizeof(ULONG)*cPal);