1 /* 2 * PROJECT: ReactOS Win32k Subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/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 if (pCS == NULL) return NULL; 27 28 hCS = pCS->BaseObject.hHmgr; 29 30 pCS->lcsColorSpace = pLogColorSpace->lcsColorSpace; 31 pCS->dwFlags = pLogColorSpace->dwFlags; 32 33 COLORSPACEOBJ_UnlockCS(pCS); 34 return hCS; 35 } 36 37 BOOL 38 FASTCALL 39 IntGdiDeleteColorSpace( 40 HCOLORSPACE hColorSpace) 41 { 42 BOOL Ret = FALSE; 43 44 if ((hColorSpace != hStockColorSpace) && 45 (GDI_HANDLE_GET_TYPE(hColorSpace) == GDILoObjType_LO_ICMLCS_TYPE)) 46 { 47 Ret = GreDeleteObject(hColorSpace); 48 if (!Ret) EngSetLastError(ERROR_INVALID_PARAMETER); 49 } 50 51 return Ret; 52 } 53 54 HANDLE 55 APIENTRY 56 NtGdiCreateColorSpace( 57 IN PLOGCOLORSPACEEXW pLogColorSpace) 58 { 59 LOGCOLORSPACEEXW Safelcs; 60 NTSTATUS Status = STATUS_SUCCESS; 61 62 _SEH2_TRY 63 { 64 ProbeForRead( pLogColorSpace, sizeof(LOGCOLORSPACEEXW), 1); 65 RtlCopyMemory(&Safelcs, pLogColorSpace, sizeof(LOGCOLORSPACEEXW)); 66 } 67 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 68 { 69 Status = _SEH2_GetExceptionCode(); 70 } 71 _SEH2_END; 72 73 if (!NT_SUCCESS(Status)) 74 { 75 SetLastNtError(Status); 76 return NULL; 77 } 78 79 return IntGdiCreateColorSpace(&Safelcs); 80 } 81 82 BOOL 83 APIENTRY 84 NtGdiDeleteColorSpace( 85 IN HANDLE hColorSpace) 86 { 87 return IntGdiDeleteColorSpace(hColorSpace); 88 } 89 90 BOOL 91 FASTCALL 92 IntGetDeviceGammaRamp(HDEV hPDev, PGAMMARAMP Ramp) 93 { 94 PPDEVOBJ pGDev = (PPDEVOBJ) hPDev; 95 int i; 96 97 if (!(pGDev->flFlags & PDEV_DISPLAY)) return FALSE; 98 99 if ((pGDev->devinfo.iDitherFormat == BMF_8BPP) || 100 (pGDev->devinfo.iDitherFormat == BMF_16BPP) || 101 (pGDev->devinfo.iDitherFormat == BMF_24BPP) || 102 (pGDev->devinfo.iDitherFormat == BMF_32BPP)) 103 { 104 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE) 105 { 106 RtlCopyMemory(Ramp, pGDev->pvGammaRamp, sizeof(GAMMARAMP)); 107 } 108 else 109 { 110 // Generate the 256-colors array 111 for (i = 0; i < 256; i++ ) 112 { 113 int NewValue = i * 256; 114 115 Ramp->Red[i] = Ramp->Green[i] = Ramp->Blue[i] = ((WORD)NewValue); 116 } 117 } 118 return TRUE; 119 } 120 121 return FALSE; 122 } 123 124 BOOL 125 APIENTRY 126 NtGdiGetDeviceGammaRamp( 127 HDC hDC, 128 LPVOID Ramp) 129 { 130 BOOL Ret; 131 PDC dc; 132 NTSTATUS Status = STATUS_SUCCESS; 133 PGAMMARAMP SafeRamp; 134 135 if (!Ramp) return FALSE; 136 137 dc = DC_LockDc(hDC); 138 if (!dc) 139 { 140 EngSetLastError(ERROR_INVALID_HANDLE); 141 return FALSE; 142 } 143 144 SafeRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), GDITAG_ICM); 145 if (!SafeRamp) 146 { 147 DC_UnlockDc(dc); 148 EngSetLastError(STATUS_NO_MEMORY); 149 return FALSE; 150 } 151 152 Ret = IntGetDeviceGammaRamp((HDEV)dc->ppdev, SafeRamp); 153 if (!Ret) 154 { 155 DC_UnlockDc(dc); 156 ExFreePoolWithTag(SafeRamp, GDITAG_ICM); 157 return Ret; 158 } 159 160 _SEH2_TRY 161 { 162 ProbeForWrite(Ramp, sizeof(GAMMARAMP), 1); 163 RtlCopyMemory(Ramp, SafeRamp, sizeof(GAMMARAMP)); 164 } 165 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 166 { 167 Status = _SEH2_GetExceptionCode(); 168 } 169 _SEH2_END; 170 171 DC_UnlockDc(dc); 172 ExFreePoolWithTag(SafeRamp, GDITAG_ICM); 173 174 if (!NT_SUCCESS(Status)) 175 { 176 SetLastNtError(Status); 177 return FALSE; 178 } 179 return Ret; 180 } 181 182 BOOL 183 APIENTRY 184 NtGdiSetColorSpace(IN HDC hdc, 185 IN HCOLORSPACE hColorSpace) 186 { 187 PDC pDC; 188 PDC_ATTR pdcattr; 189 PCOLORSPACE pCS; 190 191 pDC = DC_LockDc(hdc); 192 if (!pDC) 193 { 194 EngSetLastError(ERROR_INVALID_HANDLE); 195 return FALSE; 196 } 197 pdcattr = pDC->pdcattr; 198 199 if (pdcattr->hColorSpace == hColorSpace) 200 { 201 DC_UnlockDc(pDC); 202 return TRUE; 203 } 204 205 pCS = COLORSPACEOBJ_LockCS(hColorSpace); 206 if (!pCS) 207 { 208 EngSetLastError(ERROR_INVALID_HANDLE); 209 return FALSE; 210 } 211 212 if (pDC->dclevel.pColorSpace) 213 { 214 GDIOBJ_vDereferenceObject((POBJ) pDC->dclevel.pColorSpace); 215 } 216 217 pDC->dclevel.pColorSpace = pCS; 218 pdcattr->hColorSpace = hColorSpace; 219 220 COLORSPACEOBJ_UnlockCS(pCS); 221 DC_UnlockDc(pDC); 222 return TRUE; 223 } 224 225 BOOL 226 FASTCALL 227 UpdateDeviceGammaRamp(HDEV hPDev) 228 { 229 BOOL Ret = FALSE; 230 PPALETTE palGDI; 231 PALOBJ *palPtr; 232 PPDEVOBJ pGDev = (PPDEVOBJ)hPDev; 233 234 if ((pGDev->devinfo.iDitherFormat == BMF_8BPP) || 235 (pGDev->devinfo.iDitherFormat == BMF_16BPP) || 236 (pGDev->devinfo.iDitherFormat == BMF_24BPP) || 237 (pGDev->devinfo.iDitherFormat == BMF_32BPP)) 238 { 239 if (pGDev->DriverFunctions.IcmSetDeviceGammaRamp) 240 return pGDev->DriverFunctions.IcmSetDeviceGammaRamp( pGDev->dhpdev, 241 IGRF_RGB_256WORDS, 242 pGDev->pvGammaRamp); 243 244 if ((pGDev->devinfo.iDitherFormat != BMF_8BPP) || 245 !(pGDev->gdiinfo.flRaster & RC_PALETTE)) return FALSE; 246 247 if (!(pGDev->flFlags & PDEV_GAMMARAMP_TABLE)) return FALSE; 248 249 palGDI = PALETTE_ShareLockPalette(pGDev->devinfo.hpalDefault); 250 if(!palGDI) return FALSE; 251 palPtr = (PALOBJ*) palGDI; 252 253 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE) 254 palGDI->flFlags |= PAL_GAMMACORRECTION; 255 else 256 palGDI->flFlags &= ~PAL_GAMMACORRECTION; 257 258 if (!(pGDev->flFlags & PDEV_DRIVER_PUNTED_CALL)) // No punting, we hook 259 { 260 // BMF_8BPP only! 261 // PALOBJ_cGetColors check mode flags and update Gamma Correction. 262 // Set the HDEV to pal and go. 263 palGDI->hPDev = hPDev; 264 Ret = pGDev->DriverFunctions.SetPalette(pGDev->dhpdev, 265 palPtr, 266 0, 267 0, 268 palGDI->NumColors); 269 } 270 PALETTE_ShareUnlockPalette(palGDI); 271 return Ret; 272 } 273 else 274 return FALSE; 275 } 276 277 // 278 // ICM registry subkey sets internal brightness range, gamma range is 128 or 279 // 256 when icm is init. 280 INT IcmGammaRangeSet = 128; // <- Make it global 281 282 BOOL 283 FASTCALL 284 IntSetDeviceGammaRamp(HDEV hPDev, PGAMMARAMP Ramp, BOOL Test) 285 { 286 WORD IcmGR, i, R, G, B; 287 BOOL Ret = FALSE, TstPeak; 288 PPDEVOBJ pGDev = (PPDEVOBJ) hPDev; 289 290 if (!hPDev) return FALSE; 291 292 if (!(pGDev->flFlags & PDEV_DISPLAY )) return FALSE; 293 294 if ((pGDev->devinfo.iDitherFormat == BMF_8BPP) || 295 (pGDev->devinfo.iDitherFormat == BMF_16BPP) || 296 (pGDev->devinfo.iDitherFormat == BMF_24BPP) || 297 (pGDev->devinfo.iDitherFormat == BMF_32BPP)) 298 { 299 if (!pGDev->DriverFunctions.IcmSetDeviceGammaRamp) 300 { 301 // No driver support 302 if (!(pGDev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP)) 303 { 304 // Driver does not support Gamma Ramp, so test to see we 305 // have BMF_8BPP only and palette operation support. 306 if ((pGDev->devinfo.iDitherFormat != BMF_8BPP) || 307 !(pGDev->gdiinfo.flRaster & RC_PALETTE)) return FALSE; 308 } 309 } 310 311 if (pGDev->flFlags & PDEV_GAMMARAMP_TABLE) 312 { 313 if (RtlCompareMemory(pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP)) == 314 sizeof(GAMMARAMP)) return TRUE; 315 } 316 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 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 337 if (Test) return Ret; // Don't set and return. 338 339 // No test override, check max range 340 if (TstPeak) 341 { 342 if ((R != (IcmGR * 256)) || 343 (G != (IcmGR * 256)) || 344 (B != (IcmGR * 256)) ) TstPeak = FALSE; // W/i range. 345 } 346 } 347 // ReactOS allocates a ramp even if it is 8BPP and Palette only. 348 // This way we have a record of the change in memory. 349 if (!pGDev->pvGammaRamp && !(pGDev->flFlags & PDEV_GAMMARAMP_TABLE)) 350 { 351 // If the above is true and we have nothing allocated, create it. 352 pGDev->pvGammaRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), GDITAG_ICM); 353 pGDev->flFlags |= PDEV_GAMMARAMP_TABLE; 354 } 355 356 if (pGDev->pvGammaRamp) 357 RtlCopyMemory(pGDev->pvGammaRamp, Ramp, sizeof(GAMMARAMP)); 358 359 Ret = UpdateDeviceGammaRamp(hPDev); 360 } 361 362 return Ret; 363 } 364 365 BOOL 366 APIENTRY 367 NtGdiSetDeviceGammaRamp( 368 HDC hDC, 369 LPVOID Ramp) 370 { 371 BOOL Ret; 372 PDC dc; 373 NTSTATUS Status = STATUS_SUCCESS; 374 PGAMMARAMP SafeRamp; 375 if (!Ramp) return FALSE; 376 377 dc = DC_LockDc(hDC); 378 if (!dc) 379 { 380 EngSetLastError(ERROR_INVALID_HANDLE); 381 return FALSE; 382 } 383 384 SafeRamp = ExAllocatePoolWithTag(PagedPool, sizeof(GAMMARAMP), GDITAG_ICM); 385 if (!SafeRamp) 386 { 387 DC_UnlockDc(dc); 388 EngSetLastError(STATUS_NO_MEMORY); 389 return FALSE; 390 } 391 _SEH2_TRY 392 { 393 ProbeForRead(Ramp, sizeof(GAMMARAMP), 1); 394 RtlCopyMemory(SafeRamp, Ramp, 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, GDITAG_ICM); 406 SetLastNtError(Status); 407 return FALSE; 408 } 409 410 Ret = IntSetDeviceGammaRamp((HDEV)dc->ppdev, SafeRamp, TRUE); 411 DC_UnlockDc(dc); 412 ExFreePoolWithTag(SafeRamp, GDITAG_ICM); 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 */ 440