1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: GDI Palette Functions 5 * FILE: win32ss/gdi/ntgdi/palette.c 6 * PROGRAMERS: Jason Filby 7 * Timo Kreuzer 8 */ 9 10 #include <win32k.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 15 static UINT SystemPaletteUse = SYSPAL_NOSTATIC; /* The program need save the pallete and restore it */ 16 17 PALETTE gpalRGB, gpalBGR, gpalRGB555, gpalRGB565, *gppalMono, *gppalDefault; 18 PPALETTE appalSurfaceDefault[11]; 19 20 const PALETTEENTRY g_sysPalTemplate[NB_RESERVED_COLORS] = 21 { 22 // First 10 entries in the system palette 23 // Red Green Blue Flags 24 { 0x00, 0x00, 0x00, PC_SYS_USED }, 25 { 0x80, 0x00, 0x00, PC_SYS_USED }, 26 { 0x00, 0x80, 0x00, PC_SYS_USED }, 27 { 0x80, 0x80, 0x00, PC_SYS_USED }, 28 { 0x00, 0x00, 0x80, PC_SYS_USED }, 29 { 0x80, 0x00, 0x80, PC_SYS_USED }, 30 { 0x00, 0x80, 0x80, PC_SYS_USED }, 31 { 0xc0, 0xc0, 0xc0, PC_SYS_USED }, 32 { 0xc0, 0xdc, 0xc0, PC_SYS_USED }, 33 { 0xa6, 0xca, 0xf0, PC_SYS_USED }, 34 35 // ... c_min/2 dynamic colorcells 36 // ... gap (for sparse palettes) 37 // ... c_min/2 dynamic colorcells 38 39 { 0xff, 0xfb, 0xf0, PC_SYS_USED }, 40 { 0xa0, 0xa0, 0xa4, PC_SYS_USED }, 41 { 0x80, 0x80, 0x80, PC_SYS_USED }, 42 { 0xff, 0x00, 0x00, PC_SYS_USED }, 43 { 0x00, 0xff, 0x00, PC_SYS_USED }, 44 { 0xff, 0xff, 0x00, PC_SYS_USED }, 45 { 0x00, 0x00, 0xff, PC_SYS_USED }, 46 { 0xff, 0x00, 0xff, PC_SYS_USED }, 47 { 0x00, 0xff, 0xff, PC_SYS_USED }, 48 { 0xff, 0xff, 0xff, PC_SYS_USED } // Last 10 49 }; 50 51 unsigned short GetNumberOfBits(unsigned int dwMask) 52 { 53 unsigned short wBits; 54 for (wBits = 0; dwMask; dwMask = dwMask & (dwMask - 1)) 55 wBits++; 56 return wBits; 57 } 58 59 // Create the system palette 60 INIT_FUNCTION 61 NTSTATUS 62 NTAPI 63 InitPaletteImpl(VOID) 64 { 65 // Create default palette (20 system colors) 66 gppalDefault = PALETTE_AllocPalWithHandle(PAL_INDEXED, 67 20, 68 g_sysPalTemplate, 69 0, 0, 0); 70 GDIOBJ_vReferenceObjectByPointer(&gppalDefault->BaseObject); 71 PALETTE_UnlockPalette(gppalDefault); 72 73 /* palette_size = visual->map_entries; */ 74 75 gpalRGB.flFlags = PAL_RGB; 76 gpalRGB.RedMask = RGB(0xFF, 0x00, 0x00); 77 gpalRGB.GreenMask = RGB(0x00, 0xFF, 0x00); 78 gpalRGB.BlueMask = RGB(0x00, 0x00, 0xFF); 79 gpalRGB.BaseObject.ulShareCount = 1; 80 gpalRGB.BaseObject.BaseFlags = 0 ; 81 82 gpalBGR.flFlags = PAL_BGR; 83 gpalBGR.RedMask = RGB(0x00, 0x00, 0xFF); 84 gpalBGR.GreenMask = RGB(0x00, 0xFF, 0x00); 85 gpalBGR.BlueMask = RGB(0xFF, 0x00, 0x00); 86 gpalBGR.BaseObject.ulShareCount = 1; 87 gpalBGR.BaseObject.BaseFlags = 0 ; 88 89 gpalRGB555.flFlags = PAL_RGB16_555 | PAL_BITFIELDS; 90 gpalRGB555.RedMask = 0x7C00; 91 gpalRGB555.GreenMask = 0x3E0; 92 gpalRGB555.BlueMask = 0x1F; 93 gpalRGB555.BaseObject.ulShareCount = 1; 94 gpalRGB555.BaseObject.BaseFlags = 0 ; 95 96 gpalRGB565.flFlags = PAL_RGB16_565 | PAL_BITFIELDS; 97 gpalRGB565.RedMask = 0xF800; 98 gpalRGB565.GreenMask = 0x7E0; 99 gpalRGB565.BlueMask = 0x1F; 100 gpalRGB565.BaseObject.ulShareCount = 1; 101 gpalRGB565.BaseObject.BaseFlags = 0 ; 102 103 gppalMono = PALETTE_AllocPalette(PAL_MONOCHROME|PAL_INDEXED, 2, NULL, 0, 0, 0); 104 PALETTE_vSetRGBColorForIndex(gppalMono, 0, 0x000000); 105 PALETTE_vSetRGBColorForIndex(gppalMono, 1, 0xffffff); 106 107 /* Initialize default surface palettes */ 108 appalSurfaceDefault[BMF_1BPP] = gppalMono; 109 appalSurfaceDefault[BMF_4BPP] = gppalDefault; 110 appalSurfaceDefault[BMF_8BPP] = gppalDefault; 111 appalSurfaceDefault[BMF_16BPP] = &gpalRGB565; 112 appalSurfaceDefault[BMF_24BPP] = &gpalBGR; 113 appalSurfaceDefault[BMF_32BPP] = &gpalBGR; 114 appalSurfaceDefault[BMF_4RLE] = gppalDefault; 115 appalSurfaceDefault[BMF_8RLE] = gppalDefault; 116 appalSurfaceDefault[BMF_JPEG] = &gpalRGB; 117 appalSurfaceDefault[BMF_PNG] = &gpalRGB; 118 119 return STATUS_SUCCESS; 120 } 121 122 VOID FASTCALL PALETTE_ValidateFlags(PALETTEENTRY* lpPalE, INT size) 123 { 124 int i = 0; 125 for (; i<size ; i++) 126 lpPalE[i].peFlags = PC_SYS_USED | (lpPalE[i].peFlags & 0x07); 127 } 128 129 130 PPALETTE 131 NTAPI 132 PALETTE_AllocPalette( 133 _In_ ULONG iMode, 134 _In_ ULONG cColors, 135 _In_opt_ const PALETTEENTRY* pEntries, 136 _In_ FLONG flRed, 137 _In_ FLONG flGreen, 138 _In_ FLONG flBlue) 139 { 140 PPALETTE ppal; 141 ULONG fl = 0, cjSize = sizeof(PALETTE); 142 143 /* Check if the palette has entries */ 144 if (iMode & PAL_INDEXED) 145 { 146 /* Check color count */ 147 if ((cColors == 0) || (cColors > 1024)) return NULL; 148 149 /* Allocate enough space for the palete entries */ 150 cjSize += cColors * sizeof(PALETTEENTRY); 151 } 152 else 153 { 154 /* There are no palette entries */ 155 cColors = 0; 156 157 /* We can use the lookaside list */ 158 fl |= BASEFLAG_LOOKASIDE; 159 } 160 161 /* Allocate the object (without a handle!) */ 162 ppal = (PPALETTE)GDIOBJ_AllocateObject(GDIObjType_PAL_TYPE, cjSize, fl); 163 if (!ppal) 164 { 165 return NULL; 166 } 167 168 /* Set mode, color count and entry pointer */ 169 ppal->flFlags = iMode; 170 ppal->NumColors = cColors; 171 ppal->IndexedColors = ppal->apalColors; 172 173 /* Check what kind of palette this is */ 174 if (iMode & PAL_INDEXED) 175 { 176 /* Check if we got a color array */ 177 if (pEntries) 178 { 179 /* Copy the entries */ 180 RtlCopyMemory(ppal->IndexedColors, pEntries, cColors * sizeof(pEntries[0])); 181 } 182 } 183 else if (iMode & PAL_BITFIELDS) 184 { 185 /* Copy the color masks */ 186 ppal->RedMask = flRed; 187 ppal->GreenMask = flGreen; 188 ppal->BlueMask = flBlue; 189 190 /* Check what masks we have and set optimization flags */ 191 if ((flRed == 0x7c00) && (flGreen == 0x3E0) && (flBlue == 0x1F)) 192 ppal->flFlags |= PAL_RGB16_555; 193 else if ((flRed == 0xF800) && (flGreen == 0x7E0) && (flBlue == 0x1F)) 194 ppal->flFlags |= PAL_RGB16_565; 195 else if ((flRed == 0xFF0000) && (flGreen == 0xFF00) && (flBlue == 0xFF)) 196 ppal->flFlags |= PAL_BGR; 197 else if ((flRed == 0xFF) && (flGreen == 0xFF00) && (flBlue == 0xFF0000)) 198 ppal->flFlags |= PAL_RGB; 199 } 200 201 return ppal; 202 } 203 204 PPALETTE 205 NTAPI 206 PALETTE_AllocPalWithHandle( 207 _In_ ULONG iMode, 208 _In_ ULONG cColors, 209 _In_opt_ const PALETTEENTRY* pEntries, 210 _In_ FLONG flRed, 211 _In_ FLONG flGreen, 212 _In_ FLONG flBlue) 213 { 214 PPALETTE ppal; 215 216 /* Allocate the palette without a handle */ 217 ppal = PALETTE_AllocPalette(iMode, cColors, pEntries, flRed, flGreen, flBlue); 218 if (!ppal) return NULL; 219 220 /* Insert the palette into the handle table */ 221 if (!GDIOBJ_hInsertObject(&ppal->BaseObject, GDI_OBJ_HMGR_POWNED)) 222 { 223 DPRINT1("Could not insert palette into handle table.\n"); 224 GDIOBJ_vFreeObject(&ppal->BaseObject); 225 return NULL; 226 } 227 228 return ppal; 229 } 230 231 VOID 232 NTAPI 233 PALETTE_vCleanup(PVOID ObjectBody) 234 { 235 PPALETTE pPal = (PPALETTE)ObjectBody; 236 if (pPal->IndexedColors && pPal->IndexedColors != pPal->apalColors) 237 { 238 ExFreePoolWithTag(pPal->IndexedColors, TAG_PALETTE); 239 } 240 } 241 242 INT 243 FASTCALL 244 PALETTE_GetObject(PPALETTE ppal, INT cbCount, LPLOGBRUSH lpBuffer) 245 { 246 if (!lpBuffer) 247 { 248 return sizeof(WORD); 249 } 250 251 if ((UINT)cbCount < sizeof(WORD)) return 0; 252 *((WORD*)lpBuffer) = (WORD)ppal->NumColors; 253 return sizeof(WORD); 254 } 255 256 ULONG 257 NTAPI 258 PALETTE_ulGetNearestPaletteIndex(PALETTE* ppal, ULONG iColor) 259 { 260 ULONG ulDiff, ulColorDiff, ulMinimalDiff = 0xFFFFFF; 261 ULONG i, ulBestIndex = 0; 262 PALETTEENTRY peColor = *(PPALETTEENTRY)&iColor; 263 264 /* Loop all palette entries */ 265 for (i = 0; i < ppal->NumColors; i++) 266 { 267 /* Calculate distance in the color cube */ 268 ulDiff = peColor.peRed - ppal->IndexedColors[i].peRed; 269 ulColorDiff = ulDiff * ulDiff; 270 ulDiff = peColor.peGreen - ppal->IndexedColors[i].peGreen; 271 ulColorDiff += ulDiff * ulDiff; 272 ulDiff = peColor.peBlue - ppal->IndexedColors[i].peBlue; 273 ulColorDiff += ulDiff * ulDiff; 274 275 /* Check for a better match */ 276 if (ulColorDiff < ulMinimalDiff) 277 { 278 ulBestIndex = i; 279 ulMinimalDiff = ulColorDiff; 280 281 /* Break on exact match */ 282 if (ulMinimalDiff == 0) break; 283 } 284 } 285 286 return ulBestIndex; 287 } 288 289 ULONG 290 NTAPI 291 PALETTE_ulGetNearestBitFieldsIndex(PALETTE* ppal, ULONG ulColor) 292 { 293 ULONG ulNewColor; 294 295 // FIXME: HACK, should be stored already 296 ppal->ulRedShift = CalculateShift(RGB(0xff,0,0), ppal->RedMask); 297 ppal->ulGreenShift = CalculateShift(RGB(0,0xff,0), ppal->GreenMask); 298 ppal->ulBlueShift = CalculateShift(RGB(0,0,0xff), ppal->BlueMask); 299 300 ulNewColor = _rotl(ulColor, ppal->ulRedShift) & ppal->RedMask; 301 ulNewColor |= _rotl(ulColor, ppal->ulGreenShift) & ppal->GreenMask; 302 ulNewColor |= _rotl(ulColor, ppal->ulBlueShift) & ppal->BlueMask; 303 304 return ulNewColor; 305 } 306 307 ULONG 308 NTAPI 309 PALETTE_ulGetNearestIndex(PALETTE* ppal, ULONG ulColor) 310 { 311 if (ppal->flFlags & PAL_INDEXED) // Use fl & PALINDEXED 312 return PALETTE_ulGetNearestPaletteIndex(ppal, ulColor); 313 else 314 return PALETTE_ulGetNearestBitFieldsIndex(ppal, ulColor); 315 } 316 317 VOID 318 NTAPI 319 PALETTE_vGetBitMasks(PPALETTE ppal, PULONG pulColors) 320 { 321 ASSERT(pulColors); 322 323 if (ppal->flFlags & PAL_INDEXED || ppal->flFlags & PAL_RGB) 324 { 325 pulColors[0] = RGB(0xFF, 0x00, 0x00); 326 pulColors[1] = RGB(0x00, 0xFF, 0x00); 327 pulColors[2] = RGB(0x00, 0x00, 0xFF); 328 } 329 else if (ppal->flFlags & PAL_BGR) 330 { 331 pulColors[0] = RGB(0x00, 0x00, 0xFF); 332 pulColors[1] = RGB(0x00, 0xFF, 0x00); 333 pulColors[2] = RGB(0xFF, 0x00, 0x00); 334 } 335 else if (ppal->flFlags & PAL_BITFIELDS) 336 { 337 pulColors[0] = ppal->RedMask; 338 pulColors[1] = ppal->GreenMask; 339 pulColors[2] = ppal->BlueMask; 340 } 341 } 342 343 VOID 344 FASTCALL 345 ColorCorrection(PPALETTE PalGDI, PPALETTEENTRY PaletteEntry, ULONG Colors) 346 { 347 PPDEVOBJ ppdev = (PPDEVOBJ)PalGDI->hPDev; 348 349 if (!ppdev) return; 350 351 if (ppdev->flFlags & PDEV_GAMMARAMP_TABLE) 352 { 353 ULONG i; 354 PGAMMARAMP GammaRamp = (PGAMMARAMP)ppdev->pvGammaRamp; 355 for ( i = 0; i < Colors; i++) 356 { 357 PaletteEntry[i].peRed += GammaRamp->Red[i]; 358 PaletteEntry[i].peGreen += GammaRamp->Green[i]; 359 PaletteEntry[i].peBlue += GammaRamp->Blue[i]; 360 } 361 } 362 return; 363 } 364 365 /** Display Driver Interface **************************************************/ 366 367 /* 368 * @implemented 369 */ 370 HPALETTE 371 APIENTRY 372 EngCreatePalette( 373 ULONG iMode, 374 ULONG cColors, 375 ULONG *pulColors, 376 ULONG flRed, 377 ULONG flGreen, 378 ULONG flBlue) 379 { 380 PPALETTE ppal; 381 HPALETTE hpal; 382 383 ppal = PALETTE_AllocPalette(iMode, cColors, (PPALETTEENTRY)pulColors, flRed, flGreen, flBlue); 384 if (!ppal) return NULL; 385 386 hpal = GDIOBJ_hInsertObject(&ppal->BaseObject, GDI_OBJ_HMGR_PUBLIC); 387 if (!hpal) 388 { 389 DPRINT1("Could not insert palette into handle table.\n"); 390 GDIOBJ_vFreeObject(&ppal->BaseObject); 391 return NULL; 392 } 393 394 PALETTE_UnlockPalette(ppal); 395 return hpal; 396 } 397 398 /* 399 * @implemented 400 */ 401 BOOL 402 APIENTRY 403 EngDeletePalette(IN HPALETTE hpal) 404 { 405 PPALETTE ppal; 406 407 ppal = PALETTE_ShareLockPalette(hpal); 408 if (!ppal) return FALSE; 409 410 GDIOBJ_vDeleteObject(&ppal->BaseObject); 411 412 return TRUE; 413 } 414 415 /* 416 * @implemented 417 */ 418 ULONG 419 APIENTRY 420 PALOBJ_cGetColors(PALOBJ *PalObj, ULONG Start, ULONG Colors, ULONG *PaletteEntry) 421 { 422 PALETTE *PalGDI; 423 424 PalGDI = (PALETTE*)PalObj; 425 426 if (Start >= PalGDI->NumColors) 427 return 0; 428 429 Colors = min(Colors, PalGDI->NumColors - Start); 430 431 /* NOTE: PaletteEntry ULONGs are in the same order as PALETTEENTRY. */ 432 RtlCopyMemory(PaletteEntry, PalGDI->IndexedColors + Start, sizeof(ULONG) * Colors); 433 434 if (PalGDI->flFlags & PAL_GAMMACORRECTION) 435 ColorCorrection(PalGDI, (PPALETTEENTRY)PaletteEntry, Colors); 436 437 return Colors; 438 } 439 440 441 /** Systemcall Interface ******************************************************/ 442 443 HPALETTE 444 NTAPI 445 GreCreatePaletteInternal( 446 IN LPLOGPALETTE pLogPal, 447 IN UINT cEntries) 448 { 449 HPALETTE hpal = NULL; 450 PPALETTE ppal; 451 452 pLogPal->palNumEntries = cEntries; 453 ppal = PALETTE_AllocPalWithHandle(PAL_INDEXED, 454 cEntries, 455 pLogPal->palPalEntry, 456 0, 0, 0); 457 458 if (ppal != NULL) 459 { 460 PALETTE_ValidateFlags(ppal->IndexedColors, ppal->NumColors); 461 462 hpal = ppal->BaseObject.hHmgr; 463 PALETTE_UnlockPalette(ppal); 464 } 465 466 return hpal; 467 } 468 469 /* 470 * @implemented 471 */ 472 HPALETTE 473 APIENTRY 474 NtGdiCreatePaletteInternal( 475 IN LPLOGPALETTE plogpalUser, 476 IN UINT cEntries) 477 { 478 HPALETTE hpal = NULL; 479 PPALETTE ppal; 480 ULONG i, cjSize; 481 482 ppal = PALETTE_AllocPalWithHandle(PAL_INDEXED, cEntries, NULL, 0, 0, 0); 483 if (ppal == NULL) 484 { 485 return NULL; 486 } 487 488 cjSize = FIELD_OFFSET(LOGPALETTE, palPalEntry[cEntries]); 489 490 _SEH2_TRY 491 { 492 ProbeForRead(plogpalUser, cjSize, 1); 493 494 for (i = 0; i < cEntries; i++) 495 { 496 ppal->IndexedColors[i] = plogpalUser->palPalEntry[i]; 497 } 498 } 499 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 500 { 501 GDIOBJ_vDeleteObject(&ppal->BaseObject); 502 _SEH2_YIELD(return NULL); 503 } 504 _SEH2_END; 505 506 PALETTE_ValidateFlags(ppal->IndexedColors, cEntries); 507 hpal = ppal->BaseObject.hHmgr; 508 PALETTE_UnlockPalette(ppal); 509 510 return hpal; 511 } 512 513 HPALETTE 514 APIENTRY 515 NtGdiCreateHalftonePalette(HDC hDC) 516 { 517 int i, r, g, b; 518 PALETTEENTRY PalEntries[256]; 519 PPALETTE ppal; 520 PDC pdc; 521 HPALETTE hpal = NULL; 522 523 pdc = DC_LockDc(hDC); 524 if (!pdc) 525 { 526 EngSetLastError(ERROR_INVALID_HANDLE); 527 return NULL; 528 } 529 530 RtlZeroMemory(PalEntries, sizeof(PalEntries)); 531 532 /* First and last ten entries are default ones */ 533 for (i = 0; i < 10; i++) 534 { 535 PalEntries[i].peRed = g_sysPalTemplate[i].peRed; 536 PalEntries[i].peGreen = g_sysPalTemplate[i].peGreen; 537 PalEntries[i].peBlue = g_sysPalTemplate[i].peBlue; 538 539 PalEntries[246 + i].peRed = g_sysPalTemplate[10 + i].peRed; 540 PalEntries[246 + i].peGreen = g_sysPalTemplate[10 + i].peGreen; 541 PalEntries[246 + i].peBlue = g_sysPalTemplate[10 + i].peBlue; 542 } 543 544 ppal = PALETTE_ShareLockPalette(pdc->dclevel.hpal); 545 if (ppal && (ppal->flFlags & PAL_INDEXED)) 546 { 547 /* FIXME: optimize the palette for the current palette */ 548 UNIMPLEMENTED; 549 } 550 else 551 { 552 for (r = 0; r < 6; r++) 553 { 554 for (g = 0; g < 6; g++) 555 { 556 for (b = 0; b < 6; b++) 557 { 558 i = r + g*6 + b*36 + 10; 559 PalEntries[i].peRed = r * 51; 560 PalEntries[i].peGreen = g * 51; 561 PalEntries[i].peBlue = b * 51; 562 } 563 } 564 } 565 566 for (i = 216; i < 246; i++) 567 { 568 int v = (i - 216) << 3; 569 PalEntries[i].peRed = v; 570 PalEntries[i].peGreen = v; 571 PalEntries[i].peBlue = v; 572 } 573 } 574 575 if (ppal) 576 PALETTE_ShareUnlockPalette(ppal); 577 578 DC_UnlockDc(pdc); 579 580 ppal = PALETTE_AllocPalWithHandle(PAL_INDEXED, 256, PalEntries, 0, 0, 0); 581 if (ppal) 582 { 583 hpal = ppal->BaseObject.hHmgr; 584 PALETTE_UnlockPalette(ppal); 585 } 586 587 return hpal; 588 } 589 590 BOOL 591 APIENTRY 592 NtGdiResizePalette( 593 HPALETTE hpal, 594 UINT Entries) 595 { 596 /* PALOBJ *palPtr = (PALOBJ*)AccessUserObject(hPal); 597 UINT cPrevEnt, prevVer; 598 INT prevsize, size = sizeof(LOGPALETTE) + (cEntries - 1) * sizeof(PALETTEENTRY); 599 XLATEOBJ *XlateObj = NULL; 600 601 if(!palPtr) return FALSE; 602 cPrevEnt = palPtr->logpalette->palNumEntries; 603 prevVer = palPtr->logpalette->palVersion; 604 prevsize = sizeof(LOGPALETTE) + (cPrevEnt - 1) * sizeof(PALETTEENTRY) + sizeof(int*) + sizeof(GDIOBJHDR); 605 size += sizeof(int*) + sizeof(GDIOBJHDR); 606 XlateObj = palPtr->logicalToSystem; 607 608 if (!(palPtr = GDI_ReallocObject(size, hPal, palPtr))) return FALSE; 609 610 if(XlateObj) 611 { 612 XLATEOBJ *NewXlateObj = (int*) HeapReAlloc(GetProcessHeap(), 0, XlateObj, cEntries * sizeof(int)); 613 if(NewXlateObj == NULL) 614 { 615 ERR("Can not resize logicalToSystem -- out of memory!"); 616 GDI_ReleaseObj( hPal ); 617 return FALSE; 618 } 619 palPtr->logicalToSystem = NewXlateObj; 620 } 621 622 if(cEntries > cPrevEnt) 623 { 624 if(XlateObj) memset(palPtr->logicalToSystem + cPrevEnt, 0, (cEntries - cPrevEnt)*sizeof(int)); 625 memset( (BYTE*)palPtr + prevsize, 0, size - prevsize ); 626 PALETTE_ValidateFlags((PALETTEENTRY*)((BYTE*)palPtr + prevsize), cEntries - cPrevEnt ); 627 } 628 palPtr->logpalette->palNumEntries = cEntries; 629 palPtr->logpalette->palVersion = prevVer; 630 // GDI_ReleaseObj( hPal ); 631 return TRUE; */ 632 633 UNIMPLEMENTED; 634 return FALSE; 635 } 636 637 BOOL 638 APIENTRY 639 NtGdiGetColorAdjustment( 640 HDC hdc, 641 LPCOLORADJUSTMENT pca) 642 { 643 UNIMPLEMENTED; 644 return FALSE; 645 } 646 647 BOOL 648 APIENTRY 649 NtGdiSetColorAdjustment( 650 HDC hdc, 651 LPCOLORADJUSTMENT pca) 652 { 653 UNIMPLEMENTED; 654 return FALSE; 655 } 656 657 COLORREF 658 APIENTRY 659 NtGdiGetNearestColor( 660 _In_ HDC hDC, 661 _In_ COLORREF Color) 662 { 663 COLORREF nearest = CLR_INVALID; 664 PDC dc; 665 EXLATEOBJ exlo; 666 PPALETTE ppal; 667 668 dc = DC_LockDc(hDC); 669 670 if(dc == NULL) 671 { 672 EngSetLastError(ERROR_INVALID_HANDLE); 673 return CLR_INVALID; 674 } 675 676 /// FIXME: shouldn't dereference pSurface while the PDEV is not locked 677 if(dc->dclevel.pSurface == NULL) 678 ppal = gppalMono; 679 else 680 ppal = dc->dclevel.pSurface->ppal; 681 682 /* Translate the color to the DC format */ 683 Color = TranslateCOLORREF(dc, Color); 684 685 /* XLATE it back to RGB color space */ 686 EXLATEOBJ_vInitialize(&exlo, 687 ppal, 688 &gpalRGB, 689 0, 690 RGB(0xff, 0xff, 0xff), 691 RGB(0, 0, 0)); 692 693 nearest = XLATEOBJ_iXlate(&exlo.xlo, Color); 694 695 EXLATEOBJ_vCleanup(&exlo); 696 697 /* We're done */ 698 DC_UnlockDc(dc); 699 700 return nearest; 701 } 702 703 UINT 704 APIENTRY 705 NtGdiGetNearestPaletteIndex( 706 HPALETTE hpal, 707 COLORREF crColor) 708 { 709 PPALETTE ppal = PALETTE_ShareLockPalette(hpal); 710 UINT index = 0; 711 712 if (ppal) 713 { 714 if (ppal->flFlags & PAL_INDEXED) 715 { 716 /* Return closest match for the given RGB color */ 717 index = PALETTE_ulGetNearestPaletteIndex(ppal, crColor); 718 } 719 // else SetLastError ? 720 PALETTE_ShareUnlockPalette(ppal); 721 } 722 723 return index; 724 } 725 726 UINT 727 FASTCALL 728 IntGdiRealizePalette(HDC hDC) 729 { 730 UINT i, realize = 0; 731 PDC pdc; 732 PALETTE *ppalSurf, *ppalDC; 733 734 pdc = DC_LockDc(hDC); 735 if (!pdc) 736 { 737 EngSetLastError(ERROR_INVALID_HANDLE); 738 return 0; 739 } 740 741 if (!pdc->dclevel.pSurface) 742 { 743 goto cleanup; 744 } 745 746 if (pdc->dctype == DCTYPE_DIRECT) 747 { 748 static BOOL g_WarnedOnce = FALSE; 749 if (!g_WarnedOnce) 750 { 751 g_WarnedOnce = TRUE; 752 UNIMPLEMENTED; 753 } 754 goto cleanup; 755 } 756 757 /// FIXME: shouldn't dereference pSurface while the PDEV is not locked 758 ppalSurf = pdc->dclevel.pSurface->ppal; 759 ppalDC = pdc->dclevel.ppal; 760 761 if (!(ppalSurf->flFlags & PAL_INDEXED)) 762 { 763 // FIXME: Set error? 764 goto cleanup; 765 } 766 767 ASSERT(ppalDC->flFlags & PAL_INDEXED); 768 769 // FIXME: Should we resize ppalSurf if it's too small? 770 realize = (ppalDC->NumColors < ppalSurf->NumColors) ? ppalDC->NumColors : ppalSurf->NumColors; 771 772 for (i=0; i<realize; i++) 773 { 774 InterlockedExchange((LONG*)&ppalSurf->IndexedColors[i], *(LONG*)&ppalDC->IndexedColors[i]); 775 } 776 777 cleanup: 778 DC_UnlockDc(pdc); 779 return realize; 780 } 781 782 UINT APIENTRY 783 IntAnimatePalette(HPALETTE hPal, 784 UINT StartIndex, 785 UINT NumEntries, 786 CONST PPALETTEENTRY PaletteColors) 787 { 788 UINT ret = 0; 789 790 if( hPal != NtGdiGetStockObject(DEFAULT_PALETTE) ) 791 { 792 PPALETTE palPtr; 793 UINT pal_entries; 794 const PALETTEENTRY *pptr = PaletteColors; 795 796 palPtr = PALETTE_ShareLockPalette(hPal); 797 if (!palPtr) return FALSE; 798 799 pal_entries = palPtr->NumColors; 800 if (StartIndex >= pal_entries) 801 { 802 PALETTE_ShareUnlockPalette(palPtr); 803 return FALSE; 804 } 805 if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex; 806 807 for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++) 808 { 809 /* According to MSDN, only animate PC_RESERVED colours */ 810 if (palPtr->IndexedColors[StartIndex].peFlags & PC_RESERVED) 811 { 812 memcpy( &palPtr->IndexedColors[StartIndex], pptr, 813 sizeof(PALETTEENTRY) ); 814 ret++; 815 PALETTE_ValidateFlags(&palPtr->IndexedColors[StartIndex], 1); 816 } 817 } 818 819 PALETTE_ShareUnlockPalette(palPtr); 820 821 #if 0 822 /* FIXME: This is completely broken! We cannot call UserGetDesktopWindow 823 without first acquiring the USER lock. But the whole process here is 824 screwed anyway. Instead of messing with the desktop DC, we need to 825 check, whether the palette is associated with a PDEV and whether that 826 PDEV supports palette operations. Then we need to call pfnDrvSetPalette. 827 But since IntGdiRealizePalette() is not even implemented for direct DCs, 828 we can as well just do nothing, that will at least not ASSERT! 829 I leave the whole thing here, to scare people away, who want to "fix" it. */ 830 831 /* Immediately apply the new palette if current window uses it */ 832 Wnd = UserGetDesktopWindow(); 833 hDC = UserGetWindowDC(Wnd); 834 dc = DC_LockDc(hDC); 835 if (NULL != dc) 836 { 837 if (dc->dclevel.hpal == hPal) 838 { 839 DC_UnlockDc(dc); 840 IntGdiRealizePalette(hDC); 841 } 842 else 843 DC_UnlockDc(dc); 844 } 845 UserReleaseDC(Wnd,hDC, FALSE); 846 #endif // 0 847 } 848 return ret; 849 } 850 851 UINT APIENTRY 852 IntGetPaletteEntries( 853 HPALETTE hpal, 854 UINT StartIndex, 855 UINT Entries, 856 LPPALETTEENTRY pe) 857 { 858 PPALETTE palGDI; 859 UINT numEntries; 860 861 palGDI = (PPALETTE) PALETTE_ShareLockPalette(hpal); 862 if (NULL == palGDI) 863 { 864 return 0; 865 } 866 867 numEntries = palGDI->NumColors; 868 if (NULL != pe) 869 { 870 if (numEntries < StartIndex + Entries) 871 { 872 Entries = numEntries - StartIndex; 873 } 874 if (numEntries <= StartIndex) 875 { 876 PALETTE_ShareUnlockPalette(palGDI); 877 return 0; 878 } 879 memcpy(pe, palGDI->IndexedColors + StartIndex, Entries * sizeof(PALETTEENTRY)); 880 } 881 else 882 { 883 Entries = numEntries; 884 } 885 886 PALETTE_ShareUnlockPalette(palGDI); 887 return Entries; 888 } 889 890 UINT APIENTRY 891 IntGetSystemPaletteEntries(HDC hDC, 892 UINT StartIndex, 893 UINT Entries, 894 LPPALETTEENTRY pe) 895 { 896 PPALETTE palGDI = NULL; 897 PDC dc = NULL; 898 UINT EntriesSize = 0; 899 UINT Ret = 0; 900 901 if (Entries == 0) 902 { 903 EngSetLastError(ERROR_INVALID_PARAMETER); 904 return 0; 905 } 906 907 if (pe != NULL) 908 { 909 EntriesSize = Entries * sizeof(pe[0]); 910 if (Entries != EntriesSize / sizeof(pe[0])) 911 { 912 /* Integer overflow! */ 913 EngSetLastError(ERROR_INVALID_PARAMETER); 914 return 0; 915 } 916 } 917 918 if (!(dc = DC_LockDc(hDC))) 919 { 920 EngSetLastError(ERROR_INVALID_HANDLE); 921 return 0; 922 } 923 924 palGDI = PALETTE_ShareLockPalette(dc->dclevel.hpal); 925 if (palGDI != NULL) 926 { 927 if (pe != NULL) 928 { 929 if (StartIndex >= palGDI->NumColors) 930 Entries = 0; 931 else if (Entries > palGDI->NumColors - StartIndex) 932 Entries = palGDI->NumColors - StartIndex; 933 934 memcpy(pe, 935 palGDI->IndexedColors + StartIndex, 936 Entries * sizeof(pe[0])); 937 938 Ret = Entries; 939 } 940 else 941 { 942 Ret = dc->ppdev->gdiinfo.ulNumPalReg; 943 } 944 } 945 946 if (palGDI != NULL) 947 PALETTE_ShareUnlockPalette(palGDI); 948 949 if (dc != NULL) 950 DC_UnlockDc(dc); 951 952 return Ret; 953 } 954 955 UINT 956 APIENTRY 957 IntSetPaletteEntries( 958 HPALETTE hpal, 959 UINT Start, 960 UINT Entries, 961 CONST LPPALETTEENTRY pe) 962 { 963 PPALETTE palGDI; 964 ULONG numEntries; 965 966 if ((UINT)hpal & GDI_HANDLE_STOCK_MASK) 967 { 968 return 0; 969 } 970 971 palGDI = PALETTE_ShareLockPalette(hpal); 972 if (!palGDI) return 0; 973 974 numEntries = palGDI->NumColors; 975 if (Start >= numEntries) 976 { 977 PALETTE_ShareUnlockPalette(palGDI); 978 return 0; 979 } 980 if (numEntries < Start + Entries) 981 { 982 Entries = numEntries - Start; 983 } 984 memcpy(palGDI->IndexedColors + Start, pe, Entries * sizeof(PALETTEENTRY)); 985 PALETTE_ShareUnlockPalette(palGDI); 986 987 return Entries; 988 } 989 990 ULONG 991 APIENTRY 992 GreGetSetColorTable( 993 HDC hdc, 994 ULONG iStartIndex, 995 ULONG cEntries, 996 RGBQUAD *prgbColors, 997 BOOL bSet) 998 { 999 PDC pdc; 1000 PSURFACE psurf; 1001 PPALETTE ppal = NULL; 1002 ULONG i, iEndIndex, iResult = 0; 1003 1004 /* Lock the DC */ 1005 pdc = DC_LockDc(hdc); 1006 if (!pdc) 1007 { 1008 return 0; 1009 } 1010 1011 /* Get the surface from the DC */ 1012 psurf = pdc->dclevel.pSurface; 1013 1014 /* Check if we have the default surface */ 1015 if (psurf == NULL) 1016 { 1017 /* Use a mono palette */ 1018 if (!bSet) 1019 ppal = gppalMono; 1020 } 1021 else if (psurf->SurfObj.iType == STYPE_BITMAP) 1022 { 1023 /* Get the palette of the surface */ 1024 ppal = psurf->ppal; 1025 } 1026 1027 /* Check if this is an indexed palette and the range is ok */ 1028 if (ppal && (ppal->flFlags & PAL_INDEXED) && 1029 (iStartIndex < ppal->NumColors)) 1030 { 1031 /* Calculate the end of the operation */ 1032 iEndIndex = min(iStartIndex + cEntries, ppal->NumColors); 1033 1034 /* Check what operation to perform */ 1035 if (bSet) 1036 { 1037 /* Loop all colors and set the palette entries */ 1038 for (i = iStartIndex; i < iEndIndex; i++, prgbColors++) 1039 { 1040 ppal->IndexedColors[i].peRed = prgbColors->rgbRed; 1041 ppal->IndexedColors[i].peGreen = prgbColors->rgbGreen; 1042 ppal->IndexedColors[i].peBlue = prgbColors->rgbBlue; 1043 } 1044 1045 /* Mark the dc brushes invalid */ 1046 pdc->pdcattr->ulDirty_ |= DIRTY_FILL|DIRTY_LINE| 1047 DIRTY_BACKGROUND|DIRTY_TEXT; 1048 } 1049 else 1050 { 1051 /* Loop all colors and get the palette entries */ 1052 for (i = iStartIndex; i < iEndIndex; i++, prgbColors++) 1053 { 1054 prgbColors->rgbRed = ppal->IndexedColors[i].peRed; 1055 prgbColors->rgbGreen = ppal->IndexedColors[i].peGreen; 1056 prgbColors->rgbBlue = ppal->IndexedColors[i].peBlue; 1057 prgbColors->rgbReserved = 0; 1058 } 1059 } 1060 1061 /* Calculate how many entries were modified */ 1062 iResult = iEndIndex - iStartIndex; 1063 } 1064 1065 /* Unlock the DC */ 1066 DC_UnlockDc(pdc); 1067 1068 return iResult; 1069 } 1070 1071 __kernel_entry 1072 LONG 1073 APIENTRY 1074 NtGdiDoPalette( 1075 _In_ HGDIOBJ hObj, 1076 _In_ WORD iStart, 1077 _In_ WORD cEntries, 1078 _When_(bInbound!=0, _In_reads_bytes_(cEntries*sizeof(PALETTEENTRY))) 1079 _When_(bInbound==0, _Out_writes_bytes_(cEntries*sizeof(PALETTEENTRY))) LPVOID pUnsafeEntries, 1080 _In_ DWORD iFunc, 1081 _In_ BOOL bInbound) 1082 { 1083 LONG ret; 1084 LPVOID pEntries = NULL; 1085 SIZE_T cjSize; 1086 1087 if (pUnsafeEntries) 1088 { 1089 if (cEntries == 0) 1090 return 0; 1091 1092 cjSize = cEntries * sizeof(PALETTEENTRY); 1093 pEntries = ExAllocatePoolWithTag(PagedPool, cjSize, TAG_PALETTE); 1094 if (!pEntries) 1095 return 0; 1096 1097 if (bInbound) 1098 { 1099 _SEH2_TRY 1100 { 1101 ProbeForRead(pUnsafeEntries, cjSize, 1); 1102 memcpy(pEntries, pUnsafeEntries, cjSize); 1103 } 1104 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1105 { 1106 ExFreePoolWithTag(pEntries, TAG_PALETTE); 1107 _SEH2_YIELD(return 0); 1108 } 1109 _SEH2_END 1110 } 1111 else 1112 { 1113 /* Zero it out, so we don't accidentally leak kernel data */ 1114 RtlZeroMemory(pEntries, cjSize); 1115 } 1116 } 1117 1118 ret = 0; 1119 switch(iFunc) 1120 { 1121 case GdiPalAnimate: 1122 if (pEntries) 1123 ret = IntAnimatePalette((HPALETTE)hObj, iStart, cEntries, (CONST PPALETTEENTRY)pEntries); 1124 break; 1125 1126 case GdiPalSetEntries: 1127 if (pEntries) 1128 ret = IntSetPaletteEntries((HPALETTE)hObj, iStart, cEntries, (CONST LPPALETTEENTRY)pEntries); 1129 break; 1130 1131 case GdiPalGetEntries: 1132 ret = IntGetPaletteEntries((HPALETTE)hObj, iStart, cEntries, (LPPALETTEENTRY)pEntries); 1133 break; 1134 1135 case GdiPalGetSystemEntries: 1136 ret = IntGetSystemPaletteEntries((HDC)hObj, iStart, cEntries, (LPPALETTEENTRY)pEntries); 1137 break; 1138 1139 case GdiPalSetColorTable: 1140 if (pEntries) 1141 ret = GreGetSetColorTable((HDC)hObj, iStart, cEntries, (RGBQUAD*)pEntries, TRUE); 1142 break; 1143 1144 case GdiPalGetColorTable: 1145 if (pEntries) 1146 ret = GreGetSetColorTable((HDC)hObj, iStart, cEntries, (RGBQUAD*)pEntries, FALSE); 1147 break; 1148 } 1149 1150 if (pEntries) 1151 { 1152 if (!bInbound && (ret > 0)) 1153 { 1154 cjSize = min(cEntries, ret) * sizeof(PALETTEENTRY); 1155 _SEH2_TRY 1156 { 1157 ProbeForWrite(pUnsafeEntries, cjSize, 1); 1158 memcpy(pUnsafeEntries, pEntries, cjSize); 1159 } 1160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1161 { 1162 ret = 0; 1163 } 1164 _SEH2_END 1165 } 1166 ExFreePoolWithTag(pEntries, TAG_PALETTE); 1167 } 1168 1169 return ret; 1170 } 1171 1172 UINT APIENTRY 1173 NtGdiSetSystemPaletteUse(HDC hDC, UINT Usage) 1174 { 1175 UINT old = SystemPaletteUse; 1176 1177 /* Device doesn't support colour palettes */ 1178 if (!(NtGdiGetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE)) { 1179 return SYSPAL_ERROR; 1180 } 1181 1182 switch (Usage) 1183 { 1184 case SYSPAL_NOSTATIC: 1185 case SYSPAL_NOSTATIC256: 1186 case SYSPAL_STATIC: 1187 SystemPaletteUse = Usage; 1188 break; 1189 1190 default: 1191 old=SYSPAL_ERROR; 1192 break; 1193 } 1194 1195 return old; 1196 } 1197 1198 UINT 1199 APIENTRY 1200 NtGdiGetSystemPaletteUse(HDC hDC) 1201 { 1202 return SystemPaletteUse; 1203 } 1204 1205 BOOL 1206 APIENTRY 1207 NtGdiUpdateColors(HDC hDC) 1208 { 1209 PWND Wnd; 1210 BOOL calledFromUser, ret; 1211 USER_REFERENCE_ENTRY Ref; 1212 1213 calledFromUser = UserIsEntered(); 1214 1215 if (!calledFromUser){ 1216 UserEnterExclusive(); 1217 } 1218 1219 Wnd = UserGetWindowObject(IntWindowFromDC(hDC)); 1220 if (Wnd == NULL) 1221 { 1222 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 1223 1224 if (!calledFromUser){ 1225 UserLeave(); 1226 } 1227 1228 return FALSE; 1229 } 1230 1231 UserRefObjectCo(Wnd, &Ref); 1232 ret = co_UserRedrawWindow(Wnd, NULL, 0, RDW_INVALIDATE); 1233 UserDerefObjectCo(Wnd); 1234 1235 if (!calledFromUser){ 1236 UserLeave(); 1237 } 1238 1239 return ret; 1240 } 1241 1242 BOOL 1243 APIENTRY 1244 NtGdiUnrealizeObject(HGDIOBJ hgdiobj) 1245 { 1246 BOOL Ret = FALSE; 1247 PPALETTE palGDI; 1248 1249 if ( !hgdiobj || 1250 ((UINT)hgdiobj & GDI_HANDLE_STOCK_MASK) || 1251 !GDI_HANDLE_IS_TYPE(hgdiobj, GDI_OBJECT_TYPE_PALETTE) ) 1252 return Ret; 1253 1254 palGDI = PALETTE_ShareLockPalette(hgdiobj); 1255 if (!palGDI) return FALSE; 1256 1257 // FIXME!! 1258 // Need to do something!!! 1259 // Zero out Current and Old Translated pointers? 1260 // 1261 Ret = TRUE; 1262 PALETTE_ShareUnlockPalette(palGDI); 1263 return Ret; 1264 } 1265 1266 1267 /* EOF */ 1268