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