1 /* 2 * PROJECT: ReactOS win32 kernel mode subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/dibobj.c 5 * PURPOSE: Dib object functions 6 * PROGRAMMER: 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 static const RGBQUAD DefLogPaletteQuads[20] = /* Copy of Default Logical Palette */ 15 { 16 /* rgbBlue, rgbGreen, rgbRed, rgbReserved */ 17 { 0x00, 0x00, 0x00, 0x00 }, 18 { 0x00, 0x00, 0x80, 0x00 }, 19 { 0x00, 0x80, 0x00, 0x00 }, 20 { 0x00, 0x80, 0x80, 0x00 }, 21 { 0x80, 0x00, 0x00, 0x00 }, 22 { 0x80, 0x00, 0x80, 0x00 }, 23 { 0x80, 0x80, 0x00, 0x00 }, 24 { 0xc0, 0xc0, 0xc0, 0x00 }, 25 { 0xc0, 0xdc, 0xc0, 0x00 }, 26 { 0xf0, 0xca, 0xa6, 0x00 }, 27 { 0xf0, 0xfb, 0xff, 0x00 }, 28 { 0xa4, 0xa0, 0xa0, 0x00 }, 29 { 0x80, 0x80, 0x80, 0x00 }, 30 { 0x00, 0x00, 0xff, 0x00 }, 31 { 0x00, 0xff, 0x00, 0x00 }, 32 { 0x00, 0xff, 0xff, 0x00 }, 33 { 0xff, 0x00, 0x00, 0x00 }, 34 { 0xff, 0x00, 0xff, 0x00 }, 35 { 0xff, 0xff, 0x00, 0x00 }, 36 { 0xff, 0xff, 0xff, 0x00 } 37 }; 38 39 PPALETTE 40 NTAPI 41 CreateDIBPalette( 42 _In_ const BITMAPINFO *pbmi, 43 _In_ PDC pdc, 44 _In_ ULONG iUsage) 45 { 46 PPALETTE ppal; 47 ULONG i, cBitsPixel, cColors; 48 49 if (pbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER)) 50 { 51 PBITMAPCOREINFO pbci = (PBITMAPCOREINFO)pbmi; 52 cBitsPixel = pbci->bmciHeader.bcBitCount; 53 } 54 else 55 { 56 cBitsPixel = pbmi->bmiHeader.biBitCount; 57 } 58 59 /* Check if the colors are indexed */ 60 if (cBitsPixel <= 8) 61 { 62 /* We create a "full" palette */ 63 cColors = 1 << cBitsPixel; 64 65 /* Allocate the palette */ 66 ppal = PALETTE_AllocPalette(PAL_INDEXED, 67 cColors, 68 NULL, 69 0, 70 0, 71 0); 72 if (ppal == NULL) 73 { 74 DPRINT1("Failed to allocate palette.\n"); 75 return NULL; 76 } 77 78 /* Check if the BITMAPINFO specifies how many colors to use */ 79 if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && 80 (pbmi->bmiHeader.biClrUsed != 0)) 81 { 82 /* This is how many colors we can actually process */ 83 cColors = min(cColors, pbmi->bmiHeader.biClrUsed); 84 } 85 86 /* Check how to use the colors */ 87 if (iUsage == DIB_PAL_COLORS) 88 { 89 COLORREF crColor; 90 91 /* The colors are an array of WORD indices into the DC palette */ 92 PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 93 94 /* Use the DCs palette or, if no DC is given, the default one */ 95 PPALETTE ppalDC = pdc ? pdc->dclevel.ppal : gppalDefault; 96 97 /* Loop all color indices in the DIB */ 98 for (i = 0; i < cColors; i++) 99 { 100 /* Get the palette index and handle wraparound when exceeding 101 the number of colors in the DC palette */ 102 WORD wIndex = pwColors[i] % ppalDC->NumColors; 103 104 /* USe the RGB value from the DC palette */ 105 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, wIndex); 106 PALETTE_vSetRGBColorForIndex(ppal, i, crColor); 107 } 108 } 109 else if (iUsage == DIB_PAL_BRUSHHACK) 110 { 111 /* The colors are an array of WORD indices into the DC palette */ 112 PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 113 114 /* Loop all color indices in the DIB */ 115 for (i = 0; i < cColors; i++) 116 { 117 /* Set the index directly as the RGB color, the real palette 118 containing RGB values will be calculated when the brush is 119 realized */ 120 PALETTE_vSetRGBColorForIndex(ppal, i, pwColors[i]); 121 } 122 123 /* Mark the palette as a brush hack palette */ 124 ppal->flFlags |= PAL_BRUSHHACK; 125 } 126 // else if (iUsage == 2) 127 // { 128 // FIXME: this one is undocumented 129 // ASSERT(FALSE); 130 // } 131 else if (pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) 132 { 133 /* The colors are an array of RGBQUAD values */ 134 RGBQUAD *prgb = (RGBQUAD*)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 135 RGBQUAD colors[256] = {{0}}; 136 137 // FIXME: do we need to handle PALETTEINDEX / PALETTERGB macro? 138 139 /* Use SEH to verify we can READ prgb[] succesfully */ 140 _SEH2_TRY 141 { 142 RtlCopyMemory(colors, prgb, cColors * sizeof(colors[0])); 143 } 144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 145 { 146 /* Do Nothing */ 147 } 148 _SEH2_END; 149 150 for (i = 0; i < cColors; ++i) 151 { 152 /* Get the color value and translate it to a COLORREF */ 153 COLORREF crColor = RGB(colors[i].rgbRed, colors[i].rgbGreen, colors[i].rgbBlue); 154 155 /* Set the RGB value in the palette */ 156 PALETTE_vSetRGBColorForIndex(ppal, i, crColor); 157 } 158 } 159 else 160 { 161 /* The colors are an array of RGBTRIPLE values */ 162 RGBTRIPLE *prgb = (RGBTRIPLE*)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 163 164 /* Loop all color indices in the DIB */ 165 for (i = 0; i < cColors; i++) 166 { 167 /* Get the color value and translate it to a COLORREF */ 168 RGBTRIPLE rgb = prgb[i]; 169 COLORREF crColor = RGB(rgb.rgbtRed, rgb.rgbtGreen, rgb.rgbtBlue); 170 171 /* Set the RGB value in the palette */ 172 PALETTE_vSetRGBColorForIndex(ppal, i, crColor); 173 } 174 } 175 } 176 else 177 { 178 /* This is a bitfield / RGB palette */ 179 ULONG flRedMask, flGreenMask, flBlueMask; 180 181 /* Check if the DIB contains bitfield values */ 182 if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && 183 (pbmi->bmiHeader.biCompression == BI_BITFIELDS)) 184 { 185 /* Check if we have a v4/v5 header */ 186 if (pbmi->bmiHeader.biSize >= sizeof(BITMAPV4HEADER)) 187 { 188 /* The masks are dedicated fields in the header */ 189 PBITMAPV4HEADER pbmV4Header = (PBITMAPV4HEADER)&pbmi->bmiHeader; 190 flRedMask = pbmV4Header->bV4RedMask; 191 flGreenMask = pbmV4Header->bV4GreenMask; 192 flBlueMask = pbmV4Header->bV4BlueMask; 193 } 194 else 195 { 196 /* The masks are the first 3 values in the DIB color table */ 197 PDWORD pdwColors = (PVOID)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 198 flRedMask = pdwColors[0]; 199 flGreenMask = pdwColors[1]; 200 flBlueMask = pdwColors[2]; 201 } 202 } 203 else 204 { 205 /* Check what bit depth we have. Note: optimization flags are 206 calculated in PALETTE_AllocPalette() */ 207 if (cBitsPixel == 16) 208 { 209 /* This is an RGB 555 palette */ 210 flRedMask = 0x7C00; 211 flGreenMask = 0x03E0; 212 flBlueMask = 0x001F; 213 } 214 else 215 { 216 /* This is an RGB 888 palette */ 217 flRedMask = 0xFF0000; 218 flGreenMask = 0x00FF00; 219 flBlueMask = 0x0000FF; 220 } 221 } 222 223 /* Allocate the bitfield palette */ 224 ppal = PALETTE_AllocPalette(PAL_BITFIELDS, 225 0, 226 NULL, 227 flRedMask, 228 flGreenMask, 229 flBlueMask); 230 } 231 232 /* We're done, return the palette */ 233 return ppal; 234 } 235 236 // Converts a DIB to a device-dependent bitmap 237 static INT 238 FASTCALL 239 IntSetDIBits( 240 PDC DC, 241 HBITMAP hBitmap, 242 UINT StartScan, 243 UINT ScanLines, 244 CONST VOID *Bits, 245 ULONG cjMaxBits, 246 CONST BITMAPINFO *bmi, 247 UINT ColorUse) 248 { 249 HBITMAP SourceBitmap; 250 PSURFACE psurfDst, psurfSrc; 251 INT result = 0; 252 RECT rcDst; 253 POINTL ptSrc; 254 EXLATEOBJ exlo; 255 PPALETTE ppalDIB = 0; 256 ULONG cjSizeImage; 257 258 if (!bmi || !Bits) return 0; 259 260 /* Check for uncompressed formats */ 261 if ((bmi->bmiHeader.biCompression == BI_RGB) || 262 (bmi->bmiHeader.biCompression == BI_BITFIELDS)) 263 { 264 /* Calculate the image size */ 265 cjSizeImage = DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth, 266 ScanLines, 267 bmi->bmiHeader.biBitCount); 268 } 269 /* Check if the header provided an image size */ 270 else if (bmi->bmiHeader.biSizeImage != 0) 271 { 272 /* Use the given size */ 273 cjSizeImage = bmi->bmiHeader.biSizeImage; 274 } 275 else 276 { 277 /* Compressed format without a size. This is invalid. */ 278 DPRINT1("Compressed format without a size!"); 279 return 0; 280 } 281 282 /* Check if the size that we have is ok */ 283 if ((cjSizeImage > cjMaxBits) || (cjSizeImage == 0)) 284 { 285 DPRINT1("Invalid bitmap size! cjSizeImage = %lu, cjMaxBits = %lu\n", 286 cjSizeImage, cjMaxBits); 287 return 0; 288 } 289 290 SourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth, 291 ScanLines, 292 0, 293 BitmapFormat(bmi->bmiHeader.biBitCount, 294 bmi->bmiHeader.biCompression), 295 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, 296 cjSizeImage, 297 (PVOID)Bits, 298 0); 299 if (!SourceBitmap) 300 { 301 DPRINT1("Error: Could not create a bitmap.\n"); 302 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 303 return 0; 304 } 305 306 psurfDst = SURFACE_ShareLockSurface(hBitmap); 307 psurfSrc = SURFACE_ShareLockSurface(SourceBitmap); 308 309 if(!(psurfSrc && psurfDst)) 310 { 311 DPRINT1("Error: Could not lock surfaces\n"); 312 goto cleanup; 313 } 314 315 /* Create a palette for the DIB */ 316 ppalDIB = CreateDIBPalette(bmi, DC, ColorUse); 317 if (!ppalDIB) 318 { 319 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 320 goto cleanup; 321 } 322 323 /* Initialize EXLATEOBJ */ 324 EXLATEOBJ_vInitialize(&exlo, 325 ppalDIB, 326 psurfDst->ppal, 327 RGB(0xff, 0xff, 0xff), 328 RGB(0xff, 0xff, 0xff), //DC->pdcattr->crBackgroundClr, 329 0); // DC->pdcattr->crForegroundClr); 330 331 rcDst.top = StartScan; 332 rcDst.left = 0; 333 rcDst.bottom = rcDst.top + ScanLines; 334 rcDst.right = psurfDst->SurfObj.sizlBitmap.cx; 335 ptSrc.x = 0; 336 ptSrc.y = 0; 337 338 result = IntEngCopyBits(&psurfDst->SurfObj, 339 &psurfSrc->SurfObj, 340 NULL, 341 &exlo.xlo, 342 &rcDst, 343 &ptSrc); 344 if(result) 345 result = ScanLines; 346 347 EXLATEOBJ_vCleanup(&exlo); 348 349 cleanup: 350 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB); 351 if(psurfSrc) SURFACE_ShareUnlockSurface(psurfSrc); 352 if(psurfDst) SURFACE_ShareUnlockSurface(psurfDst); 353 GreDeleteObject(SourceBitmap); 354 355 return result; 356 } 357 358 static 359 HBITMAP 360 IntGdiCreateMaskFromRLE( 361 DWORD Width, 362 DWORD Height, 363 ULONG Compression, 364 const BYTE* Bits, 365 DWORD BitsSize) 366 { 367 HBITMAP Mask; 368 DWORD x, y; 369 SURFOBJ* SurfObj; 370 UINT i = 0; 371 BYTE Data, NumPixels, ToSkip; 372 373 ASSERT((Compression == BI_RLE8) || (Compression == BI_RLE4)); 374 375 /* Create the bitmap */ 376 Mask = GreCreateBitmapEx(Width, Height, 0, BMF_1BPP, 0, 0, NULL, 0); 377 if (!Mask) 378 return NULL; 379 380 SurfObj = EngLockSurface((HSURF)Mask); 381 if (!SurfObj) 382 { 383 GreDeleteObject(Mask); 384 return NULL; 385 } 386 ASSERT(SurfObj->pvBits != NULL); 387 388 x = y = 0; 389 390 while (i < BitsSize) 391 { 392 NumPixels = Bits[i]; 393 Data = Bits[i + 1]; 394 i += 2; 395 396 if (NumPixels != 0) 397 { 398 if ((x + NumPixels) > Width) 399 NumPixels = Width - x; 400 401 if (NumPixels == 0) 402 continue; 403 404 DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1); 405 x += NumPixels; 406 continue; 407 } 408 409 if (Data < 3) 410 { 411 switch (Data) 412 { 413 case 0: 414 /* End of line */ 415 y++; 416 if (y == Height) 417 goto done; 418 x = 0; 419 break; 420 case 1: 421 /* End of file */ 422 goto done; 423 case 2: 424 /* Jump */ 425 if (i >= (BitsSize - 1)) 426 goto done; 427 x += Bits[i]; 428 if (x > Width) 429 x = Width; 430 y += Bits[i + 1]; 431 if (y >= Height) 432 goto done; 433 i += 2; 434 break; 435 } 436 /* Done for this run */ 437 continue; 438 } 439 440 /* Embedded data into the RLE */ 441 NumPixels = Data; 442 if (Compression == BI_RLE8) 443 ToSkip = NumPixels; 444 else 445 ToSkip = (NumPixels / 2) + (NumPixels & 1); 446 447 if ((i + ToSkip) > BitsSize) 448 goto done; 449 ToSkip = (ToSkip + 1) & ~1; 450 451 if ((x + NumPixels) > Width) 452 NumPixels = Width - x; 453 454 if (NumPixels != 0) 455 { 456 DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1); 457 x += NumPixels; 458 } 459 i += ToSkip; 460 } 461 462 done: 463 EngUnlockSurface(SurfObj); 464 return Mask; 465 } 466 467 W32KAPI 468 INT 469 APIENTRY 470 NtGdiSetDIBitsToDeviceInternal( 471 IN HDC hDC, 472 IN INT XDest, 473 IN INT YDest, 474 IN DWORD Width, 475 IN DWORD Height, 476 IN INT XSrc, 477 IN INT YSrc, 478 IN DWORD StartScan, 479 IN DWORD ScanLines, 480 IN LPBYTE Bits, 481 IN LPBITMAPINFO bmi, 482 IN DWORD ColorUse, 483 IN UINT cjMaxBits, 484 IN UINT cjMaxInfo, 485 IN BOOL bTransformCoordinates, 486 IN OPTIONAL HANDLE hcmXform) 487 { 488 INT ret; 489 PDC pDC = NULL; 490 HBITMAP hSourceBitmap = NULL, hMaskBitmap = NULL; 491 SURFOBJ *pDestSurf, *pSourceSurf = NULL, *pMaskSurf = NULL; 492 SURFACE *pSurf; 493 RECTL rcDest; 494 POINTL ptSource; 495 //INT DIBWidth; 496 SIZEL SourceSize; 497 EXLATEOBJ exlo; 498 PPALETTE ppalDIB = NULL; 499 LPBITMAPINFO pbmiSafe; 500 BOOL bResult; 501 502 if (!Bits) return 0; 503 504 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjMaxInfo, 'pmTG'); 505 if (!pbmiSafe) return 0; 506 507 _SEH2_TRY 508 { 509 ProbeForRead(bmi, cjMaxInfo, 1); 510 ProbeForRead(Bits, cjMaxBits, 1); 511 RtlCopyMemory(pbmiSafe, bmi, cjMaxInfo); 512 bmi = pbmiSafe; 513 } 514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 515 { 516 ret = 0; 517 goto Exit; 518 } 519 _SEH2_END; 520 521 ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan); 522 if (ScanLines == 0) 523 { 524 DPRINT1("ScanLines == 0\n"); 525 ret = 0; 526 goto Exit; 527 } 528 529 pDC = DC_LockDc(hDC); 530 if (!pDC) 531 { 532 EngSetLastError(ERROR_INVALID_HANDLE); 533 ret = 0; 534 goto Exit; 535 } 536 537 if (pDC->dctype == DCTYPE_INFO) 538 { 539 ret = 0; 540 goto Exit; 541 } 542 543 rcDest.left = XDest; 544 rcDest.top = YDest; 545 if (bTransformCoordinates) 546 { 547 IntLPtoDP(pDC, (LPPOINT)&rcDest, 2); 548 } 549 rcDest.left += pDC->ptlDCOrig.x; 550 rcDest.top += pDC->ptlDCOrig.y; 551 rcDest.right = rcDest.left + Width; 552 rcDest.bottom = rcDest.top + Height; 553 rcDest.top += StartScan; 554 555 if (pDC->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 556 { 557 IntUpdateBoundsRect(pDC, &rcDest); 558 } 559 560 ptSource.x = XSrc; 561 ptSource.y = YSrc; 562 563 SourceSize.cx = bmi->bmiHeader.biWidth; 564 SourceSize.cy = ScanLines; 565 566 //DIBWidth = WIDTH_BYTES_ALIGN32(SourceSize.cx, bmi->bmiHeader.biBitCount); 567 568 hSourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth, 569 ScanLines, 570 0, 571 BitmapFormat(bmi->bmiHeader.biBitCount, 572 bmi->bmiHeader.biCompression), 573 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, 574 bmi->bmiHeader.biSizeImage, 575 Bits, 576 0); 577 578 if (!hSourceBitmap) 579 { 580 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 581 ret = 0; 582 goto Exit; 583 } 584 585 pSourceSurf = EngLockSurface((HSURF)hSourceBitmap); 586 if (!pSourceSurf) 587 { 588 ret = 0; 589 goto Exit; 590 } 591 592 /* HACK: If this is a RLE bitmap, only the relevant pixels must be set. */ 593 if ((bmi->bmiHeader.biCompression == BI_RLE8) || (bmi->bmiHeader.biCompression == BI_RLE4)) 594 { 595 hMaskBitmap = IntGdiCreateMaskFromRLE(bmi->bmiHeader.biWidth, 596 ScanLines, 597 bmi->bmiHeader.biCompression, 598 Bits, 599 cjMaxBits); 600 if (!hMaskBitmap) 601 { 602 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 603 ret = 0; 604 goto Exit; 605 } 606 pMaskSurf = EngLockSurface((HSURF)hMaskBitmap); 607 if (!pMaskSurf) 608 { 609 ret = 0; 610 goto Exit; 611 } 612 } 613 614 /* Create a palette for the DIB */ 615 ppalDIB = CreateDIBPalette(bmi, pDC, ColorUse); 616 if (!ppalDIB) 617 { 618 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 619 ret = 0; 620 goto Exit; 621 } 622 623 /* This is actually a blit */ 624 DC_vPrepareDCsForBlit(pDC, &rcDest, NULL, NULL); 625 pSurf = pDC->dclevel.pSurface; 626 if (!pSurf) 627 { 628 DC_vFinishBlit(pDC, NULL); 629 ret = ScanLines; 630 goto Exit; 631 } 632 633 ASSERT(pSurf->ppal); 634 635 /* Initialize EXLATEOBJ */ 636 EXLATEOBJ_vInitialize(&exlo, 637 ppalDIB, 638 pSurf->ppal, 639 RGB(0xff, 0xff, 0xff), 640 pDC->pdcattr->crBackgroundClr, 641 pDC->pdcattr->crForegroundClr); 642 643 pDestSurf = &pSurf->SurfObj; 644 645 /* Copy the bits */ 646 DPRINT("BitsToDev with rcDest=(%d|%d) (%d|%d), ptSource=(%d|%d) w=%d h=%d\n", 647 rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, 648 ptSource.x, ptSource.y, SourceSize.cx, SourceSize.cy); 649 650 /* This fixes the large Google text on Google.com from being upside down */ 651 if (rcDest.top > rcDest.bottom) 652 { 653 RECTL_vMakeWellOrdered(&rcDest); 654 ptSource.y -= SourceSize.cy; 655 } 656 657 bResult = IntEngBitBlt(pDestSurf, 658 pSourceSurf, 659 pMaskSurf, 660 (CLIPOBJ *)&pDC->co, 661 &exlo.xlo, 662 &rcDest, 663 &ptSource, 664 pMaskSurf ? &ptSource : NULL, 665 NULL, 666 NULL, 667 pMaskSurf ? ROP4_MASK : ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY)); 668 669 /* Cleanup EXLATEOBJ */ 670 EXLATEOBJ_vCleanup(&exlo); 671 672 /* We're done */ 673 DC_vFinishBlit(pDC, NULL); 674 675 ret = bResult ? ScanLines : 0; 676 677 Exit: 678 679 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB); 680 if (pSourceSurf) EngUnlockSurface(pSourceSurf); 681 if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap); 682 if (pMaskSurf) EngUnlockSurface(pMaskSurf); 683 if (hMaskBitmap) EngDeleteSurface((HSURF)hMaskBitmap); 684 if (pDC) DC_UnlockDc(pDC); 685 ExFreePoolWithTag(pbmiSafe, 'pmTG'); 686 687 return ret; 688 } 689 690 691 /* Converts a device-dependent bitmap to a DIB */ 692 INT 693 APIENTRY 694 GreGetDIBitsInternal( 695 HDC hDC, 696 HBITMAP hBitmap, 697 UINT StartScan, 698 UINT ScanLines, 699 LPBYTE Bits, 700 LPBITMAPINFO Info, 701 UINT Usage, 702 UINT MaxBits, 703 UINT MaxInfo) 704 { 705 BITMAPCOREINFO* pbmci = NULL; 706 PSURFACE psurf = NULL; 707 PDC pDC; 708 LONG width, height; 709 WORD planes, bpp; 710 DWORD compr, size ; 711 USHORT i; 712 int bitmap_type; 713 RGBQUAD* rgbQuads; 714 VOID* colorPtr; 715 716 DPRINT("Entered GreGetDIBitsInternal()\n"); 717 718 if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap) 719 return 0; 720 721 pDC = DC_LockDc(hDC); 722 if (pDC == NULL || pDC->dctype == DCTYPE_INFO) 723 { 724 ScanLines = 0; 725 goto done; 726 } 727 728 /* Get a pointer to the source bitmap object */ 729 psurf = SURFACE_ShareLockSurface(hBitmap); 730 if (psurf == NULL) 731 { 732 ScanLines = 0; 733 goto done; 734 } 735 736 colorPtr = (LPBYTE)Info + Info->bmiHeader.biSize; 737 rgbQuads = colorPtr; 738 739 bitmap_type = DIB_GetBitmapInfo(&Info->bmiHeader, 740 &width, 741 &height, 742 &planes, 743 &bpp, 744 &compr, 745 &size); 746 if(bitmap_type == -1) 747 { 748 DPRINT1("Wrong bitmap format\n"); 749 EngSetLastError(ERROR_INVALID_PARAMETER); 750 ScanLines = 0; 751 goto done; 752 } 753 else if(bitmap_type == 0) 754 { 755 /* We need a BITMAPINFO to create a DIB, but we have to fill 756 * the BITMAPCOREINFO we're provided */ 757 pbmci = (BITMAPCOREINFO*)Info; 758 /* fill in the the bit count, so we can calculate the right ColorsSize during the conversion */ 759 pbmci->bmciHeader.bcBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat); 760 Info = DIB_ConvertBitmapInfo((BITMAPINFO*)pbmci, Usage); 761 if(Info == NULL) 762 { 763 DPRINT1("Error, could not convert the BITMAPCOREINFO!\n"); 764 ScanLines = 0; 765 goto done; 766 } 767 rgbQuads = Info->bmiColors; 768 } 769 770 /* Validate input: 771 - negative width is always an invalid value 772 - non-null Bits and zero bpp is an invalid combination 773 - only check the rest of the input params if either bpp is non-zero or Bits are set */ 774 if (width < 0 || (bpp == 0 && Bits)) 775 { 776 ScanLines = 0; 777 goto done; 778 } 779 780 if (Bits || bpp) 781 { 782 if ((height == 0 || width == 0) || (compr && compr != BI_BITFIELDS && compr != BI_RGB)) 783 { 784 ScanLines = 0; 785 goto done; 786 } 787 } 788 789 Info->bmiHeader.biClrUsed = 0; 790 Info->bmiHeader.biClrImportant = 0; 791 792 /* Fill in the structure */ 793 switch(bpp) 794 { 795 case 0: /* Only info */ 796 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx; 797 Info->bmiHeader.biHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ? 798 -psurf->SurfObj.sizlBitmap.cy : 799 psurf->SurfObj.sizlBitmap.cy; 800 Info->bmiHeader.biPlanes = 1; 801 Info->bmiHeader.biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat); 802 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( Info->bmiHeader.biWidth, 803 Info->bmiHeader.biHeight, 804 Info->bmiHeader.biBitCount); 805 Info->bmiHeader.biCompression = (Info->bmiHeader.biBitCount == 16 || Info->bmiHeader.biBitCount == 32) ? 806 BI_BITFIELDS : BI_RGB; 807 Info->bmiHeader.biXPelsPerMeter = 0; 808 Info->bmiHeader.biYPelsPerMeter = 0; 809 810 if (Info->bmiHeader.biBitCount <= 8 && Info->bmiHeader.biClrUsed == 0) 811 Info->bmiHeader.biClrUsed = 1 << Info->bmiHeader.biBitCount; 812 813 ScanLines = 1; 814 goto done; 815 816 case 1: 817 case 4: 818 case 8: 819 Info->bmiHeader.biClrUsed = 1 << bpp; 820 821 /* If the bitmap is a DIB section and has the same format as what 822 * is requested, go ahead! */ 823 if((psurf->hSecure) && 824 (BitsPerFormat(psurf->SurfObj.iBitmapFormat) == bpp)) 825 { 826 if(Usage == DIB_RGB_COLORS) 827 { 828 ULONG colors = min(psurf->ppal->NumColors, 256); 829 if(colors != 256) Info->bmiHeader.biClrUsed = colors; 830 for(i = 0; i < colors; i++) 831 { 832 rgbQuads[i].rgbRed = psurf->ppal->IndexedColors[i].peRed; 833 rgbQuads[i].rgbGreen = psurf->ppal->IndexedColors[i].peGreen; 834 rgbQuads[i].rgbBlue = psurf->ppal->IndexedColors[i].peBlue; 835 rgbQuads[i].rgbReserved = 0; 836 } 837 } 838 else 839 { 840 for(i = 0; i < 256; i++) 841 ((WORD*)rgbQuads)[i] = i; 842 } 843 } 844 else 845 { 846 if(Usage == DIB_PAL_COLORS) 847 { 848 for(i = 0; i < 256; i++) 849 { 850 ((WORD*)rgbQuads)[i] = i; 851 } 852 } 853 else if(bpp > 1 && bpp == BitsPerFormat(psurf->SurfObj.iBitmapFormat)) 854 { 855 /* For color DDBs in native depth (mono DDBs always have 856 a black/white palette): 857 Generate the color map from the selected palette */ 858 PPALETTE pDcPal = PALETTE_ShareLockPalette(pDC->dclevel.hpal); 859 if(!pDcPal) 860 { 861 ScanLines = 0 ; 862 goto done ; 863 } 864 for (i = 0; i < pDcPal->NumColors; i++) 865 { 866 rgbQuads[i].rgbRed = pDcPal->IndexedColors[i].peRed; 867 rgbQuads[i].rgbGreen = pDcPal->IndexedColors[i].peGreen; 868 rgbQuads[i].rgbBlue = pDcPal->IndexedColors[i].peBlue; 869 rgbQuads[i].rgbReserved = 0; 870 } 871 PALETTE_ShareUnlockPalette(pDcPal); 872 } 873 else 874 { 875 switch (bpp) 876 { 877 case 1: 878 rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0; 879 rgbQuads[0].rgbReserved = 0; 880 rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff; 881 rgbQuads[1].rgbReserved = 0; 882 break; 883 884 case 4: 885 /* The EGA palette is the first and last 8 colours of the default palette 886 with the innermost pair swapped */ 887 RtlCopyMemory(rgbQuads, DefLogPaletteQuads, 7 * sizeof(RGBQUAD)); 888 RtlCopyMemory(rgbQuads + 7, DefLogPaletteQuads + 12, 1 * sizeof(RGBQUAD)); 889 RtlCopyMemory(rgbQuads + 8, DefLogPaletteQuads + 7, 1 * sizeof(RGBQUAD)); 890 RtlCopyMemory(rgbQuads + 9, DefLogPaletteQuads + 13, 7 * sizeof(RGBQUAD)); 891 break; 892 893 case 8: 894 { 895 INT i; 896 897 memcpy(rgbQuads, DefLogPaletteQuads, 10 * sizeof(RGBQUAD)); 898 memcpy(rgbQuads + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD)); 899 900 for (i = 10; i < 246; i++) 901 { 902 rgbQuads[i].rgbRed = (i & 0x07) << 5; 903 rgbQuads[i].rgbGreen = (i & 0x38) << 2; 904 rgbQuads[i].rgbBlue = i & 0xc0; 905 rgbQuads[i].rgbReserved = 0; 906 } 907 } 908 } 909 } 910 } 911 break; 912 913 case 15: 914 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 915 { 916 ((PDWORD)Info->bmiColors)[0] = 0x7c00; 917 ((PDWORD)Info->bmiColors)[1] = 0x03e0; 918 ((PDWORD)Info->bmiColors)[2] = 0x001f; 919 } 920 break; 921 922 case 16: 923 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 924 { 925 if (psurf->hSecure) 926 { 927 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask; 928 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask; 929 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask; 930 } 931 else 932 { 933 ((PDWORD)Info->bmiColors)[0] = 0xf800; 934 ((PDWORD)Info->bmiColors)[1] = 0x07e0; 935 ((PDWORD)Info->bmiColors)[2] = 0x001f; 936 } 937 } 938 break; 939 940 case 24: 941 case 32: 942 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 943 { 944 if (psurf->hSecure) 945 { 946 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask; 947 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask; 948 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask; 949 } 950 else 951 { 952 ((PDWORD)Info->bmiColors)[0] = 0xff0000; 953 ((PDWORD)Info->bmiColors)[1] = 0x00ff00; 954 ((PDWORD)Info->bmiColors)[2] = 0x0000ff; 955 } 956 } 957 break; 958 959 default: 960 ScanLines = 0; 961 goto done; 962 } 963 964 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(width, height, bpp); 965 Info->bmiHeader.biPlanes = 1; 966 967 if(Bits && ScanLines) 968 { 969 /* Create a DIBSECTION, blt it, profit */ 970 PVOID pDIBits ; 971 HBITMAP hBmpDest; 972 PSURFACE psurfDest; 973 EXLATEOBJ exlo; 974 RECT rcDest; 975 POINTL srcPoint; 976 BOOL ret ; 977 int newLines = -1; 978 979 if (StartScan >= abs(Info->bmiHeader.biHeight)) 980 { 981 ScanLines = 1; 982 goto done; 983 } 984 else 985 { 986 ScanLines = min(ScanLines, abs(Info->bmiHeader.biHeight) - StartScan); 987 } 988 989 if (abs(Info->bmiHeader.biHeight) < psurf->SurfObj.sizlBitmap.cy) 990 { 991 StartScan += psurf->SurfObj.sizlBitmap.cy - abs(Info->bmiHeader.biHeight); 992 } 993 /* Fixup values */ 994 Info->bmiHeader.biHeight = (height < 0) ? 995 -(LONG)ScanLines : ScanLines; 996 /* Create the DIB */ 997 hBmpDest = DIB_CreateDIBSection(pDC, Info, Usage, &pDIBits, NULL, 0, 0); 998 /* Restore them */ 999 Info->bmiHeader.biHeight = height; 1000 1001 if(!hBmpDest) 1002 { 1003 DPRINT1("Unable to create a DIB Section!\n"); 1004 EngSetLastError(ERROR_INVALID_PARAMETER); 1005 ScanLines = 0; 1006 goto done ; 1007 } 1008 1009 psurfDest = SURFACE_ShareLockSurface(hBmpDest); 1010 1011 RECTL_vSetRect(&rcDest, 0, 0, Info->bmiHeader.biWidth, ScanLines); 1012 Info->bmiHeader.biWidth = width; 1013 srcPoint.x = 0; 1014 1015 if (abs(Info->bmiHeader.biHeight) <= psurf->SurfObj.sizlBitmap.cy) 1016 { 1017 srcPoint.y = psurf->SurfObj.sizlBitmap.cy - StartScan - ScanLines; 1018 } 1019 else 1020 { 1021 /* Determine the actual number of lines copied from the */ 1022 /* original bitmap. It might be different from ScanLines. */ 1023 newLines = abs(Info->bmiHeader.biHeight) - psurf->SurfObj.sizlBitmap.cy; 1024 newLines = min((int)(StartScan + ScanLines - newLines), psurf->SurfObj.sizlBitmap.cy); 1025 if (newLines > 0) 1026 { 1027 srcPoint.y = psurf->SurfObj.sizlBitmap.cy - newLines; 1028 if (StartScan > psurf->SurfObj.sizlBitmap.cy) 1029 { 1030 newLines -= (StartScan - psurf->SurfObj.sizlBitmap.cy); 1031 } 1032 } 1033 else 1034 { 1035 newLines = 0; 1036 srcPoint.y = psurf->SurfObj.sizlBitmap.cy; 1037 } 1038 } 1039 1040 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xffffff, 0xffffff, 0); 1041 1042 ret = IntEngCopyBits(&psurfDest->SurfObj, 1043 &psurf->SurfObj, 1044 NULL, 1045 &exlo.xlo, 1046 &rcDest, 1047 &srcPoint); 1048 1049 SURFACE_ShareUnlockSurface(psurfDest); 1050 1051 if(!ret) 1052 ScanLines = 0; 1053 else 1054 { 1055 RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp)); 1056 } 1057 /* Update if line count has changed */ 1058 if (newLines != -1) 1059 { 1060 ScanLines = (UINT)newLines; 1061 } 1062 GreDeleteObject(hBmpDest); 1063 EXLATEOBJ_vCleanup(&exlo); 1064 } 1065 else 1066 { 1067 /* Signals success and not the actual number of scan lines*/ 1068 ScanLines = 1; 1069 } 1070 1071 done: 1072 1073 if (pbmci) 1074 DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci, Usage); 1075 1076 if (psurf) 1077 SURFACE_ShareUnlockSurface(psurf); 1078 1079 if (pDC) 1080 DC_UnlockDc(pDC); 1081 1082 return ScanLines; 1083 } 1084 1085 _Success_(return!=0) 1086 __kernel_entry 1087 INT 1088 APIENTRY 1089 NtGdiGetDIBitsInternal( 1090 _In_ HDC hdc, 1091 _In_ HBITMAP hbm, 1092 _In_ UINT iStartScan, 1093 _In_ UINT cScans, 1094 _Out_writes_bytes_opt_(cjMaxBits) LPBYTE pjBits, 1095 _Inout_ LPBITMAPINFO pbmi, 1096 _In_ UINT iUsage, 1097 _In_ UINT cjMaxBits, 1098 _In_ UINT cjMaxInfo) 1099 { 1100 PBITMAPINFO pbmiSafe; 1101 HANDLE hSecure = NULL; 1102 INT iResult = 0; 1103 UINT cjAlloc; 1104 1105 /* Check for bad iUsage */ 1106 if (iUsage > 2) return 0; 1107 1108 /* Check if the size of the bitmap info is large enough */ 1109 if (cjMaxInfo < sizeof(BITMAPCOREHEADER)) 1110 { 1111 return 0; 1112 } 1113 1114 /* Use maximum size */ 1115 cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)); 1116 1117 // HACK: the underlying code sucks and doesn't care for the size, so we 1118 // give it the maximum ever needed 1119 cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD); 1120 1121 /* Allocate a buffer the bitmapinfo */ 1122 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG'); 1123 if (!pbmiSafe) 1124 { 1125 /* Fail */ 1126 return 0; 1127 } 1128 1129 /* Use SEH */ 1130 _SEH2_TRY 1131 { 1132 /* Probe and copy the BITMAPINFO */ 1133 ProbeForRead(pbmi, cjMaxInfo, 1); 1134 RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo); 1135 } 1136 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1137 { 1138 goto cleanup; 1139 } 1140 _SEH2_END; 1141 1142 /* Check if the header size is large enough */ 1143 if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) || 1144 (pbmiSafe->bmiHeader.biSize > cjMaxInfo)) 1145 { 1146 goto cleanup; 1147 } 1148 1149 /* Check if the caller provided bitmap bits */ 1150 if (pjBits) 1151 { 1152 /* Secure the user mode memory */ 1153 hSecure = EngSecureMem(pjBits, cjMaxBits); 1154 if (!hSecure) 1155 { 1156 goto cleanup; 1157 } 1158 } 1159 1160 /* Now call the internal function */ 1161 iResult = GreGetDIBitsInternal(hdc, 1162 hbm, 1163 iStartScan, 1164 cScans, 1165 pjBits, 1166 pbmiSafe, 1167 iUsage, 1168 cjMaxBits, 1169 cjMaxInfo); 1170 1171 /* Check for success */ 1172 if (iResult) 1173 { 1174 /* Use SEH to copy back to user mode */ 1175 _SEH2_TRY 1176 { 1177 /* Copy the data back */ 1178 cjMaxInfo = min(cjMaxInfo, (UINT)DIB_BitmapInfoSize(pbmiSafe, (WORD)iUsage)); 1179 ProbeForWrite(pbmi, cjMaxInfo, 1); 1180 RtlCopyMemory(pbmi, pbmiSafe, cjMaxInfo); 1181 } 1182 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1183 { 1184 /* Ignore */ 1185 (VOID)0; 1186 } 1187 _SEH2_END; 1188 } 1189 1190 cleanup: 1191 if (hSecure) EngUnsecureMem(hSecure); 1192 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1193 1194 return iResult; 1195 } 1196 1197 1198 W32KAPI 1199 INT 1200 APIENTRY 1201 NtGdiStretchDIBitsInternal( 1202 IN HDC hdc, 1203 IN INT xDst, 1204 IN INT yDst, 1205 IN INT cxDst, 1206 IN INT cyDst, 1207 IN INT xSrc, 1208 IN INT ySrc, 1209 IN INT cxSrc, 1210 IN INT cySrc, 1211 IN OPTIONAL LPBYTE pjInit, 1212 IN LPBITMAPINFO pbmi, 1213 IN DWORD dwUsage, 1214 IN DWORD dwRop, // MS ntgdi.h says dwRop4(?) 1215 IN UINT cjMaxInfo, 1216 IN UINT cjMaxBits, 1217 IN HANDLE hcmXform) 1218 { 1219 SIZEL sizel; 1220 RECTL rcSrc, rcDst; 1221 PDC pdc; 1222 HBITMAP hbmTmp = 0; 1223 PSURFACE psurfTmp = 0, psurfDst = 0; 1224 PPALETTE ppalDIB = 0; 1225 EXLATEOBJ exlo; 1226 PBYTE pvBits; 1227 1228 LPBITMAPINFO pbmiSafe; 1229 UINT cjAlloc; 1230 HBITMAP hBitmap, hOldBitmap = NULL; 1231 HDC hdcMem; 1232 HPALETTE hPal = NULL; 1233 ULONG BmpFormat = 0; 1234 INT LinesCopied = 0; 1235 1236 /* Check for bad iUsage */ 1237 if (dwUsage > 2) return 0; 1238 1239 /* We must have LPBITMAPINFO */ 1240 if (!pbmi) 1241 { 1242 DPRINT1("Error, Invalid Parameter.\n"); 1243 EngSetLastError(ERROR_INVALID_PARAMETER); 1244 return 0; 1245 } 1246 1247 /* Check if the size of the bitmap info is large enough */ 1248 if (cjMaxInfo < sizeof(BITMAPCOREHEADER)) 1249 { 1250 return 0; 1251 } 1252 1253 /* Use maximum size */ 1254 cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)); 1255 1256 // HACK: the underlying code sucks and doesn't care for the size, so we 1257 // give it the maximum ever needed 1258 cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD); 1259 1260 /* Allocate a buffer the bitmapinfo */ 1261 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG'); 1262 if (!pbmiSafe) 1263 { 1264 /* Fail */ 1265 return 0; 1266 } 1267 1268 /* Use SEH */ 1269 _SEH2_TRY 1270 { 1271 /* Probe and copy the BITMAPINFO */ 1272 ProbeForRead(pbmi, cjMaxInfo, 1); 1273 RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo); 1274 } 1275 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1276 { 1277 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1278 return 0; 1279 } 1280 _SEH2_END; 1281 1282 /* Check if the header size is large enough */ 1283 if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) || 1284 (pbmiSafe->bmiHeader.biSize > cjMaxInfo)) 1285 { 1286 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1287 return 0; 1288 } 1289 1290 if (!(pdc = DC_LockDc(hdc))) 1291 { 1292 EngSetLastError(ERROR_INVALID_HANDLE); 1293 return 0; 1294 } 1295 1296 /* Check for info / mem DC without surface */ 1297 if (!pdc->dclevel.pSurface) 1298 { 1299 DC_UnlockDc(pdc); 1300 // CHECKME 1301 return TRUE; 1302 } 1303 1304 /* Transform dest size */ 1305 sizel.cx = cxDst; 1306 sizel.cy = cyDst; 1307 IntLPtoDP(pdc, (POINTL*)&sizel, 1); 1308 DC_UnlockDc(pdc); 1309 1310 if (pjInit && (cjMaxBits > 0)) 1311 { 1312 pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB); 1313 if (!pvBits) 1314 { 1315 return 0; 1316 } 1317 1318 _SEH2_TRY 1319 { 1320 ProbeForRead(pjInit, cjMaxBits, 1); 1321 RtlCopyMemory(pvBits, pjInit, cjMaxBits); 1322 } 1323 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1324 { 1325 ExFreePoolWithTag(pvBits, TAG_DIB); 1326 return 0; 1327 } 1328 _SEH2_END; 1329 } 1330 else 1331 { 1332 pvBits = NULL; 1333 } 1334 1335 /* Here we select between the dwRop with SRCCOPY or not. */ 1336 if (dwRop == SRCCOPY) 1337 { 1338 hdcMem = NtGdiCreateCompatibleDC(hdc); 1339 if (hdcMem == NULL) 1340 { 1341 DPRINT1("NtGdiCreateCompatibleDC failed to create hdc.\n"); 1342 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 1343 return 0; 1344 } 1345 1346 hBitmap = NtGdiCreateCompatibleBitmap(hdc, 1347 abs(pbmiSafe->bmiHeader.biWidth), 1348 abs(pbmiSafe->bmiHeader.biHeight)); 1349 if (hBitmap == NULL) 1350 { 1351 DPRINT1("NtGdiCreateCompatibleBitmap failed to create bitmap.\n"); 1352 DPRINT1("hdc : 0x%08x \n", hdc); 1353 DPRINT1("width : 0x%08x \n", pbmiSafe->bmiHeader.biWidth); 1354 DPRINT1("height : 0x%08x \n", pbmiSafe->bmiHeader.biHeight); 1355 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 1356 return 0; 1357 } 1358 1359 /* Select the bitmap into hdcMem, and save a handle to the old bitmap */ 1360 hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap); 1361 1362 if (dwUsage == DIB_PAL_COLORS) 1363 { 1364 hPal = NtGdiGetDCObject(hdc, GDI_OBJECT_TYPE_PALETTE); 1365 hPal = GdiSelectPalette(hdcMem, hPal, FALSE); 1366 } 1367 1368 pdc = DC_LockDc(hdcMem); 1369 if (pdc != NULL) 1370 { 1371 IntSetDIBits(pdc, hBitmap, 0, abs(pbmiSafe->bmiHeader.biHeight), pvBits, 1372 cjMaxBits, pbmiSafe, dwUsage); 1373 DC_UnlockDc(pdc); 1374 } 1375 1376 /* Origin for DIBitmap may be bottom left (positive biHeight) or top 1377 left (negative biHeight) */ 1378 if (cxSrc == cxDst && cySrc == cyDst) 1379 { 1380 NtGdiBitBlt(hdc, xDst, yDst, cxDst, cyDst, 1381 hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc - ySrc, 1382 dwRop, 0, 0); 1383 } 1384 else 1385 { 1386 NtGdiStretchBlt(hdc, xDst, yDst, cxDst, cyDst, 1387 hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc - ySrc, 1388 cxSrc, cySrc, dwRop, 0); 1389 } 1390 1391 /* cleanup */ 1392 if (hPal) 1393 GdiSelectPalette(hdcMem, hPal, FALSE); 1394 1395 if (hOldBitmap) 1396 NtGdiSelectBitmap(hdcMem, hOldBitmap); 1397 1398 NtGdiDeleteObjectApp(hdcMem); 1399 GreDeleteObject(hBitmap); 1400 1401 } /* End of dwRop == SRCCOPY */ 1402 else 1403 { /* Start of dwRop != SRCCOPY */ 1404 /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */ 1405 if (!(pdc = DC_LockDc(hdc))) 1406 { 1407 DPRINT1("Could not lock dc\n"); 1408 EngSetLastError(ERROR_INVALID_HANDLE); 1409 goto cleanup; 1410 } 1411 1412 /* Calculate source and destination rect */ 1413 rcSrc.left = xSrc; 1414 rcSrc.top = ySrc; 1415 rcSrc.right = xSrc + abs(cxSrc); 1416 rcSrc.bottom = ySrc + abs(cySrc); 1417 rcDst.left = xDst; 1418 rcDst.top = yDst; 1419 rcDst.right = rcDst.left + cxDst; 1420 rcDst.bottom = rcDst.top + cyDst; 1421 IntLPtoDP(pdc, (POINTL*)&rcDst, 2); 1422 RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); 1423 1424 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 1425 { 1426 IntUpdateBoundsRect(pdc, &rcDst); 1427 } 1428 1429 BmpFormat = BitmapFormat(pbmiSafe->bmiHeader.biBitCount, 1430 pbmiSafe->bmiHeader.biCompression); 1431 1432 hbmTmp = GreCreateBitmapEx(pbmiSafe->bmiHeader.biWidth, 1433 abs(pbmiSafe->bmiHeader.biHeight), 1434 0, 1435 BmpFormat, 1436 pbmiSafe->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, 1437 cjMaxBits, 1438 pvBits, 1439 0); 1440 1441 if (!hbmTmp) 1442 { 1443 goto cleanup; 1444 } 1445 1446 psurfTmp = SURFACE_ShareLockSurface(hbmTmp); 1447 if (!psurfTmp) 1448 { 1449 goto cleanup; 1450 } 1451 1452 /* Create a palette for the DIB */ 1453 ppalDIB = CreateDIBPalette(pbmiSafe, pdc, dwUsage); 1454 if (!ppalDIB) 1455 { 1456 goto cleanup; 1457 } 1458 1459 /* Prepare DC for blit */ 1460 DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL); 1461 1462 psurfDst = pdc->dclevel.pSurface; 1463 1464 /* Initialize XLATEOBJ */ 1465 EXLATEOBJ_vInitialize(&exlo, 1466 ppalDIB, 1467 psurfDst->ppal, 1468 RGB(0xff, 0xff, 0xff), 1469 pdc->pdcattr->crBackgroundClr, 1470 pdc->pdcattr->crForegroundClr); 1471 1472 /* Perform the stretch operation */ 1473 IntEngStretchBlt(&psurfDst->SurfObj, 1474 &psurfTmp->SurfObj, 1475 NULL, 1476 (CLIPOBJ *)&pdc->co, 1477 &exlo.xlo, 1478 &pdc->dclevel.ca, 1479 &rcDst, 1480 &rcSrc, 1481 NULL, 1482 &pdc->eboFill.BrushObject, 1483 NULL, 1484 WIN32_ROP3_TO_ENG_ROP4(dwRop)); 1485 1486 /* Cleanup */ 1487 DC_vFinishBlit(pdc, NULL); 1488 EXLATEOBJ_vCleanup(&exlo); 1489 1490 cleanup: 1491 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB); 1492 if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp); 1493 if (hbmTmp) GreDeleteObject(hbmTmp); 1494 if (pdc) DC_UnlockDc(pdc); 1495 } 1496 1497 if (pvBits) ExFreePoolWithTag(pvBits, TAG_DIB); 1498 1499 /* This is not what MSDN says is returned from this function, but it 1500 * follows Wine's dlls/gdi32/dib.c function nulldrv_StretchDIBits 1501 * and it fixes over 100 gdi32:dib regression tests. */ 1502 if (dwRop == SRCCOPY) 1503 { 1504 LinesCopied = abs(pbmiSafe->bmiHeader.biHeight); 1505 } 1506 else 1507 { 1508 LinesCopied = pbmiSafe->bmiHeader.biHeight; 1509 } 1510 1511 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1512 1513 return LinesCopied; 1514 } 1515 1516 1517 HBITMAP 1518 FASTCALL 1519 IntCreateDIBitmap( 1520 PDC Dc, 1521 INT width, 1522 INT height, 1523 UINT planes, 1524 UINT bpp, 1525 ULONG compression, 1526 DWORD init, 1527 LPBYTE bits, 1528 ULONG cjMaxBits, 1529 PBITMAPINFO data, 1530 DWORD coloruse) 1531 { 1532 HBITMAP handle; 1533 BOOL fColor; 1534 ULONG BmpFormat = 0; 1535 1536 if (planes && bpp) 1537 BmpFormat = BitmapFormat(planes * bpp, compression); 1538 1539 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2 1540 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap. 1541 1542 if (BmpFormat != BMF_1BPP) fColor = TRUE; 1543 else if ((coloruse > DIB_RGB_COLORS) || ((init & CBM_INIT) == 0) || !data) fColor = FALSE; 1544 else 1545 { 1546 const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize); 1547 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue); 1548 1549 // Check if the first color of the colormap is black 1550 if (col == RGB(0, 0, 0)) 1551 { 1552 rgb++; 1553 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue); 1554 1555 // If the second color is white, create a monochrome bitmap 1556 fColor = (col != RGB(0xff,0xff,0xff)); 1557 } 1558 else fColor = TRUE; 1559 } 1560 1561 // Now create the bitmap 1562 if (fColor) 1563 { 1564 if (init & CBM_CREATDIB) 1565 { 1566 PSURFACE Surface; 1567 PPALETTE Palette; 1568 1569 /* Undocumented flag which creates a DDB of the format specified by the bitmap info. */ 1570 handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp); 1571 if (!handle) 1572 { 1573 DPRINT1("IntCreateCompatibleBitmap() failed!\n"); 1574 return NULL; 1575 } 1576 1577 /* The palette must also match the given data */ 1578 Surface = SURFACE_ShareLockSurface(handle); 1579 ASSERT(Surface); 1580 Palette = CreateDIBPalette(data, Dc, coloruse); 1581 ASSERT(Palette); 1582 SURFACE_vSetPalette(Surface, Palette); 1583 1584 PALETTE_ShareUnlockPalette(Palette); 1585 SURFACE_ShareUnlockSurface(Surface); 1586 } 1587 else 1588 { 1589 /* Create a regular compatible bitmap, in the same format as the device */ 1590 handle = IntCreateCompatibleBitmap(Dc, width, height, 0, 0); 1591 } 1592 } 1593 else 1594 { 1595 handle = GreCreateBitmap(width, 1596 abs(height), 1597 1, 1598 1, 1599 NULL); 1600 } 1601 1602 if (height < 0) 1603 height = -height; 1604 1605 if ((NULL != handle) && (CBM_INIT & init)) 1606 { 1607 IntSetDIBits(Dc, handle, 0, height, bits, cjMaxBits, data, coloruse); 1608 } 1609 1610 return handle; 1611 } 1612 1613 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits 1614 // The DDB that is created will be whatever bit depth your reference DC is 1615 HBITMAP 1616 APIENTRY 1617 NtGdiCreateDIBitmapInternal( 1618 IN HDC hDc, 1619 IN INT cx, 1620 IN INT cy, 1621 IN DWORD fInit, 1622 IN OPTIONAL LPBYTE pjInit, 1623 IN OPTIONAL LPBITMAPINFO pbmi, 1624 IN DWORD iUsage, 1625 IN UINT cjMaxInitInfo, 1626 IN UINT cjMaxBits, 1627 IN FLONG fl, 1628 IN HANDLE hcmXform) 1629 { 1630 NTSTATUS Status = STATUS_SUCCESS; 1631 PBYTE safeBits = NULL; 1632 HBITMAP hbmResult = NULL; 1633 1634 if (pjInit == NULL) 1635 { 1636 fInit &= ~CBM_INIT; 1637 } 1638 1639 if(pjInit && (fInit & CBM_INIT)) 1640 { 1641 if (cjMaxBits == 0) return NULL; 1642 safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB); 1643 if(!safeBits) 1644 { 1645 DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits); 1646 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1647 return NULL; 1648 } 1649 } 1650 1651 _SEH2_TRY 1652 { 1653 if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1); 1654 if(pjInit && (fInit & CBM_INIT)) 1655 { 1656 ProbeForRead(pjInit, cjMaxBits, 1); 1657 RtlCopyMemory(safeBits, pjInit, cjMaxBits); 1658 } 1659 } 1660 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1661 { 1662 Status = _SEH2_GetExceptionCode(); 1663 } 1664 _SEH2_END; 1665 1666 if(!NT_SUCCESS(Status)) 1667 { 1668 DPRINT1("Got an exception! pjInit = %p\n", pjInit); 1669 SetLastNtError(Status); 1670 goto cleanup; 1671 } 1672 1673 hbmResult = GreCreateDIBitmapInternal(hDc, 1674 cx, 1675 cy, 1676 fInit, 1677 safeBits, 1678 pbmi, 1679 iUsage, 1680 fl, 1681 cjMaxBits, 1682 hcmXform); 1683 1684 cleanup: 1685 if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB); 1686 return hbmResult; 1687 } 1688 1689 HBITMAP 1690 NTAPI 1691 GreCreateDIBitmapInternal( 1692 IN HDC hDc, 1693 IN INT cx, 1694 IN INT cy, 1695 IN DWORD fInit, 1696 IN OPTIONAL LPBYTE pjInit, 1697 IN OPTIONAL PBITMAPINFO pbmi, 1698 IN DWORD iUsage, 1699 IN FLONG fl, 1700 IN UINT cjMaxBits, 1701 IN HANDLE hcmXform) 1702 { 1703 PDC Dc; 1704 HBITMAP Bmp; 1705 USHORT bpp, planes; 1706 DWORD compression; 1707 HDC hdcDest; 1708 1709 if (!hDc) /* 1bpp monochrome bitmap */ 1710 { 1711 // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this. 1712 hdcDest = NtGdiCreateCompatibleDC(0); 1713 if(!hdcDest) 1714 { 1715 DPRINT1("NtGdiCreateCompatibleDC failed\n"); 1716 return NULL; 1717 } 1718 } 1719 else 1720 { 1721 hdcDest = hDc; 1722 } 1723 1724 Dc = DC_LockDc(hdcDest); 1725 if (!Dc) 1726 { 1727 DPRINT1("Failed to lock hdcDest %p\n", hdcDest); 1728 EngSetLastError(ERROR_INVALID_HANDLE); 1729 return NULL; 1730 } 1731 /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap 1732 * if bpp != 1 and ignore the real value that was passed */ 1733 if (pbmi) 1734 { 1735 if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 1736 { 1737 BITMAPCOREHEADER* CoreHeader = (BITMAPCOREHEADER*)&pbmi->bmiHeader; 1738 bpp = CoreHeader->bcBitCount; 1739 planes = CoreHeader->bcPlanes ? CoreHeader->bcPlanes : 1; 1740 compression = BI_RGB; 1741 } 1742 else 1743 { 1744 bpp = pbmi->bmiHeader.biBitCount; 1745 planes = pbmi->bmiHeader.biPlanes ? pbmi->bmiHeader.biPlanes : 1; 1746 compression = pbmi->bmiHeader.biCompression; 1747 } 1748 } 1749 else 1750 { 1751 bpp = 0; 1752 planes = 0; 1753 compression = 0; 1754 } 1755 Bmp = IntCreateDIBitmap(Dc, cx, cy, planes, bpp, compression, fInit, pjInit, cjMaxBits, pbmi, iUsage); 1756 DC_UnlockDc(Dc); 1757 1758 if(!hDc) 1759 { 1760 NtGdiDeleteObjectApp(hdcDest); 1761 } 1762 return Bmp; 1763 } 1764 1765 HBITMAP 1766 NTAPI 1767 GreCreateDIBitmapFromPackedDIB( 1768 _In_reads_(cjPackedDIB )PVOID pvPackedDIB, 1769 _In_ UINT cjPackedDIB, 1770 _In_ ULONG uUsage) 1771 { 1772 PBITMAPINFO pbmi; 1773 PBYTE pjBits; 1774 UINT cjInfo, cjBits; 1775 HBITMAP hbm; 1776 1777 /* We only support BITMAPINFOHEADER, make sure the size is ok */ 1778 if (cjPackedDIB < sizeof(BITMAPINFOHEADER)) 1779 { 1780 return NULL; 1781 } 1782 1783 /* The packed DIB starts with the BITMAPINFOHEADER */ 1784 pbmi = pvPackedDIB; 1785 1786 if (cjPackedDIB < pbmi->bmiHeader.biSize) 1787 { 1788 return NULL; 1789 } 1790 1791 /* Calculate the info size and make sure the packed DIB is large enough */ 1792 cjInfo = DIB_BitmapInfoSize(pbmi, uUsage); 1793 if (cjPackedDIB <= cjInfo) 1794 { 1795 return NULL; 1796 } 1797 1798 /* The bitmap bits start after the header */ 1799 pjBits = (PBYTE)pvPackedDIB + cjInfo; 1800 cjBits = cjPackedDIB - cjInfo; 1801 1802 hbm = GreCreateDIBitmapInternal(NULL, 1803 pbmi->bmiHeader.biWidth, 1804 abs(pbmi->bmiHeader.biHeight), 1805 CBM_INIT | CBM_CREATDIB, 1806 pjBits, 1807 pbmi, 1808 uUsage, 1809 0, 1810 cjBits, 1811 NULL); 1812 1813 return hbm; 1814 } 1815 1816 HBITMAP 1817 APIENTRY 1818 NtGdiCreateDIBSection( 1819 IN HDC hDC, 1820 IN OPTIONAL HANDLE hSection, 1821 IN DWORD dwOffset, 1822 IN BITMAPINFO* bmi, 1823 IN DWORD Usage, 1824 IN UINT cjHeader, 1825 IN FLONG fl, 1826 IN ULONG_PTR dwColorSpace, 1827 OUT PVOID *Bits) 1828 { 1829 HBITMAP hbitmap = 0; 1830 DC *dc; 1831 BOOL bDesktopDC = FALSE; 1832 NTSTATUS Status = STATUS_SUCCESS; 1833 1834 if (!bmi) return hbitmap; // Make sure. 1835 1836 _SEH2_TRY 1837 { 1838 ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1); 1839 ProbeForRead(bmi, bmi->bmiHeader.biSize, 1); 1840 ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, (WORD)Usage), 1); 1841 } 1842 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1843 { 1844 Status = _SEH2_GetExceptionCode(); 1845 } 1846 _SEH2_END; 1847 1848 if(!NT_SUCCESS(Status)) 1849 { 1850 SetLastNtError(Status); 1851 return NULL; 1852 } 1853 1854 // If the reference hdc is null, take the desktop dc 1855 if (hDC == 0) 1856 { 1857 hDC = NtGdiCreateCompatibleDC(0); 1858 bDesktopDC = TRUE; 1859 } 1860 1861 if ((dc = DC_LockDc(hDC))) 1862 { 1863 hbitmap = DIB_CreateDIBSection(dc, 1864 bmi, 1865 Usage, 1866 Bits, 1867 hSection, 1868 dwOffset, 1869 0); 1870 DC_UnlockDc(dc); 1871 } 1872 else 1873 { 1874 EngSetLastError(ERROR_INVALID_HANDLE); 1875 } 1876 1877 if (bDesktopDC) 1878 NtGdiDeleteObjectApp(hDC); 1879 1880 return hbitmap; 1881 } 1882 1883 HBITMAP 1884 APIENTRY 1885 DIB_CreateDIBSection( 1886 PDC dc, 1887 CONST BITMAPINFO *bmi, 1888 UINT usage, 1889 LPVOID *bits, 1890 HANDLE section, 1891 DWORD offset, 1892 DWORD ovr_pitch) 1893 { 1894 HBITMAP res = 0; 1895 SURFACE *bmp = NULL; 1896 void *mapBits = NULL; 1897 PPALETTE ppalDIB = NULL; 1898 1899 // Fill BITMAP32 structure with DIB data 1900 CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader; 1901 INT effHeight; 1902 ULONG totalSize; 1903 BITMAP bm; 1904 //SIZEL Size; 1905 HANDLE hSecure; 1906 1907 DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n", 1908 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount, 1909 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB"); 1910 1911 /* CreateDIBSection should fail for compressed formats */ 1912 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8) 1913 { 1914 DPRINT1("no compressed format allowed\n"); 1915 return (HBITMAP)NULL; 1916 } 1917 1918 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight; 1919 bm.bmType = 0; 1920 bm.bmWidth = bi->biWidth; 1921 bm.bmHeight = effHeight; 1922 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount); 1923 1924 bm.bmPlanes = bi->biPlanes; 1925 bm.bmBitsPixel = bi->biBitCount; 1926 bm.bmBits = NULL; 1927 1928 // Get storage location for DIB bits. Only use biSizeImage if it's valid and 1929 // we're dealing with a compressed bitmap. Otherwise, use width * height. 1930 totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS)) 1931 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight); 1932 1933 if (section) 1934 { 1935 SYSTEM_BASIC_INFORMATION Sbi; 1936 NTSTATUS Status; 1937 DWORD mapOffset; 1938 LARGE_INTEGER SectionOffset; 1939 SIZE_T mapSize; 1940 1941 Status = ZwQuerySystemInformation(SystemBasicInformation, 1942 &Sbi, 1943 sizeof Sbi, 1944 0); 1945 if (!NT_SUCCESS(Status)) 1946 { 1947 DPRINT1("ZwQuerySystemInformation failed (0x%lx)\n", Status); 1948 return NULL; 1949 } 1950 1951 mapOffset = offset - (offset % Sbi.AllocationGranularity); 1952 mapSize = totalSize + (offset - mapOffset); 1953 1954 SectionOffset.LowPart = mapOffset; 1955 SectionOffset.HighPart = 0; 1956 1957 Status = ZwMapViewOfSection(section, 1958 NtCurrentProcess(), 1959 &mapBits, 1960 0, 1961 0, 1962 &SectionOffset, 1963 &mapSize, 1964 ViewShare, 1965 0, 1966 PAGE_READWRITE); 1967 if (!NT_SUCCESS(Status)) 1968 { 1969 DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status); 1970 EngSetLastError(ERROR_INVALID_PARAMETER); 1971 return NULL; 1972 } 1973 1974 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset); 1975 } 1976 else if (ovr_pitch && offset) 1977 bm.bmBits = UlongToPtr(offset); 1978 else 1979 { 1980 offset = 0; 1981 bm.bmBits = EngAllocUserMem(totalSize, 0); 1982 if(!bm.bmBits) 1983 { 1984 DPRINT1("Failed to allocate memory\n"); 1985 goto cleanup; 1986 } 1987 } 1988 1989 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE); 1990 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!! 1991 1992 1993 // Create Device Dependent Bitmap and add DIB pointer 1994 //Size.cx = bm.bmWidth; 1995 //Size.cy = abs(bm.bmHeight); 1996 res = GreCreateBitmapEx(bm.bmWidth, 1997 abs(bm.bmHeight), 1998 bm.bmWidthBytes, 1999 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression), 2000 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT | 2001 ((bi->biHeight < 0) ? BMF_TOPDOWN : 0), 2002 totalSize, 2003 bm.bmBits, 2004 0); 2005 if (!res) 2006 { 2007 DPRINT1("GreCreateBitmapEx failed\n"); 2008 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 2009 goto cleanup; 2010 } 2011 bmp = SURFACE_ShareLockSurface(res); // HACK 2012 if (NULL == bmp) 2013 { 2014 DPRINT1("SURFACE_LockSurface failed\n"); 2015 EngSetLastError(ERROR_INVALID_HANDLE); 2016 goto cleanup; 2017 } 2018 2019 /* WINE NOTE: WINE makes use of a colormap, which is a color translation 2020 table between the DIB and the X physical device. Obviously, 2021 this is left out of the ReactOS implementation. Instead, 2022 we call NtGdiSetDIBColorTable. */ 2023 bmp->hDIBSection = section; 2024 bmp->hSecure = hSecure; 2025 bmp->dwOffset = offset; 2026 bmp->flags = API_BITMAP; 2027 bmp->biClrImportant = bi->biClrImportant; 2028 2029 /* Create a palette for the DIB */ 2030 ppalDIB = CreateDIBPalette(bmi, dc, usage); 2031 2032 // Clean up in case of errors 2033 cleanup: 2034 if (!res || !bmp || !bm.bmBits || !ppalDIB) 2035 { 2036 DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits); 2037 if (bm.bmBits) 2038 { 2039 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this! 2040 if (section) 2041 { 2042 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits); 2043 bm.bmBits = NULL; 2044 } 2045 else if (!offset) 2046 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL; 2047 } 2048 2049 if (bmp) 2050 { 2051 SURFACE_ShareUnlockSurface(bmp); 2052 bmp = NULL; 2053 } 2054 2055 if (res) 2056 { 2057 GreDeleteObject(res); 2058 res = 0; 2059 } 2060 2061 if(ppalDIB) 2062 { 2063 PALETTE_ShareUnlockPalette(ppalDIB); 2064 } 2065 } 2066 2067 if (bmp) 2068 { 2069 /* If we're here, everything went fine */ 2070 SURFACE_vSetPalette(bmp, ppalDIB); 2071 PALETTE_ShareUnlockPalette(ppalDIB); 2072 SURFACE_ShareUnlockSurface(bmp); 2073 } 2074 2075 // Return BITMAP handle and storage location 2076 if (NULL != bm.bmBits && NULL != bits) 2077 { 2078 *bits = bm.bmBits; 2079 } 2080 2081 return res; 2082 } 2083 2084 /*********************************************************************** 2085 * DIB_GetBitmapInfo 2086 * 2087 * Get the info from a bitmap header. 2088 * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error. 2089 */ 2090 int 2091 FASTCALL 2092 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width, 2093 LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size ) 2094 { 2095 if (header->biSize == sizeof(BITMAPCOREHEADER)) 2096 { 2097 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header; 2098 *width = core->bcWidth; 2099 *height = core->bcHeight; 2100 *planes = core->bcPlanes; 2101 *bpp = core->bcBitCount; 2102 *compr = BI_RGB; 2103 *size = 0; 2104 return 0; 2105 } 2106 if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* Assume BITMAPINFOHEADER */ 2107 { 2108 *width = header->biWidth; 2109 *height = header->biHeight; 2110 *planes = header->biPlanes; 2111 *bpp = header->biBitCount; 2112 *compr = header->biCompression; 2113 *size = header->biSizeImage; 2114 return 1; 2115 } 2116 DPRINT1("(%u): unknown/wrong size for header\n", header->biSize ); 2117 return -1; 2118 } 2119 2120 /*********************************************************************** 2121 * DIB_GetDIBImageBytes 2122 * 2123 * Return the number of bytes used to hold the image in a DIB bitmap. 2124 * 11/16/1999 (RJJ) lifted from wine 2125 */ 2126 2127 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth) 2128 { 2129 return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height); 2130 } 2131 2132 /*********************************************************************** 2133 * DIB_BitmapInfoSize 2134 * 2135 * Return the size of the bitmap info structure including color table. 2136 * 11/16/1999 (RJJ) lifted from wine 2137 */ 2138 2139 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse) 2140 { 2141 unsigned int colors, size, masks = 0; 2142 unsigned int colorsize; 2143 2144 colorsize = (coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : 2145 (coloruse == DIB_PAL_INDICES) ? 0 : 2146 sizeof(WORD); 2147 2148 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 2149 { 2150 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info; 2151 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0; 2152 return sizeof(BITMAPCOREHEADER) + colors * colorsize; 2153 } 2154 else /* Assume BITMAPINFOHEADER */ 2155 { 2156 colors = info->bmiHeader.biClrUsed; 2157 if (colors > 256) colors = 256; 2158 if (!colors && (info->bmiHeader.biBitCount <= 8)) 2159 colors = 1 << info->bmiHeader.biBitCount; 2160 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3; 2161 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) ); 2162 return size + colors * colorsize; 2163 } 2164 } 2165 2166 HPALETTE 2167 FASTCALL 2168 DIB_MapPaletteColors(PPALETTE ppalDc, CONST BITMAPINFO* lpbmi) 2169 { 2170 PPALETTE ppalNew; 2171 ULONG nNumColors,i; 2172 USHORT *lpIndex; 2173 HPALETTE hpal; 2174 2175 if (!(ppalDc->flFlags & PAL_INDEXED)) 2176 { 2177 return NULL; 2178 } 2179 2180 nNumColors = 1 << lpbmi->bmiHeader.biBitCount; 2181 if (lpbmi->bmiHeader.biClrUsed) 2182 { 2183 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed); 2184 } 2185 2186 ppalNew = PALETTE_AllocPalWithHandle(PAL_INDEXED, nNumColors, NULL, 0, 0, 0); 2187 if (ppalNew == NULL) 2188 { 2189 DPRINT1("Could not allocate palette\n"); 2190 return NULL; 2191 } 2192 2193 lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize); 2194 2195 for (i = 0; i < nNumColors; i++) 2196 { 2197 ULONG iColorIndex = *lpIndex % ppalDc->NumColors; 2198 ppalNew->IndexedColors[i] = ppalDc->IndexedColors[iColorIndex]; 2199 lpIndex++; 2200 } 2201 2202 hpal = ppalNew->BaseObject.hHmgr; 2203 PALETTE_UnlockPalette(ppalNew); 2204 2205 return hpal; 2206 } 2207 2208 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure, 2209 * or does nothing if it's already a BITMAPINFO (or V4 or V5) */ 2210 BITMAPINFO* 2211 FASTCALL 2212 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage) 2213 { 2214 CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi; 2215 BITMAPINFO* pNewBmi ; 2216 UINT numColors = 0, ColorsSize = 0; 2217 2218 if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi; 2219 if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL; 2220 2221 if(pbmci->bmciHeader.bcBitCount <= 8) 2222 { 2223 numColors = 1 << pbmci->bmciHeader.bcBitCount; 2224 if(Usage == DIB_PAL_COLORS) 2225 { 2226 ColorsSize = numColors * sizeof(WORD); 2227 } 2228 else 2229 { 2230 ColorsSize = numColors * sizeof(RGBQUAD); 2231 } 2232 } 2233 else if (Usage == DIB_PAL_COLORS) 2234 { 2235 /* Invalid at high-res */ 2236 return NULL; 2237 } 2238 2239 pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB); 2240 if(!pNewBmi) return NULL; 2241 2242 RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize); 2243 2244 pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 2245 pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount; 2246 pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth; 2247 pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight; 2248 pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes; 2249 pNewBmi->bmiHeader.biCompression = BI_RGB ; 2250 pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth, 2251 pNewBmi->bmiHeader.biHeight, 2252 pNewBmi->bmiHeader.biBitCount); 2253 pNewBmi->bmiHeader.biClrUsed = numColors; 2254 2255 if(Usage == DIB_PAL_COLORS) 2256 { 2257 RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize); 2258 } 2259 else 2260 { 2261 UINT i; 2262 for(i=0; i<numColors; i++) 2263 { 2264 pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed; 2265 pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen; 2266 pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue; 2267 } 2268 } 2269 2270 return pNewBmi ; 2271 } 2272 2273 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */ 2274 VOID 2275 FASTCALL 2276 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage) 2277 { 2278 BITMAPCOREINFO* pbmci; 2279 if(converted == orig) 2280 return; 2281 2282 if(usage == -1) 2283 { 2284 /* Caller don't want any conversion */ 2285 ExFreePoolWithTag(converted, TAG_DIB); 2286 return; 2287 } 2288 2289 /* Perform inverse conversion */ 2290 pbmci = (BITMAPCOREINFO*)orig; 2291 2292 ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER)); 2293 pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount; 2294 pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth; 2295 pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight; 2296 pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes; 2297 2298 if(pbmci->bmciHeader.bcBitCount <= 8) 2299 { 2300 UINT numColors = converted->bmiHeader.biClrUsed; 2301 if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount; 2302 if(usage == DIB_PAL_COLORS) 2303 { 2304 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD)); 2305 RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD)); 2306 } 2307 else 2308 { 2309 UINT i; 2310 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE)); 2311 for(i=0; i<numColors; i++) 2312 { 2313 pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed; 2314 pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen; 2315 pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue; 2316 } 2317 } 2318 } 2319 /* Now free it, it's not needed anymore */ 2320 ExFreePoolWithTag(converted, TAG_DIB); 2321 } 2322 2323 /* EOF */ 2324