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