2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: GDI Color Translation Functions
5 * FILE: win32ss/gdi/eng/xlateobj.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
14 _Post_satisfies_(return==iColor
)
15 _Function_class_(FN_XLATE
)
18 EXLATEOBJ_iXlateTrivial(
19 _In_ PEXLATEOBJ pexlo
,
22 /** Globals *******************************************************************/
24 EXLATEOBJ gexloTrivial
= {{0, XO_TRIVIAL
, 0, 0, 0, 0}, EXLATEOBJ_iXlateTrivial
};
26 static ULONG giUniqueXlate
= 0;
28 static const BYTE gajXlate5to8
[32] =
29 { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99,107,115,123,
30 132,140,148,156,165,173,181,189,197,206,214,222,231,239,247,255};
32 static const BYTE gajXlate6to8
[64] =
33 { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 52, 57, 61,
34 65, 69, 73, 77, 81, 85, 89, 93, 97,101,105,109,113,117,121,125,
35 130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,
36 194,198,202,207,210,215,219,223,227,231,235,239,243,247,251,255};
39 /** iXlate functions **********************************************************/
41 _Post_satisfies_(return==iColor
)
42 _Function_class_(FN_XLATE
)
45 EXLATEOBJ_iXlateTrivial(
46 _In_ PEXLATEOBJ pexlo
,
52 _Function_class_(FN_XLATE
)
55 EXLATEOBJ_iXlateToMono(_In_ PEXLATEOBJ pexlo
, ULONG iColor
)
57 return (iColor
== pexlo
->xlo
.pulXlate
[0]);
60 _Function_class_(FN_XLATE
)
63 EXLATEOBJ_iXlateTable(PEXLATEOBJ pexlo
, ULONG iColor
)
65 if (iColor
>= pexlo
->xlo
.cEntries
) return 0;
66 return pexlo
->xlo
.pulXlate
[iColor
];
69 _Function_class_(FN_XLATE
)
72 EXLATEOBJ_iXlateRGBtoBGR(PEXLATEOBJ pxlo
, ULONG iColor
)
77 iNewColor
= iColor
& 0xff00ff00;
79 /* Mask red and blue */
82 /* Shift and copy red and blue */
83 iNewColor
|= iColor
>> 16;
84 iNewColor
|= iColor
<< 16;
89 _Function_class_(FN_XLATE
)
92 EXLATEOBJ_iXlateRGBto555(PEXLATEOBJ pxlo
, ULONG iColor
)
98 iNewColor
= iColor
& 0x7C00;
102 iNewColor
|= iColor
& 0x3E0;
106 iNewColor
|= iColor
& 0x1F;
111 _Function_class_(FN_XLATE
)
114 EXLATEOBJ_iXlateBGRto555(PEXLATEOBJ pxlo
, ULONG iColor
)
120 iNewColor
= iColor
& 0x1f;
124 iNewColor
|= (iColor
& 0x3E0);
128 iNewColor
|= (iColor
& 0x7C00);
133 _Function_class_(FN_XLATE
)
136 EXLATEOBJ_iXlateRGBto565(PEXLATEOBJ pxlo
, ULONG iColor
)
142 iNewColor
= iColor
& 0xF800;
146 iNewColor
|= iColor
& 0x7E0;
150 iNewColor
|= iColor
& 0x1F;
155 _Function_class_(FN_XLATE
)
158 EXLATEOBJ_iXlateBGRto565(PEXLATEOBJ pxlo
, ULONG iColor
)
164 iNewColor
= iColor
& 0x1f;
168 iNewColor
|= (iColor
& 0x7E0);
172 iNewColor
|= (iColor
& 0xF800);
177 _Function_class_(FN_XLATE
)
180 EXLATEOBJ_iXlateRGBtoPal(PEXLATEOBJ pexlo
, ULONG iColor
)
182 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
185 _Function_class_(FN_XLATE
)
188 EXLATEOBJ_iXlate555toRGB(PEXLATEOBJ pxlo
, ULONG iColor
)
193 iNewColor
= gajXlate5to8
[iColor
& 0x1F] << 16;
197 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 8;
201 iNewColor
|= gajXlate5to8
[iColor
& 0x1F];
206 _Function_class_(FN_XLATE
)
209 EXLATEOBJ_iXlate555toBGR(PEXLATEOBJ pxlo
, ULONG iColor
)
214 iNewColor
= gajXlate5to8
[iColor
& 0x1F];
218 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 8;
222 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 16;
227 _Function_class_(FN_XLATE
)
230 EXLATEOBJ_iXlate555to565(PEXLATEOBJ pxlo
, ULONG iColor
)
235 iNewColor
= iColor
& 0x1f;
237 /* Copy red and green */
239 iNewColor
|= iColor
& 0xFFC0;
241 /* Duplicate highest green bit */
243 iNewColor
|= (iColor
& 0x20);
248 _Function_class_(FN_XLATE
)
251 EXLATEOBJ_iXlate555toPal(PEXLATEOBJ pexlo
, ULONG iColor
)
253 iColor
= EXLATEOBJ_iXlate555toRGB(pexlo
, iColor
);
255 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
258 _Function_class_(FN_XLATE
)
261 EXLATEOBJ_iXlate565to555(PEXLATEOBJ pxlo
, ULONG iColor
)
266 iNewColor
= iColor
& 0x1f;
268 /* Copy red and green */
270 iNewColor
|= iColor
& 0x7FE0;
275 _Function_class_(FN_XLATE
)
278 EXLATEOBJ_iXlate565toRGB(PEXLATEOBJ pexlo
, ULONG iColor
)
283 iNewColor
= gajXlate5to8
[iColor
& 0x1F] << 16;
287 iNewColor
|= gajXlate6to8
[iColor
& 0x3F] << 8;
291 iNewColor
|= gajXlate5to8
[iColor
& 0x1F];
296 _Function_class_(FN_XLATE
)
299 EXLATEOBJ_iXlate565toBGR(PEXLATEOBJ pexlo
, ULONG iColor
)
304 iNewColor
= gajXlate5to8
[iColor
& 0x1F];
308 iNewColor
|= gajXlate6to8
[iColor
& 0x3F] << 8;
312 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 16;
317 _Function_class_(FN_XLATE
)
320 EXLATEOBJ_iXlate565toPal(EXLATEOBJ
*pexlo
, ULONG iColor
)
322 iColor
= EXLATEOBJ_iXlate565toRGB(pexlo
, iColor
);
324 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
327 _Function_class_(FN_XLATE
)
330 EXLATEOBJ_iXlateShiftAndMask(PEXLATEOBJ pexlo
, ULONG iColor
)
334 iNewColor
= _rotl(iColor
, pexlo
->ulRedShift
) & pexlo
->ulRedMask
;
335 iNewColor
|= _rotl(iColor
, pexlo
->ulGreenShift
) & pexlo
->ulGreenMask
;
336 iNewColor
|= _rotl(iColor
, pexlo
->ulBlueShift
) & pexlo
->ulBlueMask
;
341 _Function_class_(FN_XLATE
)
344 EXLATEOBJ_iXlateBitfieldsToPal(PEXLATEOBJ pexlo
, ULONG iColor
)
346 /* Convert bitfields to RGB */
347 iColor
= EXLATEOBJ_iXlateShiftAndMask(pexlo
, iColor
);
349 /* Return nearest index */
350 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
354 /** Private Functions *********************************************************/
358 EXLATEOBJ_vInitialize(
359 _Out_ PEXLATEOBJ pexlo
,
360 _In_opt_ PALETTE
*ppalSrc
,
361 _In_opt_ PALETTE
*ppalDst
,
362 _In_ COLORREF crSrcBackColor
,
363 _In_ COLORREF crDstBackColor
,
364 _In_ COLORREF crDstForeColor
)
369 if (!ppalSrc
) ppalSrc
= &gpalRGB
;
370 if (!ppalDst
) ppalDst
= &gpalRGB
;
372 pexlo
->xlo
.iUniq
= InterlockedIncrement((LONG
*)&giUniqueXlate
);
373 pexlo
->xlo
.cEntries
= 0;
374 pexlo
->xlo
.flXlate
= 0;
375 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
376 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
377 pexlo
->hColorTransform
= NULL
;
378 pexlo
->ppalSrc
= ppalSrc
;
379 pexlo
->ppalDst
= ppalDst
;
380 pexlo
->xlo
.iSrcType
= (USHORT
)ppalSrc
->flFlags
;
381 pexlo
->xlo
.iDstType
= (USHORT
)ppalDst
->flFlags
;
382 pexlo
->ppalDstDc
= &gpalRGB
;
384 if (ppalDst
== ppalSrc
)
386 pexlo
->xlo
.flXlate
|= XO_TRIVIAL
;
390 /* Check if both of the pallettes are indexed */
391 if (!(ppalSrc
->flFlags
& PAL_INDEXED
) || !(ppalDst
->flFlags
& PAL_INDEXED
))
393 /* At least one palette is not indexed, calculate shifts/masks */
394 ULONG aulMasksSrc
[3], aulMasksDst
[3];
396 PALETTE_vGetBitMasks(ppalSrc
, aulMasksSrc
);
397 PALETTE_vGetBitMasks(ppalDst
, aulMasksDst
);
399 pexlo
->ulRedMask
= aulMasksDst
[0];
400 pexlo
->ulGreenMask
= aulMasksDst
[1];
401 pexlo
->ulBlueMask
= aulMasksDst
[2];
403 pexlo
->ulRedShift
= CalculateShift(aulMasksSrc
[0], aulMasksDst
[0]);
404 pexlo
->ulGreenShift
= CalculateShift(aulMasksSrc
[1], aulMasksDst
[1]);
405 pexlo
->ulBlueShift
= CalculateShift(aulMasksSrc
[2], aulMasksDst
[2]);
408 if (ppalSrc
->flFlags
& PAL_MONOCHROME
)
410 /* This is a monochrome palette */
411 if (!(ppalDst
->flFlags
& PAL_MONOCHROME
))
413 /* Mono to color, use the dest DC's fore and back color */
414 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTable
;
415 pexlo
->xlo
.flXlate
|= XO_TABLE
;
416 pexlo
->xlo
.cEntries
= 2;
417 pexlo
->xlo
.pulXlate
[0] =
418 PALETTE_ulGetNearestIndex(ppalDst
, crDstForeColor
);
419 pexlo
->xlo
.pulXlate
[1] =
420 PALETTE_ulGetNearestIndex(ppalDst
, crDstBackColor
);
423 else if (ppalDst
->flFlags
& PAL_MONOCHROME
)
425 pexlo
->pfnXlate
= EXLATEOBJ_iXlateToMono
;
426 pexlo
->xlo
.flXlate
|= XO_TO_MONO
;
427 pexlo
->xlo
.cEntries
= 1;
429 if (ppalSrc
->flFlags
& PAL_INDEXED
)
432 PALETTE_ulGetNearestPaletteIndex(ppalSrc
, crSrcBackColor
);
434 else if (ppalSrc
->flFlags
& PAL_RGB
)
436 pexlo
->aulXlate
[0] = crSrcBackColor
;
438 else if (ppalSrc
->flFlags
& PAL_BGR
)
440 pexlo
->aulXlate
[0] = RGB(GetBValue(crSrcBackColor
),
441 GetGValue(crSrcBackColor
),
442 GetRValue(crSrcBackColor
));
444 else if (ppalSrc
->flFlags
& PAL_BITFIELDS
)
446 PALETTE_vGetBitMasks(ppalSrc
, &pexlo
->ulRedMask
);
447 pexlo
->ulRedShift
= CalculateShift(RGB(0xFF,0,0), pexlo
->ulRedMask
);
448 pexlo
->ulGreenShift
= CalculateShift(RGB(0,0xFF,0), pexlo
->ulGreenMask
);
449 pexlo
->ulBlueShift
= CalculateShift(RGB(0,0,0xFF), pexlo
->ulBlueMask
);
451 pexlo
->aulXlate
[0] = EXLATEOBJ_iXlateShiftAndMask(pexlo
, crSrcBackColor
);
454 else if (ppalSrc
->flFlags
& PAL_INDEXED
)
456 cEntries
= ppalSrc
->NumColors
;
458 /* Allocate buffer if needed */
461 pexlo
->xlo
.pulXlate
= EngAllocMem(0,
462 cEntries
* sizeof(ULONG
),
464 if (!pexlo
->xlo
.pulXlate
)
466 DPRINT1("Could not allocate pulXlate buffer.\n");
467 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
468 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
473 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTable
;
474 pexlo
->xlo
.cEntries
= cEntries
;
475 pexlo
->xlo
.flXlate
|= XO_TABLE
;
477 if (ppalDst
->flFlags
& PAL_INDEXED
)
481 for (i
= 0; i
< cEntries
; i
++)
483 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
484 ppalSrc
->IndexedColors
[i
].peGreen
,
485 ppalSrc
->IndexedColors
[i
].peBlue
);
487 pexlo
->xlo
.pulXlate
[i
] =
488 PALETTE_ulGetNearestPaletteIndex(ppalDst
, ulColor
);
490 if (pexlo
->xlo
.pulXlate
[i
] != i
) cDiff
++;
493 /* Check if we have only trivial mappings */
496 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
498 EngFreeMem(pexlo
->xlo
.pulXlate
);
499 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
501 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
502 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
503 pexlo
->xlo
.cEntries
= 0;
509 for (i
= 0; i
< pexlo
->xlo
.cEntries
; i
++)
511 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
512 ppalSrc
->IndexedColors
[i
].peGreen
,
513 ppalSrc
->IndexedColors
[i
].peBlue
);
514 pexlo
->xlo
.pulXlate
[i
] = PALETTE_ulGetNearestBitFieldsIndex(ppalDst
, ulColor
);
518 else if (ppalSrc
->flFlags
& PAL_RGB
)
520 if (ppalDst
->flFlags
& PAL_INDEXED
)
521 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoPal
;
523 else if (ppalDst
->flFlags
& PAL_BGR
)
524 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
526 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
527 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto555
;
529 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
530 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto565
;
532 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
533 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
535 else if (ppalSrc
->flFlags
& PAL_BGR
)
537 if (ppalDst
->flFlags
& PAL_INDEXED
)
538 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
540 else if (ppalDst
->flFlags
& PAL_RGB
)
541 /* The inverse function works the same */
542 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
544 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
545 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto555
;
547 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
548 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto565
;
550 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
551 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
553 else if (ppalSrc
->flFlags
& PAL_RGB16_555
)
555 if (ppalDst
->flFlags
& PAL_INDEXED
)
556 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toPal
;
558 else if (ppalDst
->flFlags
& PAL_RGB
)
559 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toRGB
;
561 else if (ppalDst
->flFlags
& PAL_BGR
)
562 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toBGR
;
564 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
565 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555to565
;
567 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
568 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
570 else if (ppalSrc
->flFlags
& PAL_RGB16_565
)
572 if (ppalDst
->flFlags
& PAL_INDEXED
)
573 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toPal
;
575 else if (ppalDst
->flFlags
& PAL_RGB
)
576 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toRGB
;
578 else if (ppalDst
->flFlags
& PAL_BGR
)
579 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toBGR
;
581 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
582 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565to555
;
584 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
585 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
587 else if (ppalSrc
->flFlags
& PAL_BITFIELDS
)
589 if (ppalDst
->flFlags
& PAL_INDEXED
)
590 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
592 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
595 /* Check for a trivial shift and mask operation */
596 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateShiftAndMask
&&
597 !pexlo
->ulRedShift
&& !pexlo
->ulGreenShift
&& !pexlo
->ulBlueShift
)
599 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
602 /* Check for trivial xlate */
603 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateTrivial
)
604 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
606 pexlo
->xlo
.flXlate
&= ~XO_TRIVIAL
;
611 EXLATEOBJ_vInitXlateFromDCs(
612 _Out_ EXLATEOBJ
* pexlo
,
616 PSURFACE psurfDst
, psurfSrc
;
618 psurfDst
= pdcDst
->dclevel
.pSurface
;
619 psurfSrc
= pdcSrc
->dclevel
.pSurface
;
621 /* Normal initialisation. No surface means DEFAULT_BITMAP */
622 EXLATEOBJ_vInitialize(pexlo
,
623 psurfSrc
? psurfSrc
->ppal
: gppalMono
,
624 psurfDst
? psurfDst
->ppal
: gppalMono
,
625 pdcSrc
->pdcattr
->crBackgroundClr
,
626 pdcDst
->pdcattr
->crBackgroundClr
,
627 pdcDst
->pdcattr
->crForegroundClr
);
629 pexlo
->ppalDstDc
= pdcDst
->dclevel
.ppal
;
632 VOID NTAPI
EXLATEOBJ_vInitSrcMonoXlate(
635 COLORREF crBackgroundClr
,
636 COLORREF crForegroundClr
)
638 /* Normal initialisation, with mono palette as source */
639 EXLATEOBJ_vInitialize(pexlo
,
650 _Inout_ PEXLATEOBJ pexlo
)
652 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
654 EngFreeMem(pexlo
->xlo
.pulXlate
);
656 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
659 /** Public DDI Functions ******************************************************/
661 #undef XLATEOBJ_iXlate
668 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
673 /* Call the iXlate function */
674 return pexlo
->pfnXlate(pexlo
, iColor
);
679 XLATEOBJ_cGetPalette(
683 _Out_cap_(cPal
) ULONG
*pPalOut
)
685 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
696 DPRINT1("XLATEOBJ_cGetPalette called with wrong iPal: %lu\n", iPal
);
700 /* Get the requested palette */
701 if (iPal
== XO_DESTDCPALETTE
)
703 ppal
= pexlo
->ppalDstDc
;
705 else if (iPal
== XO_SRCPALETTE
|| iPal
== XO_SRCBITFIELDS
)
707 ppal
= pexlo
->ppalSrc
;
711 ppal
= pexlo
->ppalDst
;
714 /* Verify palette type match */
716 ((iPal
== XO_SRCPALETTE
|| iPal
== XO_DESTPALETTE
)
717 && !(ppal
->flFlags
& PAL_INDEXED
)) ||
718 ((iPal
== XO_SRCBITFIELDS
|| iPal
== XO_DESTBITFIELDS
)
719 && !(ppal
->flFlags
& PAL_BITFIELDS
)))
726 return ppal
->NumColors
;
729 /* Copy the values into the buffer */
730 if (ppal
->flFlags
& PAL_INDEXED
)
732 cPal
= min(cPal
, ppal
->NumColors
);
733 for (i
= 0; i
< cPal
; i
++)
735 pPalOut
[i
] = RGB(ppal
->IndexedColors
[i
].peRed
,
736 ppal
->IndexedColors
[i
].peGreen
,
737 ppal
->IndexedColors
[i
].peBlue
);
742 // FIXME: should use the above code
743 pPalOut
[0] = ppal
->RedMask
;
744 pPalOut
[1] = ppal
->GreenMask
;
745 pPalOut
[2] = ppal
->BlueMask
;
753 XLATEOBJ_hGetColorTransform(
756 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
757 return pexlo
->hColorTransform
;
765 if (pxlo
->iSrcType
== PAL_INDEXED
)
767 return pxlo
->pulXlate
;