Fix set device gamma ramp. Now we test the range of the ramp.
[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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$ */
20
21 #include <w32k.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 BOOL
27 STDCALL
28 NtGdiColorMatchToTarget(HDC hDC,
29 HDC hDCTarget,
30 DWORD Action)
31 {
32 UNIMPLEMENTED;
33 return FALSE;
34 }
35
36 HANDLE
37 APIENTRY
38 NtGdiCreateColorSpace(
39 IN PLOGCOLORSPACEEXW pLogColorSpace)
40 {
41 UNIMPLEMENTED;
42 return 0;
43 }
44
45 BOOL
46 APIENTRY
47 NtGdiDeleteColorSpace(
48 IN HANDLE hColorSpace)
49 {
50 UNIMPLEMENTED;
51 return FALSE;
52 }
53
54 INT
55 STDCALL
56 NtGdiEnumICMProfiles(HDC hDC,
57 LPWSTR lpstrBuffer,
58 UINT cch )
59 {
60 /*
61 * FIXME - build list of file names into lpstrBuffer.
62 * (MULTI-SZ would probably be best format)
63 * return (needed) length of buffer in bytes
64 */
65 UNIMPLEMENTED;
66 return 0;
67 }
68
69 HCOLORSPACE
70 STDCALL
71 NtGdiGetColorSpace(HDC hDC)
72 {
73 /* FIXME: Need to to whatever GetColorSpace actually does */
74 return 0;
75 }
76
77 BOOL
78 FASTCALL
79 IntGetDeviceGammaRamp(HDEV hPDev, PGAMMARAMP Ramp)
80 {
81 PGDIDEVICE pGDev = (PGDIDEVICE) hPDev;
82 int i;
83
84 if (!(pGDev->flFlags & PDEV_DISPLAY )) return FALSE;
85
86 if ((pGDev->DevInfo.iDitherFormat == BMF_8BPP) ||
87 (pGDev->DevInfo.iDitherFormat == BMF_16BPP) ||
88 (pGDev->DevInfo.iDitherFormat == BMF_24BPP) ||
89 (pGDev->DevInfo.iDitherFormat == BMF_32BPP))
90 {
91 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
92 RtlCopyMemory( Ramp,
93 pGDev->pvGammaRamp,
94 sizeof(GAMMARAMP));
95 else
96 // Generate the 256-colors array
97 for(i=0; i<256; i++ )
98 {
99 int NewValue = i * 256;
100 if (NewValue > 65535) NewValue = 65535;
101
102 Ramp->Red[i] = Ramp->Green[i] = Ramp->Blue[i] = ((WORD)NewValue);
103 }
104 return TRUE;
105 }
106 else
107 return FALSE;
108 }
109
110 BOOL
111 STDCALL
112 NtGdiGetDeviceGammaRamp(HDC hDC,
113 LPVOID Ramp)
114 {
115 BOOL Ret;
116 PDC dc;
117 NTSTATUS Status = STATUS_SUCCESS;
118 PGAMMARAMP SafeRamp;
119
120 if (!Ramp) return FALSE;
121
122 dc = DC_LockDc(hDC);
123 if (!dc)
124 {
125 SetLastWin32Error(ERROR_INVALID_HANDLE);
126 return FALSE;
127 }
128
129 SafeRamp = ExAllocatePool(PagedPool, sizeof(GAMMARAMP));
130 if (!SafeRamp)
131 {
132 DC_UnlockDc(dc);
133 SetLastWin32Error(STATUS_NO_MEMORY);
134 return FALSE;
135 }
136
137 Ret = IntGetDeviceGammaRamp((HDEV)dc->pPDev, SafeRamp);
138
139 if (!Ret) return Ret;
140
141 _SEH_TRY
142 {
143 ProbeForWrite( Ramp,
144 sizeof(PVOID),
145 1);
146 RtlCopyMemory( Ramp,
147 SafeRamp,
148 sizeof(GAMMARAMP));
149 }
150 _SEH_HANDLE
151 {
152 Status = _SEH_GetExceptionCode();
153 }
154 _SEH_END;
155
156 DC_UnlockDc(dc);
157 ExFreePool(SafeRamp);
158
159 if (!NT_SUCCESS(Status))
160 {
161 SetLastNtError(Status);
162 return FALSE;
163 }
164 return Ret;
165 }
166
167 BOOL
168 STDCALL
169 NtGdiGetICMProfile(HDC hDC,
170 LPDWORD NameSize,
171 LPWSTR Filename)
172 {
173 UNIMPLEMENTED;
174 return FALSE;
175 }
176
177 BOOL
178 STDCALL
179 NtGdiGetLogColorSpace(HCOLORSPACE hColorSpace,
180 LPLOGCOLORSPACEW Buffer,
181 DWORD Size)
182 {
183 UNIMPLEMENTED;
184 return FALSE;
185 }
186
187 BOOL
188 STDCALL
189 NtGdiSetColorSpace(IN HDC hdc,
190 IN HCOLORSPACE hColorSpace)
191 {
192 UNIMPLEMENTED;
193 return 0;
194 }
195
196 BOOL
197 FASTCALL
198 UpdateDeviceGammaRamp( HDEV hPDev )
199 {
200 BOOL Ret = FALSE;
201 PPALGDI palGDI;
202 PALOBJ *palPtr;
203 PGDIDEVICE pGDev = (PGDIDEVICE) hPDev;
204
205 if ((pGDev->DevInfo.iDitherFormat == BMF_8BPP) ||
206 (pGDev->DevInfo.iDitherFormat == BMF_16BPP) ||
207 (pGDev->DevInfo.iDitherFormat == BMF_24BPP) ||
208 (pGDev->DevInfo.iDitherFormat == BMF_32BPP))
209 {
210 if (pGDev->DriverFunctions.IcmSetDeviceGammaRamp)
211 return pGDev->DriverFunctions.IcmSetDeviceGammaRamp( pGDev->PDev,
212 IGRF_RGB_256WORDS,
213 pGDev->pvGammaRamp);
214
215 if ( (pGDev->DevInfo.iDitherFormat != BMF_8BPP) ||
216 !(pGDev->GDIInfo.flRaster & RC_PALETTE)) return FALSE;
217
218 if (!(pGDev->flFlags & PDEV_GAMMARAMP_TABLE)) return FALSE;
219
220 palGDI = PALETTE_LockPalette(pGDev->DevInfo.hpalDefault);
221 if(!palGDI) return FALSE;
222 palPtr = (PALOBJ*) palGDI;
223
224 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
225 palGDI->Mode |= PAL_GAMMACORRECTION;
226 else
227 palGDI->Mode &= ~PAL_GAMMACORRECTION;
228
229 if (!(pGDev->flFlags & PDEV_DRIVER_PUNTED_CALL)) // No punting, we hook
230 {
231 // BMF_8BPP only!
232 // PALOBJ_cGetColors check mode flags and update Gamma Correction.
233 // Set the HDEV to pal and go.
234 palGDI->hPDev = hPDev;
235 Ret = pGDev->DriverFunctions.SetPalette(pGDev->PDev,
236 palPtr,
237 0,
238 0,
239 palGDI->NumColors);
240 }
241 PALETTE_UnlockPalette(palGDI);
242 return Ret;
243 }
244 else
245 return FALSE;
246 }
247
248 //
249 // ICM registry subkey sets internal brightness range, gamma range is 128 or
250 // 256 when icm is init.
251 INT IcmGammaRangeSet = 128; // <- make it global
252
253 BOOL
254 FASTCALL
255 IntSetDeviceGammaRamp(HDEV hPDev, PGAMMARAMP Ramp, BOOL Test)
256 {
257 WORD IcmGR, i, R, G, B;
258 BOOL Ret = FALSE, TstPeak;
259 PGDIDEVICE pGDev = (PGDIDEVICE) hPDev;
260
261 if (!hPDev) return FALSE;
262
263 if (!(pGDev->flFlags & PDEV_DISPLAY )) return FALSE;
264
265 if ((pGDev->DevInfo.iDitherFormat == BMF_8BPP) ||
266 (pGDev->DevInfo.iDitherFormat == BMF_16BPP) ||
267 (pGDev->DevInfo.iDitherFormat == BMF_24BPP) ||
268 (pGDev->DevInfo.iDitherFormat == BMF_32BPP))
269 {
270 if (!pGDev->DriverFunctions.IcmSetDeviceGammaRamp)
271 { // No driver support
272 if (!(pGDev->DevInfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP))
273 { // Driver does not support Gamma Ramp, so test to see we
274 // have BMF_8BPP only and palette operation support.
275 if ((pGDev->DevInfo.iDitherFormat != BMF_8BPP) ||
276 !(pGDev->GDIInfo.flRaster & RC_PALETTE)) return FALSE;
277 }
278 }
279
280 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
281 if (RtlCompareMemory( pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP)) ==
282 sizeof(GAMMARAMP)) return TRUE;
283 // Verify Ramp is inside range.
284 IcmGR = -IcmGammaRangeSet;
285 TstPeak = (Test == FALSE);
286 for (i = 0; i < 256; i++)
287 {
288 R = Ramp->Red[i] / 256;
289 G = Ramp->Green[i] / 256;
290 B = Ramp->Blue[i] / 256;
291 if ( R >= IcmGR)
292 {
293 if ( R <= IcmGammaRangeSet + i)
294 {
295 if ( G >= IcmGR &&
296 (G <= IcmGammaRangeSet + i) &&
297 B >= IcmGR &&
298 (B <= IcmGammaRangeSet + i) ) continue;
299 }
300 }
301 if (Test) return Ret; // Don't set and return.
302 // No test override, check max range
303 if (TstPeak)
304 {
305 if ( R != (IcmGR * 256) ||
306 G != (IcmGR * 256) ||
307 B != (IcmGR * 256) ) TstPeak = FALSE; // W/i range.
308 }
309 }
310 // ReactOS allocates a ramp even if it is 8BPP and Palette only.
311 // This way we have a record of the change in memory.
312 if (!pGDev->pvGammaRamp && !(pGDev->flFlags & PDEV_GAMMARAMP_TABLE))
313 { // If the above is true and we have nothing allocated, create it.
314 pGDev->pvGammaRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), TAG_GDIICM);
315 pGDev->flFlags |= PDEV_GAMMARAMP_TABLE;
316 }
317 RtlCopyMemory( pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP));
318
319 Ret = UpdateDeviceGammaRamp(hPDev);
320
321 return Ret;
322 }
323 else
324 return Ret;
325 }
326
327 BOOL
328 STDCALL
329 NtGdiSetDeviceGammaRamp(HDC hDC,
330 LPVOID Ramp)
331 {
332 BOOL Ret;
333 PDC dc;
334 NTSTATUS Status = STATUS_SUCCESS;
335 PGAMMARAMP SafeRamp;
336 if (!Ramp) return FALSE;
337
338 dc = DC_LockDc(hDC);
339 if (!dc)
340 {
341 SetLastWin32Error(ERROR_INVALID_HANDLE);
342 return FALSE;
343 }
344
345 SafeRamp = ExAllocatePool(PagedPool, sizeof(GAMMARAMP));
346 if (!SafeRamp)
347 {
348 DC_UnlockDc(dc);
349 SetLastWin32Error(STATUS_NO_MEMORY);
350 return FALSE;
351 }
352 _SEH_TRY
353 {
354 ProbeForRead( Ramp,
355 sizeof(PVOID),
356 1);
357 RtlCopyMemory( SafeRamp,
358 Ramp,
359 sizeof(GAMMARAMP));
360 }
361 _SEH_HANDLE
362 {
363 Status = _SEH_GetExceptionCode();
364 }
365 _SEH_END;
366
367 if (!NT_SUCCESS(Status))
368 {
369 DC_UnlockDc(dc);
370 ExFreePool(SafeRamp);
371 SetLastNtError(Status);
372 return FALSE;
373 }
374
375 Ret = IntSetDeviceGammaRamp((HDEV)dc->pPDev, SafeRamp, TRUE);
376 DC_UnlockDc(dc);
377 ExFreePool(SafeRamp);
378 return Ret;
379 }
380
381 INT
382 STDCALL
383 NtGdiSetIcmMode(HDC hDC,
384 ULONG nCommand,
385 ULONG EnableICM) // ulMode
386 {
387 /* FIXME: this should be coded someday */
388 if (EnableICM == ICM_OFF)
389 {
390 return ICM_OFF;
391 }
392 if (EnableICM == ICM_ON)
393 {
394 return 0;
395 }
396 if (EnableICM == ICM_QUERY)
397 {
398 return ICM_OFF;
399 }
400
401 return 0;
402 }
403
404 BOOL
405 STDCALL
406 NtGdiSetICMProfile(HDC hDC,
407 LPWSTR Filename)
408 {
409 UNIMPLEMENTED;
410 return FALSE;
411 }
412
413 BOOL
414 STDCALL
415 NtGdiUpdateICMRegKey(DWORD Reserved,
416 LPWSTR CMID,
417 LPWSTR Filename,
418 UINT Command)
419 {
420 UNIMPLEMENTED;
421 return FALSE;
422 }
423
424 /* EOF */