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 switch (SourcePalType
)
319 XlateGDI
->BackgroundColor
= NtGdiGetNearestPaletteIndex(
320 PaletteSource
, BackgroundColor
);
323 XlateGDI
->BackgroundColor
= BackgroundColor
;
326 XlateGDI
->BackgroundColor
=
327 ((BackgroundColor
& 0xFF) << 16) |
328 ((BackgroundColor
& 0xFF0000) >> 16) |
329 (BackgroundColor
& 0xFF00);
333 BitMasksFromPal(SourcePalType
, SourcePalGDI
, &XlateGDI
->RedMask
,
334 &XlateGDI
->BlueMask
, &XlateGDI
->GreenMask
);
335 XlateGDI
->RedShift
= CalculateShift(0xFF) - CalculateShift(XlateGDI
->RedMask
);
336 XlateGDI
->GreenShift
= CalculateShift(0xFF00) - CalculateShift(XlateGDI
->GreenMask
);
337 XlateGDI
->BlueShift
= CalculateShift(0xFF0000) - CalculateShift(XlateGDI
->BlueMask
);
338 XlateGDI
->BackgroundColor
= ShiftAndMask(XlateGDI
, BackgroundColor
);
343 PALETTE_UnlockPalette(SourcePalGDI
);
349 IntEngCreateSrcMonoXlate(HPALETTE PaletteDest
,
350 ULONG ForegroundColor
,
351 ULONG BackgroundColor
)
357 DestPalGDI
= PALETTE_LockPalette(PaletteDest
);
358 if (DestPalGDI
== NULL
)
361 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
362 if (XlateGDI
== NULL
)
364 PALETTE_UnlockPalette(DestPalGDI
);
365 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
368 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
370 XlateGDI
->translationTable
= EngAllocMem(0, sizeof(ULONG
) * 2, 0);
371 if (XlateGDI
->translationTable
== NULL
)
373 PALETTE_UnlockPalette(DestPalGDI
);
374 EngFreeMem(XlateGDI
);
378 XlateObj
->pulXlate
= XlateGDI
->translationTable
;
380 XlateObj
->iSrcType
= PAL_INDEXED
;
381 XlateObj
->iDstType
= DestPalGDI
->Mode
;
383 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
384 XlateGDI
->SourcePal
= NULL
;
385 XlateGDI
->DestPal
= PaletteDest
;
387 XlateObj
->flXlate
= XO_TABLE
;
389 BitMasksFromPal(DestPalGDI
->Mode
, DestPalGDI
, &XlateGDI
->RedMask
,
390 &XlateGDI
->BlueMask
, &XlateGDI
->GreenMask
);
392 XlateGDI
->RedShift
= CalculateShift(RGB(0xFF, 0x00, 0x00)) - CalculateShift(XlateGDI
->RedMask
);
393 XlateGDI
->GreenShift
= CalculateShift(RGB(0x00, 0xFF, 0x00)) - CalculateShift(XlateGDI
->GreenMask
);
394 XlateGDI
->BlueShift
= CalculateShift(RGB(0x00, 0x00, 0xFF)) - CalculateShift(XlateGDI
->BlueMask
);
396 XlateGDI
->translationTable
[0] = ShiftAndMask(XlateGDI
, BackgroundColor
);
397 XlateGDI
->translationTable
[1] = ShiftAndMask(XlateGDI
, ForegroundColor
);
399 if (XlateObj
->iDstType
== PAL_INDEXED
)
401 XlateGDI
->translationTable
[0] =
402 ClosestColorMatch(XlateGDI
,
403 (LPPALETTEENTRY
)&XlateGDI
->translationTable
[0],
404 DestPalGDI
->IndexedColors
,
405 DestPalGDI
->NumColors
);
406 XlateGDI
->translationTable
[1] =
407 ClosestColorMatch(XlateGDI
,
408 (LPPALETTEENTRY
)&XlateGDI
->translationTable
[1],
409 DestPalGDI
->IndexedColors
,
410 DestPalGDI
->NumColors
);
413 PALETTE_UnlockPalette(DestPalGDI
);
418 /* PUBLIC FUNCTIONS ***********************************************************/
424 EngDeleteXlate(XLATEOBJ
*XlateObj
)
428 if (XlateObj
== NULL
)
430 DPRINT1("Trying to delete NULL XLATEOBJ\n");
434 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
436 if ((XlateObj
->flXlate
& XO_TABLE
) &&
437 XlateGDI
->translationTable
!= NULL
)
439 EngFreeMem(XlateGDI
->translationTable
);
442 EngFreeMem(XlateGDI
);
449 XLATEOBJ_piVector(XLATEOBJ
*XlateObj
)
451 XLATEGDI
*XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
453 if (XlateObj
->iSrcType
== PAL_INDEXED
)
455 return XlateGDI
->translationTable
;
465 XLATEOBJ_iXlate(XLATEOBJ
*XlateObj
, ULONG Color
)
471 /* Return the original color if there's no color translation object. */
475 if (XlateObj
->flXlate
& XO_TRIVIAL
)
478 if (XlateObj
->flXlate
& XO_TABLE
)
479 return XlateObj
->pulXlate
[Color
];
481 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
483 if (XlateObj
->flXlate
& XO_TO_MONO
)
484 return Color
== XlateGDI
->BackgroundColor
;
486 if (XlateGDI
->UseShiftAndMask
)
487 return ShiftAndMask(XlateGDI
, Color
);
489 if (XlateObj
->iSrcType
== PAL_RGB
|| XlateObj
->iSrcType
== PAL_BGR
||
490 XlateObj
->iSrcType
== PAL_BITFIELDS
)
492 /* FIXME: should we cache colors used often? */
493 /* FIXME: won't work if destination isn't indexed */
495 /* Convert the source color to the palette RGB format. */
496 Color
= ShiftAndMask(XlateGDI
, Color
);
498 /* Extract the destination palette. */
499 PalGDI
= PALETTE_LockPalette(XlateGDI
->DestPal
);
502 /* Return closest match for the given color. */
503 Closest
= ClosestColorMatch(XlateGDI
, (LPPALETTEENTRY
)&Color
, PalGDI
->IndexedColors
, PalGDI
->NumColors
);
504 PALETTE_UnlockPalette(PalGDI
);
516 XLATEOBJ_cGetPalette(XLATEOBJ
*XlateObj
, ULONG PalOutType
, ULONG cPal
,
524 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
525 if (PalOutType
== XO_SRCPALETTE
)
526 hPalette
= XlateGDI
->SourcePal
;
527 else if (PalOutType
== XO_DESTPALETTE
)
528 hPalette
= XlateGDI
->DestPal
;
532 PalGDI
= PALETTE_LockPalette(hPalette
);
535 /* copy the indexed colors into the buffer */
537 for(InPal
= (ULONG
*)PalGDI
->IndexedColors
;
539 cPal
--, InPal
++, OutPal
++)
544 PALETTE_UnlockPalette(PalGDI
);