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