Synchronize with trunk.
[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 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
154 if (!Ret) return Ret;
155
156 _SEH2_TRY
157 {
158 ProbeForWrite(Ramp, sizeof(GAMMARAMP), 1);
159 RtlCopyMemory(Ramp, SafeRamp, sizeof(GAMMARAMP));
160 }
161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
162 {
163 Status = _SEH2_GetExceptionCode();
164 }
165 _SEH2_END;
166
167 DC_UnlockDc(dc);
168 ExFreePoolWithTag(SafeRamp, GDITAG_ICM);
169
170 if (!NT_SUCCESS(Status))
171 {
172 SetLastNtError(Status);
173 return FALSE;
174 }
175 return Ret;
176 }
177
178 BOOL
179 APIENTRY
180 NtGdiSetColorSpace(IN HDC hdc,
181 IN HCOLORSPACE hColorSpace)
182 {
183 PDC pDC;
184 PDC_ATTR pdcattr;
185 PCOLORSPACE pCS;
186
187 pDC = DC_LockDc(hdc);
188 if (!pDC)
189 {
190 EngSetLastError(ERROR_INVALID_HANDLE);
191 return FALSE;
192 }
193 pdcattr = pDC->pdcattr;
194
195 if (pdcattr->hColorSpace == hColorSpace)
196 {
197 DC_UnlockDc(pDC);
198 return TRUE;
199 }
200
201 pCS = COLORSPACEOBJ_LockCS(hColorSpace);
202 if (!pCS)
203 {
204 EngSetLastError(ERROR_INVALID_HANDLE);
205 return FALSE;
206 }
207
208 if (pDC->dclevel.pColorSpace)
209 {
210 GDIOBJ_vDereferenceObject((POBJ) pDC->dclevel.pColorSpace);
211 }
212
213 pDC->dclevel.pColorSpace = pCS;
214 pdcattr->hColorSpace = hColorSpace;
215
216 COLORSPACEOBJ_UnlockCS(pCS);
217 DC_UnlockDc(pDC);
218 return TRUE;
219 }
220
221 BOOL
222 FASTCALL
223 UpdateDeviceGammaRamp(HDEV hPDev)
224 {
225 BOOL Ret = FALSE;
226 PPALETTE palGDI;
227 PALOBJ *palPtr;
228 PPDEVOBJ pGDev = (PPDEVOBJ)hPDev;
229
230 if ((pGDev->devinfo.iDitherFormat == BMF_8BPP) ||
231 (pGDev->devinfo.iDitherFormat == BMF_16BPP) ||
232 (pGDev->devinfo.iDitherFormat == BMF_24BPP) ||
233 (pGDev->devinfo.iDitherFormat == BMF_32BPP))
234 {
235 if (pGDev->DriverFunctions.IcmSetDeviceGammaRamp)
236 return pGDev->DriverFunctions.IcmSetDeviceGammaRamp( pGDev->dhpdev,
237 IGRF_RGB_256WORDS,
238 pGDev->pvGammaRamp);
239
240 if ((pGDev->devinfo.iDitherFormat != BMF_8BPP) ||
241 !(pGDev->gdiinfo.flRaster & RC_PALETTE)) return FALSE;
242
243 if (!(pGDev->flFlags & PDEV_GAMMARAMP_TABLE)) return FALSE;
244
245 palGDI = PALETTE_ShareLockPalette(pGDev->devinfo.hpalDefault);
246 if(!palGDI) return FALSE;
247 palPtr = (PALOBJ*) palGDI;
248
249 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
250 palGDI->flFlags |= PAL_GAMMACORRECTION;
251 else
252 palGDI->flFlags &= ~PAL_GAMMACORRECTION;
253
254 if (!(pGDev->flFlags & PDEV_DRIVER_PUNTED_CALL)) // No punting, we hook
255 {
256 // BMF_8BPP only!
257 // PALOBJ_cGetColors check mode flags and update Gamma Correction.
258 // Set the HDEV to pal and go.
259 palGDI->hPDev = hPDev;
260 Ret = pGDev->DriverFunctions.SetPalette(pGDev->dhpdev,
261 palPtr,
262 0,
263 0,
264 palGDI->NumColors);
265 }
266 PALETTE_ShareUnlockPalette(palGDI);
267 return Ret;
268 }
269 else
270 return FALSE;
271 }
272
273 //
274 // ICM registry subkey sets internal brightness range, gamma range is 128 or
275 // 256 when icm is init.
276 INT IcmGammaRangeSet = 128; // <- Make it global
277
278 BOOL
279 FASTCALL
280 IntSetDeviceGammaRamp(HDEV hPDev, PGAMMARAMP Ramp, BOOL Test)
281 {
282 WORD IcmGR, i, R, G, B;
283 BOOL Ret = FALSE, TstPeak;
284 PPDEVOBJ pGDev = (PPDEVOBJ) hPDev;
285
286 if (!hPDev) return FALSE;
287
288 if (!(pGDev->flFlags & PDEV_DISPLAY )) return FALSE;
289
290 if ((pGDev->devinfo.iDitherFormat == BMF_8BPP) ||
291 (pGDev->devinfo.iDitherFormat == BMF_16BPP) ||
292 (pGDev->devinfo.iDitherFormat == BMF_24BPP) ||
293 (pGDev->devinfo.iDitherFormat == BMF_32BPP))
294 {
295 if (!pGDev->DriverFunctions.IcmSetDeviceGammaRamp)
296 {
297 // No driver support
298 if (!(pGDev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP))
299 {
300 // Driver does not support Gamma Ramp, so test to see we
301 // have BMF_8BPP only and palette operation support.
302 if ((pGDev->devinfo.iDitherFormat != BMF_8BPP) ||
303 !(pGDev->gdiinfo.flRaster & RC_PALETTE)) return FALSE;
304 }
305 }
306
307 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
308 {
309 if (RtlCompareMemory(pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP)) ==
310 sizeof(GAMMARAMP)) return TRUE;
311 }
312
313 // Verify Ramp is inside range.
314 IcmGR = -IcmGammaRangeSet;
315 TstPeak = (Test == FALSE);
316 for (i = 0; i < 256; i++)
317 {
318 R = Ramp->Red[i] / 256;
319 G = Ramp->Green[i] / 256;
320 B = Ramp->Blue[i] / 256;
321
322 if (R >= IcmGR)
323 {
324 if (R <= IcmGammaRangeSet + i)
325 {
326 if ((G >= IcmGR) &&
327 (G <= IcmGammaRangeSet + i) &&
328 (B >= IcmGR) &&
329 (B <= IcmGammaRangeSet + i) ) continue;
330 }
331 }
332
333 if (Test) return Ret; // Don't set and return.
334
335 // No test override, check max range
336 if (TstPeak)
337 {
338 if ((R != (IcmGR * 256)) ||
339 (G != (IcmGR * 256)) ||
340 (B != (IcmGR * 256)) ) TstPeak = FALSE; // W/i range.
341 }
342 }
343 // ReactOS allocates a ramp even if it is 8BPP and Palette only.
344 // This way we have a record of the change in memory.
345 if (!pGDev->pvGammaRamp && !(pGDev->flFlags & PDEV_GAMMARAMP_TABLE))
346 {
347 // If the above is true and we have nothing allocated, create it.
348 pGDev->pvGammaRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), GDITAG_ICM);
349 pGDev->flFlags |= PDEV_GAMMARAMP_TABLE;
350 }
351
352 if (pGDev->pvGammaRamp)
353 RtlCopyMemory(pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP));
354
355 Ret = UpdateDeviceGammaRamp(hPDev);
356 }
357
358 return Ret;
359 }
360
361 BOOL
362 APIENTRY
363 NtGdiSetDeviceGammaRamp(
364 HDC hDC,
365 LPVOID Ramp)
366 {
367 BOOL Ret;
368 PDC dc;
369 NTSTATUS Status = STATUS_SUCCESS;
370 PGAMMARAMP SafeRamp;
371 if (!Ramp) return FALSE;
372
373 dc = DC_LockDc(hDC);
374 if (!dc)
375 {
376 EngSetLastError(ERROR_INVALID_HANDLE);
377 return FALSE;
378 }
379
380 SafeRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), GDITAG_ICM);
381 if (!SafeRamp)
382 {
383 DC_UnlockDc(dc);
384 EngSetLastError(STATUS_NO_MEMORY);
385 return FALSE;
386 }
387 _SEH2_TRY
388 {
389 ProbeForRead(Ramp, sizeof(GAMMARAMP), 1);
390 RtlCopyMemory(SafeRamp, Ramp, sizeof(GAMMARAMP));
391 }
392 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
393 {
394 Status = _SEH2_GetExceptionCode();
395 }
396 _SEH2_END;
397
398 if (!NT_SUCCESS(Status))
399 {
400 DC_UnlockDc(dc);
401 ExFreePoolWithTag(SafeRamp, GDITAG_ICM);
402 SetLastNtError(Status);
403 return FALSE;
404 }
405
406 Ret = IntSetDeviceGammaRamp((HDEV)dc->ppdev, SafeRamp, TRUE);
407 DC_UnlockDc(dc);
408 ExFreePoolWithTag(SafeRamp, GDITAG_ICM);
409 return Ret;
410 }
411
412 INT
413 APIENTRY
414 NtGdiSetIcmMode(HDC hDC,
415 ULONG nCommand,
416 ULONG EnableICM) // ulMode
417 {
418 /* FIXME: This should be coded someday */
419 if (EnableICM == ICM_OFF)
420 {
421 return ICM_OFF;
422 }
423 if (EnableICM == ICM_ON)
424 {
425 return 0;
426 }
427 if (EnableICM == ICM_QUERY)
428 {
429 return ICM_OFF;
430 }
431
432 return 0;
433 }
434
435 /* EOF */