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