2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Color Translation Functions
5 * FILE: subsystems/win32/win32k/eng/xlate.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
17 /** Globals *******************************************************************/
19 ULONG giUniqueXlate
= 0;
20 EXLATEOBJ gexloTrivial
;
21 XLATEOBJ
* gpxloTrivial
= &gexloTrivial
.xlo
;
23 const BYTE gajXlate5to8
[32] =
24 { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99,107,115,123,
25 132,140,148,156,165,173,181,189,197,206,214,222,231,239,247,255};
27 const BYTE gajXlate6to8
[64] =
28 { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 52, 57, 61,
29 65, 69, 73, 77, 81, 85, 89, 93, 97,101,105,109,113,117,121,125,
30 130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,
31 194,198,202,207,210,215,219,223,227,231,235,239,243,247,251,255};
34 /** iXlate functions **********************************************************/
38 EXLATEOBJ_iXlateTrivial(PEXLATEOBJ pexlo
, ULONG iColor
)
45 EXLATEOBJ_iXlateToMono(PEXLATEOBJ pexlo
, ULONG iColor
)
47 return (iColor
== pexlo
->xlo
.pulXlate
[0]);
52 EXLATEOBJ_iXlateTable(PEXLATEOBJ pexlo
, ULONG iColor
)
54 if (iColor
>= pexlo
->xlo
.cEntries
)
56 iColor
%= pexlo
->xlo
.cEntries
;
58 return pexlo
->xlo
.pulXlate
[iColor
];
63 EXLATEOBJ_iXlateRGBtoBGR(PEXLATEOBJ pxlo
, ULONG iColor
)
68 iNewColor
= iColor
& 0x00ff00;
70 /* Mask red and blue */
73 /* Shift and copy red and blue */
74 iNewColor
|= iColor
>> 16;
75 iNewColor
|= iColor
<< 16;
82 EXLATEOBJ_iXlateRGBto555(PEXLATEOBJ pxlo
, ULONG iColor
)
88 iNewColor
= iColor
& 0x7C00;
92 iNewColor
|= iColor
& 0x3E0;
96 iNewColor
|= iColor
& 0x1F;
103 EXLATEOBJ_iXlateBGRto555(PEXLATEOBJ pxlo
, ULONG iColor
)
109 iNewColor
= iColor
& 0x1f;
113 iNewColor
|= (iColor
& 0x3E0);
117 iNewColor
|= (iColor
& 0x7C00);
124 EXLATEOBJ_iXlateRGBto565(PEXLATEOBJ pxlo
, ULONG iColor
)
130 iNewColor
= iColor
& 0xF800;
134 iNewColor
|= iColor
& 0x7E0;
138 iNewColor
|= iColor
& 0x1F;
145 EXLATEOBJ_iXlateBGRto565(PEXLATEOBJ pxlo
, ULONG iColor
)
151 iNewColor
= iColor
& 0x1f;
155 iNewColor
|= (iColor
& 0x7E0);
159 iNewColor
|= (iColor
& 0xF800);
166 EXLATEOBJ_iXlateRGBtoPal(PEXLATEOBJ pexlo
, ULONG iColor
)
168 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
173 EXLATEOBJ_iXlate555toRGB(PEXLATEOBJ pxlo
, ULONG iColor
)
178 iNewColor
= gajXlate5to8
[iColor
& 0x1F] << 16;
182 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 8;
186 iNewColor
|= gajXlate5to8
[iColor
& 0x1F];
193 EXLATEOBJ_iXlate555toBGR(PEXLATEOBJ pxlo
, ULONG iColor
)
198 iNewColor
= gajXlate5to8
[iColor
& 0x1F];
202 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 8;
206 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 16;
213 EXLATEOBJ_iXlate555to565(PEXLATEOBJ pxlo
, ULONG iColor
)
218 iNewColor
= iColor
& 0x1f;
220 /* Copy red and green */
222 iNewColor
|= iColor
& 0xFFC0;
224 /* Duplicate highest green bit */
226 iNewColor
|= (iColor
& 0x20);
233 EXLATEOBJ_iXlate555toPal(PEXLATEOBJ pexlo
, ULONG iColor
)
235 iColor
= EXLATEOBJ_iXlate555toRGB(pexlo
, iColor
);
237 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
242 EXLATEOBJ_iXlate565to555(PEXLATEOBJ pxlo
, ULONG iColor
)
247 iNewColor
= iColor
& 0x1f;
249 /* Copy red and green */
251 iNewColor
|= iColor
& 0x7FE0;
258 EXLATEOBJ_iXlate565toRGB(PEXLATEOBJ pexlo
, ULONG iColor
)
263 iNewColor
= gajXlate5to8
[iColor
& 0x1F] << 16;
267 iNewColor
|= gajXlate6to8
[iColor
& 0x3F] << 8;
271 iNewColor
|= gajXlate5to8
[iColor
& 0x1F];
278 EXLATEOBJ_iXlate565toBGR(PEXLATEOBJ pexlo
, ULONG iColor
)
283 iNewColor
= gajXlate5to8
[iColor
& 0x1F];
287 iNewColor
|= gajXlate6to8
[iColor
& 0x3F] << 8;
291 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 16;
298 EXLATEOBJ_iXlate565toPal(EXLATEOBJ
*pexlo
, ULONG iColor
)
300 iColor
= EXLATEOBJ_iXlate565toRGB(pexlo
, iColor
);
302 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
307 EXLATEOBJ_iXlateShiftAndMask(PEXLATEOBJ pexlo
, ULONG iColor
)
311 iNewColor
= _rotl(iColor
, pexlo
->ulRedShift
) & pexlo
->ulRedMask
;
312 iNewColor
|= _rotl(iColor
, pexlo
->ulGreenShift
) & pexlo
->ulGreenMask
;
313 iNewColor
|= _rotl(iColor
, pexlo
->ulBlueShift
) & pexlo
->ulBlueMask
;
320 EXLATEOBJ_iXlateBitfieldsToPal(PEXLATEOBJ pexlo
, ULONG iColor
)
322 /* Convert bitfields to RGB */
323 iColor
= EXLATEOBJ_iXlateShiftAndMask(pexlo
, iColor
);
325 /* Return nearest index */
326 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
330 /** Private Functions *********************************************************/
334 EXLATEOBJ_vInitTrivial(PEXLATEOBJ pexlo
)
336 pexlo
->xlo
.iUniq
= InterlockedIncrement((LONG
*)&giUniqueXlate
);
337 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
338 pexlo
->xlo
.iSrcType
= PAL_RGB
;
339 pexlo
->xlo
.iDstType
= PAL_RGB
;
340 pexlo
->xlo
.cEntries
= 0;
341 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
342 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
343 pexlo
->ppalSrc
= &gpalRGB
;
344 pexlo
->ppalDst
= &gpalRGB
;
345 pexlo
->ppalDstDc
= &gpalRGB
;
346 pexlo
->hColorTransform
= NULL
;
351 EXLATEOBJ_vInitialize(
355 COLORREF crSrcBackColor
,
356 COLORREF crDstBackColor
,
357 COLORREF crDstForeColor
)
362 EXLATEOBJ_vInitTrivial(pexlo
);
364 if (ppalDst
== ppalSrc
|| !ppalSrc
|| !ppalDst
||
365 ((ppalDst
->Mode
== PAL_RGB
|| ppalDst
->Mode
== PAL_BGR
) &&
366 ppalDst
->Mode
== ppalSrc
->Mode
))
371 pexlo
->ppalSrc
= ppalSrc
;
372 pexlo
->ppalDst
= ppalDst
;
373 pexlo
->xlo
.iSrcType
= ppalSrc
->Mode
;
374 pexlo
->xlo
.iDstType
= ppalDst
->Mode
;
376 /* Chack if both of the pallettes are indexed */
377 if (!(ppalSrc
->Mode
& PAL_INDEXED
) || !(ppalDst
->Mode
& PAL_INDEXED
))
379 /* At least one palette is not indexed, calculate shifts/masks */
380 ULONG aulMasksSrc
[3], aulMasksDst
[3];
382 PALETTE_vGetBitMasks(ppalSrc
, aulMasksSrc
);
383 PALETTE_vGetBitMasks(ppalDst
, aulMasksDst
);
385 pexlo
->ulRedMask
= aulMasksDst
[0];
386 pexlo
->ulGreenMask
= aulMasksDst
[1];
387 pexlo
->ulBlueMask
= aulMasksDst
[2];
389 pexlo
->ulRedShift
= CalculateShift(aulMasksSrc
[0], aulMasksDst
[0]);
390 pexlo
->ulGreenShift
= CalculateShift(aulMasksSrc
[1], aulMasksDst
[1]);
391 pexlo
->ulBlueShift
= CalculateShift(aulMasksSrc
[2], aulMasksDst
[2]);
394 if (ppalSrc
->Mode
& PAL_MONOCHROME
)
396 /* This is a monochrome palette */
397 if (!(ppalDst
->Mode
& PAL_MONOCHROME
))
399 /* Mono to color, use the dest DC's fore and back color */
400 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTable
;
401 pexlo
->xlo
.flXlate
|= XO_TABLE
;
402 pexlo
->xlo
.cEntries
= 2;
403 pexlo
->xlo
.pulXlate
[0] =
404 PALETTE_ulGetNearestIndex(ppalDst
, crDstForeColor
);
405 pexlo
->xlo
.pulXlate
[1] =
406 PALETTE_ulGetNearestIndex(ppalDst
, crDstBackColor
);
409 else if (ppalDst
->Mode
& PAL_MONOCHROME
)
411 pexlo
->pfnXlate
= EXLATEOBJ_iXlateToMono
;
412 pexlo
->xlo
.flXlate
|= XO_TO_MONO
;
413 pexlo
->xlo
.cEntries
= 1;
415 if (ppalSrc
->Mode
& PAL_INDEXED
)
418 PALETTE_ulGetNearestPaletteIndex(ppalSrc
, crSrcBackColor
);
420 else if (ppalSrc
->Mode
& PAL_BGR
)
422 pexlo
->aulXlate
[0] = crSrcBackColor
;
424 else if (ppalSrc
->Mode
& PAL_RGB
)
426 pexlo
->aulXlate
[0] = RGB(GetBValue(crSrcBackColor
),
427 GetGValue(crSrcBackColor
),
428 GetRValue(crSrcBackColor
));
430 else if (ppalSrc
->Mode
& PAL_BITFIELDS
)
432 PALETTE_vGetBitMasks(ppalSrc
, &pexlo
->ulRedMask
);
433 pexlo
->ulRedShift
= CalculateShift(0xFF, pexlo
->ulRedMask
);
434 pexlo
->ulGreenShift
= CalculateShift(0xFF00, pexlo
->ulGreenMask
);
435 pexlo
->ulBlueShift
= CalculateShift(0xFF0000, pexlo
->ulBlueMask
);
437 pexlo
->aulXlate
[0] = EXLATEOBJ_iXlateShiftAndMask(pexlo
, crSrcBackColor
);
440 else if (ppalSrc
->Mode
& PAL_INDEXED
)
442 cEntries
= ppalSrc
->NumColors
;
444 /* Allocate buffer if needed */
447 pexlo
->xlo
.pulXlate
= EngAllocMem(0,
448 cEntries
* sizeof(ULONG
),
450 if (!pexlo
->xlo
.pulXlate
)
452 DPRINT1("Could not allocate pulXlate buffer.\n");
453 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
454 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
458 pexlo
->xlo
.cEntries
= cEntries
;
460 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTable
;
461 if (ppalDst
->Mode
& PAL_INDEXED
)
463 pexlo
->xlo
.flXlate
|= XO_TABLE
;
465 for (i
= 0; i
< cEntries
; i
++)
467 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
468 ppalSrc
->IndexedColors
[i
].peGreen
,
469 ppalSrc
->IndexedColors
[i
].peBlue
);
471 pexlo
->xlo
.pulXlate
[i
] =
472 PALETTE_ulGetNearestPaletteIndex(ppalDst
, ulColor
);
474 if (pexlo
->xlo
.pulXlate
[i
] != i
)
475 pexlo
->xlo
.flXlate
&= ~XO_TRIVIAL
;
478 if (pexlo
->xlo
.flXlate
& XO_TRIVIAL
)
480 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
482 EngFreeMem(pexlo
->xlo
.pulXlate
);
483 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
485 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
486 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
492 // FIXME: use PALETTE_ulGetNearest
493 EXLATEOBJ exloTmp
= *pexlo
;
494 exloTmp
.xlo
.pulXlate
= exloTmp
.aulXlate
;
496 pexlo
->xlo
.flXlate
|= XO_TABLE
;
497 for (i
= 0; i
< pexlo
->xlo
.cEntries
; i
++)
499 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
500 ppalSrc
->IndexedColors
[i
].peGreen
,
501 ppalSrc
->IndexedColors
[i
].peBlue
);
502 pexlo
->xlo
.pulXlate
[i
] =
503 EXLATEOBJ_iXlateShiftAndMask(&exloTmp
, ulColor
);
507 else if (ppalSrc
->Mode
& PAL_RGB
)
509 if (ppalDst
->Mode
& PAL_INDEXED
)
510 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoPal
;
512 else if (ppalDst
->Mode
& PAL_BGR
)
513 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
515 else if (ppalDst
->Mode
& PAL_RGB16_555
)
516 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto555
;
518 else if (ppalDst
->Mode
& PAL_RGB16_565
)
519 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto565
;
521 else if (ppalDst
->Mode
& PAL_BITFIELDS
)
522 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
524 else if (ppalSrc
->Mode
& PAL_BGR
)
526 if (ppalDst
->Mode
& PAL_INDEXED
)
527 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
529 else if (ppalDst
->Mode
& PAL_RGB
)
530 /* The inverse function works the same */
531 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
533 else if (ppalDst
->Mode
& PAL_RGB16_555
)
534 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto555
;
536 else if (ppalDst
->Mode
& PAL_RGB16_565
)
537 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto565
;
539 else if (ppalDst
->Mode
& PAL_BITFIELDS
)
540 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
542 else if (ppalSrc
->Mode
& PAL_RGB16_555
)
544 if (ppalDst
->Mode
& PAL_INDEXED
)
545 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toPal
;
547 else if (ppalDst
->Mode
& PAL_RGB
)
548 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toRGB
;
550 else if (ppalDst
->Mode
& PAL_BGR
)
551 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toBGR
;
553 else if (ppalDst
->Mode
& PAL_RGB16_565
)
554 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555to565
;
556 else if (ppalDst
->Mode
& PAL_BITFIELDS
)
557 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
559 else if (ppalSrc
->Mode
& PAL_RGB16_565
)
561 if (ppalDst
->Mode
& PAL_INDEXED
)
562 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toPal
;
564 else if (ppalDst
->Mode
& PAL_RGB
)
565 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toRGB
;
567 else if (ppalDst
->Mode
& PAL_BGR
)
568 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toBGR
;
570 else if (ppalDst
->Mode
& PAL_RGB16_555
)
571 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565to555
;
573 else if (ppalDst
->Mode
& PAL_BITFIELDS
)
574 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
576 else if (ppalSrc
->Mode
& PAL_BITFIELDS
)
578 if (ppalDst
->Mode
& PAL_INDEXED
)
579 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
581 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
584 /* Check for a trivial shift and mask operation */
585 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateShiftAndMask
&&
586 !pexlo
->ulRedShift
&& !pexlo
->ulGreenShift
&& !pexlo
->ulBlueShift
)
588 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
591 /* Check for trivial xlate */
592 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateTrivial
)
593 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
595 pexlo
->xlo
.flXlate
&= ~XO_TRIVIAL
;
600 EXLATEOBJ_vInitXlateFromDCs(
605 PSURFACE psurfDst
, psurfSrc
;
607 psurfDst
= pdcDst
->dclevel
.pSurface
;
608 psurfSrc
= pdcSrc
->dclevel
.pSurface
;
610 /* Check for trivial color translation */
611 if (psurfDst
== psurfSrc
)
613 EXLATEOBJ_vInitTrivial(pexlo
);
617 /* Normal initialisation. No surface means DEFAULT_BITMAP */
618 EXLATEOBJ_vInitialize(pexlo
,
619 psurfSrc
? psurfSrc
->ppal
: &gpalMono
,
620 psurfDst
? psurfDst
->ppal
: &gpalMono
,
621 pdcSrc
->pdcattr
->crBackgroundClr
,
622 pdcDst
->pdcattr
->crBackgroundClr
,
623 pdcDst
->pdcattr
->crForegroundClr
);
628 EXLATEOBJ_vCleanup(PEXLATEOBJ pexlo
)
630 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
632 EngFreeMem(pexlo
->xlo
.pulXlate
);
634 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
641 EXLATEOBJ_vInitTrivial(&gexloTrivial
);
645 /** Public DDI Functions ******************************************************/
647 #undef XLATEOBJ_iXlate
650 XLATEOBJ_iXlate(XLATEOBJ
*pxlo
, ULONG iColor
)
652 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
657 /* Call the iXlate function */
658 return pexlo
->pfnXlate(pexlo
, iColor
);
663 XLATEOBJ_cGetPalette(XLATEOBJ
*pxlo
, ULONG iPal
, ULONG cPal
, ULONG
*pPalOut
)
665 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
676 DPRINT1("XLATEOBJ_cGetPalette called with wrong iPal: %d\n", iPal
);
680 /* Get the requested palette */
681 if (iPal
== XO_DESTDCPALETTE
)
683 ppal
= pexlo
->ppalDstDc
;
685 else if (iPal
== XO_SRCPALETTE
|| iPal
== XO_SRCBITFIELDS
)
687 ppal
= pexlo
->ppalSrc
;
691 ppal
= pexlo
->ppalDst
;
694 /* Verify palette type match */
696 ((iPal
== XO_SRCPALETTE
|| iPal
== XO_DESTPALETTE
)
697 && !(ppal
->Mode
& PAL_INDEXED
)) ||
698 ((iPal
== XO_SRCBITFIELDS
|| iPal
== XO_DESTBITFIELDS
)
699 && !(ppal
->Mode
& PAL_BITFIELDS
)))
706 return ppal
->NumColors
;
709 /* Copy the values into the buffer */
710 if (ppal
->Mode
& PAL_INDEXED
)
712 cPal
= min(cPal
, ppal
->NumColors
);
713 for (i
= 0; i
< cPal
; i
++)
715 pPalOut
[i
] = RGB(ppal
->IndexedColors
[i
].peRed
,
716 ppal
->IndexedColors
[i
].peGreen
,
717 ppal
->IndexedColors
[i
].peBlue
);
722 // FIXME: should use the above code
723 pPalOut
[0] = ppal
->RedMask
;
724 pPalOut
[1] = ppal
->GreenMask
;
725 pPalOut
[2] = ppal
->BlueMask
;
733 XLATEOBJ_hGetColorTransform(XLATEOBJ
*pxlo
)
735 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
736 return pexlo
->hColorTransform
;
741 XLATEOBJ_piVector(XLATEOBJ
*pxlo
)
743 if (pxlo
->iSrcType
== PAL_INDEXED
)
745 return pxlo
->pulXlate
;