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
36 ShiftAndMask(XLATEGDI
*XlateGDI
, ULONG Color
)
38 ULONG TranslatedColor
;
40 if (XlateGDI
->RedShift
< 0)
41 TranslatedColor
= (Color
>> -(XlateGDI
->RedShift
)) & XlateGDI
->RedMask
;
43 TranslatedColor
= (Color
<< XlateGDI
->RedShift
) & XlateGDI
->RedMask
;
44 if (XlateGDI
->GreenShift
< 0)
45 TranslatedColor
|= (Color
>> -(XlateGDI
->GreenShift
)) & XlateGDI
->GreenMask
;
47 TranslatedColor
|= (Color
<< XlateGDI
->GreenShift
) & XlateGDI
->GreenMask
;
48 if (XlateGDI
->BlueShift
< 0)
49 TranslatedColor
|= (Color
>> -(XlateGDI
->BlueShift
)) & XlateGDI
->BlueMask
;
51 TranslatedColor
|= (Color
<< XlateGDI
->BlueShift
) & XlateGDI
->BlueMask
;
53 return TranslatedColor
;
58 ClosestColorMatch(XLATEGDI
*XlateGDI
, LPPALETTEENTRY SourceColor
,
59 PALETTEENTRY
*DestColors
, ULONG NumColors
)
61 ULONG SourceRed
, SourceGreen
, SourceBlue
;
62 ULONG cxRed
, cxGreen
, cxBlue
, Rating
, BestMatch
= 0xFFFFFF;
63 ULONG CurrentIndex
, BestIndex
= 0;
65 SourceRed
= SourceColor
->peRed
;
66 SourceGreen
= SourceColor
->peGreen
;
67 SourceBlue
= SourceColor
->peBlue
;
69 for (CurrentIndex
= 0; CurrentIndex
< NumColors
; CurrentIndex
++, DestColors
++)
71 cxRed
= abs((SHORT
)SourceRed
- (SHORT
)DestColors
->peRed
);
73 cxGreen
= abs((SHORT
)SourceGreen
- (SHORT
)DestColors
->peGreen
);
75 cxBlue
= abs((SHORT
)SourceBlue
- (SHORT
)DestColors
->peBlue
);
78 Rating
= cxRed
+ cxGreen
+ cxBlue
;
83 BestIndex
= CurrentIndex
;
87 if (Rating
< BestMatch
)
89 BestIndex
= CurrentIndex
;
98 BitMasksFromPal(USHORT PalType
, PPALGDI Palette
,
99 PULONG RedMask
, PULONG BlueMask
, PULONG GreenMask
)
101 static const union { PALETTEENTRY Color
; ULONG Mask
; } Red
= {{0xFF, 0x00, 0x00}};
102 static const union { PALETTEENTRY Color
; ULONG Mask
; } Green
= {{0x00, 0xFF, 0x00}};
103 static const union { PALETTEENTRY Color
; ULONG Mask
; } Blue
= {{0x00, 0x00, 0xFF}};
108 *RedMask
= RGB(0xFF, 0x00, 0x00);
109 *GreenMask
= RGB(0x00, 0xFF, 0x00);
110 *BlueMask
= RGB(0x00, 0x00, 0xFF);
113 *RedMask
= RGB(0x00, 0x00, 0xFF);
114 *GreenMask
= RGB(0x00, 0xFF, 0x00);
115 *BlueMask
= RGB(0xFF, 0x00, 0x00);
118 *RedMask
= Palette
->RedMask
;
119 *GreenMask
= Palette
->GreenMask
;
120 *BlueMask
= Palette
->BlueMask
;
124 *GreenMask
= Green
.Mask
;
125 *BlueMask
= Blue
.Mask
;
131 * Calculate the number of bits Mask must be shift to the left to get a
132 * 1 in the most significant bit position
135 CalculateShift(ULONG Mask
)
138 ULONG LeftmostBit
= 1 << (8 * sizeof(ULONG
) - 1);
140 while (0 == (Mask
& LeftmostBit
) && Shift
< 8 * sizeof(ULONG
))
150 IntEngCreateXlate(USHORT DestPalType
, USHORT SourcePalType
,
151 HPALETTE PaletteDest
, HPALETTE PaletteSource
)
155 PALGDI
*SourcePalGDI
= 0;
156 PALGDI
*DestPalGDI
= 0;
157 ULONG SourceRedMask
= 0, SourceGreenMask
= 0, SourceBlueMask
= 0;
158 ULONG DestRedMask
= 0, DestGreenMask
= 0, DestBlueMask
= 0;
161 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
162 if (XlateGDI
== NULL
)
164 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
167 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
169 if (PaletteSource
!= NULL
)
170 SourcePalGDI
= PALETTE_LockPalette(PaletteSource
);
171 if (PaletteDest
== PaletteSource
)
172 DestPalGDI
= SourcePalGDI
;
173 else if (PaletteDest
!= NULL
)
174 DestPalGDI
= PALETTE_LockPalette(PaletteDest
);
176 if (SourcePalType
== 0)
177 SourcePalType
= SourcePalGDI
->Mode
;
178 if (DestPalType
== 0)
179 DestPalType
= DestPalGDI
->Mode
;
181 XlateObj
->iSrcType
= SourcePalType
;
182 XlateObj
->iDstType
= DestPalType
;
183 XlateObj
->flXlate
= 0;
185 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
186 XlateGDI
->SourcePal
= PaletteSource
;
187 XlateGDI
->DestPal
= PaletteDest
;
189 XlateGDI
->UseShiftAndMask
= FALSE
;
192 * Compute bit fiddeling constants unless both palettes are indexed, then
193 * we don't need them.
195 if (SourcePalType
!= PAL_INDEXED
|| DestPalType
!= PAL_INDEXED
)
197 BitMasksFromPal(SourcePalType
, SourcePalGDI
, &SourceRedMask
,
198 &SourceBlueMask
, &SourceGreenMask
);
199 BitMasksFromPal(DestPalType
, DestPalGDI
, &DestRedMask
,
200 &DestBlueMask
, &DestGreenMask
);
201 XlateGDI
->RedShift
= CalculateShift(SourceRedMask
) - CalculateShift(DestRedMask
);
202 XlateGDI
->RedMask
= DestRedMask
;
203 XlateGDI
->GreenShift
= CalculateShift(SourceGreenMask
) - CalculateShift(DestGreenMask
);
204 XlateGDI
->GreenMask
= DestGreenMask
;
205 XlateGDI
->BlueShift
= CalculateShift(SourceBlueMask
) - CalculateShift(DestBlueMask
);
206 XlateGDI
->BlueMask
= DestBlueMask
;
209 /* If source and destination palettes are the same or if they're RGB/BGR */
210 if (PaletteDest
== PaletteSource
||
211 (DestPalType
== PAL_RGB
&& SourcePalType
== PAL_RGB
) ||
212 (DestPalType
== PAL_BGR
&& SourcePalType
== PAL_BGR
))
214 XlateObj
->flXlate
|= XO_TRIVIAL
;
219 * If source and destination are bitfield based (RGB and BGR are just
220 * special bitfields) we can use simple shifting.
222 if ((DestPalType
== PAL_RGB
|| DestPalType
== PAL_BGR
||
223 DestPalType
== PAL_BITFIELDS
) &&
224 (SourcePalType
== PAL_RGB
|| SourcePalType
== PAL_BGR
||
225 SourcePalType
== PAL_BITFIELDS
))
227 if (SourceRedMask
== DestRedMask
&&
228 SourceBlueMask
== DestBlueMask
&&
229 SourceGreenMask
== DestGreenMask
)
231 XlateObj
->flXlate
|= XO_TRIVIAL
;
233 XlateGDI
->UseShiftAndMask
= TRUE
;
237 /* Indexed -> Indexed */
238 if (SourcePalType
== PAL_INDEXED
&& DestPalType
== PAL_INDEXED
)
240 XlateGDI
->translationTable
=
241 EngAllocMem(0, sizeof(ULONG
) * SourcePalGDI
->NumColors
, 0);
243 XlateObj
->flXlate
|= XO_TRIVIAL
;
244 for (i
= 0; i
< SourcePalGDI
->NumColors
; i
++)
246 XlateGDI
->translationTable
[i
] = ClosestColorMatch(
247 XlateGDI
, SourcePalGDI
->IndexedColors
+ i
,
248 DestPalGDI
->IndexedColors
, DestPalGDI
->NumColors
);
249 if (XlateGDI
->translationTable
[i
] != i
)
250 XlateObj
->flXlate
&= ~XO_TRIVIAL
;
253 XlateObj
->flXlate
|= XO_TABLE
;
254 XlateObj
->pulXlate
= XlateGDI
->translationTable
;
258 /* Indexed -> Bitfields/RGB/BGR */
259 if (SourcePalType
== PAL_INDEXED
)
261 XlateGDI
->translationTable
=
262 EngAllocMem(0, sizeof(ULONG
) * SourcePalGDI
->NumColors
, 0);
263 for (i
= 0; i
< SourcePalGDI
->NumColors
; i
++)
264 XlateGDI
->translationTable
[i
] =
265 ShiftAndMask(XlateGDI
, *((ULONG
*)&SourcePalGDI
->IndexedColors
[i
]));
266 XlateObj
->flXlate
|= XO_TABLE
;
267 XlateObj
->pulXlate
= XlateGDI
->translationTable
;
272 * Last case: Bitfields/RGB/BGR -> Indexed
273 * isn't handled here yet and all the logic is in XLATEOBJ_iXlate now.
277 if (PaletteSource
!= NULL
)
278 PALETTE_UnlockPalette(SourcePalGDI
);
279 if (PaletteDest
!= NULL
&& PaletteDest
!= PaletteSource
)
280 PALETTE_UnlockPalette(DestPalGDI
);
285 IntEngCreateMonoXlate(
286 USHORT SourcePalType
, HPALETTE PaletteDest
, HPALETTE PaletteSource
,
287 ULONG BackgroundColor
)
291 PALGDI
*SourcePalGDI
;
293 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
294 if (XlateGDI
== NULL
)
296 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
299 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
301 SourcePalGDI
= PALETTE_LockPalette(PaletteSource
);
302 /* FIXME - SourcePalGDI can be NULL!!! Handle this case instead of ASSERT! */
303 ASSERT(SourcePalGDI
);
305 if (SourcePalType
== 0)
306 SourcePalType
= SourcePalGDI
->Mode
;
308 XlateObj
->iSrcType
= SourcePalType
;
309 XlateObj
->iDstType
= PAL_INDEXED
;
311 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
312 XlateGDI
->DestPal
= PaletteDest
;
313 XlateGDI
->SourcePal
= PaletteSource
;
315 XlateObj
->flXlate
= XO_TO_MONO
;
316 XlateObj
->pulXlate
= &XlateGDI
->BackgroundColor
;
317 switch (SourcePalType
)
320 XlateGDI
->BackgroundColor
= NtGdiGetNearestPaletteIndex(
321 PaletteSource
, BackgroundColor
);
324 XlateGDI
->BackgroundColor
= BackgroundColor
;
327 XlateGDI
->BackgroundColor
=
328 ((BackgroundColor
& 0xFF) << 16) |
329 ((BackgroundColor
& 0xFF0000) >> 16) |
330 (BackgroundColor
& 0xFF00);
334 BitMasksFromPal(SourcePalType
, SourcePalGDI
, &XlateGDI
->RedMask
,
335 &XlateGDI
->BlueMask
, &XlateGDI
->GreenMask
);
336 XlateGDI
->RedShift
= CalculateShift(0xFF) - CalculateShift(XlateGDI
->RedMask
);
337 XlateGDI
->GreenShift
= CalculateShift(0xFF00) - CalculateShift(XlateGDI
->GreenMask
);
338 XlateGDI
->BlueShift
= CalculateShift(0xFF0000) - CalculateShift(XlateGDI
->BlueMask
);
339 XlateGDI
->BackgroundColor
= ShiftAndMask(XlateGDI
, BackgroundColor
);
344 PALETTE_UnlockPalette(SourcePalGDI
);
350 IntEngCreateSrcMonoXlate(HPALETTE PaletteDest
,
351 ULONG ForegroundColor
,
352 ULONG BackgroundColor
)
358 DestPalGDI
= PALETTE_LockPalette(PaletteDest
);
359 if (DestPalGDI
== NULL
)
362 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
363 if (XlateGDI
== NULL
)
365 PALETTE_UnlockPalette(DestPalGDI
);
366 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
369 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
371 XlateGDI
->translationTable
= EngAllocMem(0, sizeof(ULONG
) * 2, 0);
372 if (XlateGDI
->translationTable
== NULL
)
374 PALETTE_UnlockPalette(DestPalGDI
);
375 EngFreeMem(XlateGDI
);
379 XlateObj
->pulXlate
= XlateGDI
->translationTable
;
381 XlateObj
->iSrcType
= PAL_INDEXED
;
382 XlateObj
->iDstType
= DestPalGDI
->Mode
;
384 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
385 XlateGDI
->SourcePal
= NULL
;
386 XlateGDI
->DestPal
= PaletteDest
;
388 XlateObj
->flXlate
= XO_TABLE
;
390 BitMasksFromPal(DestPalGDI
->Mode
, DestPalGDI
, &XlateGDI
->RedMask
,
391 &XlateGDI
->BlueMask
, &XlateGDI
->GreenMask
);
393 XlateGDI
->RedShift
= CalculateShift(RGB(0xFF, 0x00, 0x00)) - CalculateShift(XlateGDI
->RedMask
);
394 XlateGDI
->GreenShift
= CalculateShift(RGB(0x00, 0xFF, 0x00)) - CalculateShift(XlateGDI
->GreenMask
);
395 XlateGDI
->BlueShift
= CalculateShift(RGB(0x00, 0x00, 0xFF)) - CalculateShift(XlateGDI
->BlueMask
);
397 XlateGDI
->translationTable
[0] = ShiftAndMask(XlateGDI
, BackgroundColor
);
398 XlateGDI
->translationTable
[1] = ShiftAndMask(XlateGDI
, ForegroundColor
);
400 if (XlateObj
->iDstType
== PAL_INDEXED
)
402 XlateGDI
->translationTable
[0] =
403 ClosestColorMatch(XlateGDI
,
404 (LPPALETTEENTRY
)&XlateGDI
->translationTable
[0],
405 DestPalGDI
->IndexedColors
,
406 DestPalGDI
->NumColors
);
407 XlateGDI
->translationTable
[1] =
408 ClosestColorMatch(XlateGDI
,
409 (LPPALETTEENTRY
)&XlateGDI
->translationTable
[1],
410 DestPalGDI
->IndexedColors
,
411 DestPalGDI
->NumColors
);
414 PALETTE_UnlockPalette(DestPalGDI
);
420 IntEngGetXlatePalette(XLATEOBJ
*XlateObj
,
423 XLATEGDI
*XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
427 return XlateGDI
->DestPal
;
431 return XlateGDI
->SourcePal
;
437 /* PUBLIC FUNCTIONS ***********************************************************/
443 EngDeleteXlate(XLATEOBJ
*XlateObj
)
447 if (XlateObj
== NULL
)
449 DPRINT1("Trying to delete NULL XLATEOBJ\n");
453 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
455 if ((XlateObj
->flXlate
& XO_TABLE
) &&
456 XlateGDI
->translationTable
!= NULL
)
458 EngFreeMem(XlateGDI
->translationTable
);
461 EngFreeMem(XlateGDI
);
468 XLATEOBJ_piVector(XLATEOBJ
*XlateObj
)
470 XLATEGDI
*XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
472 if (XlateObj
->iSrcType
== PAL_INDEXED
)
474 return XlateGDI
->translationTable
;
484 XLATEOBJ_iXlate(XLATEOBJ
*XlateObj
, ULONG Color
)
490 /* Return the original color if there's no color translation object. */
494 if (XlateObj
->flXlate
& XO_TRIVIAL
)
497 if (XlateObj
->flXlate
& XO_TABLE
)
498 return XlateObj
->pulXlate
[Color
];
500 if (XlateObj
->flXlate
& XO_TO_MONO
)
501 return Color
== XlateObj
->pulXlate
[0];
503 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
505 if (XlateGDI
->UseShiftAndMask
)
506 return ShiftAndMask(XlateGDI
, Color
);
508 if (XlateObj
->iSrcType
== PAL_RGB
|| XlateObj
->iSrcType
== PAL_BGR
||
509 XlateObj
->iSrcType
== PAL_BITFIELDS
)
511 /* FIXME: should we cache colors used often? */
512 /* FIXME: won't work if destination isn't indexed */
514 /* Convert the source color to the palette RGB format. */
515 Color
= ShiftAndMask(XlateGDI
, Color
);
517 /* Extract the destination palette. */
518 PalGDI
= PALETTE_LockPalette(XlateGDI
->DestPal
);
521 /* Return closest match for the given color. */
522 Closest
= ClosestColorMatch(XlateGDI
, (LPPALETTEENTRY
)&Color
, PalGDI
->IndexedColors
, PalGDI
->NumColors
);
523 PALETTE_UnlockPalette(PalGDI
);
535 XLATEOBJ_cGetPalette(XLATEOBJ
*XlateObj
, ULONG PalOutType
, ULONG cPal
,
543 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
544 if (PalOutType
== XO_SRCPALETTE
)
545 hPalette
= XlateGDI
->SourcePal
;
546 else if (PalOutType
== XO_DESTPALETTE
)
547 hPalette
= XlateGDI
->DestPal
;
554 PalGDI
= PALETTE_LockPalette(hPalette
);
557 /* copy the indexed colors into the buffer */
559 for(InPal
= (ULONG
*)PalGDI
->IndexedColors
;
561 cPal
--, InPal
++, OutPal
++)
566 PALETTE_UnlockPalette(PalGDI
);