2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI Color Translation Functions
24 * FILE: subsys/win32k/eng/xlate.c
25 * PROGRAMER: Jason Filby
30 // TODO: Cache XLATEOBJs that are created by EngCreateXlate by checking if the given palettes match a cached list
32 #include <ddk/ntddk.h>
33 #include <ddk/winddi.h>
34 #include <ddk/ntddvid.h>
36 #include <include/object.h>
37 #include <include/palette.h>
41 #include <win32k/debug1.h>
43 ULONG CCMLastSourceColor = 0, CCMLastColorMatch = 0;
45 ULONG STDCALL RGBtoULONG(BYTE Red, BYTE Green, BYTE Blue)
47 return ((Red & 0xff) << 16) | ((Green & 0xff) << 8) | (Blue & 0xff);
50 ULONG STDCALL BGRtoULONG(BYTE Blue, BYTE Green, BYTE Red)
52 return ((Blue & 0xff) << 16) | ((Green & 0xff) << 8) | (Red & 0xff);
55 static ULONG FASTCALL ShiftAndMask(XLATEGDI *XlateGDI, ULONG Color)
57 ULONG TranslatedColor;
60 if (XlateGDI->RedShift < 0)
62 TranslatedColor = (Color >> -(XlateGDI->RedShift)) & XlateGDI->RedMask;
64 TranslatedColor = (Color << XlateGDI->RedShift) & XlateGDI->RedMask;
65 if (XlateGDI->GreenShift < 0)
67 TranslatedColor |= (Color >> -(XlateGDI->GreenShift)) & XlateGDI->GreenMask;
69 TranslatedColor |= (Color << XlateGDI->GreenShift) & XlateGDI->GreenMask;
70 if (XlateGDI->BlueShift < 0)
72 TranslatedColor |= (Color >> -(XlateGDI->BlueShift)) & XlateGDI->BlueMask;
74 TranslatedColor |= (Color << XlateGDI->BlueShift) & XlateGDI->BlueMask;
76 return TranslatedColor;
80 // FIXME: If the caller knows that the destinations are indexed and not RGB
81 // then we should cache more than one value. Same with the source.
83 // Takes indexed palette and a
85 ClosestColorMatch(XLATEGDI *XlateGDI, ULONG SourceColor, ULONG *DestColors,
88 PVIDEO_CLUTDATA cSourceColor;
89 PVIDEO_CLUTDATA cDestColors;
93 ULONG SourceRed, SourceGreen, SourceBlue;
94 ULONG cxRed, cxGreen, cxBlue, rt, BestMatch = 16777215;
96 // Simple cache -- only one value because we don't want to waste time
97 // if the colors aren't very sequential
99 if(SourceColor == CCMLastSourceColor)
101 return CCMLastColorMatch;
104 if (PAL_BITFIELDS == XlateGDI->XlateObj.iSrcType || PAL_BGR == XlateGDI->XlateObj.iSrcType)
106 /* FIXME: must use bitfields */
107 SourceRGB = ShiftAndMask(XlateGDI, SourceColor);
108 cSourceColor = (PVIDEO_CLUTDATA) &SourceRGB;
112 cSourceColor = (PVIDEO_CLUTDATA)&SourceColor;
114 SourceRed = cSourceColor->Red;
115 SourceGreen = cSourceColor->Green;
116 SourceBlue = cSourceColor->Blue;
118 for (i=0; i<NumColors; i++)
120 cDestColors = (PVIDEO_CLUTDATA)&DestColors[i];
122 cxRed = (SourceRed - cDestColors->Red);
123 cxRed *= cxRed; //compute cxRed squared
124 cxGreen = (SourceGreen - cDestColors->Green);
126 cxBlue = (SourceBlue - cDestColors->Blue);
129 rt = /* sqrt */ (cxRed + cxGreen + cxBlue);
138 CCMLastSourceColor = SourceColor;
139 CCMLastColorMatch = idx;
145 IndexedToIndexedTranslationTable(XLATEGDI *XlateGDI, ULONG *TranslationTable,
146 PALGDI *PalDest, PALGDI *PalSource)
152 for(i=0; i<PalSource->NumColors; i++)
154 TranslationTable[i] = ClosestColorMatch(XlateGDI, PalSource->IndexedColors[i], PalDest->IndexedColors, PalDest->NumColors);
155 Trivial = Trivial && (TranslationTable[i] == i);
159 XlateGDI->XlateObj.flXlate |= XO_TRIVIAL;
164 BitMasksFromPal(USHORT PalType, PPALGDI Palette,
165 PULONG RedMask, PULONG BlueMask, PULONG GreenMask)
170 *RedMask = RGB(255, 0, 0);
171 *GreenMask = RGB(0, 255, 0);
172 *BlueMask = RGB(0, 0, 255);
175 *RedMask = RGB(0, 0, 255);
176 *GreenMask = RGB(0, 255, 0);
177 *BlueMask = RGB(255, 0, 0);
180 *RedMask = Palette->RedMask;
181 *BlueMask = Palette->BlueMask;
182 *GreenMask = Palette->GreenMask;
188 * Calculate the number of bits Mask must be shift to the left to get a
189 * 1 in the most significant bit position
191 static INT FASTCALL CalculateShift(ULONG Mask)
194 ULONG LeftmostBit = 1 << (8 * sizeof(ULONG) - 1);
196 while (0 == (Mask & LeftmostBit) && Shift < 8 * sizeof(ULONG))
205 XLATEOBJ * STDCALL IntEngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
206 HPALETTE PaletteDest, HPALETTE PaletteSource)
208 // FIXME: Add support for BGR conversions
213 PALGDI *SourcePalGDI, *DestPalGDI;
215 ULONG SourceRedMask, SourceGreenMask, SourceBlueMask;
216 ULONG DestRedMask, DestGreenMask, DestBlueMask;
219 NewXlate = (HPALETTE)CreateGDIHandle(sizeof( XLATEGDI ), sizeof( XLATEOBJ ));
220 if ( !ValidEngHandle ( NewXlate ) )
223 XlateObj = (XLATEOBJ*) AccessUserObject( (ULONG) NewXlate );
224 XlateGDI = (XLATEGDI*) AccessInternalObject( (ULONG) NewXlate );
228 if (NULL != PaletteSource)
230 SourcePalGDI = PALETTE_LockPalette(PaletteSource);
232 if (PaletteDest == PaletteSource)
234 DestPalGDI = SourcePalGDI;
236 else if (NULL != PaletteDest)
238 DestPalGDI = PALETTE_LockPalette(PaletteDest);
241 XlateObj->iSrcType = SourcePalType;
242 XlateObj->iDstType = DestPalType;
244 // Store handles of palettes in internal Xlate GDI object (or NULLs)
245 XlateGDI->DestPal = PaletteDest;
246 XlateGDI->SourcePal = PaletteSource;
248 XlateObj->flXlate = 0;
250 XlateGDI->UseShiftAndMask = FALSE;
252 /* Compute bit fiddeling constants unless both palettes are indexed, then we don't need them */
253 if (PAL_INDEXED != SourcePalType || PAL_INDEXED != DestPalType)
255 BitMasksFromPal(PAL_INDEXED == SourcePalType ? PAL_RGB : SourcePalType,
256 SourcePalGDI, &SourceRedMask, &SourceBlueMask, &SourceGreenMask);
257 BitMasksFromPal(PAL_INDEXED == DestPalType ? PAL_RGB : DestPalType,
258 DestPalGDI, &DestRedMask, &DestBlueMask, &DestGreenMask);
259 XlateGDI->RedShift = CalculateShift(SourceRedMask) - CalculateShift(DestRedMask);
260 XlateGDI->RedMask = DestRedMask;
261 XlateGDI->GreenShift = CalculateShift(SourceGreenMask) - CalculateShift(DestGreenMask);
262 XlateGDI->GreenMask = DestGreenMask;
263 XlateGDI->BlueShift = CalculateShift(SourceBlueMask) - CalculateShift(DestBlueMask);
264 XlateGDI->BlueMask = DestBlueMask;
267 // If source and destination palettes are the same or if they're RGB/BGR
268 if( (PaletteDest == PaletteSource) ||
269 ((DestPalType == PAL_RGB) && (SourcePalType == PAL_RGB)) ||
270 ((DestPalType == PAL_BGR) && (SourcePalType == PAL_BGR)) )
272 XlateObj->flXlate |= XO_TRIVIAL;
273 if (NULL != PaletteSource)
275 PALETTE_UnlockPalette(PaletteSource);
277 if (NULL != PaletteDest && PaletteDest != PaletteSource)
279 PALETTE_UnlockPalette(PaletteDest);
284 /* If source and destination are bitfield based (RGB and BGR are just special bitfields) */
285 if ((PAL_RGB == DestPalType || PAL_BGR == DestPalType || PAL_BITFIELDS == DestPalType) &&
286 (PAL_RGB == SourcePalType || PAL_BGR == SourcePalType || PAL_BITFIELDS == SourcePalType))
288 if (SourceRedMask == DestRedMask &&
289 SourceBlueMask == DestBlueMask &&
290 SourceGreenMask == DestGreenMask)
292 XlateObj->flXlate |= XO_TRIVIAL;
294 XlateGDI->UseShiftAndMask = TRUE;
295 if (NULL != PaletteSource)
297 PALETTE_UnlockPalette(PaletteSource);
299 if (NULL != PaletteDest && PaletteDest != PaletteSource)
301 PALETTE_UnlockPalette(PaletteDest);
306 // Prepare the translation table
307 if (PAL_INDEXED == SourcePalType || PAL_RGB == SourcePalType || PAL_BGR == SourcePalType)
309 XlateObj->flXlate |= XO_TABLE;
310 if ((SourcePalType == PAL_INDEXED) && (DestPalType == PAL_INDEXED))
312 if(SourcePalGDI->NumColors > DestPalGDI->NumColors)
314 IndexedColors = SourcePalGDI->NumColors;
316 IndexedColors = DestPalGDI->NumColors;
318 else if (SourcePalType == PAL_INDEXED) { IndexedColors = SourcePalGDI->NumColors; }
319 else if (DestPalType == PAL_INDEXED) { IndexedColors = DestPalGDI->NumColors; }
321 XlateGDI->translationTable = EngAllocMem(FL_ZERO_MEMORY, sizeof(ULONG)*IndexedColors, 0);
324 // Source palette is indexed
325 if(XlateObj->iSrcType == PAL_INDEXED)
327 if(XlateObj->iDstType == PAL_INDEXED)
329 // Converting from indexed to indexed
330 IndexedToIndexedTranslationTable(XlateGDI, XlateGDI->translationTable, DestPalGDI, SourcePalGDI);
332 if (PAL_RGB == XlateObj->iDstType || PAL_BITFIELDS == XlateObj->iDstType )
334 // FIXME: Is this necessary? I think the driver has to call this
335 // function anyways if pulXlate is NULL and Source is PAL_INDEXED
337 // Converting from indexed to RGB
339 RtlCopyMemory(XlateGDI->translationTable, SourcePalGDI->IndexedColors, sizeof(ULONG) * SourcePalGDI->NumColors);
340 if (PAL_BITFIELDS == XlateObj->iDstType)
342 for (i = 0; i < SourcePalGDI->NumColors; i++)
344 XlateGDI->translationTable[i] = ShiftAndMask(XlateGDI, XlateGDI->translationTable[i]);
349 XlateObj->pulXlate = XlateGDI->translationTable;
352 // Source palette is RGB
353 if (PAL_RGB == XlateObj->iSrcType || PAL_BGR == XlateObj->iSrcType)
355 if(PAL_INDEXED == XlateObj->iDstType)
357 // FIXME: Is this necessary? I think the driver has to call this
358 // function anyways if pulXlate is NULL and Dest is PAL_INDEXED
360 // Converting from RGB to indexed
361 RtlCopyMemory(XlateGDI->translationTable, DestPalGDI->IndexedColors, sizeof(ULONG) * DestPalGDI->NumColors);
365 // FIXME: Add support for XO_TO_MONO
366 if (NULL != PaletteSource)
368 PALETTE_UnlockPalette(PaletteSource);
370 if (NULL != PaletteDest && PaletteDest != PaletteSource)
372 PALETTE_UnlockPalette(PaletteDest);
378 VOID FASTCALL EngDeleteXlate(XLATEOBJ *XlateObj)
380 HANDLE HXlate = (HANDLE)AccessHandleFromUserObject(XlateObj);
381 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObject((ULONG)HXlate);
383 if(XlateGDI->translationTable!=NULL)
385 EngFreeMem(XlateGDI->translationTable);
388 FreeGDIHandle((ULONG)HXlate);
395 XLATEOBJ_piVector(XLATEOBJ *XlateObj)
397 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
399 if(XlateObj->iSrcType == PAL_INDEXED)
401 return XlateGDI->translationTable;
411 XLATEOBJ_iXlate(XLATEOBJ *XlateObj,
415 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
418 // Return the original color if there's no color translation object
419 if(!XlateObj) return Color;
421 if(XlateObj->flXlate & XO_TRIVIAL)
425 if(XlateGDI->UseShiftAndMask)
427 return ShiftAndMask(XlateGDI, Color);
429 if (PAL_RGB == XlateObj->iSrcType || PAL_BGR == XlateObj->iSrcType
430 || PAL_BITFIELDS == XlateObj->iSrcType)
432 // FIXME: should we cache colors used often?
433 // FIXME: won't work if destination isn't indexed
435 // Extract the destination palette
436 PalGDI = PALETTE_LockPalette(XlateGDI->DestPal);
438 // Return closest match for the given color
439 Closest = ClosestColorMatch(XlateGDI, Color, PalGDI->IndexedColors, PalGDI->NumColors);
440 PALETTE_UnlockPalette(XlateGDI->DestPal);
443 if(XlateObj->iSrcType == PAL_INDEXED)
445 return XlateGDI->translationTable[Color];
455 XLATEOBJ_cGetPalette(XLATEOBJ *XlateObj,
465 XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
467 if(PalOutType == XO_SRCPALETTE)
469 HPal = XlateGDI->SourcePal;
471 if(PalOutType == XO_DESTPALETTE)
473 HPal = XlateGDI->DestPal;
476 PalGDI = PALETTE_LockPalette(HPal);
477 RtlCopyMemory(OutPal, PalGDI->IndexedColors, sizeof(ULONG)*cPal);
478 PALETTE_UnlockPalette(HPal);