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 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)
180 SourcePalType
= SourcePalGDI
->Mode
;
181 if (DestPalType
== 0)
182 DestPalType
= DestPalGDI
->Mode
;
184 XlateObj
->iSrcType
= SourcePalType
;
185 XlateObj
->iDstType
= DestPalType
;
186 XlateObj
->flXlate
= 0;
187 XlateObj
->cEntries
= 0;
189 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
190 XlateGDI
->SourcePal
= PaletteSource
;
191 XlateGDI
->DestPal
= PaletteDest
;
193 XlateGDI
->UseShiftAndMask
= FALSE
;
196 * Compute bit fiddeling constants unless both palettes are indexed, then
197 * we don't need them.
199 if (SourcePalType
!= PAL_INDEXED
|| DestPalType
!= PAL_INDEXED
)
201 BitMasksFromPal(SourcePalType
, SourcePalGDI
, &SourceRedMask
,
202 &SourceBlueMask
, &SourceGreenMask
);
203 BitMasksFromPal(DestPalType
, DestPalGDI
, &DestRedMask
,
204 &DestBlueMask
, &DestGreenMask
);
205 XlateGDI
->RedShift
= CalculateShift(SourceRedMask
) - CalculateShift(DestRedMask
);
206 XlateGDI
->RedMask
= DestRedMask
;
207 XlateGDI
->GreenShift
= CalculateShift(SourceGreenMask
) - CalculateShift(DestGreenMask
);
208 XlateGDI
->GreenMask
= DestGreenMask
;
209 XlateGDI
->BlueShift
= CalculateShift(SourceBlueMask
) - CalculateShift(DestBlueMask
);
210 XlateGDI
->BlueMask
= DestBlueMask
;
213 /* If source and destination palettes are the same or if they're RGB/BGR */
214 if (PaletteDest
== PaletteSource
||
215 (DestPalType
== PAL_RGB
&& SourcePalType
== PAL_RGB
) ||
216 (DestPalType
== PAL_BGR
&& SourcePalType
== PAL_BGR
))
218 XlateObj
->flXlate
|= XO_TRIVIAL
;
223 * If source and destination are bitfield based (RGB and BGR are just
224 * special bitfields) we can use simple shifting.
226 if ((DestPalType
== PAL_RGB
|| DestPalType
== PAL_BGR
||
227 DestPalType
== PAL_BITFIELDS
) &&
228 (SourcePalType
== PAL_RGB
|| SourcePalType
== PAL_BGR
||
229 SourcePalType
== PAL_BITFIELDS
))
231 if (SourceRedMask
== DestRedMask
&&
232 SourceBlueMask
== DestBlueMask
&&
233 SourceGreenMask
== DestGreenMask
)
235 XlateObj
->flXlate
|= XO_TRIVIAL
;
237 XlateGDI
->UseShiftAndMask
= TRUE
;
241 /* Indexed -> Indexed */
242 if (SourcePalType
== PAL_INDEXED
&& DestPalType
== PAL_INDEXED
)
244 XlateObj
->cEntries
= SourcePalGDI
->NumColors
;
246 EngAllocMem(0, sizeof(ULONG
) * XlateObj
->cEntries
, TAG_XLATEOBJ
);
248 XlateObj
->flXlate
|= XO_TRIVIAL
;
249 for (i
= 0; i
< XlateObj
->cEntries
; i
++)
251 XlateObj
->pulXlate
[i
] = ClosestColorMatch(
252 XlateGDI
, SourcePalGDI
->IndexedColors
+ i
,
253 DestPalGDI
->IndexedColors
, XlateObj
->cEntries
);
254 if (XlateObj
->pulXlate
[i
] != i
)
255 XlateObj
->flXlate
&= ~XO_TRIVIAL
;
258 XlateObj
->flXlate
|= XO_TABLE
;
262 /* Indexed -> Bitfields/RGB/BGR */
263 if (SourcePalType
== PAL_INDEXED
)
265 XlateObj
->cEntries
= SourcePalGDI
->NumColors
;
267 EngAllocMem(0, sizeof(ULONG
) * XlateObj
->cEntries
, TAG_XLATEOBJ
);
268 for (i
= 0; i
< XlateObj
->cEntries
; i
++)
269 XlateObj
->pulXlate
[i
] =
270 ShiftAndMask(XlateGDI
, *((ULONG
*)&SourcePalGDI
->IndexedColors
[i
]));
271 XlateObj
->flXlate
|= XO_TABLE
;
276 * Last case: Bitfields/RGB/BGR -> Indexed
277 * isn't handled here yet and all the logic is in XLATEOBJ_iXlate now.
281 if (PaletteDest
!= NULL
)
282 if (PaletteDest
!= PaletteSource
)
283 if (DestPalGDI
!= NULL
)
284 PALETTE_UnlockPalette(DestPalGDI
);
287 if (PaletteSource
!= NULL
)
288 PALETTE_UnlockPalette(SourcePalGDI
);
294 IntEngCreateMonoXlate(
295 USHORT SourcePalType
, HPALETTE PaletteDest
, HPALETTE PaletteSource
,
296 ULONG BackgroundColor
)
300 PALGDI
*SourcePalGDI
;
302 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
303 if (XlateGDI
== NULL
)
305 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
308 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
310 SourcePalGDI
= PALETTE_LockPalette(PaletteSource
);
311 /* FIXME - SourcePalGDI can be NULL!!! Handle this case instead of ASSERT! */
312 ASSERT(SourcePalGDI
);
314 if (SourcePalType
== 0)
315 SourcePalType
= SourcePalGDI
->Mode
;
317 XlateObj
->iSrcType
= SourcePalType
;
318 XlateObj
->iDstType
= PAL_INDEXED
;
320 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
321 XlateGDI
->DestPal
= PaletteDest
;
322 XlateGDI
->SourcePal
= PaletteSource
;
324 XlateObj
->flXlate
= XO_TO_MONO
;
325 XlateObj
->cEntries
= 1;
326 XlateObj
->pulXlate
= &XlateGDI
->BackgroundColor
;
327 switch (SourcePalType
)
330 XlateGDI
->BackgroundColor
= NtGdiGetNearestPaletteIndex(
331 PaletteSource
, BackgroundColor
);
334 XlateGDI
->BackgroundColor
= BackgroundColor
;
337 XlateGDI
->BackgroundColor
=
338 ((BackgroundColor
& 0xFF) << 16) |
339 ((BackgroundColor
& 0xFF0000) >> 16) |
340 (BackgroundColor
& 0xFF00);
344 BitMasksFromPal(SourcePalType
, SourcePalGDI
, &XlateGDI
->RedMask
,
345 &XlateGDI
->BlueMask
, &XlateGDI
->GreenMask
);
346 XlateGDI
->RedShift
= CalculateShift(0xFF) - CalculateShift(XlateGDI
->RedMask
);
347 XlateGDI
->GreenShift
= CalculateShift(0xFF00) - CalculateShift(XlateGDI
->GreenMask
);
348 XlateGDI
->BlueShift
= CalculateShift(0xFF0000) - CalculateShift(XlateGDI
->BlueMask
);
349 XlateGDI
->BackgroundColor
= ShiftAndMask(XlateGDI
, BackgroundColor
);
354 PALETTE_UnlockPalette(SourcePalGDI
);
360 IntEngCreateSrcMonoXlate(HPALETTE PaletteDest
,
368 DestPalGDI
= PALETTE_LockPalette(PaletteDest
);
369 if (DestPalGDI
== NULL
)
372 XlateGDI
= EngAllocMem(0, sizeof(XLATEGDI
), TAG_XLATEOBJ
);
373 if (XlateGDI
== NULL
)
375 PALETTE_UnlockPalette(DestPalGDI
);
376 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
379 XlateObj
= GDIToObj(XlateGDI
, XLATE
);
381 XlateObj
->cEntries
= 2;
382 XlateObj
->pulXlate
= EngAllocMem(0, sizeof(ULONG
) * XlateObj
->cEntries
, TAG_XLATEOBJ
);
383 if (XlateObj
->pulXlate
== NULL
)
385 PALETTE_UnlockPalette(DestPalGDI
);
386 EngFreeMem(XlateGDI
);
390 XlateObj
->iSrcType
= PAL_INDEXED
;
391 XlateObj
->iDstType
= DestPalGDI
->Mode
;
393 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
394 XlateGDI
->SourcePal
= NULL
;
395 XlateGDI
->DestPal
= PaletteDest
;
397 XlateObj
->flXlate
= XO_TABLE
;
399 BitMasksFromPal(DestPalGDI
->Mode
, DestPalGDI
, &XlateGDI
->RedMask
,
400 &XlateGDI
->BlueMask
, &XlateGDI
->GreenMask
);
402 XlateGDI
->RedShift
= CalculateShift(RGB(0xFF, 0x00, 0x00)) - CalculateShift(XlateGDI
->RedMask
);
403 XlateGDI
->GreenShift
= CalculateShift(RGB(0x00, 0xFF, 0x00)) - CalculateShift(XlateGDI
->GreenMask
);
404 XlateGDI
->BlueShift
= CalculateShift(RGB(0x00, 0x00, 0xFF)) - CalculateShift(XlateGDI
->BlueMask
);
406 /* Yes, that's how Windows works, ... */
407 XlateObj
->pulXlate
[1] = ShiftAndMask(XlateGDI
, Color1
);
408 XlateObj
->pulXlate
[0] = ShiftAndMask(XlateGDI
, Color0
);
410 if (XlateObj
->iDstType
== PAL_INDEXED
)
412 XlateObj
->pulXlate
[0] =
413 ClosestColorMatch(XlateGDI
,
414 (LPPALETTEENTRY
)&XlateObj
->pulXlate
[0],
415 DestPalGDI
->IndexedColors
,
416 DestPalGDI
->NumColors
);
417 XlateObj
->pulXlate
[1] =
418 ClosestColorMatch(XlateGDI
,
419 (LPPALETTEENTRY
)&XlateObj
->pulXlate
[1],
420 DestPalGDI
->IndexedColors
,
421 DestPalGDI
->NumColors
);
424 PALETTE_UnlockPalette(DestPalGDI
);
430 IntEngGetXlatePalette(XLATEOBJ
*XlateObj
,
433 XLATEGDI
*XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
437 return XlateGDI
->DestPal
;
441 return XlateGDI
->SourcePal
;
449 IntCreateXlateForBlt(PDC pDCDest
, PDC pDCSrc
, SURFACE
* psurfDest
, SURFACE
* psurfSrc
)
452 HPALETTE DestPalette
, SourcePalette
;
455 DPRINT("Enter IntCreateXlateFromDCs\n");
457 if (psurfDest
== psurfSrc
)
462 DestPalette
= psurfDest
->hDIBPalette
;
463 if (!DestPalette
) DestPalette
= pPrimarySurface
->DevInfo
.hpalDefault
;
465 SourcePalette
= psurfSrc
->hDIBPalette
;
466 if (!SourcePalette
) SourcePalette
= pPrimarySurface
->DevInfo
.hpalDefault
;
468 DPRINT("DestPalette = %p, SourcePalette = %p, DefaultPatelle = %p\n", DestPalette
, SourcePalette
, NtGdiGetStockObject((INT
)DEFAULT_PALETTE
));
470 /* KB41464 details how to convert between mono and color */
471 if (psurfDest
->SurfObj
.iBitmapFormat
== BMF_1BPP
)
473 if (psurfSrc
->SurfObj
.iBitmapFormat
== BMF_1BPP
)
479 pDc_Attr
= pDCSrc
->pDc_Attr
;
480 if (!pDc_Attr
) pDc_Attr
= &pDCSrc
->Dc_Attr
;
481 XlateObj
= IntEngCreateMonoXlate(0, DestPalette
, SourcePalette
, pDc_Attr
->crBackgroundClr
);
486 if (psurfSrc
->SurfObj
.iBitmapFormat
== BMF_1BPP
)
488 /* DIB sections need special handling */
489 if (psurfSrc
->hSecure
)
491 PPALGDI ppal
= PALETTE_LockPalette(psurfSrc
->hDIBPalette
);
494 XlateObj
= IntEngCreateSrcMonoXlate(DestPalette
, ((ULONG
*)ppal
->IndexedColors
)[0], ((ULONG
*)ppal
->IndexedColors
)[1]);
495 PALETTE_UnlockPalette(ppal
);
502 pDc_Attr
= pDCDest
->pDc_Attr
;
503 if (!pDc_Attr
) pDc_Attr
= &pDCDest
->Dc_Attr
;
504 XlateObj
= IntEngCreateSrcMonoXlate(DestPalette
, pDc_Attr
->crForegroundClr
, pDc_Attr
->crBackgroundClr
);
509 XlateObj
= IntEngCreateXlate(0, 0, DestPalette
, SourcePalette
);
513 return (XLATEOBJ
*)-1;
519 /* PUBLIC FUNCTIONS ***********************************************************/
522 * @implemented /// this is not a public function!
525 EngDeleteXlate(XLATEOBJ
*XlateObj
)
529 if (XlateObj
== NULL
)
531 DPRINT1("Trying to delete NULL XLATEOBJ\n");
535 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
537 if (!XlateGDI
) return;
539 if ((XlateObj
->flXlate
& XO_TABLE
) &&
540 XlateObj
->pulXlate
!= NULL
)
542 EngFreeMem(XlateObj
->pulXlate
);
545 EngFreeMem(XlateGDI
);
552 XLATEOBJ_piVector(XLATEOBJ
*XlateObj
)
554 if (XlateObj
->iSrcType
== PAL_INDEXED
)
556 return XlateObj
->pulXlate
;
566 XLATEOBJ_iXlate(XLATEOBJ
*XlateObj
, ULONG Color
)
572 /* Return the original color if there's no color translation object. */
576 if (XlateObj
->flXlate
& XO_TRIVIAL
)
579 if (XlateObj
->flXlate
& XO_TABLE
)
581 if (Color
>= XlateObj
->cEntries
)
582 Color
%= XlateObj
->cEntries
;
584 return XlateObj
->pulXlate
[Color
];
588 if (XlateObj
->flXlate
& XO_TO_MONO
)
589 return Color
== XlateObj
->pulXlate
[0];
591 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
593 if (XlateGDI
->UseShiftAndMask
)
594 return ShiftAndMask(XlateGDI
, Color
);
596 if (XlateObj
->iSrcType
== PAL_RGB
|| XlateObj
->iSrcType
== PAL_BGR
||
597 XlateObj
->iSrcType
== PAL_BITFIELDS
)
599 /* FIXME: should we cache colors used often? */
600 /* FIXME: won't work if destination isn't indexed */
602 /* Convert the source color to the palette RGB format. */
603 Color
= ShiftAndMask(XlateGDI
, Color
);
605 /* Extract the destination palette. */
606 PalGDI
= PALETTE_LockPalette(XlateGDI
->DestPal
);
609 /* Return closest match for the given color. */
610 Closest
= ClosestColorMatch(XlateGDI
, (LPPALETTEENTRY
)&Color
, PalGDI
->IndexedColors
, PalGDI
->NumColors
);
611 PALETTE_UnlockPalette(PalGDI
);
623 XLATEOBJ_cGetPalette(XLATEOBJ
*XlateObj
, ULONG PalOutType
, ULONG cPal
,
631 XlateGDI
= ObjToGDI(XlateObj
, XLATE
);
632 if (PalOutType
== XO_SRCPALETTE
)
633 hPalette
= XlateGDI
->SourcePal
;
634 else if (PalOutType
== XO_DESTPALETTE
)
635 hPalette
= XlateGDI
->DestPal
;
642 PalGDI
= PALETTE_LockPalette(hPalette
);
645 /* copy the indexed colors into the buffer */
647 for(InPal
= (ULONG
*)PalGDI
->IndexedColors
;
649 cPal
--, InPal
++, OutPal
++)
654 PALETTE_UnlockPalette(PalGDI
);