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