Move the inclusion of <debug.h> to individual files and consolidate the inclusion...
[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 switch (SourcePalType)
317 {
318 case PAL_INDEXED:
319 XlateGDI->BackgroundColor = NtGdiGetNearestPaletteIndex(
320 PaletteSource, BackgroundColor);
321 break;
322 case PAL_BGR:
323 XlateGDI->BackgroundColor = BackgroundColor;
324 break;
325 case PAL_RGB:
326 XlateGDI->BackgroundColor =
327 ((BackgroundColor & 0xFF) << 16) |
328 ((BackgroundColor & 0xFF0000) >> 16) |
329 (BackgroundColor & 0xFF00);
330 break;
331 case PAL_BITFIELDS:
332 {
333 BitMasksFromPal(SourcePalType, SourcePalGDI, &XlateGDI->RedMask,
334 &XlateGDI->BlueMask, &XlateGDI->GreenMask);
335 XlateGDI->RedShift = CalculateShift(0xFF) - CalculateShift(XlateGDI->RedMask);
336 XlateGDI->GreenShift = CalculateShift(0xFF00) - CalculateShift(XlateGDI->GreenMask);
337 XlateGDI->BlueShift = CalculateShift(0xFF0000) - CalculateShift(XlateGDI->BlueMask);
338 XlateGDI->BackgroundColor = ShiftAndMask(XlateGDI, BackgroundColor);
339 }
340 break;
341 }
342
343 PALETTE_UnlockPalette(SourcePalGDI);
344
345 return XlateObj;
346 }
347
348 XLATEOBJ* FASTCALL
349 IntEngCreateSrcMonoXlate(HPALETTE PaletteDest,
350 ULONG ForegroundColor,
351 ULONG BackgroundColor)
352 {
353 XLATEOBJ *XlateObj;
354 XLATEGDI *XlateGDI;
355 PALGDI *DestPalGDI;
356
357 DestPalGDI = PALETTE_LockPalette(PaletteDest);
358 if (DestPalGDI == NULL)
359 return NULL;
360
361 XlateGDI = EngAllocMem(0, sizeof(XLATEGDI), TAG_XLATEOBJ);
362 if (XlateGDI == NULL)
363 {
364 PALETTE_UnlockPalette(DestPalGDI);
365 DPRINT1("Failed to allocate memory for a XLATE structure!\n");
366 return NULL;
367 }
368 XlateObj = GDIToObj(XlateGDI, XLATE);
369
370 XlateGDI->translationTable = EngAllocMem(0, sizeof(ULONG) * 2, 0);
371 if (XlateGDI->translationTable == NULL)
372 {
373 PALETTE_UnlockPalette(DestPalGDI);
374 EngFreeMem(XlateGDI);
375 return NULL;
376 }
377
378 XlateObj->pulXlate = XlateGDI->translationTable;
379
380 XlateObj->iSrcType = PAL_INDEXED;
381 XlateObj->iDstType = DestPalGDI->Mode;
382
383 /* Store handles of palettes in internal Xlate GDI object (or NULLs) */
384 XlateGDI->SourcePal = NULL;
385 XlateGDI->DestPal = PaletteDest;
386
387 XlateObj->flXlate = XO_TABLE;
388
389 BitMasksFromPal(DestPalGDI->Mode, DestPalGDI, &XlateGDI->RedMask,
390 &XlateGDI->BlueMask, &XlateGDI->GreenMask);
391
392 XlateGDI->RedShift = CalculateShift(RGB(0xFF, 0x00, 0x00)) - CalculateShift(XlateGDI->RedMask);
393 XlateGDI->GreenShift = CalculateShift(RGB(0x00, 0xFF, 0x00)) - CalculateShift(XlateGDI->GreenMask);
394 XlateGDI->BlueShift = CalculateShift(RGB(0x00, 0x00, 0xFF)) - CalculateShift(XlateGDI->BlueMask);
395
396 XlateGDI->translationTable[0] = ShiftAndMask(XlateGDI, BackgroundColor);
397 XlateGDI->translationTable[1] = ShiftAndMask(XlateGDI, ForegroundColor);
398
399 if (XlateObj->iDstType == PAL_INDEXED)
400 {
401 XlateGDI->translationTable[0] =
402 ClosestColorMatch(XlateGDI,
403 (LPPALETTEENTRY)&XlateGDI->translationTable[0],
404 DestPalGDI->IndexedColors,
405 DestPalGDI->NumColors);
406 XlateGDI->translationTable[1] =
407 ClosestColorMatch(XlateGDI,
408 (LPPALETTEENTRY)&XlateGDI->translationTable[1],
409 DestPalGDI->IndexedColors,
410 DestPalGDI->NumColors);
411 }
412
413 PALETTE_UnlockPalette(DestPalGDI);
414
415 return XlateObj;
416 }
417
418 /* PUBLIC FUNCTIONS ***********************************************************/
419
420 /*
421 * @implemented
422 */
423 VOID FASTCALL
424 EngDeleteXlate(XLATEOBJ *XlateObj)
425 {
426 XLATEGDI *XlateGDI;
427
428 if (XlateObj == NULL)
429 {
430 DPRINT1("Trying to delete NULL XLATEOBJ\n");
431 return;
432 }
433
434 XlateGDI = ObjToGDI(XlateObj, XLATE);
435
436 if ((XlateObj->flXlate & XO_TABLE) &&
437 XlateGDI->translationTable != NULL)
438 {
439 EngFreeMem(XlateGDI->translationTable);
440 }
441
442 EngFreeMem(XlateGDI);
443 }
444
445 /*
446 * @implemented
447 */
448 PULONG STDCALL
449 XLATEOBJ_piVector(XLATEOBJ *XlateObj)
450 {
451 XLATEGDI *XlateGDI = ObjToGDI(XlateObj, XLATE);
452
453 if (XlateObj->iSrcType == PAL_INDEXED)
454 {
455 return XlateGDI->translationTable;
456 }
457
458 return NULL;
459 }
460
461 /*
462 * @implemented
463 */
464 ULONG STDCALL
465 XLATEOBJ_iXlate(XLATEOBJ *XlateObj, ULONG Color)
466 {
467 XLATEGDI *XlateGDI;
468 PALGDI *PalGDI;
469 ULONG Closest;
470
471 /* Return the original color if there's no color translation object. */
472 if (!XlateObj)
473 return Color;
474
475 if (XlateObj->flXlate & XO_TRIVIAL)
476 return Color;
477
478 if (XlateObj->flXlate & XO_TABLE)
479 return XlateObj->pulXlate[Color];
480
481 XlateGDI = ObjToGDI(XlateObj, XLATE);
482
483 if (XlateObj->flXlate & XO_TO_MONO)
484 return Color == XlateGDI->BackgroundColor;
485
486 if (XlateGDI->UseShiftAndMask)
487 return ShiftAndMask(XlateGDI, Color);
488
489 if (XlateObj->iSrcType == PAL_RGB || XlateObj->iSrcType == PAL_BGR ||
490 XlateObj->iSrcType == PAL_BITFIELDS)
491 {
492 /* FIXME: should we cache colors used often? */
493 /* FIXME: won't work if destination isn't indexed */
494
495 /* Convert the source color to the palette RGB format. */
496 Color = ShiftAndMask(XlateGDI, Color);
497
498 /* Extract the destination palette. */
499 PalGDI = PALETTE_LockPalette(XlateGDI->DestPal);
500 if(PalGDI != NULL)
501 {
502 /* Return closest match for the given color. */
503 Closest = ClosestColorMatch(XlateGDI, (LPPALETTEENTRY)&Color, PalGDI->IndexedColors, PalGDI->NumColors);
504 PALETTE_UnlockPalette(PalGDI);
505 return Closest;
506 }
507 }
508
509 return 0;
510 }
511
512 /*
513 * @implemented
514 */
515 ULONG STDCALL
516 XLATEOBJ_cGetPalette(XLATEOBJ *XlateObj, ULONG PalOutType, ULONG cPal,
517 ULONG *OutPal)
518 {
519 HPALETTE hPalette;
520 XLATEGDI *XlateGDI;
521 PALGDI *PalGDI;
522 ULONG *InPal;
523
524 XlateGDI = ObjToGDI(XlateObj, XLATE);
525 if (PalOutType == XO_SRCPALETTE)
526 hPalette = XlateGDI->SourcePal;
527 else if (PalOutType == XO_DESTPALETTE)
528 hPalette = XlateGDI->DestPal;
529 else
530 UNIMPLEMENTED;
531
532 PalGDI = PALETTE_LockPalette(hPalette);
533 if(PalGDI != NULL)
534 {
535 /* copy the indexed colors into the buffer */
536
537 for(InPal = (ULONG*)PalGDI->IndexedColors;
538 cPal > 0;
539 cPal--, InPal++, OutPal++)
540 {
541 *OutPal = *InPal;
542 }
543
544 PALETTE_UnlockPalette(PalGDI);
545
546 return cPal;
547 }
548
549 return 0;
550 }
551
552 /* EOF */