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
, PPALETTE 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 PALETTE
*SourcePalGDI
= 0;
156 PALETTE
*DestPalGDI
= 0;
157 ULONG SourceRedMask
= 0, SourceGreenMask
= 0, SourceBlueMask
= 0;
158 ULONG DestRedMask
= 0, DestGreenMask
= 0, DestBlueMask
= 0;
161 ASSERT(SourcePalType
|| PaletteSource
);
162 ASSERT(DestPalType
|| PaletteDest
);
164 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
165 if (XlateGDI
== NULL
)
167 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
170 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
172 if (PaletteSource
!= NULL
)
173 SourcePalGDI
= PALETTE_LockPalette(PaletteSource
);
174 if (PaletteDest
== PaletteSource
)
175 DestPalGDI
= SourcePalGDI
;
176 else if (PaletteDest
!= NULL
)
177 DestPalGDI
= PALETTE_LockPalette(PaletteDest
);
179 if (SourcePalType
== 0)
183 DPRINT1("Failed to lock source palette %p\n", PaletteSource
);
186 SourcePalType
= SourcePalGDI
->Mode
;
188 if (DestPalType
== 0)
192 DPRINT1("Failed to lock dest palette %p\n", PaletteDest
);
195 DestPalType
= DestPalGDI
->Mode
;
198 XlateObj
->iSrcType
= SourcePalType
;
199 XlateObj
->iDstType
= DestPalType
;
200 XlateObj
->flXlate
= 0;
201 XlateObj
->cEntries
= 0;
203 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
204 XlateGDI
->SourcePal
= PaletteSource
;
205 XlateGDI
->DestPal
= PaletteDest
;
207 XlateGDI
->UseShiftAndMask
= FALSE
;
210 * Compute bit fiddeling constants unless both palettes are indexed, then
211 * we don't need them.
213 if (SourcePalType
!= PAL_INDEXED
|| DestPalType
!= PAL_INDEXED
)
215 BitMasksFromPal(SourcePalType
, SourcePalGDI
, &SourceRedMask
,
216 &SourceBlueMask
, &SourceGreenMask
);
217 BitMasksFromPal(DestPalType
, DestPalGDI
, &DestRedMask
,
218 &DestBlueMask
, &DestGreenMask
);
219 XlateGDI
->RedShift
= CalculateShift(SourceRedMask
) - CalculateShift(DestRedMask
);
220 XlateGDI
->RedMask
= DestRedMask
;
221 XlateGDI
->GreenShift
= CalculateShift(SourceGreenMask
) - CalculateShift(DestGreenMask
);
222 XlateGDI
->GreenMask
= DestGreenMask
;
223 XlateGDI
->BlueShift
= CalculateShift(SourceBlueMask
) - CalculateShift(DestBlueMask
);
224 XlateGDI
->BlueMask
= DestBlueMask
;
227 /* If source and destination palettes are the same or if they're RGB/BGR */
228 if (PaletteDest
== PaletteSource
||
229 (DestPalType
== PAL_RGB
&& SourcePalType
== PAL_RGB
) ||
230 (DestPalType
== PAL_BGR
&& SourcePalType
== PAL_BGR
))
232 XlateObj
->flXlate
|= XO_TRIVIAL
;
237 * If source and destination are bitfield based (RGB and BGR are just
238 * special bitfields) we can use simple shifting.
240 if ((DestPalType
== PAL_RGB
|| DestPalType
== PAL_BGR
||
241 DestPalType
== PAL_BITFIELDS
) &&
242 (SourcePalType
== PAL_RGB
|| SourcePalType
== PAL_BGR
||
243 SourcePalType
== PAL_BITFIELDS
))
245 if (SourceRedMask
== DestRedMask
&&
246 SourceBlueMask
== DestBlueMask
&&
247 SourceGreenMask
== DestGreenMask
)
249 XlateObj
->flXlate
|= XO_TRIVIAL
;
251 XlateGDI
->UseShiftAndMask
= TRUE
;
255 /* Indexed -> Indexed */
256 if (SourcePalType
== PAL_INDEXED
&& DestPalType
== PAL_INDEXED
)
258 XlateObj
->cEntries
= SourcePalGDI
->NumColors
;
260 EngAllocMem(0, sizeof(ULONG
) * XlateObj
->cEntries
, TAG_XLATEOBJ
);
262 XlateObj
->flXlate
|= XO_TRIVIAL
;
263 for (i
= 0; i
< XlateObj
->cEntries
; i
++)
265 XlateObj
->pulXlate
[i
] = ClosestColorMatch(
266 XlateGDI
, SourcePalGDI
->IndexedColors
+ i
,
267 DestPalGDI
->IndexedColors
, DestPalGDI
->NumColors
);
268 if (XlateObj
->pulXlate
[i
] != i
)
269 XlateObj
->flXlate
&= ~XO_TRIVIAL
;
272 XlateObj
->flXlate
|= XO_TABLE
;
276 /* Indexed -> Bitfields/RGB/BGR */
277 if (SourcePalType
== PAL_INDEXED
)
279 XlateObj
->cEntries
= SourcePalGDI
->NumColors
;
281 EngAllocMem(0, sizeof(ULONG
) * XlateObj
->cEntries
, TAG_XLATEOBJ
);
282 for (i
= 0; i
< XlateObj
->cEntries
; i
++)
283 XlateObj
->pulXlate
[i
] =
284 ShiftAndMask(XlateGDI
, *((ULONG
*)&SourcePalGDI
->IndexedColors
[i
]));
285 XlateObj
->flXlate
|= XO_TABLE
;
290 * Last case: Bitfields/RGB/BGR -> Indexed
291 * isn't handled here yet and all the logic is in XLATEOBJ_iXlate now.
295 if (PaletteDest
!= NULL
)
296 if (PaletteDest
!= PaletteSource
)
297 if (DestPalGDI
!= NULL
)
298 PALETTE_UnlockPalette(DestPalGDI
);
301 if (PaletteSource
!= NULL
)
302 PALETTE_UnlockPalette(SourcePalGDI
);
308 IntEngCreateMonoXlate(
309 USHORT SourcePalType
, HPALETTE PaletteDest
, HPALETTE PaletteSource
,
310 ULONG BackgroundColor
)
314 PALETTE
*SourcePalGDI
;
316 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
317 if (XlateGDI
== NULL
)
319 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
322 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
324 SourcePalGDI
= PALETTE_LockPalette(PaletteSource
);
325 /* FIXME - SourcePalGDI can be NULL!!! Handle this case instead of ASSERT! */
326 ASSERT(SourcePalGDI
);
328 if (SourcePalType
== 0)
329 SourcePalType
= SourcePalGDI
->Mode
;
331 XlateObj
->iSrcType
= SourcePalType
;
332 XlateObj
->iDstType
= PAL_INDEXED
;
334 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
335 XlateGDI
->DestPal
= PaletteDest
;
336 XlateGDI
->SourcePal
= PaletteSource
;
338 XlateObj
->flXlate
= XO_TO_MONO
;
339 XlateObj
->cEntries
= 1;
340 XlateObj
->pulXlate
= &XlateGDI
->BackgroundColor
;
341 switch (SourcePalType
)
344 XlateGDI
->BackgroundColor
= NtGdiGetNearestPaletteIndex(
345 PaletteSource
, BackgroundColor
);
348 XlateGDI
->BackgroundColor
= BackgroundColor
;
351 XlateGDI
->BackgroundColor
=
352 ((BackgroundColor
& 0xFF) << 16) |
353 ((BackgroundColor
& 0xFF0000) >> 16) |
354 (BackgroundColor
& 0xFF00);
358 BitMasksFromPal(SourcePalType
, SourcePalGDI
, &XlateGDI
->RedMask
,
359 &XlateGDI
->BlueMask
, &XlateGDI
->GreenMask
);
360 XlateGDI
->RedShift
= CalculateShift(0xFF) - CalculateShift(XlateGDI
->RedMask
);
361 XlateGDI
->GreenShift
= CalculateShift(0xFF00) - CalculateShift(XlateGDI
->GreenMask
);
362 XlateGDI
->BlueShift
= CalculateShift(0xFF0000) - CalculateShift(XlateGDI
->BlueMask
);
363 XlateGDI
->BackgroundColor
= ShiftAndMask(XlateGDI
, BackgroundColor
);
368 PALETTE_UnlockPalette(SourcePalGDI
);
374 IntEngCreateSrcMonoXlate(HPALETTE PaletteDest
,
382 DestPalGDI
= PALETTE_LockPalette(PaletteDest
);
383 if (DestPalGDI
== NULL
)
386 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
387 if (XlateGDI
== NULL
)
389 PALETTE_UnlockPalette(DestPalGDI
);
390 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
393 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
395 XlateObj
->cEntries
= 2;
396 XlateObj
->pulXlate
= EngAllocMem(0, sizeof(ULONG
) * XlateObj
->cEntries
, TAG_XLATEOBJ
);
397 if (XlateObj
->pulXlate
== NULL
)
399 PALETTE_UnlockPalette(DestPalGDI
);
400 EngFreeMem(XlateGDI
);
404 XlateObj
->iSrcType
= PAL_INDEXED
;
405 XlateObj
->iDstType
= DestPalGDI
->Mode
;
407 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
408 XlateGDI
->SourcePal
= NULL
;
409 XlateGDI
->DestPal
= PaletteDest
;
411 XlateObj
->flXlate
= XO_TABLE
;
413 BitMasksFromPal(DestPalGDI
->Mode
, DestPalGDI
, &XlateGDI
->RedMask
,
414 &XlateGDI
->BlueMask
, &XlateGDI
->GreenMask
);
416 XlateGDI
->RedShift
= CalculateShift(RGB(0xFF, 0x00, 0x00)) - CalculateShift(XlateGDI
->RedMask
);
417 XlateGDI
->GreenShift
= CalculateShift(RGB(0x00, 0xFF, 0x00)) - CalculateShift(XlateGDI
->GreenMask
);
418 XlateGDI
->BlueShift
= CalculateShift(RGB(0x00, 0x00, 0xFF)) - CalculateShift(XlateGDI
->BlueMask
);
420 /* Yes, that's how Windows works, ... */
421 XlateObj
->pulXlate
[1] = ShiftAndMask(XlateGDI
, Color1
);
422 XlateObj
->pulXlate
[0] = ShiftAndMask(XlateGDI
, Color0
);
424 if (XlateObj
->iDstType
== PAL_INDEXED
)
426 XlateObj
->pulXlate
[0] =
427 ClosestColorMatch(XlateGDI
,
428 (LPPALETTEENTRY
)&XlateObj
->pulXlate
[0],
429 DestPalGDI
->IndexedColors
,
430 DestPalGDI
->NumColors
);
431 XlateObj
->pulXlate
[1] =
432 ClosestColorMatch(XlateGDI
,
433 (LPPALETTEENTRY
)&XlateObj
->pulXlate
[1],
434 DestPalGDI
->IndexedColors
,
435 DestPalGDI
->NumColors
);
438 PALETTE_UnlockPalette(DestPalGDI
);
444 IntEngGetXlatePalette(XLATEOBJ
*XlateObj
,
447 XLATEGDI
*XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
451 return XlateGDI
->DestPal
;
455 return XlateGDI
->SourcePal
;
463 IntCreateXlateForBlt(PDC pDCDest
, PDC pDCSrc
, SURFACE
* psurfDest
, SURFACE
* psurfSrc
)
466 HPALETTE DestPalette
, SourcePalette
;
469 DPRINT("Enter IntCreateXlateFromDCs\n");
471 if (psurfDest
== psurfSrc
)
476 DestPalette
= psurfDest
->hDIBPalette
;
477 if (!DestPalette
) DestPalette
= pPrimarySurface
->DevInfo
.hpalDefault
;
479 SourcePalette
= psurfSrc
->hDIBPalette
;
480 if (!SourcePalette
) SourcePalette
= pPrimarySurface
->DevInfo
.hpalDefault
;
482 DPRINT("DestPalette = %p, SourcePalette = %p, DefaultPatelle = %p\n", DestPalette
, SourcePalette
, NtGdiGetStockObject((INT
)DEFAULT_PALETTE
));
484 /* KB41464 details how to convert between mono and color */
485 if (psurfDest
->SurfObj
.iBitmapFormat
== BMF_1BPP
)
487 if (psurfSrc
->SurfObj
.iBitmapFormat
== BMF_1BPP
)
493 pdcattr
= pDCSrc
->pdcattr
;
494 XlateObj
= IntEngCreateMonoXlate(0, DestPalette
, SourcePalette
, pdcattr
->crBackgroundClr
);
499 if (psurfSrc
->SurfObj
.iBitmapFormat
== BMF_1BPP
)
501 /* DIB sections need special handling */
502 if (psurfSrc
->hSecure
)
504 PPALETTE ppal
= PALETTE_LockPalette(psurfSrc
->hDIBPalette
);
507 XlateObj
= IntEngCreateSrcMonoXlate(DestPalette
, ((ULONG
*)ppal
->IndexedColors
)[0], ((ULONG
*)ppal
->IndexedColors
)[1]);
508 PALETTE_UnlockPalette(ppal
);
515 pdcattr
= pDCDest
->pdcattr
;
516 XlateObj
= IntEngCreateSrcMonoXlate(DestPalette
, pdcattr
->crForegroundClr
, pdcattr
->crBackgroundClr
);
521 XlateObj
= IntEngCreateXlate(0, 0, DestPalette
, SourcePalette
);
525 return (XLATEOBJ
*)-1;
531 /* PUBLIC FUNCTIONS ***********************************************************/
534 * @implemented /// this is not a public function!
537 EngDeleteXlate(XLATEOBJ
*XlateObj
)
541 if (XlateObj
== NULL
)
543 DPRINT1("Trying to delete NULL XLATEOBJ\n");
547 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
549 if (!XlateGDI
) return;
551 if ((XlateObj
->flXlate
& XO_TABLE
) &&
552 XlateObj
->pulXlate
!= NULL
)
554 EngFreeMem(XlateObj
->pulXlate
);
557 EngFreeMem(XlateGDI
);
564 XLATEOBJ_piVector(XLATEOBJ
*XlateObj
)
566 if (XlateObj
->iSrcType
== PAL_INDEXED
)
568 return XlateObj
->pulXlate
;
578 XLATEOBJ_iXlate(XLATEOBJ
*XlateObj
, ULONG Color
)
584 /* Return the original color if there's no color translation object. */
588 if (XlateObj
->flXlate
& XO_TRIVIAL
)
591 if (XlateObj
->flXlate
& XO_TABLE
)
593 if (Color
>= XlateObj
->cEntries
)
594 Color
%= XlateObj
->cEntries
;
596 return XlateObj
->pulXlate
[Color
];
600 if (XlateObj
->flXlate
& XO_TO_MONO
)
601 return Color
== XlateObj
->pulXlate
[0];
603 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
605 if (XlateGDI
->UseShiftAndMask
)
606 return ShiftAndMask(XlateGDI
, Color
);
608 if (XlateObj
->iSrcType
== PAL_RGB
|| XlateObj
->iSrcType
== PAL_BGR
||
609 XlateObj
->iSrcType
== PAL_BITFIELDS
)
611 /* FIXME: should we cache colors used often? */
612 /* FIXME: won't work if destination isn't indexed */
614 /* Convert the source color to the palette RGB format. */
615 Color
= ShiftAndMask(XlateGDI
, Color
);
617 /* Extract the destination palette. */
618 PalGDI
= PALETTE_LockPalette(XlateGDI
->DestPal
);
621 /* Return closest match for the given color. */
622 Closest
= ClosestColorMatch(XlateGDI
, (LPPALETTEENTRY
)&Color
, PalGDI
->IndexedColors
, PalGDI
->NumColors
);
623 PALETTE_UnlockPalette(PalGDI
);
635 XLATEOBJ_cGetPalette(XLATEOBJ
*XlateObj
, ULONG PalOutType
, ULONG cPal
,
643 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
644 if (PalOutType
== XO_SRCPALETTE
)
645 hPalette
= XlateGDI
->SourcePal
;
646 else if (PalOutType
== XO_DESTPALETTE
)
647 hPalette
= XlateGDI
->DestPal
;
654 PalGDI
= PALETTE_LockPalette(hPalette
);
657 /* copy the indexed colors into the buffer */
659 for(InPal
= (ULONG
*)PalGDI
->IndexedColors
;
661 cPal
--, InPal
++, OutPal
++)
666 PALETTE_UnlockPalette(PalGDI
);