xref: /reactos/win32ss/gdi/ntgdi/icm.c (revision 1734f297)
1 /*
2  * PROJECT:         ReactOS Win32k Subsystem
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            win32ss/gdi/ntgdi/icm.c
5  * PURPOSE:         Icm functions
6  * PROGRAMMERS:     ...
7  */
8 
9 #include <win32k.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 HCOLORSPACE hStockColorSpace = NULL;
15 
16 
17 HCOLORSPACE
18 FASTCALL
19 IntGdiCreateColorSpace(
20     PLOGCOLORSPACEEXW pLogColorSpace)
21 {
22     PCOLORSPACE pCS;
23     HCOLORSPACE hCS;
24 
25     pCS = COLORSPACEOBJ_AllocCSWithHandle();
26     if (pCS == NULL) return NULL;
27 
28     hCS = pCS->BaseObject.hHmgr;
29 
30     pCS->lcsColorSpace = pLogColorSpace->lcsColorSpace;
31     pCS->dwFlags = pLogColorSpace->dwFlags;
32 
33     COLORSPACEOBJ_UnlockCS(pCS);
34     return hCS;
35 }
36 
37 BOOL
38 FASTCALL
39 IntGdiDeleteColorSpace(
40     HCOLORSPACE hColorSpace)
41 {
42     BOOL Ret = FALSE;
43 
44     if ((hColorSpace != hStockColorSpace) &&
45         (GDI_HANDLE_GET_TYPE(hColorSpace) == GDILoObjType_LO_ICMLCS_TYPE))
46     {
47         Ret = GreDeleteObject(hColorSpace);
48         if (!Ret) EngSetLastError(ERROR_INVALID_PARAMETER);
49     }
50 
51     return Ret;
52 }
53 
54 HANDLE
55 APIENTRY
56 NtGdiCreateColorSpace(
57     IN PLOGCOLORSPACEEXW pLogColorSpace)
58 {
59     LOGCOLORSPACEEXW Safelcs;
60     NTSTATUS Status = STATUS_SUCCESS;
61 
62     _SEH2_TRY
63     {
64         ProbeForRead( pLogColorSpace, sizeof(LOGCOLORSPACEEXW), 1);
65         RtlCopyMemory(&Safelcs, pLogColorSpace, sizeof(LOGCOLORSPACEEXW));
66     }
67     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
68     {
69         Status = _SEH2_GetExceptionCode();
70     }
71     _SEH2_END;
72 
73     if (!NT_SUCCESS(Status))
74     {
75         SetLastNtError(Status);
76         return NULL;
77     }
78 
79     return IntGdiCreateColorSpace(&Safelcs);
80 }
81 
82 BOOL
83 APIENTRY
84 NtGdiDeleteColorSpace(
85     IN HANDLE hColorSpace)
86 {
87     return IntGdiDeleteColorSpace(hColorSpace);
88 }
89 
90 BOOL
91 FASTCALL
92 IntGetDeviceGammaRamp(HDEV hPDev, PGAMMARAMP Ramp)
93 {
94     PPDEVOBJ pGDev = (PPDEVOBJ) hPDev;
95     int i;
96 
97     if (!(pGDev->flFlags & PDEV_DISPLAY)) return FALSE;
98 
99     if ((pGDev->devinfo.iDitherFormat == BMF_8BPP)  ||
100         (pGDev->devinfo.iDitherFormat == BMF_16BPP) ||
101         (pGDev->devinfo.iDitherFormat == BMF_24BPP) ||
102         (pGDev->devinfo.iDitherFormat == BMF_32BPP))
103     {
104         if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
105         {
106             RtlCopyMemory(Ramp, pGDev->pvGammaRamp, sizeof(GAMMARAMP));
107         }
108         else
109         {
110             // Generate the 256-colors array
111             for (i = 0; i < 256; i++ )
112             {
113                 int NewValue = i * 256;
114 
115                 Ramp->Red[i] = Ramp->Green[i] = Ramp->Blue[i] = ((WORD)NewValue);
116             }
117         }
118         return TRUE;
119     }
120 
121     return FALSE;
122 }
123 
124 BOOL
125 APIENTRY
126 NtGdiGetDeviceGammaRamp(
127     HDC hDC,
128     LPVOID Ramp)
129 {
130     BOOL Ret;
131     PDC dc;
132     NTSTATUS Status = STATUS_SUCCESS;
133     PGAMMARAMP SafeRamp;
134 
135     if (!Ramp) return FALSE;
136 
137     dc = DC_LockDc(hDC);
138     if (!dc)
139     {
140         EngSetLastError(ERROR_INVALID_HANDLE);
141         return FALSE;
142     }
143 
144     SafeRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), GDITAG_ICM);
145     if (!SafeRamp)
146     {
147         DC_UnlockDc(dc);
148         EngSetLastError(STATUS_NO_MEMORY);
149         return FALSE;
150     }
151 
152     Ret = IntGetDeviceGammaRamp((HDEV)dc->ppdev, SafeRamp);
153     if (!Ret)
154     {
155         DC_UnlockDc(dc);
156         ExFreePoolWithTag(SafeRamp, GDITAG_ICM);
157         return Ret;
158     }
159 
160     _SEH2_TRY
161     {
162         ProbeForWrite(Ramp, sizeof(GAMMARAMP), 1);
163         RtlCopyMemory(Ramp, SafeRamp, sizeof(GAMMARAMP));
164     }
165     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
166     {
167         Status = _SEH2_GetExceptionCode();
168     }
169     _SEH2_END;
170 
171     DC_UnlockDc(dc);
172     ExFreePoolWithTag(SafeRamp, GDITAG_ICM);
173 
174     if (!NT_SUCCESS(Status))
175     {
176         SetLastNtError(Status);
177         return FALSE;
178     }
179     return Ret;
180 }
181 
182 BOOL
183 APIENTRY
184 NtGdiSetColorSpace(IN HDC hdc,
185                    IN HCOLORSPACE hColorSpace)
186 {
187     PDC pDC;
188     PDC_ATTR pdcattr;
189     PCOLORSPACE pCS;
190 
191     pDC = DC_LockDc(hdc);
192     if (!pDC)
193     {
194         EngSetLastError(ERROR_INVALID_HANDLE);
195         return FALSE;
196     }
197     pdcattr = pDC->pdcattr;
198 
199     if (pdcattr->hColorSpace == hColorSpace)
200     {
201         DC_UnlockDc(pDC);
202         return TRUE;
203     }
204 
205     pCS = COLORSPACEOBJ_LockCS(hColorSpace);
206     if (!pCS)
207     {
208         EngSetLastError(ERROR_INVALID_HANDLE);
209         return FALSE;
210     }
211 
212     if (pDC->dclevel.pColorSpace)
213     {
214         GDIOBJ_vDereferenceObject((POBJ) pDC->dclevel.pColorSpace);
215     }
216 
217     pDC->dclevel.pColorSpace = pCS;
218     pdcattr->hColorSpace = hColorSpace;
219 
220     COLORSPACEOBJ_UnlockCS(pCS);
221     DC_UnlockDc(pDC);
222     return TRUE;
223 }
224 
225 BOOL
226 FASTCALL
227 UpdateDeviceGammaRamp(HDEV hPDev)
228 {
229     BOOL Ret = FALSE;
230     PPALETTE palGDI;
231     PALOBJ *palPtr;
232     PPDEVOBJ pGDev = (PPDEVOBJ)hPDev;
233 
234     if ((pGDev->devinfo.iDitherFormat == BMF_8BPP)  ||
235         (pGDev->devinfo.iDitherFormat == BMF_16BPP) ||
236         (pGDev->devinfo.iDitherFormat == BMF_24BPP) ||
237         (pGDev->devinfo.iDitherFormat == BMF_32BPP))
238     {
239         if (pGDev->DriverFunctions.IcmSetDeviceGammaRamp)
240             return pGDev->DriverFunctions.IcmSetDeviceGammaRamp( pGDev->dhpdev,
241                     IGRF_RGB_256WORDS,
242                     pGDev->pvGammaRamp);
243 
244         if ((pGDev->devinfo.iDitherFormat != BMF_8BPP) ||
245             !(pGDev->gdiinfo.flRaster & RC_PALETTE)) return FALSE;
246 
247         if (!(pGDev->flFlags & PDEV_GAMMARAMP_TABLE)) return FALSE;
248 
249         palGDI = PALETTE_ShareLockPalette(pGDev->devinfo.hpalDefault);
250         if(!palGDI) return FALSE;
251         palPtr = (PALOBJ*) palGDI;
252 
253         if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
254             palGDI->flFlags |= PAL_GAMMACORRECTION;
255         else
256             palGDI->flFlags &= ~PAL_GAMMACORRECTION;
257 
258         if (!(pGDev->flFlags & PDEV_DRIVER_PUNTED_CALL)) // No punting, we hook
259         {
260             // BMF_8BPP only!
261             // PALOBJ_cGetColors check mode flags and update Gamma Correction.
262             // Set the HDEV to pal and go.
263             palGDI->hPDev = hPDev;
264             Ret = pGDev->DriverFunctions.SetPalette(pGDev->dhpdev,
265                                                     palPtr,
266                                                     0,
267                                                     0,
268                                                     palGDI->NumColors);
269         }
270         PALETTE_ShareUnlockPalette(palGDI);
271         return Ret;
272     }
273     else
274         return FALSE;
275 }
276 
277 //
278 // ICM registry subkey sets internal brightness range, gamma range is 128 or
279 // 256 when icm is init.
280 INT IcmGammaRangeSet = 128; // <- Make it global
281 
282 BOOL
283 FASTCALL
284 IntSetDeviceGammaRamp(HDEV hPDev, PGAMMARAMP Ramp, BOOL Test)
285 {
286     WORD IcmGR, i, R, G, B;
287     BOOL Ret = FALSE, TstPeak;
288     PPDEVOBJ pGDev = (PPDEVOBJ) hPDev;
289 
290     if (!hPDev) return FALSE;
291 
292     if (!(pGDev->flFlags & PDEV_DISPLAY )) return FALSE;
293 
294     if ((pGDev->devinfo.iDitherFormat == BMF_8BPP)  ||
295         (pGDev->devinfo.iDitherFormat == BMF_16BPP) ||
296         (pGDev->devinfo.iDitherFormat == BMF_24BPP) ||
297         (pGDev->devinfo.iDitherFormat == BMF_32BPP))
298     {
299         if (!pGDev->DriverFunctions.IcmSetDeviceGammaRamp)
300         {
301             // No driver support
302             if (!(pGDev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP))
303             {
304                 // Driver does not support Gamma Ramp, so test to see we
305                 // have BMF_8BPP only and palette operation support.
306                 if ((pGDev->devinfo.iDitherFormat != BMF_8BPP) ||
307                     !(pGDev->gdiinfo.flRaster & RC_PALETTE))  return FALSE;
308             }
309         }
310 
311         if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
312         {
313             if (RtlCompareMemory(pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP)) ==
314                     sizeof(GAMMARAMP)) return TRUE;
315         }
316 
317         // Verify Ramp is inside range.
318         IcmGR = -IcmGammaRangeSet;
319         TstPeak = (Test == FALSE);
320         for (i = 0; i < 256; i++)
321         {
322             R = Ramp->Red[i]   / 256;
323             G = Ramp->Green[i] / 256;
324             B = Ramp->Blue[i]  / 256;
325 
326             if (R >= IcmGR)
327             {
328                 if (R <= IcmGammaRangeSet + i)
329                 {
330                     if ((G >= IcmGR) &&
331                         (G <= IcmGammaRangeSet + i) &&
332                         (B >= IcmGR) &&
333                         (B <= IcmGammaRangeSet + i) ) continue;
334                 }
335             }
336 
337             if (Test) return Ret; // Don't set and return.
338 
339             // No test override, check max range
340             if (TstPeak)
341             {
342                 if ((R != (IcmGR * 256)) ||
343                     (G != (IcmGR * 256)) ||
344                     (B != (IcmGR * 256)) ) TstPeak = FALSE; // W/i range.
345             }
346         }
347         // ReactOS allocates a ramp even if it is 8BPP and Palette only.
348         // This way we have a record of the change in memory.
349         if (!pGDev->pvGammaRamp && !(pGDev->flFlags & PDEV_GAMMARAMP_TABLE))
350         {
351             // If the above is true and we have nothing allocated, create it.
352             pGDev->pvGammaRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), GDITAG_ICM);
353             pGDev->flFlags |= PDEV_GAMMARAMP_TABLE;
354         }
355 
356         if (pGDev->pvGammaRamp)
357             RtlCopyMemory(pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP));
358 
359         Ret = UpdateDeviceGammaRamp(hPDev);
360     }
361 
362     return Ret;
363 }
364 
365 BOOL
366 APIENTRY
367 NtGdiSetDeviceGammaRamp(
368     HDC hDC,
369     LPVOID Ramp)
370 {
371     BOOL Ret;
372     PDC dc;
373     NTSTATUS Status = STATUS_SUCCESS;
374     PGAMMARAMP SafeRamp;
375     if (!Ramp) return FALSE;
376 
377     dc = DC_LockDc(hDC);
378     if (!dc)
379     {
380         EngSetLastError(ERROR_INVALID_HANDLE);
381         return FALSE;
382     }
383 
384     SafeRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), GDITAG_ICM);
385     if (!SafeRamp)
386     {
387         DC_UnlockDc(dc);
388         EngSetLastError(STATUS_NO_MEMORY);
389         return FALSE;
390     }
391     _SEH2_TRY
392     {
393         ProbeForRead(Ramp, sizeof(GAMMARAMP), 1);
394         RtlCopyMemory(SafeRamp, Ramp, sizeof(GAMMARAMP));
395     }
396     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
397     {
398         Status = _SEH2_GetExceptionCode();
399     }
400     _SEH2_END;
401 
402     if (!NT_SUCCESS(Status))
403     {
404         DC_UnlockDc(dc);
405         ExFreePoolWithTag(SafeRamp, GDITAG_ICM);
406         SetLastNtError(Status);
407         return FALSE;
408     }
409 
410     Ret = IntSetDeviceGammaRamp((HDEV)dc->ppdev, SafeRamp, TRUE);
411     DC_UnlockDc(dc);
412     ExFreePoolWithTag(SafeRamp, GDITAG_ICM);
413     return Ret;
414 }
415 
416 INT
417 APIENTRY
418 NtGdiSetIcmMode(HDC  hDC,
419                 ULONG nCommand,
420                 ULONG EnableICM) // ulMode
421 {
422     /* FIXME: This should be coded someday  */
423     if (EnableICM == ICM_OFF)
424     {
425         return  ICM_OFF;
426     }
427     if (EnableICM == ICM_ON)
428     {
429         return  0;
430     }
431     if (EnableICM == ICM_QUERY)
432     {
433         return  ICM_OFF;
434     }
435 
436     return  0;
437 }
438 
439 /* EOF */
440