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
) return 0;
53 return pexlo
->xlo
.pulXlate
[iColor
];
58 EXLATEOBJ_iXlateRGBtoBGR(PEXLATEOBJ pxlo
, ULONG iColor
)
63 iNewColor
= iColor
& 0xff00ff00;
65 /* Mask red and blue */
68 /* Shift and copy red and blue */
69 iNewColor
|= iColor
>> 16;
70 iNewColor
|= iColor
<< 16;
77 EXLATEOBJ_iXlateRGBto555(PEXLATEOBJ pxlo
, ULONG iColor
)
83 iNewColor
= iColor
& 0x7C00;
87 iNewColor
|= iColor
& 0x3E0;
91 iNewColor
|= iColor
& 0x1F;
98 EXLATEOBJ_iXlateBGRto555(PEXLATEOBJ pxlo
, ULONG iColor
)
104 iNewColor
= iColor
& 0x1f;
108 iNewColor
|= (iColor
& 0x3E0);
112 iNewColor
|= (iColor
& 0x7C00);
119 EXLATEOBJ_iXlateRGBto565(PEXLATEOBJ pxlo
, ULONG iColor
)
125 iNewColor
= iColor
& 0xF800;
129 iNewColor
|= iColor
& 0x7E0;
133 iNewColor
|= iColor
& 0x1F;
140 EXLATEOBJ_iXlateBGRto565(PEXLATEOBJ pxlo
, ULONG iColor
)
146 iNewColor
= iColor
& 0x1f;
150 iNewColor
|= (iColor
& 0x7E0);
154 iNewColor
|= (iColor
& 0xF800);
161 EXLATEOBJ_iXlateRGBtoPal(PEXLATEOBJ pexlo
, ULONG iColor
)
163 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
168 EXLATEOBJ_iXlate555toRGB(PEXLATEOBJ pxlo
, ULONG iColor
)
173 iNewColor
= gajXlate5to8
[iColor
& 0x1F] << 16;
177 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 8;
181 iNewColor
|= gajXlate5to8
[iColor
& 0x1F];
188 EXLATEOBJ_iXlate555toBGR(PEXLATEOBJ pxlo
, ULONG iColor
)
193 iNewColor
= gajXlate5to8
[iColor
& 0x1F];
197 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 8;
201 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 16;
208 EXLATEOBJ_iXlate555to565(PEXLATEOBJ pxlo
, ULONG iColor
)
213 iNewColor
= iColor
& 0x1f;
215 /* Copy red and green */
217 iNewColor
|= iColor
& 0xFFC0;
219 /* Duplicate highest green bit */
221 iNewColor
|= (iColor
& 0x20);
228 EXLATEOBJ_iXlate555toPal(PEXLATEOBJ pexlo
, ULONG iColor
)
230 iColor
= EXLATEOBJ_iXlate555toRGB(pexlo
, iColor
);
232 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
237 EXLATEOBJ_iXlate565to555(PEXLATEOBJ pxlo
, ULONG iColor
)
242 iNewColor
= iColor
& 0x1f;
244 /* Copy red and green */
246 iNewColor
|= iColor
& 0x7FE0;
253 EXLATEOBJ_iXlate565toRGB(PEXLATEOBJ pexlo
, ULONG iColor
)
258 iNewColor
= gajXlate5to8
[iColor
& 0x1F] << 16;
262 iNewColor
|= gajXlate6to8
[iColor
& 0x3F] << 8;
266 iNewColor
|= gajXlate5to8
[iColor
& 0x1F];
273 EXLATEOBJ_iXlate565toBGR(PEXLATEOBJ pexlo
, ULONG iColor
)
278 iNewColor
= gajXlate5to8
[iColor
& 0x1F];
282 iNewColor
|= gajXlate6to8
[iColor
& 0x3F] << 8;
286 iNewColor
|= gajXlate5to8
[iColor
& 0x1F] << 16;
293 EXLATEOBJ_iXlate565toPal(EXLATEOBJ
*pexlo
, ULONG iColor
)
295 iColor
= EXLATEOBJ_iXlate565toRGB(pexlo
, iColor
);
297 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
302 EXLATEOBJ_iXlateShiftAndMask(PEXLATEOBJ pexlo
, ULONG iColor
)
306 iNewColor
= _rotl(iColor
, pexlo
->ulRedShift
) & pexlo
->ulRedMask
;
307 iNewColor
|= _rotl(iColor
, pexlo
->ulGreenShift
) & pexlo
->ulGreenMask
;
308 iNewColor
|= _rotl(iColor
, pexlo
->ulBlueShift
) & pexlo
->ulBlueMask
;
315 EXLATEOBJ_iXlateBitfieldsToPal(PEXLATEOBJ pexlo
, ULONG iColor
)
317 /* Convert bitfields to RGB */
318 iColor
= EXLATEOBJ_iXlateShiftAndMask(pexlo
, iColor
);
320 /* Return nearest index */
321 return PALETTE_ulGetNearestPaletteIndex(pexlo
->ppalDst
, iColor
);
325 /** Private Functions *********************************************************/
329 EXLATEOBJ_vInitialize(
333 COLORREF crSrcBackColor
,
334 COLORREF crDstBackColor
,
335 COLORREF crDstForeColor
)
340 if (!ppalSrc
) ppalSrc
= &gpalRGB
;
341 if (!ppalDst
) ppalDst
= &gpalRGB
;
343 pexlo
->xlo
.iUniq
= InterlockedIncrement((LONG
*)&giUniqueXlate
);
344 pexlo
->xlo
.cEntries
= 0;
345 pexlo
->xlo
.flXlate
= 0;
346 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
347 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
348 pexlo
->hColorTransform
= NULL
;
349 pexlo
->ppalSrc
= ppalSrc
;
350 pexlo
->ppalDst
= ppalDst
;
351 pexlo
->xlo
.iSrcType
= (USHORT
)ppalSrc
->flFlags
;
352 pexlo
->xlo
.iDstType
= (USHORT
)ppalDst
->flFlags
;
353 pexlo
->ppalDstDc
= &gpalRGB
;
355 if (ppalDst
== ppalSrc
)
357 pexlo
->xlo
.flXlate
|= XO_TRIVIAL
;
361 /* Check if both of the pallettes are indexed */
362 if (!(ppalSrc
->flFlags
& PAL_INDEXED
) || !(ppalDst
->flFlags
& PAL_INDEXED
))
364 /* At least one palette is not indexed, calculate shifts/masks */
365 ULONG aulMasksSrc
[3], aulMasksDst
[3];
367 PALETTE_vGetBitMasks(ppalSrc
, aulMasksSrc
);
368 PALETTE_vGetBitMasks(ppalDst
, aulMasksDst
);
370 pexlo
->ulRedMask
= aulMasksDst
[0];
371 pexlo
->ulGreenMask
= aulMasksDst
[1];
372 pexlo
->ulBlueMask
= aulMasksDst
[2];
374 pexlo
->ulRedShift
= CalculateShift(aulMasksSrc
[0], aulMasksDst
[0]);
375 pexlo
->ulGreenShift
= CalculateShift(aulMasksSrc
[1], aulMasksDst
[1]);
376 pexlo
->ulBlueShift
= CalculateShift(aulMasksSrc
[2], aulMasksDst
[2]);
379 if (ppalSrc
->flFlags
& PAL_MONOCHROME
)
381 /* This is a monochrome palette */
382 if (!(ppalDst
->flFlags
& PAL_MONOCHROME
))
384 /* Mono to color, use the dest DC's fore and back color */
385 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTable
;
386 pexlo
->xlo
.flXlate
|= XO_TABLE
;
387 pexlo
->xlo
.cEntries
= 2;
388 pexlo
->xlo
.pulXlate
[0] =
389 PALETTE_ulGetNearestIndex(ppalDst
, crDstForeColor
);
390 pexlo
->xlo
.pulXlate
[1] =
391 PALETTE_ulGetNearestIndex(ppalDst
, crDstBackColor
);
394 else if (ppalDst
->flFlags
& PAL_MONOCHROME
)
396 pexlo
->pfnXlate
= EXLATEOBJ_iXlateToMono
;
397 pexlo
->xlo
.flXlate
|= XO_TO_MONO
;
398 pexlo
->xlo
.cEntries
= 1;
400 if (ppalSrc
->flFlags
& PAL_INDEXED
)
403 PALETTE_ulGetNearestPaletteIndex(ppalSrc
, crSrcBackColor
);
405 else if (ppalSrc
->flFlags
& PAL_RGB
)
407 pexlo
->aulXlate
[0] = crSrcBackColor
;
409 else if (ppalSrc
->flFlags
& PAL_BGR
)
411 pexlo
->aulXlate
[0] = RGB(GetBValue(crSrcBackColor
),
412 GetGValue(crSrcBackColor
),
413 GetRValue(crSrcBackColor
));
415 else if (ppalSrc
->flFlags
& PAL_BITFIELDS
)
417 PALETTE_vGetBitMasks(ppalSrc
, &pexlo
->ulRedMask
);
418 pexlo
->ulRedShift
= CalculateShift(RGB(0xFF,0,0), pexlo
->ulRedMask
);
419 pexlo
->ulGreenShift
= CalculateShift(RGB(0,0xFF,0), pexlo
->ulGreenMask
);
420 pexlo
->ulBlueShift
= CalculateShift(RGB(0,0,0xFF), pexlo
->ulBlueMask
);
422 pexlo
->aulXlate
[0] = EXLATEOBJ_iXlateShiftAndMask(pexlo
, crSrcBackColor
);
425 else if (ppalSrc
->flFlags
& PAL_INDEXED
)
427 cEntries
= ppalSrc
->NumColors
;
429 /* Allocate buffer if needed */
432 pexlo
->xlo
.pulXlate
= EngAllocMem(0,
433 cEntries
* sizeof(ULONG
),
435 if (!pexlo
->xlo
.pulXlate
)
437 DPRINT1("Could not allocate pulXlate buffer.\n");
438 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
439 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
444 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTable
;
445 pexlo
->xlo
.cEntries
= cEntries
;
446 pexlo
->xlo
.flXlate
|= XO_TABLE
;
448 if (ppalDst
->flFlags
& PAL_INDEXED
)
452 for (i
= 0; i
< cEntries
; i
++)
454 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
455 ppalSrc
->IndexedColors
[i
].peGreen
,
456 ppalSrc
->IndexedColors
[i
].peBlue
);
458 pexlo
->xlo
.pulXlate
[i
] =
459 PALETTE_ulGetNearestPaletteIndex(ppalDst
, ulColor
);
461 if (pexlo
->xlo
.pulXlate
[i
] != i
) cDiff
++;
464 /* Check if we have only trivial mappings */
467 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
469 EngFreeMem(pexlo
->xlo
.pulXlate
);
470 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
472 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
473 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
474 pexlo
->xlo
.cEntries
= 0;
480 for (i
= 0; i
< pexlo
->xlo
.cEntries
; i
++)
482 ulColor
= RGB(ppalSrc
->IndexedColors
[i
].peRed
,
483 ppalSrc
->IndexedColors
[i
].peGreen
,
484 ppalSrc
->IndexedColors
[i
].peBlue
);
485 pexlo
->xlo
.pulXlate
[i
] = PALETTE_ulGetNearestBitFieldsIndex(ppalDst
, ulColor
);
489 else if (ppalSrc
->flFlags
& PAL_RGB
)
491 if (ppalDst
->flFlags
& PAL_INDEXED
)
492 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoPal
;
494 else if (ppalDst
->flFlags
& PAL_BGR
)
495 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
497 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
498 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto555
;
500 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
501 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBto565
;
503 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
504 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
506 else if (ppalSrc
->flFlags
& PAL_BGR
)
508 if (ppalDst
->flFlags
& PAL_INDEXED
)
509 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
511 else if (ppalDst
->flFlags
& PAL_RGB
)
512 /* The inverse function works the same */
513 pexlo
->pfnXlate
= EXLATEOBJ_iXlateRGBtoBGR
;
515 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
516 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto555
;
518 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
519 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBGRto565
;
521 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
522 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
524 else if (ppalSrc
->flFlags
& PAL_RGB16_555
)
526 if (ppalDst
->flFlags
& PAL_INDEXED
)
527 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toPal
;
529 else if (ppalDst
->flFlags
& PAL_RGB
)
530 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toRGB
;
532 else if (ppalDst
->flFlags
& PAL_BGR
)
533 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555toBGR
;
535 else if (ppalDst
->flFlags
& PAL_RGB16_565
)
536 pexlo
->pfnXlate
= EXLATEOBJ_iXlate555to565
;
538 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
539 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
541 else if (ppalSrc
->flFlags
& PAL_RGB16_565
)
543 if (ppalDst
->flFlags
& PAL_INDEXED
)
544 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toPal
;
546 else if (ppalDst
->flFlags
& PAL_RGB
)
547 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toRGB
;
549 else if (ppalDst
->flFlags
& PAL_BGR
)
550 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565toBGR
;
552 else if (ppalDst
->flFlags
& PAL_RGB16_555
)
553 pexlo
->pfnXlate
= EXLATEOBJ_iXlate565to555
;
555 else if (ppalDst
->flFlags
& PAL_BITFIELDS
)
556 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
558 else if (ppalSrc
->flFlags
& PAL_BITFIELDS
)
560 if (ppalDst
->flFlags
& PAL_INDEXED
)
561 pexlo
->pfnXlate
= EXLATEOBJ_iXlateBitfieldsToPal
;
563 pexlo
->pfnXlate
= EXLATEOBJ_iXlateShiftAndMask
;
566 /* Check for a trivial shift and mask operation */
567 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateShiftAndMask
&&
568 !pexlo
->ulRedShift
&& !pexlo
->ulGreenShift
&& !pexlo
->ulBlueShift
)
570 pexlo
->pfnXlate
= EXLATEOBJ_iXlateTrivial
;
573 /* Check for trivial xlate */
574 if (pexlo
->pfnXlate
== EXLATEOBJ_iXlateTrivial
)
575 pexlo
->xlo
.flXlate
= XO_TRIVIAL
;
577 pexlo
->xlo
.flXlate
&= ~XO_TRIVIAL
;
582 EXLATEOBJ_vInitXlateFromDCs(
587 PSURFACE psurfDst
, psurfSrc
;
589 psurfDst
= pdcDst
->dclevel
.pSurface
;
590 psurfSrc
= pdcSrc
->dclevel
.pSurface
;
592 /* Normal initialisation. No surface means DEFAULT_BITMAP */
593 EXLATEOBJ_vInitialize(pexlo
,
594 psurfSrc
? psurfSrc
->ppal
: gppalMono
,
595 psurfDst
? psurfDst
->ppal
: gppalMono
,
596 pdcSrc
->pdcattr
->crBackgroundClr
,
597 pdcDst
->pdcattr
->crBackgroundClr
,
598 pdcDst
->pdcattr
->crForegroundClr
);
600 pexlo
->ppalDstDc
= pdcDst
->dclevel
.ppal
;
605 EXLATEOBJ_vCleanup(PEXLATEOBJ pexlo
)
607 if (pexlo
->xlo
.pulXlate
!= pexlo
->aulXlate
)
609 EngFreeMem(pexlo
->xlo
.pulXlate
);
611 pexlo
->xlo
.pulXlate
= pexlo
->aulXlate
;
614 /** Public DDI Functions ******************************************************/
616 #undef XLATEOBJ_iXlate
619 XLATEOBJ_iXlate(XLATEOBJ
*pxlo
, ULONG iColor
)
621 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
626 /* Call the iXlate function */
627 return pexlo
->pfnXlate(pexlo
, iColor
);
632 XLATEOBJ_cGetPalette(XLATEOBJ
*pxlo
, ULONG iPal
, ULONG cPal
, ULONG
*pPalOut
)
634 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
645 DPRINT1("XLATEOBJ_cGetPalette called with wrong iPal: %d\n", iPal
);
649 /* Get the requested palette */
650 if (iPal
== XO_DESTDCPALETTE
)
652 ppal
= pexlo
->ppalDstDc
;
654 else if (iPal
== XO_SRCPALETTE
|| iPal
== XO_SRCBITFIELDS
)
656 ppal
= pexlo
->ppalSrc
;
660 ppal
= pexlo
->ppalDst
;
663 /* Verify palette type match */
665 ((iPal
== XO_SRCPALETTE
|| iPal
== XO_DESTPALETTE
)
666 && !(ppal
->flFlags
& PAL_INDEXED
)) ||
667 ((iPal
== XO_SRCBITFIELDS
|| iPal
== XO_DESTBITFIELDS
)
668 && !(ppal
->flFlags
& PAL_BITFIELDS
)))
675 return ppal
->NumColors
;
678 /* Copy the values into the buffer */
679 if (ppal
->flFlags
& PAL_INDEXED
)
681 cPal
= min(cPal
, ppal
->NumColors
);
682 for (i
= 0; i
< cPal
; i
++)
684 pPalOut
[i
] = RGB(ppal
->IndexedColors
[i
].peRed
,
685 ppal
->IndexedColors
[i
].peGreen
,
686 ppal
->IndexedColors
[i
].peBlue
);
691 // FIXME: should use the above code
692 pPalOut
[0] = ppal
->RedMask
;
693 pPalOut
[1] = ppal
->GreenMask
;
694 pPalOut
[2] = ppal
->BlueMask
;
702 XLATEOBJ_hGetColorTransform(XLATEOBJ
*pxlo
)
704 PEXLATEOBJ pexlo
= (PEXLATEOBJ
)pxlo
;
705 return pexlo
->hColorTransform
;
710 XLATEOBJ_piVector(XLATEOBJ
*pxlo
)
712 if (pxlo
->iSrcType
== PAL_INDEXED
)
714 return pxlo
->pulXlate
;