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