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;
21 const BYTE gajXlate5to8
[32] =
22 { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99,107,115,123,
23 132,140,148,156,165,173,181,189,197,206,214,222,231,239,247,255};
25 const BYTE gajXlate6to8
[64] =
26 { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 52, 57, 61,
27 65, 69, 73, 77, 81, 85, 89, 93, 97,101,105,109,113,117,121,125,
28 130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,
29 194,198,202,207,210,215,219,223,227,231,235,239,243,247,251,255};
32 /** iXlate functions **********************************************************/
36 EXLATEOBJ_iXlateTrivial(PEXLATEOBJ pexlo
, ULONG iColor
)
43 EXLATEOBJ_iXlateToMono(PEXLATEOBJ pexlo
, ULONG iColor
)
45 return (iColor
== pexlo
->xlo
.pulXlate
[0]);
50 EXLATEOBJ_iXlateTable(PEXLATEOBJ pexlo
, ULONG iColor
)
52 if (iColor
>= pexlo
->xlo
.cEntries
)
54 iColor
%= pexlo
->xlo
.cEntries
;
56 return pexlo
->xlo
.pulXlate
[iColor
];
61 EXLATEOBJ_iXlateRGBtoBGR(PEXLATEOBJ pxlo
, ULONG iColor
)
66 iNewColor
= iColor
& 0xff00ff00;
68 /* Mask red and blue */
71 /* Shift and copy red and blue */
72 iNewColor
|= iColor
>> 16;
73 iNewColor
|= iColor
<< 16;
80 EXLATEOBJ_iXlateRGBto555(PEXLATEOBJ pxlo
, ULONG iColor
)
86 iNewColor
= iColor
& 0x7C00;
90 iNewColor
|= iColor
& 0x3E0;
94 iNewColor
|= iColor
& 0x1F;
101 EXLATEOBJ_iXlateBGRto555(PEXLATEOBJ pxlo
, ULONG iColor
)
107 iNewColor
= iColor
& 0x1f;
111 iNewColor
|= (iColor
& 0x3E0);
115 iNewColor
|= (iColor
& 0x7C00);
122 EXLATEOBJ_iXlateRGBto565(PEXLATEOBJ pxlo
, ULONG iColor
)
128 iNewColor
= iColor
& 0xF800;
132 iNewColor
|= iColor
& 0x7E0;
136 iNewColor
|= iColor
& 0x1F;
143 EXLATEOBJ_iXlateBGRto565(PEXLATEOBJ pxlo
, ULONG iColor
)
149 iNewColor
= iColor
& 0x1f;
153 iNewColor
|= (iColor
& 0x7E0);
157 iNewColor
|= (iColor
& 0xF800);
164 EXLATEOBJ_iXlateRGBtoPal(PEXLATEOBJ pexlo
, ULONG iColor
)
166 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
171 EXLATEOBJ_iXlate555toRGB(PEXLATEOBJ pxlo
, ULONG iColor
)
176 iNewColor
= gajXlate5to8
[iColor
& 0x1F] << 16;
180 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 8;
184 iNewColor
|= gajXlate5to8
[iColor
& 0x1F];
191 EXLATEOBJ_iXlate555toBGR(PEXLATEOBJ pxlo
, ULONG iColor
)
196 iNewColor
= gajXlate5to8
[iColor
& 0x1F];
200 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 8;
204 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 16;
211 EXLATEOBJ_iXlate555to565(PEXLATEOBJ pxlo
, ULONG iColor
)
216 iNewColor
= iColor
& 0x1f;
218 /* Copy red and green */
220 iNewColor
|= iColor
& 0xFFC0;
222 /* Duplicate highest green bit */
224 iNewColor
|= (iColor
& 0x20);
231 EXLATEOBJ_iXlate555toPal(PEXLATEOBJ pexlo
, ULONG iColor
)
233 iColor
= EXLATEOBJ_iXlate555toRGB(pexlo
, iColor
);
235 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
240 EXLATEOBJ_iXlate565to555(PEXLATEOBJ pxlo
, ULONG iColor
)
245 iNewColor
= iColor
& 0x1f;
247 /* Copy red and green */
249 iNewColor
|= iColor
& 0x7FE0;
256 EXLATEOBJ_iXlate565toRGB(PEXLATEOBJ pexlo
, ULONG iColor
)
261 iNewColor
= gajXlate5to8
[iColor
& 0x1F] << 16;
265 iNewColor
|= gajXlate6to8
[iColor
& 0x3F] << 8;
269 iNewColor
|= gajXlate5to8
[iColor
& 0x1F];
276 EXLATEOBJ_iXlate565toBGR(PEXLATEOBJ pexlo
, ULONG iColor
)
281 iNewColor
= gajXlate5to8
[iColor
& 0x1F];
285 iNewColor
|= gajXlate6to8
[iColor
& 0x3F] << 8;
289 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 16;
296 EXLATEOBJ_iXlate565toPal(EXLATEOBJ
*pexlo
, ULONG iColor
)
298 iColor
= EXLATEOBJ_iXlate565toRGB(pexlo
, iColor
);
300 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
305 EXLATEOBJ_iXlateShiftAndMask(PEXLATEOBJ pexlo
, ULONG iColor
)
309 iNewColor
= _rotl(iColor
, pexlo
->ulRedShift
) & pexlo
->ulRedMask
;
310 iNewColor
|= _rotl(iColor
, pexlo
->ulGreenShift
) & pexlo
->ulGreenMask
;
311 iNewColor
|= _rotl(iColor
, pexlo
->ulBlueShift
) & pexlo
->ulBlueMask
;
318 EXLATEOBJ_iXlateBitfieldsToPal(PEXLATEOBJ pexlo
, ULONG iColor
)
320 /* Convert bitfields to RGB */
321 iColor
= EXLATEOBJ_iXlateShiftAndMask(pexlo
, iColor
);
323 /* Return nearest index */
324 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
328 /** Private Functions *********************************************************/
332 EXLATEOBJ_vInitialize(
336 COLORREF crSrcBackColor
,
337 COLORREF crDstBackColor
,
338 COLORREF crDstForeColor
)
343 if (!ppalSrc
) ppalSrc
= &gpalRGB
;
344 if (!ppalDst
) ppalDst
= &gpalRGB
;
346 pexlo
->xlo
.iUniq
= InterlockedIncrement((LONG
*)&giUniqueXlate
);
347 pexlo
->xlo
.cEntries
= 0;
348 pexlo
->xlo
.flXlate
= 0;
349 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
350 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
351 pexlo
->hColorTransform
= NULL
;
352 pexlo
->ppalSrc
= ppalSrc
;
353 pexlo
->ppalDst
= ppalDst
;
354 pexlo
->xlo
.iSrcType
= ppalSrc
->flFlags
;
355 pexlo
->xlo
.iDstType
= ppalDst
->flFlags
;
356 pexlo
->ppalDstDc
= &gpalRGB
;
358 if (ppalDst
== ppalSrc
)
360 pexlo
->xlo
.flXlate
|= XO_TRIVIAL
;
364 /* Chack if both of the pallettes are indexed */
365 if (!(ppalSrc
->flFlags
& PAL_INDEXED
) || !(ppalDst
->flFlags
& PAL_INDEXED
))
367 /* At least one palette is not indexed, calculate shifts/masks */
368 ULONG aulMasksSrc
[3], aulMasksDst
[3];
370 PALETTE_vGetBitMasks(ppalSrc
, aulMasksSrc
);
371 PALETTE_vGetBitMasks(ppalDst
, aulMasksDst
);
373 pexlo
->ulRedMask
= aulMasksDst
[0];
374 pexlo
->ulGreenMask
= aulMasksDst
[1];
375 pexlo
->ulBlueMask
= aulMasksDst
[2];
377 pexlo
->ulRedShift
= CalculateShift(aulMasksSrc
[0], aulMasksDst
[0]);
378 pexlo
->ulGreenShift
= CalculateShift(aulMasksSrc
[1], aulMasksDst
[1]);
379 pexlo
->ulBlueShift
= CalculateShift(aulMasksSrc
[2], aulMasksDst
[2]);
382 if (ppalSrc
->flFlags
& PAL_MONOCHROME
)
384 /* This is a monochrome palette */
385 if (!(ppalDst
->flFlags
& PAL_MONOCHROME
))
387 /* Mono to color, use the dest DC's fore and back color */
388 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTable
;
389 pexlo
->xlo
.flXlate
|= XO_TABLE
;
390 pexlo
->xlo
.cEntries
= 2;
391 pexlo
->xlo
.pulXlate
[0] =
392 PALETTE_ulGetNearestIndex(ppalDst
, crDstForeColor
);
393 pexlo
->xlo
.pulXlate
[1] =
394 PALETTE_ulGetNearestIndex(ppalDst
, crDstBackColor
);
397 else if (ppalDst
->flFlags
& PAL_MONOCHROME
)
399 pexlo
->pfnXlate
= EXLATEOBJ_iXlateToMono
;
400 pexlo
->xlo
.flXlate
|= XO_TO_MONO
;
401 pexlo
->xlo
.cEntries
= 1;
403 if (ppalSrc
->flFlags
& PAL_INDEXED
)
406 PALETTE_ulGetNearestPaletteIndex(ppalSrc
, crSrcBackColor
);
408 else if (ppalSrc
->flFlags
& PAL_RGB
)
410 pexlo
->aulXlate
[0] = crSrcBackColor
;
412 else if (ppalSrc
->flFlags
& PAL_BGR
)
414 pexlo
->aulXlate
[0] = RGB(GetBValue(crSrcBackColor
),
415 GetGValue(crSrcBackColor
),
416 GetRValue(crSrcBackColor
));
418 else if (ppalSrc
->flFlags
& PAL_BITFIELDS
)
420 PALETTE_vGetBitMasks(ppalSrc
, &pexlo
->ulRedMask
);
421 pexlo
->ulRedShift
= CalculateShift(0xFF, pexlo
->ulRedMask
);
422 pexlo
->ulGreenShift
= CalculateShift(0xFF00, pexlo
->ulGreenMask
);
423 pexlo
->ulBlueShift
= CalculateShift(0xFF0000, pexlo
->ulBlueMask
);
425 pexlo
->aulXlate
[0] = EXLATEOBJ_iXlateShiftAndMask(pexlo
, crSrcBackColor
);
428 else if (ppalSrc
->flFlags
& PAL_INDEXED
)
430 cEntries
= ppalSrc
->NumColors
;
432 /* Allocate buffer if needed */
435 pexlo
->xlo
.pulXlate
= EngAllocMem(0,
436 cEntries
* sizeof(ULONG
),
438 if (!pexlo
->xlo
.pulXlate
)
440 DPRINT1("Could not allocate pulXlate buffer.\n");
441 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
442 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
447 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTable
;
448 pexlo
->xlo
.cEntries
= cEntries
;
449 pexlo
->xlo
.flXlate
|= XO_TABLE
;
451 if (ppalDst
->flFlags
& PAL_INDEXED
)
455 for (i
= 0; i
< cEntries
; i
++)
457 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
458 ppalSrc
->IndexedColors
[i
].peGreen
,
459 ppalSrc
->IndexedColors
[i
].peBlue
);
461 pexlo
->xlo
.pulXlate
[i
] =
462 PALETTE_ulGetNearestPaletteIndex(ppalDst
, ulColor
);
464 if (pexlo
->xlo
.pulXlate
[i
] != i
) cDiff
++;
467 /* Check if we have only trivial mappings */
470 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
472 EngFreeMem(pexlo
->xlo
.pulXlate
);
473 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
475 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
476 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
477 pexlo
->xlo
.cEntries
= 0;
483 // FIXME: use PALETTE_ulGetNearest
484 EXLATEOBJ exloTmp
= *pexlo
;
485 exloTmp
.xlo
.pulXlate
= exloTmp
.aulXlate
;
487 pexlo
->xlo
.flXlate
|= XO_TABLE
;
488 for (i
= 0; i
< pexlo
->xlo
.cEntries
; i
++)
490 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
491 ppalSrc
->IndexedColors
[i
].peGreen
,
492 ppalSrc
->IndexedColors
[i
].peBlue
);
493 pexlo
->xlo
.pulXlate
[i
] =
494 EXLATEOBJ_iXlateShiftAndMask(&exloTmp
, ulColor
);
498 else if (ppalSrc
->flFlags
& PAL_RGB
)
500 if (ppalDst
->flFlags
& PAL_INDEXED
)
501 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoPal
;
503 else if (ppalDst
->flFlags
& PAL_BGR
)
504 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
506 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
507 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto555
;
509 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
510 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto565
;
512 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
513 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
515 else if (ppalSrc
->flFlags
& PAL_BGR
)
517 if (ppalDst
->flFlags
& PAL_INDEXED
)
518 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
520 else if (ppalDst
->flFlags
& PAL_RGB
)
521 /* The inverse function works the same */
522 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
524 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
525 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto555
;
527 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
528 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto565
;
530 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
531 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
533 else if (ppalSrc
->flFlags
& PAL_RGB16_555
)
535 if (ppalDst
->flFlags
& PAL_INDEXED
)
536 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toPal
;
538 else if (ppalDst
->flFlags
& PAL_RGB
)
539 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toRGB
;
541 else if (ppalDst
->flFlags
& PAL_BGR
)
542 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toBGR
;
544 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
545 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555to565
;
547 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
548 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
550 else if (ppalSrc
->flFlags
& PAL_RGB16_565
)
552 if (ppalDst
->flFlags
& PAL_INDEXED
)
553 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toPal
;
555 else if (ppalDst
->flFlags
& PAL_RGB
)
556 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toRGB
;
558 else if (ppalDst
->flFlags
& PAL_BGR
)
559 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toBGR
;
561 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
562 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565to555
;
564 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
565 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
567 else if (ppalSrc
->flFlags
& PAL_BITFIELDS
)
569 if (ppalDst
->flFlags
& PAL_INDEXED
)
570 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
572 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
575 /* Check for a trivial shift and mask operation */
576 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateShiftAndMask
&&
577 !pexlo
->ulRedShift
&& !pexlo
->ulGreenShift
&& !pexlo
->ulBlueShift
)
579 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
582 /* Check for trivial xlate */
583 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateTrivial
)
584 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
586 pexlo
->xlo
.flXlate
&= ~XO_TRIVIAL
;
591 EXLATEOBJ_vInitXlateFromDCs(
596 PSURFACE psurfDst
, psurfSrc
;
598 psurfDst
= pdcDst
->dclevel
.pSurface
;
599 psurfSrc
= pdcSrc
->dclevel
.pSurface
;
601 /* Normal initialisation. No surface means DEFAULT_BITMAP */
602 EXLATEOBJ_vInitialize(pexlo
,
603 psurfSrc
? psurfSrc
->ppal
: &gpalMono
,
604 psurfDst
? psurfDst
->ppal
: &gpalMono
,
605 pdcSrc
->pdcattr
->crBackgroundClr
,
606 pdcDst
->pdcattr
->crBackgroundClr
,
607 pdcDst
->pdcattr
->crForegroundClr
);
609 pexlo
->ppalDstDc
= pdcDst
->dclevel
.ppal
;
614 EXLATEOBJ_vCleanup(PEXLATEOBJ pexlo
)
616 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
618 EngFreeMem(pexlo
->xlo
.pulXlate
);
620 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
628 return STATUS_SUCCESS
;
632 /** Public DDI Functions ******************************************************/
634 #undef XLATEOBJ_iXlate
637 XLATEOBJ_iXlate(XLATEOBJ
*pxlo
, ULONG iColor
)
639 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
644 /* Call the iXlate function */
645 return pexlo
->pfnXlate(pexlo
, iColor
);
650 XLATEOBJ_cGetPalette(XLATEOBJ
*pxlo
, ULONG iPal
, ULONG cPal
, ULONG
*pPalOut
)
652 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
663 DPRINT1("XLATEOBJ_cGetPalette called with wrong iPal: %d\n", iPal
);
667 /* Get the requested palette */
668 if (iPal
== XO_DESTDCPALETTE
)
670 ppal
= pexlo
->ppalDstDc
;
672 else if (iPal
== XO_SRCPALETTE
|| iPal
== XO_SRCBITFIELDS
)
674 ppal
= pexlo
->ppalSrc
;
678 ppal
= pexlo
->ppalDst
;
681 /* Verify palette type match */
683 ((iPal
== XO_SRCPALETTE
|| iPal
== XO_DESTPALETTE
)
684 && !(ppal
->flFlags
& PAL_INDEXED
)) ||
685 ((iPal
== XO_SRCBITFIELDS
|| iPal
== XO_DESTBITFIELDS
)
686 && !(ppal
->flFlags
& PAL_BITFIELDS
)))
693 return ppal
->NumColors
;
696 /* Copy the values into the buffer */
697 if (ppal
->flFlags
& PAL_INDEXED
)
699 cPal
= min(cPal
, ppal
->NumColors
);
700 for (i
= 0; i
< cPal
; i
++)
702 pPalOut
[i
] = RGB(ppal
->IndexedColors
[i
].peRed
,
703 ppal
->IndexedColors
[i
].peGreen
,
704 ppal
->IndexedColors
[i
].peBlue
);
709 // FIXME: should use the above code
710 pPalOut
[0] = ppal
->RedMask
;
711 pPalOut
[1] = ppal
->GreenMask
;
712 pPalOut
[2] = ppal
->BlueMask
;
720 XLATEOBJ_hGetColorTransform(XLATEOBJ
*pxlo
)
722 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
723 return pexlo
->hColorTransform
;
728 XLATEOBJ_piVector(XLATEOBJ
*pxlo
)
730 if (pxlo
->iSrcType
== PAL_INDEXED
)
732 return pxlo
->pulXlate
;