[Win32k|User32]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / palette.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Palette Functions
5 * FILE: subsys/win32k/eng/palette.c
6 * PROGRAMERS: Jason Filby
7 * Timo Kreuzer
8 */
9
10 #include <win32k.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 static UINT SystemPaletteUse = SYSPAL_NOSTATIC; /* the program need save the pallete and restore it */
16
17 PALETTE gpalRGB, gpalBGR, gpalMono;
18
19 const PALETTEENTRY g_sysPalTemplate[NB_RESERVED_COLORS] =
20 {
21 // first 10 entries in the system palette
22 // red green blue flags
23 { 0x00, 0x00, 0x00, PC_SYS_USED },
24 { 0x80, 0x00, 0x00, PC_SYS_USED },
25 { 0x00, 0x80, 0x00, PC_SYS_USED },
26 { 0x80, 0x80, 0x00, PC_SYS_USED },
27 { 0x00, 0x00, 0x80, PC_SYS_USED },
28 { 0x80, 0x00, 0x80, PC_SYS_USED },
29 { 0x00, 0x80, 0x80, PC_SYS_USED },
30 { 0xc0, 0xc0, 0xc0, PC_SYS_USED },
31 { 0xc0, 0xdc, 0xc0, PC_SYS_USED },
32 { 0xa6, 0xca, 0xf0, PC_SYS_USED },
33
34 // ... c_min/2 dynamic colorcells
35 // ... gap (for sparse palettes)
36 // ... c_min/2 dynamic colorcells
37
38 { 0xff, 0xfb, 0xf0, PC_SYS_USED },
39 { 0xa0, 0xa0, 0xa4, PC_SYS_USED },
40 { 0x80, 0x80, 0x80, PC_SYS_USED },
41 { 0xff, 0x00, 0x00, PC_SYS_USED },
42 { 0x00, 0xff, 0x00, PC_SYS_USED },
43 { 0xff, 0xff, 0x00, PC_SYS_USED },
44 { 0x00, 0x00, 0xff, PC_SYS_USED },
45 { 0xff, 0x00, 0xff, PC_SYS_USED },
46 { 0x00, 0xff, 0xff, PC_SYS_USED },
47 { 0xff, 0xff, 0xff, PC_SYS_USED } // last 10
48 };
49
50 unsigned short GetNumberOfBits(unsigned int dwMask)
51 {
52 unsigned short wBits;
53 for (wBits = 0; dwMask; dwMask = dwMask & (dwMask - 1))
54 wBits++;
55 return wBits;
56 }
57
58 // Create the system palette
59 HPALETTE FASTCALL PALETTE_Init(VOID)
60 {
61 int i;
62 HPALETTE hpalette;
63 PLOGPALETTE palPtr;
64
65 // create default palette (20 system colors)
66 palPtr = ExAllocatePoolWithTag(PagedPool,
67 sizeof(LOGPALETTE) +
68 (NB_RESERVED_COLORS * sizeof(PALETTEENTRY)),
69 TAG_PALETTE);
70 if (!palPtr) return FALSE;
71
72 palPtr->palVersion = 0x300;
73 palPtr->palNumEntries = NB_RESERVED_COLORS;
74 for (i=0; i<NB_RESERVED_COLORS; i++)
75 {
76 palPtr->palPalEntry[i].peRed = g_sysPalTemplate[i].peRed;
77 palPtr->palPalEntry[i].peGreen = g_sysPalTemplate[i].peGreen;
78 palPtr->palPalEntry[i].peBlue = g_sysPalTemplate[i].peBlue;
79 palPtr->palPalEntry[i].peFlags = 0;
80 }
81
82 hpalette = NtGdiCreatePaletteInternal(palPtr,NB_RESERVED_COLORS);
83 ExFreePoolWithTag(palPtr, TAG_PALETTE);
84
85 /* palette_size = visual->map_entries; */
86
87 gpalRGB.Mode = PAL_RGB;
88 gpalRGB.RedMask = RGB(0xFF, 0x00, 0x00);
89 gpalRGB.GreenMask = RGB(0x00, 0xFF, 0x00);
90 gpalRGB.BlueMask = RGB(0x00, 0x00, 0xFF);
91
92 gpalBGR.Mode = PAL_BGR;
93 gpalBGR.RedMask = RGB(0x00, 0x00, 0xFF);
94 gpalBGR.GreenMask = RGB(0x00, 0xFF, 0x00);
95 gpalBGR.BlueMask = RGB(0xFF, 0x00, 0x00);
96
97 memset(&gpalMono, 0, sizeof(PALETTE));
98 gpalMono.Mode = PAL_MONOCHROME;
99
100 return hpalette;
101 }
102
103 VOID FASTCALL PALETTE_ValidateFlags(PALETTEENTRY* lpPalE, INT size)
104 {
105 int i = 0;
106 for (; i<size ; i++)
107 lpPalE[i].peFlags = PC_SYS_USED | (lpPalE[i].peFlags & 0x07);
108 }
109
110 HPALETTE
111 FASTCALL
112 PALETTE_AllocPalette(ULONG Mode,
113 ULONG NumColors,
114 ULONG *Colors,
115 ULONG Red,
116 ULONG Green,
117 ULONG Blue)
118 {
119 HPALETTE NewPalette;
120 PPALETTE PalGDI;
121
122 PalGDI = (PPALETTE)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_PALETTE);
123 if (!PalGDI)
124 {
125 return NULL;
126 }
127
128 NewPalette = PalGDI->BaseObject.hHmgr;
129
130 PalGDI->Self = NewPalette;
131 PalGDI->Mode = Mode;
132
133 if (NULL != Colors)
134 {
135 PalGDI->IndexedColors = ExAllocatePoolWithTag(PagedPool,
136 sizeof(PALETTEENTRY) * NumColors,
137 TAG_PALETTE);
138 if (NULL == PalGDI->IndexedColors)
139 {
140 PALETTE_UnlockPalette(PalGDI);
141 PALETTE_FreePaletteByHandle(NewPalette);
142 return NULL;
143 }
144 RtlCopyMemory(PalGDI->IndexedColors, Colors, sizeof(PALETTEENTRY) * NumColors);
145 }
146
147 if (PAL_INDEXED == Mode)
148 {
149 PalGDI->NumColors = NumColors;
150 }
151 else if (PAL_BITFIELDS == Mode)
152 {
153 PalGDI->RedMask = Red;
154 PalGDI->GreenMask = Green;
155 PalGDI->BlueMask = Blue;
156
157 if (Red == 0x7c00 && Green == 0x3E0 && Blue == 0x1F)
158 PalGDI->Mode |= PAL_RGB16_555;
159 else if (Red == 0xF800 && Green == 0x7E0 && Blue == 0x1F)
160 PalGDI->Mode |= PAL_RGB16_565;
161 }
162
163 PALETTE_UnlockPalette(PalGDI);
164
165 return NewPalette;
166 }
167
168 HPALETTE
169 FASTCALL
170 PALETTE_AllocPaletteIndexedRGB(ULONG NumColors,
171 CONST RGBQUAD *Colors)
172 {
173 HPALETTE NewPalette;
174 PPALETTE PalGDI;
175 UINT i;
176
177 PalGDI = (PPALETTE)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_PALETTE);
178 if (!PalGDI)
179 {
180 return NULL;
181 }
182
183 NewPalette = PalGDI->BaseObject.hHmgr;
184
185 PalGDI->Self = NewPalette;
186 PalGDI->Mode = PAL_INDEXED;
187
188 PalGDI->IndexedColors = ExAllocatePoolWithTag(PagedPool,
189 sizeof(PALETTEENTRY) * NumColors,
190 TAG_PALETTE);
191 if (NULL == PalGDI->IndexedColors)
192 {
193 PALETTE_UnlockPalette(PalGDI);
194 PALETTE_FreePaletteByHandle(NewPalette);
195 return NULL;
196 }
197
198 for (i = 0; i < NumColors; i++)
199 {
200 PalGDI->IndexedColors[i].peRed = Colors[i].rgbRed;
201 PalGDI->IndexedColors[i].peGreen = Colors[i].rgbGreen;
202 PalGDI->IndexedColors[i].peBlue = Colors[i].rgbBlue;
203 PalGDI->IndexedColors[i].peFlags = 0;
204 }
205
206 PalGDI->NumColors = NumColors;
207
208 PALETTE_UnlockPalette(PalGDI);
209
210 return NewPalette;
211 }
212
213 BOOL INTERNAL_CALL
214 PALETTE_Cleanup(PVOID ObjectBody)
215 {
216 PPALETTE pPal = (PPALETTE)ObjectBody;
217 if (NULL != pPal->IndexedColors)
218 {
219 ExFreePoolWithTag(pPal->IndexedColors, TAG_PALETTE);
220 }
221
222 return TRUE;
223 }
224
225 INT FASTCALL
226 PALETTE_GetObject(PPALETTE ppal, INT cbCount, LPLOGBRUSH lpBuffer)
227 {
228 if (!lpBuffer)
229 {
230 return sizeof(WORD);
231 }
232
233 if ((UINT)cbCount < sizeof(WORD)) return 0;
234 *((WORD*)lpBuffer) = (WORD)ppal->NumColors;
235 return sizeof(WORD);
236 }
237
238 ULONG
239 NTAPI
240 PALETTE_ulGetNearestPaletteIndex(PALETTE* ppal, ULONG iColor)
241 {
242 ULONG ulDiff, ulColorDiff, ulMinimalDiff = 0xFFFFFF;
243 ULONG i, ulBestIndex = 0;
244 PALETTEENTRY peColor = *(PPALETTEENTRY)&iColor;
245
246 /* Loop all palette entries, break on exact match */
247 for (i = 0; i < ppal->NumColors && ulMinimalDiff != 0; i++)
248 {
249 /* Calculate distance in the color cube */
250 ulDiff = peColor.peRed - ppal->IndexedColors[i].peRed;
251 ulColorDiff = ulDiff * ulDiff;
252 ulDiff = peColor.peGreen - ppal->IndexedColors[i].peGreen;
253 ulColorDiff += ulDiff * ulDiff;
254 ulDiff = peColor.peBlue - ppal->IndexedColors[i].peBlue;
255 ulColorDiff += ulDiff * ulDiff;
256
257 /* Check for a better match */
258 if (ulColorDiff < ulMinimalDiff)
259 {
260 ulBestIndex = i;
261 ulMinimalDiff = ulColorDiff;
262 }
263 }
264
265 return ulBestIndex;
266 }
267
268 ULONG
269 NTAPI
270 PALETTE_ulGetNearestBitFieldsIndex(PALETTE* ppal, ULONG ulColor)
271 {
272 ULONG ulNewColor;
273
274 // FIXME: HACK, should be stored already
275 ppal->ulRedShift = CalculateShift(RGB(0xff,0,0), ppal->RedMask);
276 ppal->ulGreenShift = CalculateShift(RGB(0,0xff,0), ppal->GreenMask);
277 ppal->ulBlueShift = CalculateShift(RGB(0,0,0xff), ppal->BlueMask);
278
279 ulNewColor = _rotl(ulColor, ppal->ulRedShift) & ppal->RedMask;
280 ulNewColor |= _rotl(ulColor, ppal->ulGreenShift) & ppal->GreenMask;
281 ulNewColor |= _rotl(ulColor, ppal->ulBlueShift) & ppal->BlueMask;
282
283 return ulNewColor;
284 }
285
286 ULONG
287 NTAPI
288 PALETTE_ulGetNearestIndex(PALETTE* ppal, ULONG ulColor)
289 {
290 if (ppal->Mode & PAL_INDEXED) // use fl & PALINDEXED
291 return PALETTE_ulGetNearestPaletteIndex(ppal, ulColor);
292 else
293 return PALETTE_ulGetNearestBitFieldsIndex(ppal, ulColor);
294 }
295
296 VOID
297 NTAPI
298 PALETTE_vGetBitMasks(PPALETTE ppal, PULONG pulColors)
299 {
300 ASSERT(pulColors);
301
302 if (ppal->Mode & PAL_INDEXED || ppal->Mode & PAL_RGB)
303 {
304 pulColors[0] = RGB(0xFF, 0x00, 0x00);
305 pulColors[1] = RGB(0x00, 0xFF, 0x00);
306 pulColors[2] = RGB(0x00, 0x00, 0xFF);
307 }
308 else if (ppal->Mode & PAL_BGR)
309 {
310 pulColors[0] = RGB(0x00, 0x00, 0xFF);
311 pulColors[1] = RGB(0x00, 0xFF, 0x00);
312 pulColors[2] = RGB(0xFF, 0x00, 0x00);
313 }
314 else if (ppal->Mode & PAL_BITFIELDS)
315 {
316 pulColors[0] = ppal->RedMask;
317 pulColors[1] = ppal->GreenMask;
318 pulColors[2] = ppal->BlueMask;
319 }
320 }
321
322 VOID
323 FASTCALL
324 ColorCorrection(PPALETTE PalGDI, PPALETTEENTRY PaletteEntry, ULONG Colors)
325 {
326 PPDEVOBJ ppdev = (PPDEVOBJ)PalGDI->hPDev;
327
328 if (!ppdev) return;
329
330 if (ppdev->flFlags & PDEV_GAMMARAMP_TABLE)
331 {
332 INT i;
333 PGAMMARAMP GammaRamp = (PGAMMARAMP)ppdev->pvGammaRamp;
334 for ( i = 0; i < Colors; i++)
335 {
336 PaletteEntry[i].peRed += GammaRamp->Red[i];
337 PaletteEntry[i].peGreen += GammaRamp->Green[i];
338 PaletteEntry[i].peBlue += GammaRamp->Blue[i];
339 }
340 }
341 return;
342 }
343
344 /** Display Driver Interface **************************************************/
345
346 /*
347 * @implemented
348 */
349 HPALETTE
350 APIENTRY
351 EngCreatePalette(
352 ULONG Mode,
353 ULONG NumColors,
354 ULONG *Colors,
355 ULONG Red,
356 ULONG Green,
357 ULONG Blue)
358 {
359 HPALETTE Palette;
360
361 Palette = PALETTE_AllocPalette(Mode, NumColors, Colors, Red, Green, Blue);
362 if (Palette != NULL)
363 {
364 GDIOBJ_SetOwnership(Palette, NULL);
365 }
366
367 return Palette;
368 }
369
370 /*
371 * @implemented
372 */
373 BOOL
374 APIENTRY
375 EngDeletePalette(IN HPALETTE Palette)
376 {
377 GDIOBJ_SetOwnership(Palette, PsGetCurrentProcess());
378
379 return PALETTE_FreePaletteByHandle(Palette);
380 }
381
382 /*
383 * @implemented
384 */
385 ULONG
386 APIENTRY
387 PALOBJ_cGetColors(PALOBJ *PalObj, ULONG Start, ULONG Colors, ULONG *PaletteEntry)
388 {
389 PALETTE *PalGDI;
390
391 PalGDI = (PALETTE*)PalObj;
392 /* PalGDI = (PALETTE*)AccessInternalObjectFromUserObject(PalObj); */
393
394 if (Start >= PalGDI->NumColors)
395 return 0;
396
397 Colors = min(Colors, PalGDI->NumColors - Start);
398
399 /* NOTE: PaletteEntry ULONGs are in the same order as PALETTEENTRY. */
400 RtlCopyMemory(PaletteEntry, PalGDI->IndexedColors + Start, sizeof(ULONG) * Colors);
401
402 if (PalGDI->Mode & PAL_GAMMACORRECTION)
403 ColorCorrection(PalGDI, (PPALETTEENTRY)PaletteEntry, Colors);
404
405 return Colors;
406 }
407
408
409 /** Systemcall Interface ******************************************************/
410
411 /*
412 * @implemented
413 */
414 HPALETTE APIENTRY
415 NtGdiCreatePaletteInternal ( IN LPLOGPALETTE pLogPal, IN UINT cEntries )
416 {
417 PPALETTE PalGDI;
418 HPALETTE NewPalette;
419
420 pLogPal->palNumEntries = cEntries;
421 NewPalette = PALETTE_AllocPalette( PAL_INDEXED,
422 cEntries,
423 (PULONG)pLogPal->palPalEntry,
424 0, 0, 0);
425
426 if (NewPalette == NULL)
427 {
428 return NULL;
429 }
430
431 PalGDI = (PPALETTE) PALETTE_LockPalette(NewPalette);
432 if (PalGDI != NULL)
433 {
434 PALETTE_ValidateFlags(PalGDI->IndexedColors, PalGDI->NumColors);
435 PALETTE_UnlockPalette(PalGDI);
436 }
437 else
438 {
439 /* FIXME - Handle PalGDI == NULL!!!! */
440 DPRINT1("PalGDI is NULL\n");
441 }
442 return NewPalette;
443 }
444
445 HPALETTE APIENTRY NtGdiCreateHalftonePalette(HDC hDC)
446 {
447 int i, r, g, b;
448 struct {
449 WORD Version;
450 WORD NumberOfEntries;
451 PALETTEENTRY aEntries[256];
452 } Palette;
453
454 Palette.Version = 0x300;
455 Palette.NumberOfEntries = 256;
456 if (IntGetSystemPaletteEntries(hDC, 0, 256, Palette.aEntries) == 0)
457 {
458 /* from wine, more that 256 color math */
459 Palette.NumberOfEntries = 20;
460 for (i = 0; i < Palette.NumberOfEntries; i++)
461 {
462 Palette.aEntries[i].peRed=0xff;
463 Palette.aEntries[i].peGreen=0xff;
464 Palette.aEntries[i].peBlue=0xff;
465 Palette.aEntries[i].peFlags=0x00;
466 }
467
468 Palette.aEntries[0].peRed=0x00;
469 Palette.aEntries[0].peBlue=0x00;
470 Palette.aEntries[0].peGreen=0x00;
471
472 /* the first 6 */
473 for (i=1; i <= 6; i++)
474 {
475 Palette.aEntries[i].peRed=(i%2)?0x80:0;
476 Palette.aEntries[i].peGreen=(i==2)?0x80:(i==3)?0x80:(i==6)?0x80:0;
477 Palette.aEntries[i].peBlue=(i>3)?0x80:0;
478 }
479
480 for (i=7; i <= 12; i++)
481 {
482 switch(i)
483 {
484 case 7:
485 Palette.aEntries[i].peRed=0xc0;
486 Palette.aEntries[i].peBlue=0xc0;
487 Palette.aEntries[i].peGreen=0xc0;
488 break;
489 case 8:
490 Palette.aEntries[i].peRed=0xc0;
491 Palette.aEntries[i].peGreen=0xdc;
492 Palette.aEntries[i].peBlue=0xc0;
493 break;
494 case 9:
495 Palette.aEntries[i].peRed=0xa6;
496 Palette.aEntries[i].peGreen=0xca;
497 Palette.aEntries[i].peBlue=0xf0;
498 break;
499 case 10:
500 Palette.aEntries[i].peRed=0xff;
501 Palette.aEntries[i].peGreen=0xfb;
502 Palette.aEntries[i].peBlue=0xf0;
503 break;
504 case 11:
505 Palette.aEntries[i].peRed=0xa0;
506 Palette.aEntries[i].peGreen=0xa0;
507 Palette.aEntries[i].peBlue=0xa4;
508 break;
509 case 12:
510 Palette.aEntries[i].peRed=0x80;
511 Palette.aEntries[i].peGreen=0x80;
512 Palette.aEntries[i].peBlue=0x80;
513 }
514 }
515
516 for (i=13; i <= 18; i++)
517 {
518 Palette.aEntries[i].peRed=(i%2)?0xff:0;
519 Palette.aEntries[i].peGreen=(i==14)?0xff:(i==15)?0xff:(i==18)?0xff:0;
520 Palette.aEntries[i].peBlue=(i>15)?0xff:0x00;
521 }
522 }
523 else
524 {
525 /* 256 color table */
526 for (r = 0; r < 6; r++)
527 for (g = 0; g < 6; g++)
528 for (b = 0; b < 6; b++)
529 {
530 i = r + g*6 + b*36 + 10;
531 Palette.aEntries[i].peRed = r * 51;
532 Palette.aEntries[i].peGreen = g * 51;
533 Palette.aEntries[i].peBlue = b * 51;
534 }
535
536 for (i = 216; i < 246; i++)
537 {
538 int v = (i - 216) << 3;
539 Palette.aEntries[i].peRed = v;
540 Palette.aEntries[i].peGreen = v;
541 Palette.aEntries[i].peBlue = v;
542 }
543 }
544
545 return NtGdiCreatePaletteInternal((LOGPALETTE *)&Palette, Palette.NumberOfEntries);
546 }
547
548 BOOL
549 APIENTRY
550 NtGdiResizePalette(
551 HPALETTE hpal,
552 UINT Entries)
553 {
554 /* PALOBJ *palPtr = (PALOBJ*)AccessUserObject(hPal);
555 UINT cPrevEnt, prevVer;
556 INT prevsize, size = sizeof(LOGPALETTE) + (cEntries - 1) * sizeof(PALETTEENTRY);
557 XLATEOBJ *XlateObj = NULL;
558
559 if(!palPtr) return FALSE;
560 cPrevEnt = palPtr->logpalette->palNumEntries;
561 prevVer = palPtr->logpalette->palVersion;
562 prevsize = sizeof(LOGPALETTE) + (cPrevEnt - 1) * sizeof(PALETTEENTRY) + sizeof(int*) + sizeof(GDIOBJHDR);
563 size += sizeof(int*) + sizeof(GDIOBJHDR);
564 XlateObj = palPtr->logicalToSystem;
565
566 if (!(palPtr = GDI_ReallocObject(size, hPal, palPtr))) return FALSE;
567
568 if(XlateObj)
569 {
570 XLATEOBJ *NewXlateObj = (int*) HeapReAlloc(GetProcessHeap(), 0, XlateObj, cEntries * sizeof(int));
571 if(NewXlateObj == NULL)
572 {
573 ERR("Can not resize logicalToSystem -- out of memory!");
574 GDI_ReleaseObj( hPal );
575 return FALSE;
576 }
577 palPtr->logicalToSystem = NewXlateObj;
578 }
579
580 if(cEntries > cPrevEnt)
581 {
582 if(XlateObj) memset(palPtr->logicalToSystem + cPrevEnt, 0, (cEntries - cPrevEnt)*sizeof(int));
583 memset( (BYTE*)palPtr + prevsize, 0, size - prevsize );
584 PALETTE_ValidateFlags((PALETTEENTRY*)((BYTE*)palPtr + prevsize), cEntries - cPrevEnt );
585 }
586 palPtr->logpalette->palNumEntries = cEntries;
587 palPtr->logpalette->palVersion = prevVer;
588 // GDI_ReleaseObj( hPal );
589 return TRUE; */
590
591 UNIMPLEMENTED;
592 return FALSE;
593 }
594
595 BOOL
596 APIENTRY
597 NtGdiGetColorAdjustment(
598 HDC hdc,
599 LPCOLORADJUSTMENT pca)
600 {
601 UNIMPLEMENTED;
602 return FALSE;
603 }
604
605 BOOL
606 APIENTRY
607 NtGdiSetColorAdjustment(
608 HDC hdc,
609 LPCOLORADJUSTMENT pca)
610 {
611 UNIMPLEMENTED;
612 return FALSE;
613 }
614
615 COLORREF APIENTRY NtGdiGetNearestColor(HDC hDC, COLORREF Color)
616 {
617 COLORREF nearest = CLR_INVALID;
618 PDC dc;
619 PPALETTE palGDI;
620 LONG RBits, GBits, BBits;
621
622 dc = DC_LockDc(hDC);
623 if (NULL != dc)
624 {
625 HPALETTE hpal = dc->dclevel.hpal;
626 palGDI = (PPALETTE) PALETTE_LockPalette(hpal);
627 if (!palGDI)
628 {
629 DC_UnlockDc(dc);
630 return nearest;
631 }
632
633 if (palGDI->Mode & PAL_INDEXED)
634 {
635 ULONG index;
636 index = PALETTE_ulGetNearestPaletteIndex(palGDI, Color);
637 nearest = PALETTE_ulGetRGBColorFromIndex(palGDI, index);
638 }
639 else if (palGDI->Mode & PAL_RGB || palGDI->Mode & PAL_BGR)
640 {
641 nearest = Color;
642 }
643 else if (palGDI->Mode & PAL_BITFIELDS)
644 {
645 RBits = 8 - GetNumberOfBits(palGDI->RedMask);
646 GBits = 8 - GetNumberOfBits(palGDI->GreenMask);
647 BBits = 8 - GetNumberOfBits(palGDI->BlueMask);
648 nearest = RGB(
649 (GetRValue(Color) >> RBits) << RBits,
650 (GetGValue(Color) >> GBits) << GBits,
651 (GetBValue(Color) >> BBits) << BBits);
652 }
653 PALETTE_UnlockPalette(palGDI);
654 DC_UnlockDc(dc);
655 }
656
657 return nearest;
658 }
659
660 UINT
661 APIENTRY
662 NtGdiGetNearestPaletteIndex(
663 HPALETTE hpal,
664 COLORREF crColor)
665 {
666 PPALETTE ppal = (PPALETTE) PALETTE_LockPalette(hpal);
667 UINT index = 0;
668
669 if (ppal)
670 {
671 if (ppal->Mode & PAL_INDEXED)
672 {
673 /* Return closest match for the given RGB color */
674 index = PALETTE_ulGetNearestPaletteIndex(ppal, crColor);
675 }
676 // else SetLastError ?
677 PALETTE_UnlockPalette(ppal);
678 }
679
680 return index;
681 }
682
683 UINT
684 FASTCALL
685 IntGdiRealizePalette(HDC hDC)
686 {
687 /*
688 * This function doesn't do any real work now and there's plenty
689 * of bugs in it.
690 */
691
692 PPALETTE palGDI, sysGDI;
693 int realized = 0;
694 PDC dc;
695 HPALETTE systemPalette;
696
697 dc = DC_LockDc(hDC);
698 if (!dc) return 0;
699
700 systemPalette = NtGdiGetStockObject(DEFAULT_PALETTE);
701 palGDI = PALETTE_LockPalette(dc->dclevel.hpal);
702
703 if (palGDI == NULL)
704 {
705 DPRINT1("IntGdiRealizePalette(): palGDI is NULL, exiting\n");
706 DC_UnlockDc(dc);
707 return 0;
708 }
709
710 sysGDI = PALETTE_LockPalette(systemPalette);
711
712 if (sysGDI == NULL)
713 {
714 DPRINT1("IntGdiRealizePalette(): sysGDI is NULL, exiting\n");
715 PALETTE_UnlockPalette(palGDI);
716 DC_UnlockDc(dc);
717 return 0;
718 }
719
720 // The RealizePalette function modifies the palette for the device associated with the specified device context. If the
721 // device context is a memory DC, the color table for the bitmap selected into the DC is modified. If the device
722 // context is a display DC, the physical palette for that device is modified.
723 if(dc->dctype == DC_TYPE_MEMORY)
724 {
725 // Memory managed DC
726 DPRINT1("RealizePalette unimplemented for memory managed DCs\n");
727 } else
728 {
729 DPRINT1("RealizePalette unimplemented for device DCs\n");
730 }
731
732 // need to pass this to IntEngCreateXlate with palettes unlocked
733 PALETTE_UnlockPalette(sysGDI);
734 PALETTE_UnlockPalette(palGDI);
735
736 DC_UnlockDc(dc);
737
738 return realized;
739 }
740
741 UINT APIENTRY
742 IntAnimatePalette(HPALETTE hPal,
743 UINT StartIndex,
744 UINT NumEntries,
745 CONST PPALETTEENTRY PaletteColors)
746 {
747 UINT ret = 0;
748
749 if( hPal != NtGdiGetStockObject(DEFAULT_PALETTE) )
750 {
751 PPALETTE palPtr;
752 UINT pal_entries;
753 HDC hDC;
754 PDC dc;
755 PWND Wnd;
756 const PALETTEENTRY *pptr = PaletteColors;
757
758 palPtr = (PPALETTE)PALETTE_LockPalette(hPal);
759 if (!palPtr) return FALSE;
760
761 pal_entries = palPtr->NumColors;
762 if (StartIndex >= pal_entries)
763 {
764 PALETTE_UnlockPalette(palPtr);
765 return FALSE;
766 }
767 if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex;
768
769 for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++)
770 {
771 /* According to MSDN, only animate PC_RESERVED colours */
772 if (palPtr->IndexedColors[StartIndex].peFlags & PC_RESERVED)
773 {
774 memcpy( &palPtr->IndexedColors[StartIndex], pptr,
775 sizeof(PALETTEENTRY) );
776 ret++;
777 PALETTE_ValidateFlags(&palPtr->IndexedColors[StartIndex], 1);
778 }
779 }
780
781 PALETTE_UnlockPalette(palPtr);
782
783 /* Immediately apply the new palette if current window uses it */
784 Wnd = UserGetDesktopWindow();
785 hDC = UserGetWindowDC(Wnd);
786 dc = DC_LockDc(hDC);
787 if (NULL != dc)
788 {
789 if (dc->dclevel.hpal == hPal)
790 {
791 DC_UnlockDc(dc);
792 IntGdiRealizePalette(hDC);
793 }
794 else
795 DC_UnlockDc(dc);
796 }
797 UserReleaseDC(Wnd,hDC, FALSE);
798 }
799 return ret;
800 }
801
802 UINT APIENTRY
803 IntGetPaletteEntries(
804 HPALETTE hpal,
805 UINT StartIndex,
806 UINT Entries,
807 LPPALETTEENTRY pe)
808 {
809 PPALETTE palGDI;
810 UINT numEntries;
811
812 palGDI = (PPALETTE) PALETTE_LockPalette(hpal);
813 if (NULL == palGDI)
814 {
815 return 0;
816 }
817
818 numEntries = palGDI->NumColors;
819 if (NULL != pe)
820 {
821 if (numEntries < StartIndex + Entries)
822 {
823 Entries = numEntries - StartIndex;
824 }
825 if (numEntries <= StartIndex)
826 {
827 PALETTE_UnlockPalette(palGDI);
828 return 0;
829 }
830 memcpy(pe, palGDI->IndexedColors + StartIndex, Entries * sizeof(PALETTEENTRY));
831 }
832 else
833 {
834 Entries = numEntries;
835 }
836
837 PALETTE_UnlockPalette(palGDI);
838 return Entries;
839 }
840
841 UINT APIENTRY
842 IntGetSystemPaletteEntries(HDC hDC,
843 UINT StartIndex,
844 UINT Entries,
845 LPPALETTEENTRY pe)
846 {
847 PPALETTE palGDI = NULL;
848 PDC dc = NULL;
849 UINT EntriesSize = 0;
850 UINT Ret = 0;
851
852 if (Entries == 0)
853 {
854 SetLastWin32Error(ERROR_INVALID_PARAMETER);
855 return 0;
856 }
857
858 if (pe != NULL)
859 {
860 EntriesSize = Entries * sizeof(pe[0]);
861 if (Entries != EntriesSize / sizeof(pe[0]))
862 {
863 /* Integer overflow! */
864 SetLastWin32Error(ERROR_INVALID_PARAMETER);
865 return 0;
866 }
867 }
868
869 if (!(dc = DC_LockDc(hDC)))
870 {
871 SetLastWin32Error(ERROR_INVALID_HANDLE);
872 return 0;
873 }
874
875 palGDI = PALETTE_LockPalette(dc->dclevel.hpal);
876 if (palGDI != NULL)
877 {
878 if (pe != NULL)
879 {
880 if (StartIndex >= palGDI->NumColors)
881 Entries = 0;
882 else if (Entries > palGDI->NumColors - StartIndex)
883 Entries = palGDI->NumColors - StartIndex;
884
885 memcpy(pe,
886 palGDI->IndexedColors + StartIndex,
887 Entries * sizeof(pe[0]));
888
889 Ret = Entries;
890 }
891 else
892 {
893 Ret = dc->ppdev->gdiinfo.ulNumPalReg;
894 }
895 }
896
897 if (palGDI != NULL)
898 PALETTE_UnlockPalette(palGDI);
899
900 if (dc != NULL)
901 DC_UnlockDc(dc);
902
903 return Ret;
904 }
905
906 UINT
907 APIENTRY
908 IntSetPaletteEntries(
909 HPALETTE hpal,
910 UINT Start,
911 UINT Entries,
912 CONST LPPALETTEENTRY pe)
913 {
914 PPALETTE palGDI;
915 WORD numEntries;
916
917 if ((UINT)hpal & GDI_HANDLE_STOCK_MASK)
918 {
919 return 0;
920 }
921
922 palGDI = PALETTE_LockPalette(hpal);
923 if (!palGDI) return 0;
924
925 numEntries = palGDI->NumColors;
926 if (Start >= numEntries)
927 {
928 PALETTE_UnlockPalette(palGDI);
929 return 0;
930 }
931 if (numEntries < Start + Entries)
932 {
933 Entries = numEntries - Start;
934 }
935 memcpy(palGDI->IndexedColors + Start, pe, Entries * sizeof(PALETTEENTRY));
936 PALETTE_UnlockPalette(palGDI);
937
938 return Entries;
939 }
940
941 W32KAPI
942 LONG
943 APIENTRY
944 NtGdiDoPalette(
945 IN HGDIOBJ hObj,
946 IN WORD iStart,
947 IN WORD cEntries,
948 IN LPVOID pUnsafeEntries,
949 IN DWORD iFunc,
950 IN BOOL bInbound)
951 {
952 LONG ret;
953 LPVOID pEntries = NULL;
954
955 /* FIXME: Handle bInbound correctly */
956
957 if (bInbound &&
958 (pUnsafeEntries == NULL || cEntries == 0))
959 {
960 return 0;
961 }
962
963 if (pUnsafeEntries)
964 {
965 pEntries = ExAllocatePoolWithTag(PagedPool, cEntries * sizeof(PALETTEENTRY), TAG_PALETTE);
966 if (!pEntries)
967 return 0;
968 if (bInbound)
969 {
970 _SEH2_TRY
971 {
972 ProbeForRead(pUnsafeEntries, cEntries * sizeof(PALETTEENTRY), 1);
973 memcpy(pEntries, pUnsafeEntries, cEntries * sizeof(PALETTEENTRY));
974 }
975 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
976 {
977 ExFreePoolWithTag(pEntries, TAG_PALETTE);
978 _SEH2_YIELD(return 0);
979 }
980 _SEH2_END
981 }
982 }
983
984 ret = 0;
985 switch(iFunc)
986 {
987 case GdiPalAnimate:
988 if (pEntries)
989 ret = IntAnimatePalette((HPALETTE)hObj, iStart, cEntries, (CONST PPALETTEENTRY)pEntries);
990 break;
991
992 case GdiPalSetEntries:
993 if (pEntries)
994 ret = IntSetPaletteEntries((HPALETTE)hObj, iStart, cEntries, (CONST LPPALETTEENTRY)pEntries);
995 break;
996
997 case GdiPalGetEntries:
998 ret = IntGetPaletteEntries((HPALETTE)hObj, iStart, cEntries, (LPPALETTEENTRY)pEntries);
999 break;
1000
1001 case GdiPalGetSystemEntries:
1002 ret = IntGetSystemPaletteEntries((HDC)hObj, iStart, cEntries, (LPPALETTEENTRY)pEntries);
1003 break;
1004
1005 case GdiPalSetColorTable:
1006 if (pEntries)
1007 ret = IntSetDIBColorTable((HDC)hObj, iStart, cEntries, (RGBQUAD*)pEntries);
1008 break;
1009
1010 case GdiPalGetColorTable:
1011 if (pEntries)
1012 ret = IntGetDIBColorTable((HDC)hObj, iStart, cEntries, (RGBQUAD*)pEntries);
1013 break;
1014 }
1015
1016 if (pEntries)
1017 {
1018 if (!bInbound)
1019 {
1020 _SEH2_TRY
1021 {
1022 ProbeForWrite(pUnsafeEntries, cEntries * sizeof(PALETTEENTRY), 1);
1023 memcpy(pUnsafeEntries, pEntries, cEntries * sizeof(PALETTEENTRY));
1024 }
1025 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1026 {
1027 ret = 0;
1028 }
1029 _SEH2_END
1030 }
1031 ExFreePoolWithTag(pEntries, TAG_PALETTE);
1032 }
1033
1034 return ret;
1035 }
1036
1037 UINT APIENTRY
1038 NtGdiSetSystemPaletteUse(HDC hDC, UINT Usage)
1039 {
1040 UINT old = SystemPaletteUse;
1041
1042 /* Device doesn't support colour palettes */
1043 if (!(NtGdiGetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE)) {
1044 return SYSPAL_ERROR;
1045 }
1046
1047 switch (Usage)
1048 {
1049 case SYSPAL_NOSTATIC:
1050 case SYSPAL_NOSTATIC256:
1051 case SYSPAL_STATIC:
1052 SystemPaletteUse = Usage;
1053 break;
1054
1055 default:
1056 old=SYSPAL_ERROR;
1057 break;
1058 }
1059
1060 return old;
1061 }
1062
1063 UINT
1064 APIENTRY
1065 NtGdiGetSystemPaletteUse(HDC hDC)
1066 {
1067 return SystemPaletteUse;
1068 }
1069
1070 BOOL
1071 APIENTRY
1072 NtGdiUpdateColors(HDC hDC)
1073 {
1074 PWND Wnd;
1075 BOOL calledFromUser, ret;
1076 USER_REFERENCE_ENTRY Ref;
1077
1078 calledFromUser = UserIsEntered();
1079
1080 if (!calledFromUser){
1081 UserEnterExclusive();
1082 }
1083
1084 Wnd = UserGetWindowObject(IntWindowFromDC(hDC));
1085 if (Wnd == NULL)
1086 {
1087 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1088
1089 if (!calledFromUser){
1090 UserLeave();
1091 }
1092
1093 return FALSE;
1094 }
1095
1096 UserRefObjectCo(Wnd, &Ref);
1097 ret = co_UserRedrawWindow(Wnd, NULL, 0, RDW_INVALIDATE);
1098 UserDerefObjectCo(Wnd);
1099
1100 if (!calledFromUser){
1101 UserLeave();
1102 }
1103
1104 return ret;
1105 }
1106
1107 BOOL
1108 APIENTRY
1109 NtGdiUnrealizeObject(HGDIOBJ hgdiobj)
1110 {
1111 BOOL Ret = FALSE;
1112 PPALETTE palGDI;
1113
1114 if ( !hgdiobj ||
1115 ((UINT)hgdiobj & GDI_HANDLE_STOCK_MASK) ||
1116 !GDI_HANDLE_IS_TYPE(hgdiobj, GDI_OBJECT_TYPE_PALETTE) )
1117 return Ret;
1118
1119 palGDI = PALETTE_LockPalette(hgdiobj);
1120 if (!palGDI) return FALSE;
1121
1122 // FIXME!!
1123 // Need to do something!!!
1124 // Zero out Current and Old Translated pointers?
1125 //
1126 Ret = TRUE;
1127 PALETTE_UnlockPalette(palGDI);
1128 return Ret;
1129 }
1130
1131
1132 /* EOF */