Revert, thx Thomas, wasnt sure.
[reactos.git] / reactos / subsys / win32k / eng / xlate.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI Color Translation Functions
24 * FILE: subsys/win32k/eng/xlate.c
25 * PROGRAMER: Jason Filby
26 * REVISION HISTORY:
27 * 8/20/1999: Created
28 */
29
30 #include <w32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35 static __inline ULONG
36 ShiftAndMask(XLATEGDI *XlateGDI, ULONG Color)
37 {
38 ULONG TranslatedColor;
39
40 if (XlateGDI->RedShift < 0)
41 TranslatedColor = (Color >> -(XlateGDI->RedShift)) & XlateGDI->RedMask;
42 else
43 TranslatedColor = (Color << XlateGDI->RedShift) & XlateGDI->RedMask;
44 if (XlateGDI->GreenShift < 0)
45 TranslatedColor |= (Color >> -(XlateGDI->GreenShift)) & XlateGDI->GreenMask;
46 else
47 TranslatedColor |= (Color << XlateGDI->GreenShift) & XlateGDI->GreenMask;
48 if (XlateGDI->BlueShift < 0)
49 TranslatedColor |= (Color >> -(XlateGDI->BlueShift)) & XlateGDI->BlueMask;
50 else
51 TranslatedColor |= (Color << XlateGDI->BlueShift) & XlateGDI->BlueMask;
52
53 return TranslatedColor;
54 }
55
56
57 static __inline ULONG
58 ClosestColorMatch(XLATEGDI *XlateGDI, LPPALETTEENTRY SourceColor,
59 PALETTEENTRY *DestColors, ULONG NumColors)
60 {
61 ULONG SourceRed, SourceGreen, SourceBlue;
62 ULONG cxRed, cxGreen, cxBlue, Rating, BestMatch = 0xFFFFFF;
63 ULONG CurrentIndex, BestIndex = 0;
64
65 SourceRed = SourceColor->peRed;
66 SourceGreen = SourceColor->peGreen;
67 SourceBlue = SourceColor->peBlue;
68
69 for (CurrentIndex = 0; CurrentIndex < NumColors; CurrentIndex++, DestColors++)
70 {
71 cxRed = abs((SHORT)SourceRed - (SHORT)DestColors->peRed);
72 cxRed *= cxRed;
73 cxGreen = abs((SHORT)SourceGreen - (SHORT)DestColors->peGreen);
74 cxGreen *= cxGreen;
75 cxBlue = abs((SHORT)SourceBlue - (SHORT)DestColors->peBlue);
76 cxBlue *= cxBlue;
77
78 Rating = cxRed + cxGreen + cxBlue;
79
80 if (Rating == 0)
81 {
82 /* Exact match */
83 BestIndex = CurrentIndex;
84 break;
85 }
86
87 if (Rating < BestMatch)
88 {
89 BestIndex = CurrentIndex;
90 BestMatch = Rating;
91 }
92 }
93
94 return BestIndex;
95 }
96
97 static __inline VOID
98 BitMasksFromPal(USHORT PalType, PPALGDI Palette,
99 PULONG RedMask, PULONG BlueMask, PULONG GreenMask)
100 {
101 static const union { PALETTEENTRY Color; ULONG Mask; } Red = {{0xFF, 0x00, 0x00}};
102 static const union { PALETTEENTRY Color; ULONG Mask; } Green = {{0x00, 0xFF, 0x00}};
103 static const union { PALETTEENTRY Color; ULONG Mask; } Blue = {{0x00, 0x00, 0xFF}};
104
105 switch (PalType)
106 {
107 case PAL_RGB:
108 *RedMask = RGB(0xFF, 0x00, 0x00);
109 *GreenMask = RGB(0x00, 0xFF, 0x00);
110 *BlueMask = RGB(0x00, 0x00, 0xFF);
111 break;
112 case PAL_BGR:
113 *RedMask = RGB(0x00, 0x00, 0xFF);
114 *GreenMask = RGB(0x00, 0xFF, 0x00);
115 *BlueMask = RGB(0xFF, 0x00, 0x00);
116 break;
117 case PAL_BITFIELDS:
118 *RedMask = Palette->RedMask;
119 *GreenMask = Palette->GreenMask;
120 *BlueMask = Palette->BlueMask;
121 break;
122 case PAL_INDEXED:
123 *RedMask = Red.Mask;
124 *GreenMask = Green.Mask;
125 *BlueMask = Blue.Mask;
126 break;
127 }
128 }
129
130 /*
131 * Calculate the number of bits Mask must be shift to the left to get a
132 * 1 in the most significant bit position
133 */
134 static __inline INT
135 CalculateShift(ULONG Mask)
136 {
137 ULONG Shift = 0;
138 ULONG LeftmostBit = 1 << (8 * sizeof(ULONG) - 1);
139
140 while (0 == (Mask & LeftmostBit) && Shift < 8 * sizeof(ULONG))
141 {
142 Mask = Mask << 1;
143 Shift++;
144 }
145
146 return Shift;
147 }
148
149 XLATEOBJ* FASTCALL
150 IntEngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
151 HPALETTE PaletteDest, HPALETTE PaletteSource)
152 {
153 XLATEOBJ *XlateObj;
154 XLATEGDI *XlateGDI;
155 PALGDI *SourcePalGDI = 0;
156 PALGDI *DestPalGDI = 0;
157 ULONG SourceRedMask = 0, SourceGreenMask = 0, SourceBlueMask = 0;
158 ULONG DestRedMask = 0, DestGreenMask = 0, DestBlueMask = 0;
159 ULONG i;
160
161 XlateGDI = EngAllocMem(0, sizeof(XLATEGDI), TAG_XLATEOBJ);
162 if (XlateGDI == NULL)
163 {
164 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
165 return NULL;
166 }
167 XlateObj = GDIToObj(XlateGDI, XLATE);
168
169 if (PaletteSource != NULL)
170 SourcePalGDI = PALETTE_LockPalette(PaletteSource);
171 if (PaletteDest == PaletteSource)
172 DestPalGDI = SourcePalGDI;
173 else if (PaletteDest != NULL)
174 DestPalGDI = PALETTE_LockPalette(PaletteDest);
175
176 if (SourcePalType == 0)
177 SourcePalType = SourcePalGDI->Mode;
178 if (DestPalType == 0)
179 DestPalType = DestPalGDI->Mode;
180
181 XlateObj->iSrcType = SourcePalType;
182 XlateObj->iDstType = DestPalType;
183 XlateObj->flXlate = 0;
184
185 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
186 XlateGDI->SourcePal = PaletteSource;
187 XlateGDI->DestPal = PaletteDest;
188
189 XlateGDI->UseShiftAndMask = FALSE;
190
191 /*
192 * Compute bit fiddeling constants unless both palettes are indexed, then
193 * we don't need them.
194 */
195 if (SourcePalType != PAL_INDEXED || DestPalType != PAL_INDEXED)
196 {
197 BitMasksFromPal(SourcePalType, SourcePalGDI, &SourceRedMask,
198 &SourceBlueMask, &SourceGreenMask);
199 BitMasksFromPal(DestPalType, DestPalGDI, &DestRedMask,
200 &DestBlueMask, &DestGreenMask);
201 XlateGDI->RedShift = CalculateShift(SourceRedMask) - CalculateShift(DestRedMask);
202 XlateGDI->RedMask = DestRedMask;
203 XlateGDI->GreenShift = CalculateShift(SourceGreenMask) - CalculateShift(DestGreenMask);
204 XlateGDI->GreenMask = DestGreenMask;
205 XlateGDI->BlueShift = CalculateShift(SourceBlueMask) - CalculateShift(DestBlueMask);
206 XlateGDI->BlueMask = DestBlueMask;
207 }
208
209 /* If source and destination palettes are the same or if they're RGB/BGR */
210 if (PaletteDest == PaletteSource ||
211 (DestPalType == PAL_RGB && SourcePalType == PAL_RGB) ||
212 (DestPalType == PAL_BGR && SourcePalType == PAL_BGR))
213 {
214 XlateObj->flXlate |= XO_TRIVIAL;
215 goto end;
216 }
217
218 /*
219 * If source and destination are bitfield based (RGB and BGR are just
220 * special bitfields) we can use simple shifting.
221 */
222 if ((DestPalType == PAL_RGB || DestPalType == PAL_BGR ||
223 DestPalType == PAL_BITFIELDS) &&
224 (SourcePalType == PAL_RGB || SourcePalType == PAL_BGR ||
225 SourcePalType == PAL_BITFIELDS))
226 {
227 if (SourceRedMask == DestRedMask &&
228 SourceBlueMask == DestBlueMask &&
229 SourceGreenMask == DestGreenMask)
230 {
231 XlateObj->flXlate |= XO_TRIVIAL;
232 }
233 XlateGDI->UseShiftAndMask = TRUE;
234 goto end;
235 }
236
237 /* Indexed -> Indexed */
238 if (SourcePalType == PAL_INDEXED && DestPalType == PAL_INDEXED)
239 {
240 XlateGDI->translationTable =
241 EngAllocMem(0, sizeof(ULONG) * SourcePalGDI->NumColors, 0);
242
243 XlateObj->flXlate |= XO_TRIVIAL;
244 for (i = 0; i < SourcePalGDI->NumColors; i++)
245 {
246 XlateGDI->translationTable[i] = ClosestColorMatch(
247 XlateGDI, SourcePalGDI->IndexedColors + i,
248 DestPalGDI->IndexedColors, DestPalGDI->NumColors);
249 if (XlateGDI->translationTable[i] != i)
250 XlateObj->flXlate &= ~XO_TRIVIAL;
251 }
252
253 XlateObj->flXlate |= XO_TABLE;
254 XlateObj->pulXlate = XlateGDI->translationTable;
255 goto end;
256 }
257
258 /* Indexed -> Bitfields/RGB/BGR */
259 if (SourcePalType == PAL_INDEXED)
260 {
261 XlateGDI->translationTable =
262 EngAllocMem(0, sizeof(ULONG) * SourcePalGDI->NumColors, 0);
263 for (i = 0; i < SourcePalGDI->NumColors; i++)
264 XlateGDI->translationTable[i] =
265 ShiftAndMask(XlateGDI, *((ULONG *)&SourcePalGDI->IndexedColors[i]));
266 XlateObj->flXlate |= XO_TABLE;
267 XlateObj->pulXlate = XlateGDI->translationTable;
268 goto end;
269 }
270
271 /*
272 * Last case: Bitfields/RGB/BGR -> Indexed
273 * isn't handled here yet and all the logic is in XLATEOBJ_iXlate now.
274 */
275
276 end:
277 if (PaletteSource != NULL)
278 PALETTE_UnlockPalette(SourcePalGDI);
279 if (PaletteDest != NULL && PaletteDest != PaletteSource)
280 PALETTE_UnlockPalette(DestPalGDI);
281 return XlateObj;
282 }
283
284 XLATEOBJ* FASTCALL
285 IntEngCreateMonoXlate(
286 USHORT SourcePalType, HPALETTE PaletteDest, HPALETTE PaletteSource,
287 ULONG BackgroundColor)
288 {
289 XLATEOBJ *XlateObj;
290 XLATEGDI *XlateGDI;
291 PALGDI *SourcePalGDI;
292
293 XlateGDI = EngAllocMem(0, sizeof(XLATEGDI), TAG_XLATEOBJ);
294 if (XlateGDI == NULL)
295 {
296 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
297 return NULL;
298 }
299 XlateObj = GDIToObj(XlateGDI, XLATE);
300
301 SourcePalGDI = PALETTE_LockPalette(PaletteSource);
302 /* FIXME - SourcePalGDI can be NULL!!! Handle this case instead of ASSERT! */
303 ASSERT(SourcePalGDI);
304
305 if (SourcePalType == 0)
306 SourcePalType = SourcePalGDI->Mode;
307
308 XlateObj->iSrcType = SourcePalType;
309 XlateObj->iDstType = PAL_INDEXED;
310
311 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
312 XlateGDI->DestPal = PaletteDest;
313 XlateGDI->SourcePal = PaletteSource;
314
315 XlateObj->flXlate = XO_TO_MONO;
316 XlateObj->pulXlate = &XlateGDI->BackgroundColor;
317 switch (SourcePalType)
318 {
319 case PAL_INDEXED:
320 XlateGDI->BackgroundColor = NtGdiGetNearestPaletteIndex(
321 PaletteSource, BackgroundColor);
322 break;
323 case PAL_BGR:
324 XlateGDI->BackgroundColor = BackgroundColor;
325 break;
326 case PAL_RGB:
327 XlateGDI->BackgroundColor =
328 ((BackgroundColor & 0xFF) << 16) |
329 ((BackgroundColor & 0xFF0000) >> 16) |
330 (BackgroundColor & 0xFF00);
331 break;
332 case PAL_BITFIELDS:
333 {
334 BitMasksFromPal(SourcePalType, SourcePalGDI, &XlateGDI->RedMask,
335 &XlateGDI->BlueMask, &XlateGDI->GreenMask);
336 XlateGDI->RedShift = CalculateShift(0xFF) - CalculateShift(XlateGDI->RedMask);
337 XlateGDI->GreenShift = CalculateShift(0xFF00) - CalculateShift(XlateGDI->GreenMask);
338 XlateGDI->BlueShift = CalculateShift(0xFF0000) - CalculateShift(XlateGDI->BlueMask);
339 XlateGDI->BackgroundColor = ShiftAndMask(XlateGDI, BackgroundColor);
340 }
341 break;
342 }
343
344 PALETTE_UnlockPalette(SourcePalGDI);
345
346 return XlateObj;
347 }
348
349 XLATEOBJ* FASTCALL
350 IntEngCreateSrcMonoXlate(HPALETTE PaletteDest,
351 ULONG ForegroundColor,
352 ULONG BackgroundColor)
353 {
354 XLATEOBJ *XlateObj;
355 XLATEGDI *XlateGDI;
356 PALGDI *DestPalGDI;
357
358 DestPalGDI = PALETTE_LockPalette(PaletteDest);
359 if (DestPalGDI == NULL)
360 return NULL;
361
362 XlateGDI = EngAllocMem(0, sizeof(XLATEGDI), TAG_XLATEOBJ);
363 if (XlateGDI == NULL)
364 {
365 PALETTE_UnlockPalette(DestPalGDI);
366 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
367 return NULL;
368 }
369 XlateObj = GDIToObj(XlateGDI, XLATE);
370
371 XlateGDI->translationTable = EngAllocMem(0, sizeof(ULONG) * 2, 0);
372 if (XlateGDI->translationTable == NULL)
373 {
374 PALETTE_UnlockPalette(DestPalGDI);
375 EngFreeMem(XlateGDI);
376 return NULL;
377 }
378
379 XlateObj->pulXlate = XlateGDI->translationTable;
380
381 XlateObj->iSrcType = PAL_INDEXED;
382 XlateObj->iDstType = DestPalGDI->Mode;
383
384 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
385 XlateGDI->SourcePal = NULL;
386 XlateGDI->DestPal = PaletteDest;
387
388 XlateObj->flXlate = XO_TABLE;
389
390 BitMasksFromPal(DestPalGDI->Mode, DestPalGDI, &XlateGDI->RedMask,
391 &XlateGDI->BlueMask, &XlateGDI->GreenMask);
392
393 XlateGDI->RedShift = CalculateShift(RGB(0xFF, 0x00, 0x00)) - CalculateShift(XlateGDI->RedMask);
394 XlateGDI->GreenShift = CalculateShift(RGB(0x00, 0xFF, 0x00)) - CalculateShift(XlateGDI->GreenMask);
395 XlateGDI->BlueShift = CalculateShift(RGB(0x00, 0x00, 0xFF)) - CalculateShift(XlateGDI->BlueMask);
396
397 XlateGDI->translationTable[0] = ShiftAndMask(XlateGDI, BackgroundColor);
398 XlateGDI->translationTable[1] = ShiftAndMask(XlateGDI, ForegroundColor);
399
400 if (XlateObj->iDstType == PAL_INDEXED)
401 {
402 XlateGDI->translationTable[0] =
403 ClosestColorMatch(XlateGDI,
404 (LPPALETTEENTRY)&XlateGDI->translationTable[0],
405 DestPalGDI->IndexedColors,
406 DestPalGDI->NumColors);
407 XlateGDI->translationTable[1] =
408 ClosestColorMatch(XlateGDI,
409 (LPPALETTEENTRY)&XlateGDI->translationTable[1],
410 DestPalGDI->IndexedColors,
411 DestPalGDI->NumColors);
412 }
413
414 PALETTE_UnlockPalette(DestPalGDI);
415
416 return XlateObj;
417 }
418
419 HPALETTE FASTCALL
420 IntEngGetXlatePalette(XLATEOBJ *XlateObj,
421 ULONG Palette)
422 {
423 XLATEGDI *XlateGDI = ObjToGDI(XlateObj, XLATE);
424 switch (Palette)
425 {
426 case XO_DESTPALETTE:
427 return XlateGDI->DestPal;
428 break;
429
430 case XO_SRCPALETTE:
431 return XlateGDI->SourcePal;
432 break;
433 }
434 return 0;
435 }
436
437 /* PUBLIC FUNCTIONS ***********************************************************/
438
439 /*
440 * @implemented
441 */
442 VOID FASTCALL
443 EngDeleteXlate(XLATEOBJ *XlateObj)
444 {
445 XLATEGDI *XlateGDI;
446
447 if (XlateObj == NULL)
448 {
449 DPRINT1("Trying to delete NULL XLATEOBJ\n");
450 return;
451 }
452
453 XlateGDI = ObjToGDI(XlateObj, XLATE);
454
455 if ((XlateObj->flXlate & XO_TABLE) &&
456 XlateGDI->translationTable != NULL)
457 {
458 EngFreeMem(XlateGDI->translationTable);
459 }
460
461 EngFreeMem(XlateGDI);
462 }
463
464 /*
465 * @implemented
466 */
467 PULONG STDCALL
468 XLATEOBJ_piVector(XLATEOBJ *XlateObj)
469 {
470 XLATEGDI *XlateGDI = ObjToGDI(XlateObj, XLATE);
471
472 if (XlateObj->iSrcType == PAL_INDEXED)
473 {
474 return XlateGDI->translationTable;
475 }
476
477 return NULL;
478 }
479
480 /*
481 * @implemented
482 */
483 ULONG STDCALL
484 XLATEOBJ_iXlate(XLATEOBJ *XlateObj, ULONG Color)
485 {
486 XLATEGDI *XlateGDI;
487 PALGDI *PalGDI;
488 ULONG Closest;
489
490 /* Return the original color if there's no color translation object. */
491 if (!XlateObj)
492 return Color;
493
494 if (XlateObj->flXlate & XO_TRIVIAL)
495 return Color;
496
497 if (XlateObj->flXlate & XO_TABLE)
498 return XlateObj->pulXlate[Color];
499
500 if (XlateObj->flXlate & XO_TO_MONO)
501 return Color == XlateObj->pulXlate[0];
502
503 XlateGDI = ObjToGDI(XlateObj, XLATE);
504
505 if (XlateGDI->UseShiftAndMask)
506 return ShiftAndMask(XlateGDI, Color);
507
508 if (XlateObj->iSrcType == PAL_RGB || XlateObj->iSrcType == PAL_BGR ||
509 XlateObj->iSrcType == PAL_BITFIELDS)
510 {
511 /* FIXME: should we cache colors used often? */
512 /* FIXME: won't work if destination isn't indexed */
513
514 /* Convert the source color to the palette RGB format. */
515 Color = ShiftAndMask(XlateGDI, Color);
516
517 /* Extract the destination palette. */
518 PalGDI = PALETTE_LockPalette(XlateGDI->DestPal);
519 if(PalGDI != NULL)
520 {
521 /* Return closest match for the given color. */
522 Closest = ClosestColorMatch(XlateGDI, (LPPALETTEENTRY)&Color, PalGDI->IndexedColors, PalGDI->NumColors);
523 PALETTE_UnlockPalette(PalGDI);
524 return Closest;
525 }
526 }
527
528 return 0;
529 }
530
531 /*
532 * @implemented
533 */
534 ULONG STDCALL
535 XLATEOBJ_cGetPalette(XLATEOBJ *XlateObj, ULONG PalOutType, ULONG cPal,
536 ULONG *OutPal)
537 {
538 HPALETTE hPalette;
539 XLATEGDI *XlateGDI;
540 PALGDI *PalGDI;
541 ULONG *InPal;
542
543 XlateGDI = ObjToGDI(XlateObj, XLATE);
544 if (PalOutType == XO_SRCPALETTE)
545 hPalette = XlateGDI->SourcePal;
546 else if (PalOutType == XO_DESTPALETTE)
547 hPalette = XlateGDI->DestPal;
548 else
549 {
550 UNIMPLEMENTED;
551 return 0;
552 }
553
554 PalGDI = PALETTE_LockPalette(hPalette);
555 if(PalGDI != NULL)
556 {
557 /* copy the indexed colors into the buffer */
558
559 for(InPal = (ULONG*)PalGDI->IndexedColors;
560 cPal > 0;
561 cPal--, InPal++, OutPal++)
562 {
563 *OutPal = *InPal;
564 }
565
566 PALETTE_UnlockPalette(PalGDI);
567
568 return cPal;
569 }
570
571 return 0;
572 }
573
574 /* EOF */