Jeffrey Morlan (mrnobo1024 at yahoo.com) - Fix ModifyWorldTransform multiplies. See...
[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
20 #include <w32k.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 _SEH_TRY
70 {
71 ProbeForRead( pLogColorSpace,
72 sizeof(LOGCOLORSPACEEXW),
73 1);
74 RtlCopyMemory(&Safelcs, pLogColorSpace, sizeof(LOGCOLORSPACEEXW));
75 }
76 _SEH_HANDLE
77 {
78 Status = _SEH_GetExceptionCode();
79 }
80 _SEH_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 PGDIDEVICE pGDev = (PGDIDEVICE) 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 if (NewValue > 65535) NewValue = 65535;
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 STDCALL
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 SetLastWin32Error(ERROR_INVALID_HANDLE);
147 return FALSE;
148 }
149
150 SafeRamp = ExAllocatePool(PagedPool, sizeof(GAMMARAMP));
151 if (!SafeRamp)
152 {
153 DC_UnlockDc(dc);
154 SetLastWin32Error(STATUS_NO_MEMORY);
155 return FALSE;
156 }
157
158 Ret = IntGetDeviceGammaRamp((HDEV)dc->pPDev, SafeRamp);
159
160 if (!Ret) return Ret;
161
162 _SEH_TRY
163 {
164 ProbeForWrite( Ramp,
165 sizeof(PVOID),
166 1);
167 RtlCopyMemory( Ramp,
168 SafeRamp,
169 sizeof(GAMMARAMP));
170 }
171 _SEH_HANDLE
172 {
173 Status = _SEH_GetExceptionCode();
174 }
175 _SEH_END;
176
177 DC_UnlockDc(dc);
178 ExFreePool(SafeRamp);
179
180 if (!NT_SUCCESS(Status))
181 {
182 SetLastNtError(Status);
183 return FALSE;
184 }
185 return Ret;
186 }
187
188 BOOL
189 STDCALL
190 NtGdiSetColorSpace(IN HDC hdc,
191 IN HCOLORSPACE hColorSpace)
192 {
193 PDC pDC;
194 PDC_ATTR pDc_Attr;
195 PCOLORSPACE pCS;
196
197 pDC = DC_LockDc(hdc);
198 if (!pDC)
199 {
200 SetLastWin32Error(ERROR_INVALID_HANDLE);
201 return FALSE;
202 }
203 pDc_Attr = pDC->pDc_Attr;
204 if(!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
205
206 if (pDc_Attr->hColorSpace == hColorSpace)
207 {
208 DC_UnlockDc(pDC);
209 return TRUE;
210 }
211
212 pCS = COLORSPACEOBJ_LockCS(hColorSpace);
213 if (!pCS)
214 {
215 SetLastWin32Error(ERROR_INVALID_HANDLE);
216 return FALSE;
217 }
218
219 if (pDC->DcLevel.pColorSpace)
220 {
221 GDIOBJ_ShareUnlockObjByPtr((POBJ) pDC->DcLevel.pColorSpace);
222 }
223
224 pDC->DcLevel.pColorSpace = pCS;
225 pDc_Attr->hColorSpace = hColorSpace;
226
227 COLORSPACEOBJ_UnlockCS(pCS);
228 DC_UnlockDc(pDC);
229 return TRUE;
230 }
231
232 BOOL
233 FASTCALL
234 UpdateDeviceGammaRamp( HDEV hPDev )
235 {
236 BOOL Ret = FALSE;
237 PPALGDI palGDI;
238 PALOBJ *palPtr;
239 PGDIDEVICE pGDev = (PGDIDEVICE) hPDev;
240
241 if ((pGDev->DevInfo.iDitherFormat == BMF_8BPP) ||
242 (pGDev->DevInfo.iDitherFormat == BMF_16BPP) ||
243 (pGDev->DevInfo.iDitherFormat == BMF_24BPP) ||
244 (pGDev->DevInfo.iDitherFormat == BMF_32BPP))
245 {
246 if (pGDev->DriverFunctions.IcmSetDeviceGammaRamp)
247 return pGDev->DriverFunctions.IcmSetDeviceGammaRamp( pGDev->hPDev,
248 IGRF_RGB_256WORDS,
249 pGDev->pvGammaRamp);
250
251 if ( (pGDev->DevInfo.iDitherFormat != BMF_8BPP) ||
252 !(pGDev->GDIInfo.flRaster & RC_PALETTE)) return FALSE;
253
254 if (!(pGDev->flFlags & PDEV_GAMMARAMP_TABLE)) return FALSE;
255
256 palGDI = PALETTE_LockPalette(pGDev->DevInfo.hpalDefault);
257 if(!palGDI) return FALSE;
258 palPtr = (PALOBJ*) palGDI;
259
260 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
261 palGDI->Mode |= PAL_GAMMACORRECTION;
262 else
263 palGDI->Mode &= ~PAL_GAMMACORRECTION;
264
265 if (!(pGDev->flFlags & PDEV_DRIVER_PUNTED_CALL)) // No punting, we hook
266 {
267 // BMF_8BPP only!
268 // PALOBJ_cGetColors check mode flags and update Gamma Correction.
269 // Set the HDEV to pal and go.
270 palGDI->hPDev = hPDev;
271 Ret = pGDev->DriverFunctions.SetPalette(pGDev->hPDev,
272 palPtr,
273 0,
274 0,
275 palGDI->NumColors);
276 }
277 PALETTE_UnlockPalette(palGDI);
278 return Ret;
279 }
280 else
281 return FALSE;
282 }
283
284 //
285 // ICM registry subkey sets internal brightness range, gamma range is 128 or
286 // 256 when icm is init.
287 INT IcmGammaRangeSet = 128; // <- make it global
288
289 BOOL
290 FASTCALL
291 IntSetDeviceGammaRamp(HDEV hPDev, PGAMMARAMP Ramp, BOOL Test)
292 {
293 WORD IcmGR, i, R, G, B;
294 BOOL Ret = FALSE, TstPeak;
295 PGDIDEVICE pGDev = (PGDIDEVICE) hPDev;
296
297 if (!hPDev) return FALSE;
298
299 if (!(pGDev->flFlags & PDEV_DISPLAY )) return FALSE;
300
301 if ((pGDev->DevInfo.iDitherFormat == BMF_8BPP) ||
302 (pGDev->DevInfo.iDitherFormat == BMF_16BPP) ||
303 (pGDev->DevInfo.iDitherFormat == BMF_24BPP) ||
304 (pGDev->DevInfo.iDitherFormat == BMF_32BPP))
305 {
306 if (!pGDev->DriverFunctions.IcmSetDeviceGammaRamp)
307 { // No driver support
308 if (!(pGDev->DevInfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP))
309 { // Driver does not support Gamma Ramp, so test to see we
310 // have BMF_8BPP only and palette operation support.
311 if ((pGDev->DevInfo.iDitherFormat != BMF_8BPP) ||
312 !(pGDev->GDIInfo.flRaster & RC_PALETTE)) return FALSE;
313 }
314 }
315
316 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE)
317 if (RtlCompareMemory( pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP)) ==
318 sizeof(GAMMARAMP)) return TRUE;
319 // Verify Ramp is inside range.
320 IcmGR = -IcmGammaRangeSet;
321 TstPeak = (Test == FALSE);
322 for (i = 0; i < 256; i++)
323 {
324 R = Ramp->Red[i] / 256;
325 G = Ramp->Green[i] / 256;
326 B = Ramp->Blue[i] / 256;
327 if ( R >= IcmGR)
328 {
329 if ( R <= IcmGammaRangeSet + i)
330 {
331 if ( G >= IcmGR &&
332 (G <= IcmGammaRangeSet + i) &&
333 B >= IcmGR &&
334 (B <= IcmGammaRangeSet + i) ) continue;
335 }
336 }
337 if (Test) return Ret; // Don't set and return.
338 // No test override, check max range
339 if (TstPeak)
340 {
341 if ( R != (IcmGR * 256) ||
342 G != (IcmGR * 256) ||
343 B != (IcmGR * 256) ) TstPeak = FALSE; // W/i range.
344 }
345 }
346 // ReactOS allocates a ramp even if it is 8BPP and Palette only.
347 // This way we have a record of the change in memory.
348 if (!pGDev->pvGammaRamp && !(pGDev->flFlags & PDEV_GAMMARAMP_TABLE))
349 { // If the above is true and we have nothing allocated, create it.
350 pGDev->pvGammaRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), TAG_GDIICM);
351 pGDev->flFlags |= PDEV_GAMMARAMP_TABLE;
352 }
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 STDCALL
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 SetLastWin32Error(ERROR_INVALID_HANDLE);
378 return FALSE;
379 }
380
381 SafeRamp = ExAllocatePool(PagedPool, sizeof(GAMMARAMP));
382 if (!SafeRamp)
383 {
384 DC_UnlockDc(dc);
385 SetLastWin32Error(STATUS_NO_MEMORY);
386 return FALSE;
387 }
388 _SEH_TRY
389 {
390 ProbeForRead( Ramp,
391 sizeof(PVOID),
392 1);
393 RtlCopyMemory( SafeRamp,
394 Ramp,
395 sizeof(GAMMARAMP));
396 }
397 _SEH_HANDLE
398 {
399 Status = _SEH_GetExceptionCode();
400 }
401 _SEH_END;
402
403 if (!NT_SUCCESS(Status))
404 {
405 DC_UnlockDc(dc);
406 ExFreePool(SafeRamp);
407 SetLastNtError(Status);
408 return FALSE;
409 }
410
411 Ret = IntSetDeviceGammaRamp((HDEV)dc->pPDev, SafeRamp, TRUE);
412 DC_UnlockDc(dc);
413 ExFreePool(SafeRamp);
414 return Ret;
415 }
416
417 INT
418 STDCALL
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 */