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