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);
36 // FIXME: If the caller knows that the destinations are indexed and not RGB
37 // then we should cache more than one value. Same with the source.
39 // Takes indexed palette and a
40 ULONG
ClosestColorMatch(ULONG SourceColor
, ULONG
*DestColors
,
43 PVIDEO_CLUTDATA cSourceColor
;
44 PVIDEO_CLUTDATA cDestColors
;
46 ULONG cxRed
, cxGreen
, cxBlue
, BestMatch
= 16777215;
48 // Simple cache -- only one value because we don't want to waste time
49 // if the colors aren't very sequential
51 if(SourceColor
== CCMLastSourceColor
)
53 return CCMLastColorMatch
;
56 cSourceColor
= (PVIDEO_CLUTDATA
)&SourceColor
;
57 for (i
=0; i
<NumColors
; i
++)
59 cDestColors
= (PVIDEO_CLUTDATA
)&DestColors
[i
];
61 cxRed
= (cSourceColor
->Red
- cDestColors
->Red
);
62 cxRed
*= cxRed
; //compute cxRed squared
63 cxGreen
= (cSourceColor
->Green
- cDestColors
->Green
);
65 cxBlue
= (cSourceColor
->Blue
- cDestColors
->Blue
);
68 rt
= /* sqrt */ (cxRed
+ cxGreen
+ cxBlue
);
77 CCMLastSourceColor
= SourceColor
;
78 CCMLastColorMatch
= idx
;
83 VOID
IndexedToIndexedTranslationTable(ULONG
*TranslationTable
,
84 PALGDI
*PalDest
, PALGDI
*PalSource
)
88 for(i
=0; i
<PalSource
->NumColors
; i
++)
90 TranslationTable
[i
] = ClosestColorMatch(PalSource
->IndexedColors
[i
], PalDest
->IndexedColors
, PalDest
->NumColors
);
94 static VOID
BitMasksFromPal(USHORT PalType
, PPALGDI Palette
,
95 PULONG RedMask
, PULONG BlueMask
, PULONG GreenMask
)
100 *RedMask
= RGB(255, 0, 0);
101 *GreenMask
= RGB(0, 255, 0);
102 *BlueMask
= RGB(0, 0, 255);
105 *RedMask
= RGB(0, 0, 255);
106 *GreenMask
= RGB(0, 255, 0);
107 *BlueMask
= RGB(255, 0, 0);
110 *RedMask
= Palette
->RedMask
;
111 *BlueMask
= Palette
->BlueMask
;
112 *GreenMask
= Palette
->GreenMask
;
118 * Calculate the number of bits Mask must be shift to the left to get a
119 * 1 in the most significant bit position
121 static INT
CalculateShift(ULONG Mask
)
124 ULONG LeftmostBit
= 1 << (8 * sizeof(ULONG
) - 1);
126 while (0 == (Mask
& LeftmostBit
) && Shift
< 8 * sizeof(ULONG
))
135 static ULONG
ShiftAndMask(XLATEGDI
*XlateGDI
, ULONG Color
)
137 ULONG TranslatedColor
;
140 if (XlateGDI
->RedShift
< 0)
142 TranslatedColor
= (Color
>> -(XlateGDI
->RedShift
)) & XlateGDI
->RedMask
;
144 TranslatedColor
= (Color
<< XlateGDI
->RedShift
) & XlateGDI
->RedMask
;
145 if (XlateGDI
->GreenShift
< 0)
147 TranslatedColor
|= (Color
>> -(XlateGDI
->GreenShift
)) & XlateGDI
->GreenMask
;
149 TranslatedColor
|= (Color
<< XlateGDI
->GreenShift
) & XlateGDI
->GreenMask
;
150 if (XlateGDI
->BlueShift
< 0)
152 TranslatedColor
|= (Color
>> -(XlateGDI
->BlueShift
)) & XlateGDI
->BlueMask
;
154 TranslatedColor
|= (Color
<< XlateGDI
->BlueShift
) & XlateGDI
->BlueMask
;
156 return TranslatedColor
;
159 XLATEOBJ
*EngCreateXlate(USHORT DestPalType
, USHORT SourcePalType
,
160 HPALETTE PaletteDest
, HPALETTE PaletteSource
)
162 // FIXME: Add support for BGR conversions
167 PALGDI
*SourcePalGDI
, *DestPalGDI
;
169 ULONG SourceRedMask
, SourceGreenMask
, SourceBlueMask
;
170 ULONG DestRedMask
, DestGreenMask
, DestBlueMask
;
173 NewXlate
= (HPALETTE
)CreateGDIHandle(sizeof( XLATEGDI
), sizeof( XLATEOBJ
));
174 if( !ValidEngHandle( NewXlate
) )
177 XlateObj
= (XLATEOBJ
*) AccessUserObject( (ULONG
) NewXlate
);
178 XlateGDI
= (XLATEGDI
*) AccessInternalObject( (ULONG
) NewXlate
);
182 SourcePalGDI
= (PALGDI
*)AccessInternalObject((ULONG
)PaletteSource
);
183 DestPalGDI
= (PALGDI
*)AccessInternalObject((ULONG
)PaletteDest
);
185 XlateObj
->iSrcType
= SourcePalType
;
186 XlateObj
->iDstType
= DestPalType
;
188 // Store handles of palettes in internal Xlate GDI object (or NULLs)
189 XlateGDI
->DestPal
= PaletteDest
;
190 XlateGDI
->SourcePal
= PaletteSource
;
192 XlateObj
->flXlate
= 0;
194 XlateGDI
->UseShiftAndMask
= FALSE
;
196 /* Compute bit fiddeling constants unless both palettes are indexed, then we don't need them */
197 if (PAL_INDEXED
!= SourcePalType
|| PAL_INDEXED
!= DestPalType
)
199 BitMasksFromPal(PAL_INDEXED
== SourcePalType
? PAL_RGB
: SourcePalType
,
200 SourcePalGDI
, &SourceRedMask
, &SourceBlueMask
, &SourceGreenMask
);
201 BitMasksFromPal(PAL_INDEXED
== DestPalType
? PAL_RGB
: DestPalType
,
202 DestPalGDI
, &DestRedMask
, &DestBlueMask
, &DestGreenMask
);
203 XlateGDI
->RedShift
= CalculateShift(SourceRedMask
) - CalculateShift(DestRedMask
);
204 XlateGDI
->RedMask
= DestRedMask
;
205 XlateGDI
->GreenShift
= CalculateShift(SourceGreenMask
) - CalculateShift(DestGreenMask
);
206 XlateGDI
->GreenMask
= DestGreenMask
;
207 XlateGDI
->BlueShift
= CalculateShift(SourceBlueMask
) - CalculateShift(DestBlueMask
);
208 XlateGDI
->BlueMask
= DestBlueMask
;
211 // If source and destination palettes are the same or if they're RGB/BGR
212 if( (PaletteDest
== PaletteSource
) ||
213 ((DestPalType
== PAL_RGB
) && (SourcePalType
== PAL_RGB
)) ||
214 ((DestPalType
== PAL_BGR
) && (SourcePalType
== PAL_BGR
)) )
216 XlateObj
->flXlate
|= XO_TRIVIAL
;
220 /* If source and destination are bitfield based (RGB and BGR are just special bitfields) */
221 if ((PAL_RGB
== DestPalType
|| PAL_BGR
== DestPalType
|| PAL_BITFIELDS
== DestPalType
) &&
222 (PAL_RGB
== SourcePalType
|| PAL_BGR
== SourcePalType
|| PAL_BITFIELDS
== SourcePalType
))
224 if (SourceRedMask
== DestRedMask
&&
225 SourceBlueMask
== DestBlueMask
&&
226 SourceGreenMask
== DestGreenMask
)
228 XlateObj
->flXlate
|= XO_TRIVIAL
;
230 XlateGDI
->UseShiftAndMask
= TRUE
;
234 // Prepare the translation table
235 if( (SourcePalType
== PAL_INDEXED
) || (SourcePalType
== PAL_RGB
) )
237 XlateObj
->flXlate
|= XO_TABLE
;
238 if ((SourcePalType
== PAL_INDEXED
) && (DestPalType
== PAL_INDEXED
))
240 if(SourcePalGDI
->NumColors
> DestPalGDI
->NumColors
)
242 IndexedColors
= SourcePalGDI
->NumColors
;
244 IndexedColors
= DestPalGDI
->NumColors
;
246 else if (SourcePalType
== PAL_INDEXED
) { IndexedColors
= SourcePalGDI
->NumColors
; }
247 else if (DestPalType
== PAL_INDEXED
) { IndexedColors
= DestPalGDI
->NumColors
; }
249 XlateGDI
->translationTable
= EngAllocMem(FL_ZERO_MEMORY
, sizeof(ULONG
)*IndexedColors
, 0);
252 // Source palette is indexed
253 if(XlateObj
->iSrcType
== PAL_INDEXED
)
255 if(XlateObj
->iDstType
== PAL_INDEXED
)
257 // Converting from indexed to indexed
258 IndexedToIndexedTranslationTable(XlateGDI
->translationTable
, DestPalGDI
, SourcePalGDI
);
260 if (PAL_RGB
== XlateObj
->iDstType
|| PAL_BITFIELDS
== XlateObj
->iDstType
)
262 // FIXME: Is this necessary? I think the driver has to call this
263 // function anyways if pulXlate is NULL and Source is PAL_INDEXED
265 // Converting from indexed to RGB
267 XLATEOBJ_cGetPalette(XlateObj
, XO_SRCPALETTE
,
268 SourcePalGDI
->NumColors
,
269 XlateGDI
->translationTable
);
270 if (PAL_BITFIELDS
== XlateObj
->iDstType
)
272 for (i
= 0; i
< SourcePalGDI
->NumColors
; i
++)
274 XlateGDI
->translationTable
[i
] = ShiftAndMask(XlateGDI
, XlateGDI
->translationTable
[i
]);
279 XlateObj
->pulXlate
= XlateGDI
->translationTable
;
282 // Source palette is RGB
283 if(XlateObj
->iSrcType
== PAL_RGB
)
285 if(XlateObj
->iDstType
== PAL_INDEXED
)
287 // FIXME: Is this necessary? I think the driver has to call this
288 // function anyways if pulXlate is NULL and Dest is PAL_INDEXED
290 // Converting from RGB to indexed
291 XLATEOBJ_cGetPalette(XlateObj
, XO_DESTPALETTE
, DestPalGDI
->NumColors
, XlateGDI
->translationTable
);
295 // FIXME: Add support for XO_TO_MONO
299 VOID
EngDeleteXlate(XLATEOBJ
*XlateObj
)
301 HPALETTE HXlate
= (HPALETTE
)AccessHandleFromUserObject(XlateObj
);
302 XLATEGDI
*XlateGDI
= (XLATEGDI
*)AccessInternalObject((ULONG
)HXlate
);
304 if(XlateGDI
->translationTable
!=NULL
)
306 EngFreeMem(XlateGDI
->translationTable
);
309 FreeGDIHandle((ULONG
)HXlate
);
313 XLATEOBJ_piVector(XLATEOBJ
*XlateObj
)
315 XLATEGDI
*XlateGDI
= (XLATEGDI
*)AccessInternalObjectFromUserObject(XlateObj
);
317 if(XlateObj
->iSrcType
== PAL_INDEXED
)
319 return XlateGDI
->translationTable
;
326 XLATEOBJ_iXlate(XLATEOBJ
*XlateObj
,
330 XLATEGDI
*XlateGDI
= (XLATEGDI
*)AccessInternalObjectFromUserObject(XlateObj
);
332 // Return the original color if there's no color translation object
333 if(!XlateObj
) return Color
;
335 if(XlateObj
->flXlate
& XO_TRIVIAL
)
339 if(XlateGDI
->UseShiftAndMask
)
341 return ShiftAndMask(XlateGDI
, Color
);
343 if(XlateObj
->iSrcType
== PAL_RGB
)
345 // FIXME: should we cache colors used often?
346 // FIXME: won't work if destination isn't indexed
348 // Extract the destination palette
349 PalGDI
= (PALGDI
*)AccessInternalObject((ULONG
)XlateGDI
->DestPal
);
351 // Return closest match for the given RGB color
352 return ClosestColorMatch(Color
, PalGDI
->IndexedColors
, PalGDI
->NumColors
);
354 if(XlateObj
->iSrcType
== PAL_INDEXED
)
356 return XlateGDI
->translationTable
[Color
];
363 XLATEOBJ_cGetPalette(XLATEOBJ
*XlateObj
,
373 XlateGDI
= (XLATEGDI
*)AccessInternalObjectFromUserObject(XlateObj
);
375 if(PalOutType
== XO_SRCPALETTE
)
377 HPal
= XlateGDI
->SourcePal
;
379 if(PalOutType
== XO_DESTPALETTE
)
381 HPal
= XlateGDI
->DestPal
;
384 PalGDI
= (PALGDI
*)AccessInternalObject((ULONG
)HPal
);
385 RtlCopyMemory(OutPal
, PalGDI
->IndexedColors
, sizeof(ULONG
)*cPal
);