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