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