xref: /reactos/win32ss/gdi/ntgdi/palette.c (revision c8d07514)
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!");
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 i, 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     // FIXME: Should we resize ppalSurf if it's too small?
773     realize = (ppalDC->NumColors < ppalSurf->NumColors) ? ppalDC->NumColors : ppalSurf->NumColors;
774 
775     for (i=0; i<realize; i++)
776     {
777         InterlockedExchange((LONG*)&ppalSurf->IndexedColors[i], *(LONG*)&ppalDC->IndexedColors[i]);
778     }
779 
780 cleanup:
781     DC_UnlockDc(pdc);
782     return realize;
783 }
784 
785 UINT APIENTRY
786 IntAnimatePalette(HPALETTE hPal,
787                   UINT StartIndex,
788                   UINT NumEntries,
789                   CONST PPALETTEENTRY PaletteColors)
790 {
791     UINT ret = 0;
792 
793     if( hPal != NtGdiGetStockObject(DEFAULT_PALETTE) )
794     {
795         PPALETTE palPtr;
796         UINT pal_entries;
797         const PALETTEENTRY *pptr = PaletteColors;
798 
799         palPtr = PALETTE_ShareLockPalette(hPal);
800         if (!palPtr) return FALSE;
801 
802         pal_entries = palPtr->NumColors;
803         if (StartIndex >= pal_entries)
804         {
805             PALETTE_ShareUnlockPalette(palPtr);
806             return FALSE;
807         }
808         if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex;
809 
810         for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++)
811         {
812             /* According to MSDN, only animate PC_RESERVED colours */
813             if (palPtr->IndexedColors[StartIndex].peFlags & PC_RESERVED)
814             {
815                 memcpy( &palPtr->IndexedColors[StartIndex], pptr,
816                         sizeof(PALETTEENTRY) );
817                 ret++;
818                 PALETTE_ValidateFlags(&palPtr->IndexedColors[StartIndex], 1);
819             }
820         }
821 
822         PALETTE_ShareUnlockPalette(palPtr);
823 
824 #if 0
825 /* FIXME: This is completely broken! We cannot call UserGetDesktopWindow
826    without first acquiring the USER lock. But the whole process here is
827    screwed anyway. Instead of messing with the desktop DC, we need to
828    check, whether the palette is associated with a PDEV and whether that
829    PDEV supports palette operations. Then we need to call pfnDrvSetPalette.
830    But since IntGdiRealizePalette() is not even implemented for direct DCs,
831    we can as well just do nothing, that will at least not ASSERT!
832    I leave the whole thing here, to scare people away, who want to "fix" it. */
833 
834         /* Immediately apply the new palette if current window uses it */
835         Wnd = UserGetDesktopWindow();
836         hDC =  UserGetWindowDC(Wnd);
837         dc = DC_LockDc(hDC);
838         if (NULL != dc)
839         {
840             if (dc->dclevel.hpal == hPal)
841             {
842                 DC_UnlockDc(dc);
843                 IntGdiRealizePalette(hDC);
844             }
845             else
846                 DC_UnlockDc(dc);
847         }
848         UserReleaseDC(Wnd,hDC, FALSE);
849 #endif // 0
850     }
851     return ret;
852 }
853 
854 UINT APIENTRY
855 IntGetPaletteEntries(
856     HPALETTE hpal,
857     UINT StartIndex,
858     UINT  Entries,
859     LPPALETTEENTRY  pe)
860 {
861     PPALETTE palGDI;
862     UINT numEntries;
863 
864     palGDI = (PPALETTE) PALETTE_ShareLockPalette(hpal);
865     if (NULL == palGDI)
866     {
867         return 0;
868     }
869 
870     numEntries = palGDI->NumColors;
871     if (NULL != pe)
872     {
873         if (numEntries < StartIndex + Entries)
874         {
875             Entries = numEntries - StartIndex;
876         }
877         if (numEntries <= StartIndex)
878         {
879             PALETTE_ShareUnlockPalette(palGDI);
880             return 0;
881         }
882         memcpy(pe, palGDI->IndexedColors + StartIndex, Entries * sizeof(PALETTEENTRY));
883     }
884     else
885     {
886         Entries = numEntries;
887     }
888 
889     PALETTE_ShareUnlockPalette(palGDI);
890     return Entries;
891 }
892 
893 UINT APIENTRY
894 IntGetSystemPaletteEntries(HDC  hDC,
895                            UINT  StartIndex,
896                            UINT  Entries,
897                            LPPALETTEENTRY  pe)
898 {
899     PPALETTE palGDI = NULL;
900     PDC dc = NULL;
901     UINT EntriesSize = 0;
902     UINT Ret = 0;
903 
904     if (Entries == 0)
905     {
906         EngSetLastError(ERROR_INVALID_PARAMETER);
907         return 0;
908     }
909 
910     if (pe != NULL)
911     {
912         EntriesSize = Entries * sizeof(pe[0]);
913         if (Entries != EntriesSize / sizeof(pe[0]))
914         {
915             /* Integer overflow! */
916             EngSetLastError(ERROR_INVALID_PARAMETER);
917             return 0;
918         }
919     }
920 
921     if (!(dc = DC_LockDc(hDC)))
922     {
923         EngSetLastError(ERROR_INVALID_HANDLE);
924         return 0;
925     }
926 
927     palGDI = PALETTE_ShareLockPalette(dc->dclevel.hpal);
928     if (palGDI != NULL)
929     {
930         if (pe != NULL)
931         {
932             if (StartIndex >= palGDI->NumColors)
933                 Entries = 0;
934             else if (Entries > palGDI->NumColors - StartIndex)
935                 Entries = palGDI->NumColors - StartIndex;
936 
937             memcpy(pe,
938                    palGDI->IndexedColors + StartIndex,
939                    Entries * sizeof(pe[0]));
940 
941             Ret = Entries;
942         }
943         else
944         {
945             Ret = dc->ppdev->gdiinfo.ulNumPalReg;
946         }
947     }
948 
949     if (palGDI != NULL)
950         PALETTE_ShareUnlockPalette(palGDI);
951 
952     if (dc != NULL)
953         DC_UnlockDc(dc);
954 
955     return Ret;
956 }
957 
958 UINT
959 APIENTRY
960 IntSetPaletteEntries(
961     HPALETTE  hpal,
962     UINT  Start,
963     UINT  Entries,
964     CONST LPPALETTEENTRY pe)
965 {
966     PPALETTE palGDI;
967     ULONG numEntries;
968 
969     if ((UINT_PTR)hpal & GDI_HANDLE_STOCK_MASK)
970     {
971     	return 0;
972     }
973 
974     palGDI = PALETTE_ShareLockPalette(hpal);
975     if (!palGDI) return 0;
976 
977     numEntries = palGDI->NumColors;
978     if (Start >= numEntries)
979     {
980         PALETTE_ShareUnlockPalette(palGDI);
981         return 0;
982     }
983     if (numEntries < Start + Entries)
984     {
985         Entries = numEntries - Start;
986     }
987     memcpy(palGDI->IndexedColors + Start, pe, Entries * sizeof(PALETTEENTRY));
988     PALETTE_ShareUnlockPalette(palGDI);
989 
990     return Entries;
991 }
992 
993 ULONG
994 APIENTRY
995 GreGetSetColorTable(
996     HDC hdc,
997     ULONG iStartIndex,
998     ULONG cEntries,
999     RGBQUAD *prgbColors,
1000     BOOL bSet)
1001 {
1002     PDC pdc;
1003     PSURFACE psurf;
1004     PPALETTE ppal = NULL;
1005     ULONG i, iEndIndex, iResult = 0;
1006 
1007     /* Lock the DC */
1008     pdc = DC_LockDc(hdc);
1009     if (!pdc)
1010     {
1011         return 0;
1012     }
1013 
1014     /* Get the surface from the DC */
1015     psurf = pdc->dclevel.pSurface;
1016 
1017     /* Check if we have the default surface */
1018     if (psurf == NULL)
1019     {
1020         /* Use a mono palette */
1021         if (!bSet)
1022             ppal = gppalMono;
1023     }
1024     else if (psurf->SurfObj.iType == STYPE_BITMAP)
1025     {
1026         /* Get the palette of the surface */
1027         ppal = psurf->ppal;
1028     }
1029 
1030     /* Check if this is an indexed palette and the range is ok */
1031     if (ppal && (ppal->flFlags & PAL_INDEXED) &&
1032         (iStartIndex < ppal->NumColors))
1033     {
1034         /* Calculate the end of the operation */
1035         iEndIndex = min(iStartIndex + cEntries, ppal->NumColors);
1036 
1037         /* Check what operation to perform */
1038         if (bSet)
1039         {
1040             /* Loop all colors and set the palette entries */
1041             for (i = iStartIndex; i < iEndIndex; i++, prgbColors++)
1042             {
1043                 ppal->IndexedColors[i].peRed = prgbColors->rgbRed;
1044                 ppal->IndexedColors[i].peGreen = prgbColors->rgbGreen;
1045                 ppal->IndexedColors[i].peBlue = prgbColors->rgbBlue;
1046             }
1047 
1048             /* Mark the dc brushes invalid */
1049             pdc->pdcattr->ulDirty_ |= DIRTY_FILL|DIRTY_LINE|
1050                                       DIRTY_BACKGROUND|DIRTY_TEXT;
1051         }
1052         else
1053         {
1054             /* Loop all colors and get the palette entries */
1055             for (i = iStartIndex; i < iEndIndex; i++, prgbColors++)
1056             {
1057                 prgbColors->rgbRed = ppal->IndexedColors[i].peRed;
1058                 prgbColors->rgbGreen = ppal->IndexedColors[i].peGreen;
1059                 prgbColors->rgbBlue = ppal->IndexedColors[i].peBlue;
1060                 prgbColors->rgbReserved = 0;
1061             }
1062         }
1063 
1064         /* Calculate how many entries were modified */
1065         iResult = iEndIndex - iStartIndex;
1066     }
1067 
1068     /* Unlock the DC */
1069     DC_UnlockDc(pdc);
1070 
1071     return iResult;
1072 }
1073 
1074 __kernel_entry
1075 LONG
1076 APIENTRY
1077 NtGdiDoPalette(
1078     _In_ HGDIOBJ hObj,
1079     _In_ WORD iStart,
1080     _In_ WORD cEntries,
1081     _When_(bInbound!=0, _In_reads_bytes_(cEntries*sizeof(PALETTEENTRY)))
1082     _When_(bInbound==0, _Out_writes_bytes_(cEntries*sizeof(PALETTEENTRY))) LPVOID pUnsafeEntries,
1083     _In_ DWORD iFunc,
1084     _In_ BOOL bInbound)
1085 {
1086 	LONG ret;
1087 	LPVOID pEntries = NULL;
1088 	SIZE_T cjSize;
1089 
1090 	if (pUnsafeEntries)
1091 	{
1092 		if (cEntries == 0)
1093 			return 0;
1094 
1095 		cjSize = cEntries * sizeof(PALETTEENTRY);
1096 		pEntries = ExAllocatePoolWithTag(PagedPool, cjSize, TAG_PALETTE);
1097 		if (!pEntries)
1098 			return 0;
1099 
1100 		if (bInbound)
1101 		{
1102 			_SEH2_TRY
1103 			{
1104 				ProbeForRead(pUnsafeEntries, cjSize, 1);
1105 				memcpy(pEntries, pUnsafeEntries, cjSize);
1106 			}
1107 			_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1108 			{
1109 				ExFreePoolWithTag(pEntries, TAG_PALETTE);
1110 				_SEH2_YIELD(return 0);
1111 			}
1112 			_SEH2_END
1113 		}
1114 		else
1115 		{
1116 		    /* Zero it out, so we don't accidentally leak kernel data */
1117 		    RtlZeroMemory(pEntries, cjSize);
1118 		}
1119 	}
1120 
1121 	ret = 0;
1122 	switch(iFunc)
1123 	{
1124 		case GdiPalAnimate:
1125 			if (pEntries)
1126 				ret = IntAnimatePalette((HPALETTE)hObj, iStart, cEntries, (CONST PPALETTEENTRY)pEntries);
1127 			break;
1128 
1129 		case GdiPalSetEntries:
1130 			if (pEntries)
1131 				ret = IntSetPaletteEntries((HPALETTE)hObj, iStart, cEntries, (CONST LPPALETTEENTRY)pEntries);
1132 			break;
1133 
1134 		case GdiPalGetEntries:
1135 			ret = IntGetPaletteEntries((HPALETTE)hObj, iStart, cEntries, (LPPALETTEENTRY)pEntries);
1136 			break;
1137 
1138 		case GdiPalGetSystemEntries:
1139 			ret = IntGetSystemPaletteEntries((HDC)hObj, iStart, cEntries, (LPPALETTEENTRY)pEntries);
1140 			break;
1141 
1142 		case GdiPalSetColorTable:
1143 			if (pEntries)
1144 				ret = GreGetSetColorTable((HDC)hObj, iStart, cEntries, (RGBQUAD*)pEntries, TRUE);
1145 			break;
1146 
1147 		case GdiPalGetColorTable:
1148 			if (pEntries)
1149 				ret = GreGetSetColorTable((HDC)hObj, iStart, cEntries, (RGBQUAD*)pEntries, FALSE);
1150 			break;
1151 	}
1152 
1153 	if (pEntries)
1154 	{
1155 		if (!bInbound && (ret > 0))
1156 		{
1157 			cjSize = min(cEntries, ret) * sizeof(PALETTEENTRY);
1158 			_SEH2_TRY
1159 			{
1160 				ProbeForWrite(pUnsafeEntries, cjSize, 1);
1161 				memcpy(pUnsafeEntries, pEntries, cjSize);
1162 			}
1163 			_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1164 			{
1165 				ret = 0;
1166 			}
1167 			_SEH2_END
1168 		}
1169 		ExFreePoolWithTag(pEntries, TAG_PALETTE);
1170 	}
1171 
1172 	return ret;
1173 }
1174 
1175 UINT APIENTRY
1176 NtGdiSetSystemPaletteUse(HDC hDC, UINT Usage)
1177 {
1178     UINT old = SystemPaletteUse;
1179 
1180     /* Device doesn't support colour palettes */
1181     if (!(NtGdiGetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE)) {
1182         return SYSPAL_ERROR;
1183     }
1184 
1185     switch (Usage)
1186 	{
1187 		case SYSPAL_NOSTATIC:
1188         case SYSPAL_NOSTATIC256:
1189         case SYSPAL_STATIC:
1190 				SystemPaletteUse = Usage;
1191 				break;
1192 
1193         default:
1194 				old=SYSPAL_ERROR;
1195 				break;
1196 	}
1197 
1198  return old;
1199 }
1200 
1201 UINT
1202 APIENTRY
1203 NtGdiGetSystemPaletteUse(HDC hDC)
1204 {
1205     return SystemPaletteUse;
1206 }
1207 
1208 BOOL
1209 APIENTRY
1210 NtGdiUpdateColors(HDC hDC)
1211 {
1212    PWND Wnd;
1213    BOOL calledFromUser, ret;
1214    USER_REFERENCE_ENTRY Ref;
1215 
1216    calledFromUser = UserIsEntered();
1217 
1218    if (!calledFromUser){
1219       UserEnterExclusive();
1220    }
1221 
1222    Wnd = UserGetWindowObject(IntWindowFromDC(hDC));
1223    if (Wnd == NULL)
1224    {
1225       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1226 
1227       if (!calledFromUser){
1228          UserLeave();
1229       }
1230 
1231       return FALSE;
1232    }
1233 
1234    UserRefObjectCo(Wnd, &Ref);
1235    ret = co_UserRedrawWindow(Wnd, NULL, 0, RDW_INVALIDATE);
1236    UserDerefObjectCo(Wnd);
1237 
1238    if (!calledFromUser){
1239       UserLeave();
1240    }
1241 
1242    return ret;
1243 }
1244 
1245 BOOL
1246 APIENTRY
1247 NtGdiUnrealizeObject(HGDIOBJ hgdiobj)
1248 {
1249    BOOL Ret = FALSE;
1250    PPALETTE palGDI;
1251 
1252    if ( !hgdiobj ||
1253         ((UINT_PTR)hgdiobj & GDI_HANDLE_STOCK_MASK) ||
1254         !GDI_HANDLE_IS_TYPE(hgdiobj, GDI_OBJECT_TYPE_PALETTE) )
1255       return Ret;
1256 
1257    palGDI = PALETTE_ShareLockPalette(hgdiobj);
1258    if (!palGDI) return FALSE;
1259 
1260    // FIXME!!
1261    // Need to do something!!!
1262    // Zero out Current and Old Translated pointers?
1263    //
1264    Ret = TRUE;
1265    PALETTE_ShareUnlockPalette(palGDI);
1266    return Ret;
1267 }
1268 
1269 __kernel_entry
1270 HPALETTE
1271 APIENTRY
1272 NtGdiEngCreatePalette(
1273     _In_ ULONG iMode,
1274     _In_ ULONG cColors,
1275     _In_ ULONG *pulColors,
1276     _In_ FLONG flRed,
1277     _In_ FLONG flGreen,
1278     _In_ FLONG flBlue)
1279 {
1280     HPALETTE hPal = NULL;
1281     ULONG *pulcSafe, ulColors[WINDDI_MAXSETPALETTECOLORS];
1282 
1283     if ( cColors > MAX_PALCOLORS ) return NULL;
1284 
1285     if ( cColors <= WINDDI_MAXSETPALETTECOLORS )
1286     {
1287         pulcSafe = ulColors;
1288     }
1289     else
1290     {
1291         pulcSafe = ExAllocatePoolWithTag(PagedPool, cColors * sizeof(ULONG), GDITAG_UMPD );
1292     }
1293 
1294         _SEH2_TRY
1295     {
1296         ProbeForRead( pulColors, cColors * sizeof(ULONG), 1);
1297         RtlCopyMemory( pulcSafe, pulColors, cColors * sizeof(ULONG) );
1298     }
1299     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1300     {
1301         SetLastNtError(_SEH2_GetExceptionCode());
1302         if ( cColors > WINDDI_MAXSETPALETTECOLORS ) ExFreePoolWithTag( pulcSafe, GDITAG_UMPD );
1303         _SEH2_YIELD(return hPal);
1304     }
1305     _SEH2_END;
1306 
1307     hPal = EngCreatePalette( iMode/*|PAL_SETPOWNER*/, cColors, pulcSafe, flRed, flGreen, flBlue );
1308 
1309     if ( cColors > WINDDI_MAXSETPALETTECOLORS ) ExFreePoolWithTag( pulcSafe, GDITAG_UMPD );
1310 
1311     return hPal;
1312 }
1313 
1314 __kernel_entry
1315 BOOL
1316 APIENTRY
1317 NtGdiEngDeletePalette(
1318     _In_ HPALETTE hPal)
1319 {
1320     return EngDeletePalette(hPal);
1321 }
1322 
1323 /* EOF */
1324