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