xref: /reactos/win32ss/gdi/ntgdi/palette.c (revision ccef43f3)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS Win32k subsystem
4  * PURPOSE:           GDI Palette Functions
5  * FILE:              win32ss/gdi/ntgdi/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 #define PAL_SETPOWNER 0x8000
16 #define MAX_PALCOLORS 65536
17 
18 static UINT SystemPaletteUse = SYSPAL_NOSTATIC;  /* The program need save the pallete and restore it */
19 
20 PALETTE gpalRGB, gpalBGR, gpalRGB555, gpalRGB565, *gppalMono, *gppalDefault;
21 PPALETTE appalSurfaceDefault[11];
22 
23 const PALETTEENTRY g_sysPalTemplate[NB_RESERVED_COLORS] =
24 {
25   // First 10 entries in the system palette
26   // Red  Green Blue  Flags
27   { 0x00, 0x00, 0x00, PC_SYS_USED },
28   { 0x80, 0x00, 0x00, PC_SYS_USED },
29   { 0x00, 0x80, 0x00, PC_SYS_USED },
30   { 0x80, 0x80, 0x00, PC_SYS_USED },
31   { 0x00, 0x00, 0x80, PC_SYS_USED },
32   { 0x80, 0x00, 0x80, PC_SYS_USED },
33   { 0x00, 0x80, 0x80, PC_SYS_USED },
34   { 0xc0, 0xc0, 0xc0, PC_SYS_USED },
35   { 0xc0, 0xdc, 0xc0, PC_SYS_USED },
36   { 0xa6, 0xca, 0xf0, PC_SYS_USED },
37 
38   // ... c_min/2 dynamic colorcells
39   // ... gap (for sparse palettes)
40   // ... c_min/2 dynamic colorcells
41 
42   { 0xff, 0xfb, 0xf0, PC_SYS_USED },
43   { 0xa0, 0xa0, 0xa4, PC_SYS_USED },
44   { 0x80, 0x80, 0x80, PC_SYS_USED },
45   { 0xff, 0x00, 0x00, PC_SYS_USED },
46   { 0x00, 0xff, 0x00, PC_SYS_USED },
47   { 0xff, 0xff, 0x00, PC_SYS_USED },
48   { 0x00, 0x00, 0xff, PC_SYS_USED },
49   { 0xff, 0x00, 0xff, PC_SYS_USED },
50   { 0x00, 0xff, 0xff, PC_SYS_USED },
51   { 0xff, 0xff, 0xff, PC_SYS_USED }     // Last 10
52 };
53 
54 unsigned short GetNumberOfBits(unsigned int dwMask)
55 {
56    unsigned short wBits;
57    for (wBits = 0; dwMask; dwMask = dwMask & (dwMask - 1))
58       wBits++;
59    return wBits;
60 }
61 
62 // Create the system palette
63 CODE_SEG("INIT")
64 NTSTATUS
65 NTAPI
66 InitPaletteImpl(VOID)
67 {
68     // Create default palette (20 system colors)
69     gppalDefault = PALETTE_AllocPalWithHandle(PAL_INDEXED,
70                                               20,
71                                               g_sysPalTemplate,
72                                               0, 0, 0);
73     GDIOBJ_vReferenceObjectByPointer(&gppalDefault->BaseObject);
74     PALETTE_UnlockPalette(gppalDefault);
75 
76     /*  palette_size = visual->map_entries; */
77 
78     gpalRGB.flFlags = PAL_RGB;
79     gpalRGB.RedMask = RGB(0xFF, 0x00, 0x00);
80     gpalRGB.GreenMask = RGB(0x00, 0xFF, 0x00);
81     gpalRGB.BlueMask = RGB(0x00, 0x00, 0xFF);
82     gpalRGB.BaseObject.ulShareCount = 1;
83     gpalRGB.BaseObject.BaseFlags = 0 ;
84 
85     gpalBGR.flFlags = PAL_BGR;
86     gpalBGR.RedMask = RGB(0x00, 0x00, 0xFF);
87     gpalBGR.GreenMask = RGB(0x00, 0xFF, 0x00);
88     gpalBGR.BlueMask = RGB(0xFF, 0x00, 0x00);
89     gpalBGR.BaseObject.ulShareCount = 1;
90     gpalBGR.BaseObject.BaseFlags = 0 ;
91 
92     gpalRGB555.flFlags = PAL_RGB16_555 | PAL_BITFIELDS;
93     gpalRGB555.RedMask = 0x7C00;
94     gpalRGB555.GreenMask = 0x3E0;
95     gpalRGB555.BlueMask = 0x1F;
96     gpalRGB555.BaseObject.ulShareCount = 1;
97     gpalRGB555.BaseObject.BaseFlags = 0 ;
98 
99     gpalRGB565.flFlags = PAL_RGB16_565 | PAL_BITFIELDS;
100     gpalRGB565.RedMask = 0xF800;
101     gpalRGB565.GreenMask = 0x7E0;
102     gpalRGB565.BlueMask = 0x1F;
103     gpalRGB565.BaseObject.ulShareCount = 1;
104     gpalRGB565.BaseObject.BaseFlags = 0 ;
105 
106     gppalMono = PALETTE_AllocPalette(PAL_MONOCHROME|PAL_INDEXED, 2, NULL, 0, 0, 0);
107     PALETTE_vSetRGBColorForIndex(gppalMono, 0, 0x000000);
108     PALETTE_vSetRGBColorForIndex(gppalMono, 1, 0xffffff);
109 
110     /* Initialize default surface palettes */
111     appalSurfaceDefault[BMF_1BPP] = gppalMono;
112     appalSurfaceDefault[BMF_4BPP] = gppalDefault;
113     appalSurfaceDefault[BMF_8BPP] = gppalDefault;
114     appalSurfaceDefault[BMF_16BPP] = &gpalRGB565;
115     appalSurfaceDefault[BMF_24BPP] = &gpalBGR;
116     appalSurfaceDefault[BMF_32BPP] = &gpalBGR;
117     appalSurfaceDefault[BMF_4RLE] = gppalDefault;
118     appalSurfaceDefault[BMF_8RLE] = gppalDefault;
119     appalSurfaceDefault[BMF_JPEG] = &gpalRGB;
120     appalSurfaceDefault[BMF_PNG] = &gpalRGB;
121 
122     return STATUS_SUCCESS;
123 }
124 
125 VOID FASTCALL PALETTE_ValidateFlags(PALETTEENTRY* lpPalE, INT size)
126 {
127     int i = 0;
128     for (; i<size ; i++)
129         lpPalE[i].peFlags = PC_SYS_USED | (lpPalE[i].peFlags & 0x07);
130 }
131 
132 
133 PPALETTE
134 NTAPI
135 PALETTE_AllocPalette(
136     _In_ ULONG iMode,
137     _In_ ULONG cColors,
138     _In_opt_ const PALETTEENTRY* pEntries,
139     _In_ FLONG flRed,
140     _In_ FLONG flGreen,
141     _In_ FLONG flBlue)
142 {
143     PPALETTE ppal;
144     ULONG fl = 0, cjSize = sizeof(PALETTE);
145 
146     /* Check if the palette has entries */
147     if (iMode & PAL_INDEXED)
148     {
149         /* Check color count */
150         if ((cColors == 0) || (cColors > 1024)) return NULL;
151 
152         /* Allocate enough space for the palete entries */
153         cjSize += cColors * sizeof(PALETTEENTRY);
154     }
155     else
156     {
157         /* There are no palette entries */
158         cColors = 0;
159 
160         /* We can use the lookaside list */
161         fl |= BASEFLAG_LOOKASIDE;
162     }
163 
164     /* Allocate the object (without a handle!) */
165     ppal = (PPALETTE)GDIOBJ_AllocateObject(GDIObjType_PAL_TYPE, cjSize, fl);
166     if (!ppal)
167     {
168         return NULL;
169     }
170 
171     /* Set mode, color count and entry pointer */
172     ppal->flFlags = iMode;
173     ppal->NumColors = cColors;
174     ppal->IndexedColors = ppal->apalColors;
175 
176     /* Check what kind of palette this is */
177     if (iMode & PAL_INDEXED)
178     {
179         /* Check if we got a color array */
180         if (pEntries)
181         {
182             /* Copy the entries */
183             RtlCopyMemory(ppal->IndexedColors, pEntries, cColors * sizeof(pEntries[0]));
184         }
185     }
186     else if (iMode & PAL_BITFIELDS)
187     {
188         /* Copy the color masks */
189         ppal->RedMask = flRed;
190         ppal->GreenMask = flGreen;
191         ppal->BlueMask = flBlue;
192 
193         /* Check what masks we have and set optimization flags */
194         if ((flRed == 0x7c00) && (flGreen == 0x3E0) && (flBlue == 0x1F))
195             ppal->flFlags |= PAL_RGB16_555;
196         else if ((flRed == 0xF800) && (flGreen == 0x7E0) && (flBlue == 0x1F))
197             ppal->flFlags |= PAL_RGB16_565;
198         else if ((flRed == 0xFF0000) && (flGreen == 0xFF00) && (flBlue == 0xFF))
199             ppal->flFlags |= PAL_BGR;
200         else if ((flRed == 0xFF) && (flGreen == 0xFF00) && (flBlue == 0xFF0000))
201             ppal->flFlags |= PAL_RGB;
202     }
203 
204     return ppal;
205 }
206 
207 PPALETTE
208 NTAPI
209 PALETTE_AllocPalWithHandle(
210     _In_ ULONG iMode,
211     _In_ ULONG cColors,
212     _In_opt_ const PALETTEENTRY* pEntries,
213     _In_ FLONG flRed,
214     _In_ FLONG flGreen,
215     _In_ FLONG flBlue)
216 {
217     PPALETTE ppal;
218 
219     /* Allocate the palette without a handle */
220     ppal = PALETTE_AllocPalette(iMode, cColors, pEntries, flRed, flGreen, flBlue);
221     if (!ppal) return NULL;
222 
223     /* Insert the palette into the handle table */
224     if (!GDIOBJ_hInsertObject(&ppal->BaseObject, GDI_OBJ_HMGR_POWNED))
225     {
226         DPRINT1("Could not insert palette into handle table.\n");
227         GDIOBJ_vFreeObject(&ppal->BaseObject);
228         return NULL;
229     }
230 
231     return ppal;
232 }
233 
234 VOID
235 NTAPI
236 PALETTE_vCleanup(PVOID ObjectBody)
237 {
238     PPALETTE pPal = (PPALETTE)ObjectBody;
239     if (pPal->IndexedColors && pPal->IndexedColors != pPal->apalColors)
240     {
241         ExFreePoolWithTag(pPal->IndexedColors, TAG_PALETTE);
242     }
243 }
244 
245 INT
246 FASTCALL
247 PALETTE_GetObject(PPALETTE ppal, INT cbCount, LPLOGBRUSH lpBuffer)
248 {
249     if (!lpBuffer)
250     {
251         return sizeof(WORD);
252     }
253 
254     if ((UINT)cbCount < sizeof(WORD)) return 0;
255     *((WORD*)lpBuffer) = (WORD)ppal->NumColors;
256     return sizeof(WORD);
257 }
258 
259 ULONG
260 NTAPI
261 PALETTE_ulGetNearestPaletteIndex(PALETTE* ppal, ULONG iColor)
262 {
263     ULONG ulDiff, ulColorDiff, ulMinimalDiff = 0xFFFFFF;
264     ULONG i, ulBestIndex = 0;
265     PALETTEENTRY peColor = *(PPALETTEENTRY)&iColor;
266 
267     /* Loop all palette entries */
268     for (i = 0; i < ppal->NumColors; i++)
269     {
270         /* Calculate distance in the color cube */
271         ulDiff = peColor.peRed - ppal->IndexedColors[i].peRed;
272         ulColorDiff = ulDiff * ulDiff;
273         ulDiff = peColor.peGreen - ppal->IndexedColors[i].peGreen;
274         ulColorDiff += ulDiff * ulDiff;
275         ulDiff = peColor.peBlue - ppal->IndexedColors[i].peBlue;
276         ulColorDiff += ulDiff * ulDiff;
277 
278         /* Check for a better match */
279         if (ulColorDiff < ulMinimalDiff)
280         {
281             ulBestIndex = i;
282             ulMinimalDiff = ulColorDiff;
283 
284             /* Break on exact match */
285             if (ulMinimalDiff == 0) break;
286         }
287     }
288 
289     return ulBestIndex;
290 }
291 
292 ULONG
293 NTAPI
294 PALETTE_ulGetNearestBitFieldsIndex(PALETTE* ppal, ULONG ulColor)
295 {
296     ULONG ulNewColor;
297 
298     // FIXME: HACK, should be stored already
299     ppal->ulRedShift = CalculateShift(RGB(0xff,0,0), ppal->RedMask);
300     ppal->ulGreenShift = CalculateShift(RGB(0,0xff,0), ppal->GreenMask);
301     ppal->ulBlueShift = CalculateShift(RGB(0,0,0xff), ppal->BlueMask);
302 
303     ulNewColor = _rotl(ulColor, ppal->ulRedShift) & ppal->RedMask;
304     ulNewColor |= _rotl(ulColor, ppal->ulGreenShift) & ppal->GreenMask;
305     ulNewColor |= _rotl(ulColor, ppal->ulBlueShift) & ppal->BlueMask;
306 
307    return ulNewColor;
308 }
309 
310 ULONG
311 NTAPI
312 PALETTE_ulGetNearestIndex(PALETTE* ppal, ULONG ulColor)
313 {
314     if (ppal->flFlags & PAL_INDEXED) // Use fl & PALINDEXED
315         return PALETTE_ulGetNearestPaletteIndex(ppal, ulColor);
316     else
317         return PALETTE_ulGetNearestBitFieldsIndex(ppal, ulColor);
318 }
319 
320 VOID
321 NTAPI
322 PALETTE_vGetBitMasks(PPALETTE ppal, PULONG pulColors)
323 {
324     ASSERT(pulColors);
325 
326     if (ppal->flFlags & PAL_INDEXED || ppal->flFlags & PAL_RGB)
327     {
328         pulColors[0] = RGB(0xFF, 0x00, 0x00);
329         pulColors[1] = RGB(0x00, 0xFF, 0x00);
330         pulColors[2] = RGB(0x00, 0x00, 0xFF);
331     }
332     else if (ppal->flFlags & PAL_BGR)
333     {
334         pulColors[0] = RGB(0x00, 0x00, 0xFF);
335         pulColors[1] = RGB(0x00, 0xFF, 0x00);
336         pulColors[2] = RGB(0xFF, 0x00, 0x00);
337     }
338     else if (ppal->flFlags & PAL_BITFIELDS)
339     {
340         pulColors[0] = ppal->RedMask;
341         pulColors[1] = ppal->GreenMask;
342         pulColors[2] = ppal->BlueMask;
343     }
344 }
345 
346 VOID
347 FASTCALL
348 ColorCorrection(PPALETTE PalGDI, PPALETTEENTRY PaletteEntry, ULONG Colors)
349 {
350     PPDEVOBJ ppdev = (PPDEVOBJ)PalGDI->hPDev;
351 
352     if (!ppdev) return;
353 
354     if (ppdev->flFlags & PDEV_GAMMARAMP_TABLE)
355     {
356         ULONG i;
357         PGAMMARAMP GammaRamp = (PGAMMARAMP)ppdev->pvGammaRamp;
358         for ( i = 0; i < Colors; i++)
359         {
360             PaletteEntry[i].peRed   += GammaRamp->Red[i];
361             PaletteEntry[i].peGreen += GammaRamp->Green[i];
362             PaletteEntry[i].peBlue  += GammaRamp->Blue[i];
363         }
364     }
365     return;
366 }
367 
368 /** Display Driver Interface **************************************************/
369 
370 /*
371  * @implemented
372  */
373 HPALETTE
374 APIENTRY
375 EngCreatePalette(
376     ULONG iMode,
377     ULONG cColors,
378     ULONG *pulColors,
379     ULONG flRed,
380     ULONG flGreen,
381     ULONG flBlue)
382 {
383     PPALETTE ppal;
384     HPALETTE hpal;
385 
386     ppal = PALETTE_AllocPalette(iMode, cColors, (PPALETTEENTRY)pulColors, flRed, flGreen, flBlue);
387     if (!ppal) return NULL;
388 
389     hpal = GDIOBJ_hInsertObject(&ppal->BaseObject, GDI_OBJ_HMGR_PUBLIC);
390     if (!hpal)
391     {
392         DPRINT1("Could not insert palette into handle table.\n");
393         GDIOBJ_vFreeObject(&ppal->BaseObject);
394         return NULL;
395     }
396 
397     PALETTE_UnlockPalette(ppal);
398     return hpal;
399 }
400 
401 /*
402  * @implemented
403  */
404 BOOL
405 APIENTRY
406 EngDeletePalette(IN HPALETTE hpal)
407 {
408     PPALETTE ppal;
409 
410     ppal = PALETTE_ShareLockPalette(hpal);
411     if (!ppal) return FALSE;
412 
413     GDIOBJ_vDeleteObject(&ppal->BaseObject);
414 
415     return TRUE;
416 }
417 
418 /*
419  * @implemented
420  */
421 ULONG
422 APIENTRY
423 PALOBJ_cGetColors(PALOBJ *PalObj, ULONG Start, ULONG Colors, ULONG *PaletteEntry)
424 {
425     PALETTE *PalGDI;
426 
427     PalGDI = (PALETTE*)PalObj;
428 
429     if (Start >= PalGDI->NumColors)
430         return 0;
431 
432     Colors = min(Colors, PalGDI->NumColors - Start);
433 
434     /* NOTE: PaletteEntry ULONGs are in the same order as PALETTEENTRY. */
435     RtlCopyMemory(PaletteEntry, PalGDI->IndexedColors + Start, sizeof(ULONG) * Colors);
436 
437     if (PalGDI->flFlags & PAL_GAMMACORRECTION)
438         ColorCorrection(PalGDI, (PPALETTEENTRY)PaletteEntry, Colors);
439 
440     return Colors;
441 }
442 
443 
444 /** Systemcall Interface ******************************************************/
445 
446 HPALETTE
447 NTAPI
448 GreCreatePaletteInternal(
449     IN LPLOGPALETTE pLogPal,
450     IN UINT cEntries)
451 {
452     HPALETTE hpal = NULL;
453     PPALETTE ppal;
454 
455     pLogPal->palNumEntries = cEntries;
456     ppal = PALETTE_AllocPalWithHandle(PAL_INDEXED,
457                                       cEntries,
458                                       pLogPal->palPalEntry,
459                                       0, 0, 0);
460 
461     if (ppal != NULL)
462     {
463         PALETTE_ValidateFlags(ppal->IndexedColors, ppal->NumColors);
464 
465         hpal = ppal->BaseObject.hHmgr;
466         PALETTE_UnlockPalette(ppal);
467     }
468 
469     return hpal;
470 }
471 
472 /*
473  * @implemented
474  */
475 HPALETTE
476 APIENTRY
477 NtGdiCreatePaletteInternal(
478     IN LPLOGPALETTE plogpalUser,
479     IN UINT cEntries)
480 {
481     HPALETTE hpal = NULL;
482     PPALETTE ppal;
483     ULONG i, cjSize;
484 
485     ppal = PALETTE_AllocPalWithHandle(PAL_INDEXED, cEntries, NULL, 0, 0, 0);
486     if (ppal == NULL)
487     {
488         return NULL;
489     }
490 
491     cjSize = FIELD_OFFSET(LOGPALETTE, palPalEntry[cEntries]);
492 
493     _SEH2_TRY
494     {
495         ProbeForRead(plogpalUser, cjSize, 1);
496 
497         for (i = 0; i < cEntries; i++)
498         {
499             ppal->IndexedColors[i] = plogpalUser->palPalEntry[i];
500         }
501     }
502     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
503     {
504         GDIOBJ_vDeleteObject(&ppal->BaseObject);
505         _SEH2_YIELD(return NULL);
506     }
507     _SEH2_END;
508 
509     PALETTE_ValidateFlags(ppal->IndexedColors, cEntries);
510     hpal = ppal->BaseObject.hHmgr;
511     PALETTE_UnlockPalette(ppal);
512 
513     return hpal;
514 }
515 
516 HPALETTE
517 APIENTRY
518 NtGdiCreateHalftonePalette(HDC  hDC)
519 {
520     int i, r, g, b;
521     PALETTEENTRY PalEntries[256];
522     PPALETTE ppal;
523     PDC pdc;
524     HPALETTE hpal = NULL;
525 
526     pdc = DC_LockDc(hDC);
527     if (!pdc)
528     {
529         EngSetLastError(ERROR_INVALID_HANDLE);
530         return NULL;
531     }
532 
533     RtlZeroMemory(PalEntries, sizeof(PalEntries));
534 
535     /* First and last ten entries are default ones */
536     for (i = 0; i < 10; i++)
537     {
538         PalEntries[i].peRed = g_sysPalTemplate[i].peRed;
539         PalEntries[i].peGreen = g_sysPalTemplate[i].peGreen;
540         PalEntries[i].peBlue = g_sysPalTemplate[i].peBlue;
541 
542         PalEntries[246 + i].peRed = g_sysPalTemplate[10 + i].peRed;
543         PalEntries[246 + i].peGreen = g_sysPalTemplate[10 + i].peGreen;
544         PalEntries[246 + i].peBlue = g_sysPalTemplate[10 + i].peBlue;
545     }
546 
547     ppal = PALETTE_ShareLockPalette(pdc->dclevel.hpal);
548     if (ppal && (ppal->flFlags & PAL_INDEXED))
549     {
550         /* FIXME: optimize the palette for the current palette */
551         UNIMPLEMENTED;
552     }
553     else
554     {
555         for (r = 0; r < 6; r++)
556         {
557             for (g = 0; g < 6; g++)
558             {
559                 for (b = 0; b < 6; b++)
560                 {
561                     i = r + g*6 + b*36 + 10;
562                     PalEntries[i].peRed = r * 51;
563                     PalEntries[i].peGreen = g * 51;
564                     PalEntries[i].peBlue = b * 51;
565                 }
566             }
567         }
568 
569         for (i = 216; i < 246; i++)
570         {
571             int v = (i - 216) << 3;
572             PalEntries[i].peRed = v;
573             PalEntries[i].peGreen = v;
574             PalEntries[i].peBlue = v;
575         }
576     }
577 
578     if (ppal)
579         PALETTE_ShareUnlockPalette(ppal);
580 
581     DC_UnlockDc(pdc);
582 
583     ppal = PALETTE_AllocPalWithHandle(PAL_INDEXED, 256, PalEntries, 0, 0, 0);
584     if (ppal)
585     {
586         hpal = ppal->BaseObject.hHmgr;
587         PALETTE_UnlockPalette(ppal);
588     }
589 
590     return hpal;
591 }
592 
593 BOOL
594 APIENTRY
595 NtGdiResizePalette(
596     HPALETTE hpal,
597     UINT Entries)
598 {
599 /*  PALOBJ *palPtr = (PALOBJ*)AccessUserObject(hPal);
600   UINT cPrevEnt, prevVer;
601   INT prevsize, size = sizeof(LOGPALETTE) + (cEntries - 1) * sizeof(PALETTEENTRY);
602   XLATEOBJ *XlateObj = NULL;
603 
604   if(!palPtr) return FALSE;
605   cPrevEnt = palPtr->logpalette->palNumEntries;
606   prevVer = palPtr->logpalette->palVersion;
607   prevsize = sizeof(LOGPALETTE) + (cPrevEnt - 1) * sizeof(PALETTEENTRY) + sizeof(int*) + sizeof(GDIOBJHDR);
608   size += sizeof(int*) + sizeof(GDIOBJHDR);
609   XlateObj = palPtr->logicalToSystem;
610 
611   if (!(palPtr = GDI_ReallocObject(size, hPal, palPtr))) return FALSE;
612 
613   if(XlateObj)
614   {
615     XLATEOBJ *NewXlateObj = (int*) HeapReAlloc(GetProcessHeap(), 0, XlateObj, cEntries * sizeof(int));
616     if(NewXlateObj == NULL)
617     {
618       ERR("Can not resize logicalToSystem -- out of memory!\n");
619       GDI_ReleaseObj( hPal );
620       return FALSE;
621     }
622     palPtr->logicalToSystem = NewXlateObj;
623   }
624 
625   if(cEntries > cPrevEnt)
626   {
627     if(XlateObj) memset(palPtr->logicalToSystem + cPrevEnt, 0, (cEntries - cPrevEnt)*sizeof(int));
628     memset( (BYTE*)palPtr + prevsize, 0, size - prevsize );
629     PALETTE_ValidateFlags((PALETTEENTRY*)((BYTE*)palPtr + prevsize), cEntries - cPrevEnt );
630   }
631   palPtr->logpalette->palNumEntries = cEntries;
632   palPtr->logpalette->palVersion = prevVer;
633 //    GDI_ReleaseObj( hPal );
634   return TRUE; */
635 
636   UNIMPLEMENTED;
637   return FALSE;
638 }
639 
640 BOOL
641 APIENTRY
642 NtGdiGetColorAdjustment(
643     HDC hdc,
644     LPCOLORADJUSTMENT pca)
645 {
646     UNIMPLEMENTED;
647     return FALSE;
648 }
649 
650 BOOL
651 APIENTRY
652 NtGdiSetColorAdjustment(
653     HDC hdc,
654     LPCOLORADJUSTMENT pca)
655 {
656     UNIMPLEMENTED;
657     return FALSE;
658 }
659 
660 COLORREF
661 APIENTRY
662 NtGdiGetNearestColor(
663     _In_ HDC hDC,
664     _In_ COLORREF Color)
665 {
666     COLORREF nearest = CLR_INVALID;
667     PDC dc;
668     EXLATEOBJ exlo;
669     PPALETTE ppal;
670 
671     dc = DC_LockDc(hDC);
672 
673     if(dc == NULL)
674     {
675         EngSetLastError(ERROR_INVALID_HANDLE);
676         return CLR_INVALID;
677     }
678 
679     /// FIXME: shouldn't dereference pSurface while the PDEV is not locked
680     if(dc->dclevel.pSurface == NULL)
681         ppal = gppalMono;
682     else
683         ppal = dc->dclevel.pSurface->ppal;
684 
685     /* Translate the color to the DC format */
686     Color = TranslateCOLORREF(dc, Color);
687 
688     /* XLATE it back to RGB color space */
689     EXLATEOBJ_vInitialize(&exlo,
690         ppal,
691         &gpalRGB,
692         0,
693         RGB(0xff, 0xff, 0xff),
694         RGB(0, 0, 0));
695 
696     nearest = XLATEOBJ_iXlate(&exlo.xlo, Color);
697 
698     EXLATEOBJ_vCleanup(&exlo);
699 
700     /* We're done */
701     DC_UnlockDc(dc);
702 
703    return nearest;
704 }
705 
706 UINT
707 APIENTRY
708 NtGdiGetNearestPaletteIndex(
709     HPALETTE hpal,
710     COLORREF crColor)
711 {
712     PPALETTE ppal = PALETTE_ShareLockPalette(hpal);
713     UINT index  = 0;
714 
715     if (ppal)
716     {
717         if (ppal->flFlags & PAL_INDEXED)
718         {
719             /* Return closest match for the given RGB color */
720             index = PALETTE_ulGetNearestPaletteIndex(ppal, crColor);
721         }
722         // else SetLastError ?
723         PALETTE_ShareUnlockPalette(ppal);
724     }
725 
726     return index;
727 }
728 
729 UINT
730 FASTCALL
731 IntGdiRealizePalette(HDC hDC)
732 {
733     UINT realize = 0;
734     PDC pdc;
735     PALETTE *ppalSurf, *ppalDC;
736 
737     pdc = DC_LockDc(hDC);
738     if (!pdc)
739     {
740         EngSetLastError(ERROR_INVALID_HANDLE);
741         return 0;
742     }
743 
744     if (!pdc->dclevel.pSurface)
745     {
746         goto cleanup;
747     }
748 
749     if (pdc->dctype == DCTYPE_DIRECT)
750     {
751         static BOOL g_WarnedOnce = FALSE;
752         if (!g_WarnedOnce)
753         {
754             g_WarnedOnce = TRUE;
755             UNIMPLEMENTED;
756         }
757         goto cleanup;
758     }
759 
760     /// FIXME: shouldn't dereference pSurface while the PDEV is not locked
761     ppalSurf = pdc->dclevel.pSurface->ppal;
762     ppalDC = pdc->dclevel.ppal;
763 
764     if (!(ppalSurf->flFlags & PAL_INDEXED))
765     {
766         // FIXME: Set error?
767         goto cleanup;
768     }
769 
770     ASSERT(ppalDC->flFlags & PAL_INDEXED);
771 
772     DPRINT1("RealizePalette unimplemented for %s\n",
773             (pdc->dctype == DCTYPE_MEMORY ? "memory managed DCs" : "device DCs"));
774 
775 cleanup:
776     DC_UnlockDc(pdc);
777     return realize;
778 }
779 
780 UINT APIENTRY
781 IntAnimatePalette(HPALETTE hPal,
782                   UINT StartIndex,
783                   UINT NumEntries,
784                   CONST PPALETTEENTRY PaletteColors)
785 {
786     UINT ret = 0;
787 
788     if( hPal != NtGdiGetStockObject(DEFAULT_PALETTE) )
789     {
790         PPALETTE palPtr;
791         UINT pal_entries;
792         const PALETTEENTRY *pptr = PaletteColors;
793 
794         palPtr = PALETTE_ShareLockPalette(hPal);
795         if (!palPtr) return FALSE;
796 
797         pal_entries = palPtr->NumColors;
798         if (StartIndex >= pal_entries)
799         {
800             PALETTE_ShareUnlockPalette(palPtr);
801             return FALSE;
802         }
803         if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex;
804 
805         for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++)
806         {
807             /* According to MSDN, only animate PC_RESERVED colours */
808             if (palPtr->IndexedColors[StartIndex].peFlags & PC_RESERVED)
809             {
810                 memcpy( &palPtr->IndexedColors[StartIndex], pptr,
811                         sizeof(PALETTEENTRY) );
812                 ret++;
813                 PALETTE_ValidateFlags(&palPtr->IndexedColors[StartIndex], 1);
814             }
815         }
816 
817         PALETTE_ShareUnlockPalette(palPtr);
818 
819 #if 0
820 /* FIXME: This is completely broken! We cannot call UserGetDesktopWindow
821    without first acquiring the USER lock. But the whole process here is
822    screwed anyway. Instead of messing with the desktop DC, we need to
823    check, whether the palette is associated with a PDEV and whether that
824    PDEV supports palette operations. Then we need to call pfnDrvSetPalette.
825    But since IntGdiRealizePalette() is not even implemented for direct DCs,
826    we can as well just do nothing, that will at least not ASSERT!
827    I leave the whole thing here, to scare people away, who want to "fix" it. */
828 
829         /* Immediately apply the new palette if current window uses it */
830         Wnd = UserGetDesktopWindow();
831         hDC =  UserGetWindowDC(Wnd);
832         dc = DC_LockDc(hDC);
833         if (NULL != dc)
834         {
835             if (dc->dclevel.hpal == hPal)
836             {
837                 DC_UnlockDc(dc);
838                 IntGdiRealizePalette(hDC);
839             }
840             else
841                 DC_UnlockDc(dc);
842         }
843         UserReleaseDC(Wnd,hDC, FALSE);
844 #endif // 0
845     }
846     return ret;
847 }
848 
849 UINT APIENTRY
850 IntGetPaletteEntries(
851     HPALETTE hpal,
852     UINT StartIndex,
853     UINT  Entries,
854     LPPALETTEENTRY  pe)
855 {
856     PPALETTE palGDI;
857     UINT numEntries;
858 
859     palGDI = (PPALETTE) PALETTE_ShareLockPalette(hpal);
860     if (NULL == palGDI)
861     {
862         return 0;
863     }
864 
865     numEntries = palGDI->NumColors;
866     if (NULL != pe)
867     {
868         if (numEntries < StartIndex + Entries)
869         {
870             Entries = numEntries - StartIndex;
871         }
872         if (numEntries <= StartIndex)
873         {
874             PALETTE_ShareUnlockPalette(palGDI);
875             return 0;
876         }
877         memcpy(pe, palGDI->IndexedColors + StartIndex, Entries * sizeof(PALETTEENTRY));
878     }
879     else
880     {
881         Entries = numEntries;
882     }
883 
884     PALETTE_ShareUnlockPalette(palGDI);
885     return Entries;
886 }
887 
888 UINT APIENTRY
889 IntGetSystemPaletteEntries(HDC  hDC,
890                            UINT  StartIndex,
891                            UINT  Entries,
892                            LPPALETTEENTRY  pe)
893 {
894     PPALETTE palGDI = NULL;
895     PDC dc = NULL;
896     UINT EntriesSize = 0;
897     UINT Ret = 0;
898 
899     if (Entries == 0)
900     {
901         EngSetLastError(ERROR_INVALID_PARAMETER);
902         return 0;
903     }
904 
905     if (pe != NULL)
906     {
907         EntriesSize = Entries * sizeof(pe[0]);
908         if (Entries != EntriesSize / sizeof(pe[0]))
909         {
910             /* Integer overflow! */
911             EngSetLastError(ERROR_INVALID_PARAMETER);
912             return 0;
913         }
914     }
915 
916     if (!(dc = DC_LockDc(hDC)))
917     {
918         EngSetLastError(ERROR_INVALID_HANDLE);
919         return 0;
920     }
921 
922     palGDI = PALETTE_ShareLockPalette(dc->dclevel.hpal);
923     if (palGDI != NULL)
924     {
925         if (pe != NULL)
926         {
927             if (StartIndex >= palGDI->NumColors)
928                 Entries = 0;
929             else if (Entries > palGDI->NumColors - StartIndex)
930                 Entries = palGDI->NumColors - StartIndex;
931 
932             memcpy(pe,
933                    palGDI->IndexedColors + StartIndex,
934                    Entries * sizeof(pe[0]));
935 
936             Ret = Entries;
937         }
938         else
939         {
940             Ret = dc->ppdev->gdiinfo.ulNumPalReg;
941         }
942     }
943 
944     if (palGDI != NULL)
945         PALETTE_ShareUnlockPalette(palGDI);
946 
947     if (dc != NULL)
948         DC_UnlockDc(dc);
949 
950     return Ret;
951 }
952 
953 UINT
954 APIENTRY
955 IntSetPaletteEntries(
956     HPALETTE  hpal,
957     UINT  Start,
958     UINT  Entries,
959     CONST LPPALETTEENTRY pe)
960 {
961     PPALETTE palGDI;
962     ULONG numEntries;
963 
964     if (GDI_HANDLE_IS_STOCKOBJ(hpal))
965     {
966     	return 0;
967     }
968 
969     palGDI = PALETTE_ShareLockPalette(hpal);
970     if (!palGDI) return 0;
971 
972     numEntries = palGDI->NumColors;
973     if (Start >= numEntries)
974     {
975         PALETTE_ShareUnlockPalette(palGDI);
976         return 0;
977     }
978     if (numEntries < Start + Entries)
979     {
980         Entries = numEntries - Start;
981     }
982     memcpy(palGDI->IndexedColors + Start, pe, Entries * sizeof(PALETTEENTRY));
983     PALETTE_ShareUnlockPalette(palGDI);
984 
985     return Entries;
986 }
987 
988 ULONG
989 APIENTRY
990 GreGetSetColorTable(
991     HDC hdc,
992     ULONG iStartIndex,
993     ULONG cEntries,
994     RGBQUAD *prgbColors,
995     BOOL bSet)
996 {
997     PDC pdc;
998     PSURFACE psurf;
999     PPALETTE ppal = NULL;
1000     ULONG i, iEndIndex, iResult = 0;
1001 
1002     /* Lock the DC */
1003     pdc = DC_LockDc(hdc);
1004     if (!pdc)
1005     {
1006         return 0;
1007     }
1008 
1009     /* Get the surface from the DC */
1010     psurf = pdc->dclevel.pSurface;
1011 
1012     /* Check if we have the default surface */
1013     if (psurf == NULL)
1014     {
1015         /* Use a mono palette */
1016         if (!bSet)
1017             ppal = gppalMono;
1018     }
1019     else if (psurf->SurfObj.iType == STYPE_BITMAP)
1020     {
1021         /* Get the palette of the surface */
1022         ppal = psurf->ppal;
1023     }
1024 
1025     /* Check if this is an indexed palette and the range is ok */
1026     if (ppal && (ppal->flFlags & PAL_INDEXED) &&
1027         (iStartIndex < ppal->NumColors))
1028     {
1029         /* Calculate the end of the operation */
1030         iEndIndex = min(iStartIndex + cEntries, ppal->NumColors);
1031 
1032         /* Check what operation to perform */
1033         if (bSet)
1034         {
1035             /* Loop all colors and set the palette entries */
1036             for (i = iStartIndex; i < iEndIndex; i++, prgbColors++)
1037             {
1038                 ppal->IndexedColors[i].peRed = prgbColors->rgbRed;
1039                 ppal->IndexedColors[i].peGreen = prgbColors->rgbGreen;
1040                 ppal->IndexedColors[i].peBlue = prgbColors->rgbBlue;
1041             }
1042 
1043             /* Mark the dc brushes invalid */
1044             pdc->pdcattr->ulDirty_ |= DIRTY_FILL|DIRTY_LINE|
1045                                       DIRTY_BACKGROUND|DIRTY_TEXT;
1046         }
1047         else
1048         {
1049             /* Loop all colors and get the palette entries */
1050             for (i = iStartIndex; i < iEndIndex; i++, prgbColors++)
1051             {
1052                 prgbColors->rgbRed = ppal->IndexedColors[i].peRed;
1053                 prgbColors->rgbGreen = ppal->IndexedColors[i].peGreen;
1054                 prgbColors->rgbBlue = ppal->IndexedColors[i].peBlue;
1055                 prgbColors->rgbReserved = 0;
1056             }
1057         }
1058 
1059         /* Calculate how many entries were modified */
1060         iResult = iEndIndex - iStartIndex;
1061     }
1062 
1063     /* Unlock the DC */
1064     DC_UnlockDc(pdc);
1065 
1066     return iResult;
1067 }
1068 
1069 __kernel_entry
1070 LONG
1071 APIENTRY
1072 NtGdiDoPalette(
1073     _In_ HGDIOBJ hObj,
1074     _In_ WORD iStart,
1075     _In_ WORD cEntries,
1076     _When_(bInbound!=0, _In_reads_bytes_(cEntries*sizeof(PALETTEENTRY)))
1077     _When_(bInbound==0, _Out_writes_bytes_(cEntries*sizeof(PALETTEENTRY))) LPVOID pUnsafeEntries,
1078     _In_ DWORD iFunc,
1079     _In_ BOOL bInbound)
1080 {
1081 	LONG ret;
1082 	LPVOID pEntries = NULL;
1083 	SIZE_T cjSize;
1084 
1085 	if (pUnsafeEntries)
1086 	{
1087 		if (cEntries == 0)
1088 			return 0;
1089 
1090 		cjSize = cEntries * sizeof(PALETTEENTRY);
1091 		pEntries = ExAllocatePoolWithTag(PagedPool, cjSize, TAG_PALETTE);
1092 		if (!pEntries)
1093 			return 0;
1094 
1095 		if (bInbound)
1096 		{
1097 			_SEH2_TRY
1098 			{
1099 				ProbeForRead(pUnsafeEntries, cjSize, 1);
1100 				memcpy(pEntries, pUnsafeEntries, cjSize);
1101 			}
1102 			_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1103 			{
1104 				ExFreePoolWithTag(pEntries, TAG_PALETTE);
1105 				_SEH2_YIELD(return 0);
1106 			}
1107 			_SEH2_END
1108 		}
1109 		else
1110 		{
1111 		    /* Zero it out, so we don't accidentally leak kernel data */
1112 		    RtlZeroMemory(pEntries, cjSize);
1113 		}
1114 	}
1115 
1116 	ret = 0;
1117 	switch(iFunc)
1118 	{
1119 		case GdiPalAnimate:
1120 			if (pEntries)
1121 				ret = IntAnimatePalette((HPALETTE)hObj, iStart, cEntries, (CONST PPALETTEENTRY)pEntries);
1122 			break;
1123 
1124 		case GdiPalSetEntries:
1125 			if (pEntries)
1126 				ret = IntSetPaletteEntries((HPALETTE)hObj, iStart, cEntries, (CONST LPPALETTEENTRY)pEntries);
1127 			break;
1128 
1129 		case GdiPalGetEntries:
1130 			ret = IntGetPaletteEntries((HPALETTE)hObj, iStart, cEntries, (LPPALETTEENTRY)pEntries);
1131 			break;
1132 
1133 		case GdiPalGetSystemEntries:
1134 			ret = IntGetSystemPaletteEntries((HDC)hObj, iStart, cEntries, (LPPALETTEENTRY)pEntries);
1135 			break;
1136 
1137 		case GdiPalSetColorTable:
1138 			if (pEntries)
1139 				ret = GreGetSetColorTable((HDC)hObj, iStart, cEntries, (RGBQUAD*)pEntries, TRUE);
1140 			break;
1141 
1142 		case GdiPalGetColorTable:
1143 			if (pEntries)
1144 				ret = GreGetSetColorTable((HDC)hObj, iStart, cEntries, (RGBQUAD*)pEntries, FALSE);
1145 			break;
1146 	}
1147 
1148 	if (pEntries)
1149 	{
1150 		if (!bInbound && (ret > 0))
1151 		{
1152 			cjSize = min(cEntries, ret) * sizeof(PALETTEENTRY);
1153 			_SEH2_TRY
1154 			{
1155 				ProbeForWrite(pUnsafeEntries, cjSize, 1);
1156 				memcpy(pUnsafeEntries, pEntries, cjSize);
1157 			}
1158 			_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1159 			{
1160 				ret = 0;
1161 			}
1162 			_SEH2_END
1163 		}
1164 		ExFreePoolWithTag(pEntries, TAG_PALETTE);
1165 	}
1166 
1167 	return ret;
1168 }
1169 
1170 UINT APIENTRY
1171 NtGdiSetSystemPaletteUse(HDC hDC, UINT Usage)
1172 {
1173     UINT old = SystemPaletteUse;
1174 
1175     /* Device doesn't support colour palettes */
1176     if (!(NtGdiGetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE)) {
1177         return SYSPAL_ERROR;
1178     }
1179 
1180     switch (Usage)
1181 	{
1182 		case SYSPAL_NOSTATIC:
1183         case SYSPAL_NOSTATIC256:
1184         case SYSPAL_STATIC:
1185 				SystemPaletteUse = Usage;
1186 				break;
1187 
1188         default:
1189 				old=SYSPAL_ERROR;
1190 				break;
1191 	}
1192 
1193  return old;
1194 }
1195 
1196 UINT
1197 APIENTRY
1198 NtGdiGetSystemPaletteUse(HDC hDC)
1199 {
1200     return SystemPaletteUse;
1201 }
1202 
1203 BOOL
1204 APIENTRY
1205 NtGdiUpdateColors(HDC hDC)
1206 {
1207    PWND Wnd;
1208    BOOL calledFromUser, ret;
1209    USER_REFERENCE_ENTRY Ref;
1210 
1211    calledFromUser = UserIsEntered();
1212 
1213    if (!calledFromUser){
1214       UserEnterExclusive();
1215    }
1216 
1217    Wnd = UserGetWindowObject(IntWindowFromDC(hDC));
1218    if (Wnd == NULL)
1219    {
1220       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1221 
1222       if (!calledFromUser){
1223          UserLeave();
1224       }
1225 
1226       return FALSE;
1227    }
1228 
1229    UserRefObjectCo(Wnd, &Ref);
1230    ret = co_UserRedrawWindow(Wnd, NULL, 0, RDW_INVALIDATE);
1231    UserDerefObjectCo(Wnd);
1232 
1233    if (!calledFromUser){
1234       UserLeave();
1235    }
1236 
1237    return ret;
1238 }
1239 
1240 BOOL
1241 APIENTRY
1242 NtGdiUnrealizeObject(HGDIOBJ hgdiobj)
1243 {
1244    BOOL Ret = FALSE;
1245    PPALETTE palGDI;
1246 
1247    if ( !hgdiobj ||
1248         GDI_HANDLE_IS_STOCKOBJ(hgdiobj) ||
1249         !GDI_HANDLE_IS_TYPE(hgdiobj, GDI_OBJECT_TYPE_PALETTE) )
1250       return Ret;
1251 
1252    palGDI = PALETTE_ShareLockPalette(hgdiobj);
1253    if (!palGDI) return FALSE;
1254 
1255    // FIXME!!
1256    // Need to do something!!!
1257    // Zero out Current and Old Translated pointers?
1258    //
1259    Ret = TRUE;
1260    PALETTE_ShareUnlockPalette(palGDI);
1261    return Ret;
1262 }
1263 
1264 __kernel_entry
1265 HPALETTE
1266 APIENTRY
1267 NtGdiEngCreatePalette(
1268     _In_ ULONG iMode,
1269     _In_ ULONG cColors,
1270     _In_ ULONG *pulColors,
1271     _In_ FLONG flRed,
1272     _In_ FLONG flGreen,
1273     _In_ FLONG flBlue)
1274 {
1275     HPALETTE hPal = NULL;
1276     ULONG *pulcSafe, ulColors[WINDDI_MAXSETPALETTECOLORS];
1277 
1278     if ( cColors > MAX_PALCOLORS ) return NULL;
1279 
1280     if ( cColors <= WINDDI_MAXSETPALETTECOLORS )
1281     {
1282         pulcSafe = ulColors;
1283     }
1284     else
1285     {
1286         pulcSafe = ExAllocatePoolWithTag(PagedPool, cColors * sizeof(ULONG), GDITAG_UMPD );
1287     }
1288 
1289         _SEH2_TRY
1290     {
1291         ProbeForRead( pulColors, cColors * sizeof(ULONG), 1);
1292         RtlCopyMemory( pulcSafe, pulColors, cColors * sizeof(ULONG) );
1293     }
1294     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1295     {
1296         SetLastNtError(_SEH2_GetExceptionCode());
1297         if ( cColors > WINDDI_MAXSETPALETTECOLORS ) ExFreePoolWithTag( pulcSafe, GDITAG_UMPD );
1298         _SEH2_YIELD(return hPal);
1299     }
1300     _SEH2_END;
1301 
1302     hPal = EngCreatePalette( iMode/*|PAL_SETPOWNER*/, cColors, pulcSafe, flRed, flGreen, flBlue );
1303 
1304     if ( cColors > WINDDI_MAXSETPALETTECOLORS ) ExFreePoolWithTag( pulcSafe, GDITAG_UMPD );
1305 
1306     return hPal;
1307 }
1308 
1309 __kernel_entry
1310 BOOL
1311 APIENTRY
1312 NtGdiEngDeletePalette(
1313     _In_ HPALETTE hPal)
1314 {
1315     return EngDeletePalette(hPal);
1316 }
1317 
1318 /* EOF */
1319