[NtGdi]
[reactos.git] / reactos / win32ss / gdi / ntgdi / icm.c
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 */