2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: GDI Color Translation Functions
5 * FILE: subsystems/win32/win32k/eng/xlate.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
15 /** Globals *******************************************************************/
17 EXLATEOBJ gexloTrivial
= {{0, XO_TRIVIAL
, 0, 0, 0, 0}, EXLATEOBJ_iXlateTrivial
};
19 static ULONG giUniqueXlate
= 0;
21 static 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 static 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
= (USHORT
)ppalSrc
->flFlags
;
355 pexlo
->xlo
.iDstType
= (USHORT
)ppalDst
->flFlags
;
356 pexlo
->ppalDstDc
= &gpalRGB
;
358 if (ppalDst
== ppalSrc
)
360 pexlo
->xlo
.flXlate
|= XO_TRIVIAL
;
364 /* Check 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(RGB(0xFF,0,0), pexlo
->ulRedMask
);
422 pexlo
->ulGreenShift
= CalculateShift(RGB(0,0xFF,0), pexlo
->ulGreenMask
);
423 pexlo
->ulBlueShift
= CalculateShift(RGB(0,0,0xFF), 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 for (i
= 0; i
< pexlo
->xlo
.cEntries
; i
++)
485 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
486 ppalSrc
->IndexedColors
[i
].peGreen
,
487 ppalSrc
->IndexedColors
[i
].peBlue
);
488 pexlo
->xlo
.pulXlate
[i
] = PALETTE_ulGetNearestBitFieldsIndex(ppalDst
, ulColor
);
492 else if (ppalSrc
->flFlags
& PAL_RGB
)
494 if (ppalDst
->flFlags
& PAL_INDEXED
)
495 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoPal
;
497 else if (ppalDst
->flFlags
& PAL_BGR
)
498 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
500 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
501 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto555
;
503 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
504 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto565
;
506 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
507 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
509 else if (ppalSrc
->flFlags
& PAL_BGR
)
511 if (ppalDst
->flFlags
& PAL_INDEXED
)
512 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
514 else if (ppalDst
->flFlags
& PAL_RGB
)
515 /* The inverse function works the same */
516 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
518 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
519 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto555
;
521 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
522 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto565
;
524 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
525 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
527 else if (ppalSrc
->flFlags
& PAL_RGB16_555
)
529 if (ppalDst
->flFlags
& PAL_INDEXED
)
530 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toPal
;
532 else if (ppalDst
->flFlags
& PAL_RGB
)
533 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toRGB
;
535 else if (ppalDst
->flFlags
& PAL_BGR
)
536 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toBGR
;
538 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
539 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555to565
;
541 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
542 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
544 else if (ppalSrc
->flFlags
& PAL_RGB16_565
)
546 if (ppalDst
->flFlags
& PAL_INDEXED
)
547 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toPal
;
549 else if (ppalDst
->flFlags
& PAL_RGB
)
550 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toRGB
;
552 else if (ppalDst
->flFlags
& PAL_BGR
)
553 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toBGR
;
555 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
556 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565to555
;
558 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
559 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
561 else if (ppalSrc
->flFlags
& PAL_BITFIELDS
)
563 if (ppalDst
->flFlags
& PAL_INDEXED
)
564 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
566 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
569 /* Check for a trivial shift and mask operation */
570 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateShiftAndMask
&&
571 !pexlo
->ulRedShift
&& !pexlo
->ulGreenShift
&& !pexlo
->ulBlueShift
)
573 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
576 /* Check for trivial xlate */
577 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateTrivial
)
578 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
580 pexlo
->xlo
.flXlate
&= ~XO_TRIVIAL
;
585 EXLATEOBJ_vInitXlateFromDCs(
590 PSURFACE psurfDst
, psurfSrc
;
592 psurfDst
= pdcDst
->dclevel
.pSurface
;
593 psurfSrc
= pdcSrc
->dclevel
.pSurface
;
595 /* Normal initialisation. No surface means DEFAULT_BITMAP */
596 EXLATEOBJ_vInitialize(pexlo
,
597 psurfSrc
? psurfSrc
->ppal
: &gpalMono
,
598 psurfDst
? psurfDst
->ppal
: &gpalMono
,
599 pdcSrc
->pdcattr
->crBackgroundClr
,
600 pdcDst
->pdcattr
->crBackgroundClr
,
601 pdcDst
->pdcattr
->crForegroundClr
);
603 pexlo
->ppalDstDc
= pdcDst
->dclevel
.ppal
;
608 EXLATEOBJ_vCleanup(PEXLATEOBJ pexlo
)
610 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
612 EngFreeMem(pexlo
->xlo
.pulXlate
);
614 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
617 /** Public DDI Functions ******************************************************/
619 #undef XLATEOBJ_iXlate
622 XLATEOBJ_iXlate(XLATEOBJ
*pxlo
, ULONG iColor
)
624 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
629 /* Call the iXlate function */
630 return pexlo
->pfnXlate(pexlo
, iColor
);
635 XLATEOBJ_cGetPalette(XLATEOBJ
*pxlo
, ULONG iPal
, ULONG cPal
, ULONG
*pPalOut
)
637 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
648 DPRINT1("XLATEOBJ_cGetPalette called with wrong iPal: %d\n", iPal
);
652 /* Get the requested palette */
653 if (iPal
== XO_DESTDCPALETTE
)
655 ppal
= pexlo
->ppalDstDc
;
657 else if (iPal
== XO_SRCPALETTE
|| iPal
== XO_SRCBITFIELDS
)
659 ppal
= pexlo
->ppalSrc
;
663 ppal
= pexlo
->ppalDst
;
666 /* Verify palette type match */
668 ((iPal
== XO_SRCPALETTE
|| iPal
== XO_DESTPALETTE
)
669 && !(ppal
->flFlags
& PAL_INDEXED
)) ||
670 ((iPal
== XO_SRCBITFIELDS
|| iPal
== XO_DESTBITFIELDS
)
671 && !(ppal
->flFlags
& PAL_BITFIELDS
)))
678 return ppal
->NumColors
;
681 /* Copy the values into the buffer */
682 if (ppal
->flFlags
& PAL_INDEXED
)
684 cPal
= min(cPal
, ppal
->NumColors
);
685 for (i
= 0; i
< cPal
; i
++)
687 pPalOut
[i
] = RGB(ppal
->IndexedColors
[i
].peRed
,
688 ppal
->IndexedColors
[i
].peGreen
,
689 ppal
->IndexedColors
[i
].peBlue
);
694 // FIXME: should use the above code
695 pPalOut
[0] = ppal
->RedMask
;
696 pPalOut
[1] = ppal
->GreenMask
;
697 pPalOut
[2] = ppal
->BlueMask
;
705 XLATEOBJ_hGetColorTransform(XLATEOBJ
*pxlo
)
707 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
708 return pexlo
->hColorTransform
;
713 XLATEOBJ_piVector(XLATEOBJ
*pxlo
)
715 if (pxlo
->iSrcType
== PAL_INDEXED
)
717 return pxlo
->pulXlate
;