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