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