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