[GDI32] Update Gdi Driver Header.
[reactos.git] / win32ss / gdi / ntgdi / palette.c
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 INIT_FUNCTION
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 */