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\n"); 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 DPRINT("StartScan %d ScanLines %d Bits %p bmi %p ColorUse %d\n" 522 " Height %d Width %d SizeImage %d\n" 523 " biHeight %d biWidth %d biBitCount %d\n" 524 " XSrc %d YSrc %d xDext %d yDest %d\n", 525 StartScan, ScanLines, Bits, bmi, ColorUse, 526 Height, Width, bmi->bmiHeader.biSizeImage, 527 bmi->bmiHeader.biHeight, bmi->bmiHeader.biWidth, 528 bmi->bmiHeader.biBitCount, 529 XSrc, YSrc, XDest, YDest); 530 531 if (YDest >= 0) 532 { 533 ScanLines = min(abs(Height), ScanLines); 534 if (YSrc > 0) 535 ScanLines += YSrc; 536 } 537 else 538 { 539 ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan); 540 } 541 542 if (ScanLines == 0) 543 { 544 DPRINT1("ScanLines == 0\n"); 545 ret = 0; 546 goto Exit; 547 } 548 549 pDC = DC_LockDc(hDC); 550 if (!pDC) 551 { 552 EngSetLastError(ERROR_INVALID_HANDLE); 553 ret = 0; 554 goto Exit; 555 } 556 557 if (pDC->dctype == DCTYPE_INFO) 558 { 559 ret = 0; 560 goto Exit; 561 } 562 563 rcDest.left = XDest; 564 rcDest.top = YDest; 565 if (bTransformCoordinates) 566 { 567 IntLPtoDP(pDC, (LPPOINT)&rcDest, 2); 568 } 569 rcDest.left += pDC->ptlDCOrig.x; 570 rcDest.top += pDC->ptlDCOrig.y; 571 rcDest.right = rcDest.left + Width; 572 rcDest.bottom = rcDest.top + Height; 573 rcDest.top += StartScan; 574 575 if (pDC->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 576 { 577 IntUpdateBoundsRect(pDC, &rcDest); 578 } 579 580 ptSource.x = XSrc; 581 ptSource.y = YSrc; 582 583 SourceSize.cx = bmi->bmiHeader.biWidth; 584 SourceSize.cy = ScanLines; 585 if (YDest >= 0 && YSrc > 0) 586 { 587 ScanLines += YSrc; 588 } 589 590 //DIBWidth = WIDTH_BYTES_ALIGN32(SourceSize.cx, bmi->bmiHeader.biBitCount); 591 592 hSourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth, 593 ScanLines, 594 0, 595 BitmapFormat(bmi->bmiHeader.biBitCount, 596 bmi->bmiHeader.biCompression), 597 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, 598 bmi->bmiHeader.biSizeImage, 599 Bits, 600 0); 601 602 if (!hSourceBitmap) 603 { 604 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 605 ret = 0; 606 goto Exit; 607 } 608 609 pSourceSurf = EngLockSurface((HSURF)hSourceBitmap); 610 if (!pSourceSurf) 611 { 612 ret = 0; 613 goto Exit; 614 } 615 616 /* HACK: If this is a RLE bitmap, only the relevant pixels must be set. */ 617 if ((bmi->bmiHeader.biCompression == BI_RLE8) || (bmi->bmiHeader.biCompression == BI_RLE4)) 618 { 619 hMaskBitmap = IntGdiCreateMaskFromRLE(bmi->bmiHeader.biWidth, 620 ScanLines, 621 bmi->bmiHeader.biCompression, 622 Bits, 623 cjMaxBits); 624 if (!hMaskBitmap) 625 { 626 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 627 ret = 0; 628 goto Exit; 629 } 630 pMaskSurf = EngLockSurface((HSURF)hMaskBitmap); 631 if (!pMaskSurf) 632 { 633 ret = 0; 634 goto Exit; 635 } 636 } 637 638 /* Create a palette for the DIB */ 639 ppalDIB = CreateDIBPalette(bmi, pDC, ColorUse); 640 if (!ppalDIB) 641 { 642 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 643 ret = 0; 644 goto Exit; 645 } 646 647 /* This is actually a blit */ 648 DC_vPrepareDCsForBlit(pDC, &rcDest, NULL, NULL); 649 pSurf = pDC->dclevel.pSurface; 650 if (!pSurf) 651 { 652 DC_vFinishBlit(pDC, NULL); 653 ret = ScanLines; 654 goto Exit; 655 } 656 657 ASSERT(pSurf->ppal); 658 659 /* Initialize EXLATEOBJ */ 660 EXLATEOBJ_vInitialize(&exlo, 661 ppalDIB, 662 pSurf->ppal, 663 RGB(0xff, 0xff, 0xff), 664 pDC->pdcattr->crBackgroundClr, 665 pDC->pdcattr->crForegroundClr); 666 667 pDestSurf = &pSurf->SurfObj; 668 669 /* Copy the bits */ 670 DPRINT("BitsToDev with rcDest=(%d|%d) (%d|%d), ptSource=(%d|%d) w=%d h=%d\n", 671 rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, 672 ptSource.x, ptSource.y, SourceSize.cx, SourceSize.cy); 673 674 /* This fixes the large Google text on Google.com from being upside down */ 675 if (rcDest.top > rcDest.bottom) 676 { 677 RECTL_vMakeWellOrdered(&rcDest); 678 ptSource.y -= SourceSize.cy; 679 } 680 681 bResult = IntEngBitBlt(pDestSurf, 682 pSourceSurf, 683 pMaskSurf, 684 (CLIPOBJ *)&pDC->co, 685 &exlo.xlo, 686 &rcDest, 687 &ptSource, 688 pMaskSurf ? &ptSource : NULL, 689 NULL, 690 NULL, 691 pMaskSurf ? ROP4_MASK : ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY)); 692 693 /* Cleanup EXLATEOBJ */ 694 EXLATEOBJ_vCleanup(&exlo); 695 696 /* We're done */ 697 DC_vFinishBlit(pDC, NULL); 698 699 ret = bResult ? ScanLines : 0; 700 701 Exit: 702 703 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB); 704 if (pSourceSurf) EngUnlockSurface(pSourceSurf); 705 if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap); 706 if (pMaskSurf) EngUnlockSurface(pMaskSurf); 707 if (hMaskBitmap) EngDeleteSurface((HSURF)hMaskBitmap); 708 if (pDC) DC_UnlockDc(pDC); 709 ExFreePoolWithTag(pbmiSafe, 'pmTG'); 710 711 return ret; 712 } 713 714 /* Converts a device-dependent bitmap to a DIB */ 715 INT 716 APIENTRY 717 GreGetDIBitsInternal( 718 HDC hDC, 719 HBITMAP hBitmap, 720 UINT StartScan, 721 UINT ScanLines, 722 LPBYTE Bits, 723 LPBITMAPINFO Info, 724 UINT Usage, 725 UINT MaxBits, 726 UINT MaxInfo) 727 { 728 BITMAPCOREINFO* pbmci = NULL; 729 PSURFACE psurf = NULL; 730 PDC pDC; 731 LONG width, height; 732 WORD planes, bpp; 733 DWORD compr, size ; 734 USHORT i; 735 int bitmap_type; 736 RGBQUAD* rgbQuads; 737 VOID* colorPtr; 738 739 DPRINT("Entered GreGetDIBitsInternal()\n"); 740 741 if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap) 742 return 0; 743 744 pDC = DC_LockDc(hDC); 745 if (pDC == NULL || pDC->dctype == DCTYPE_INFO) 746 { 747 ScanLines = 0; 748 goto done; 749 } 750 751 /* Get a pointer to the source bitmap object */ 752 psurf = SURFACE_ShareLockSurface(hBitmap); 753 if (psurf == NULL) 754 { 755 ScanLines = 0; 756 goto done; 757 } 758 759 colorPtr = (LPBYTE)Info + Info->bmiHeader.biSize; 760 rgbQuads = colorPtr; 761 762 bitmap_type = DIB_GetBitmapInfo(&Info->bmiHeader, 763 &width, 764 &height, 765 &planes, 766 &bpp, 767 &compr, 768 &size); 769 if(bitmap_type == -1) 770 { 771 DPRINT1("Wrong bitmap format\n"); 772 EngSetLastError(ERROR_INVALID_PARAMETER); 773 ScanLines = 0; 774 goto done; 775 } 776 else if(bitmap_type == 0) 777 { 778 /* We need a BITMAPINFO to create a DIB, but we have to fill 779 * the BITMAPCOREINFO we're provided */ 780 pbmci = (BITMAPCOREINFO*)Info; 781 /* fill in the the bit count, so we can calculate the right ColorsSize during the conversion */ 782 pbmci->bmciHeader.bcBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat); 783 Info = DIB_ConvertBitmapInfo((BITMAPINFO*)pbmci, Usage); 784 if(Info == NULL) 785 { 786 DPRINT1("Error, could not convert the BITMAPCOREINFO!\n"); 787 ScanLines = 0; 788 goto done; 789 } 790 rgbQuads = Info->bmiColors; 791 } 792 793 /* Validate input: 794 - negative width is always an invalid value 795 - non-null Bits and zero bpp is an invalid combination 796 - only check the rest of the input params if either bpp is non-zero or Bits are set */ 797 if (width < 0 || (bpp == 0 && Bits)) 798 { 799 ScanLines = 0; 800 goto done; 801 } 802 803 if (Bits || bpp) 804 { 805 if ((height == 0 || width == 0) || (compr && compr != BI_BITFIELDS && compr != BI_RGB)) 806 { 807 ScanLines = 0; 808 goto done; 809 } 810 } 811 812 Info->bmiHeader.biClrUsed = 0; 813 Info->bmiHeader.biClrImportant = 0; 814 815 /* Fill in the structure */ 816 switch(bpp) 817 { 818 case 0: /* Only info */ 819 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx; 820 Info->bmiHeader.biHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ? 821 -psurf->SurfObj.sizlBitmap.cy : 822 psurf->SurfObj.sizlBitmap.cy; 823 Info->bmiHeader.biPlanes = 1; 824 Info->bmiHeader.biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat); 825 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( Info->bmiHeader.biWidth, 826 Info->bmiHeader.biHeight, 827 Info->bmiHeader.biBitCount); 828 Info->bmiHeader.biCompression = (Info->bmiHeader.biBitCount == 16 || Info->bmiHeader.biBitCount == 32) ? 829 BI_BITFIELDS : BI_RGB; 830 Info->bmiHeader.biXPelsPerMeter = 0; 831 Info->bmiHeader.biYPelsPerMeter = 0; 832 833 if (Info->bmiHeader.biBitCount <= 8 && Info->bmiHeader.biClrUsed == 0) 834 Info->bmiHeader.biClrUsed = 1 << Info->bmiHeader.biBitCount; 835 836 ScanLines = 1; 837 goto done; 838 839 case 1: 840 case 4: 841 case 8: 842 Info->bmiHeader.biClrUsed = 1 << bpp; 843 844 /* If the bitmap is a DIB section and has the same format as what 845 * is requested, go ahead! */ 846 if((psurf->hSecure) && 847 (BitsPerFormat(psurf->SurfObj.iBitmapFormat) == bpp)) 848 { 849 if(Usage == DIB_RGB_COLORS) 850 { 851 ULONG colors = min(psurf->ppal->NumColors, 256); 852 if(colors != 256) Info->bmiHeader.biClrUsed = colors; 853 for(i = 0; i < colors; i++) 854 { 855 rgbQuads[i].rgbRed = psurf->ppal->IndexedColors[i].peRed; 856 rgbQuads[i].rgbGreen = psurf->ppal->IndexedColors[i].peGreen; 857 rgbQuads[i].rgbBlue = psurf->ppal->IndexedColors[i].peBlue; 858 rgbQuads[i].rgbReserved = 0; 859 } 860 } 861 else 862 { 863 for(i = 0; i < 256; i++) 864 ((WORD*)rgbQuads)[i] = i; 865 } 866 } 867 else 868 { 869 if(Usage == DIB_PAL_COLORS) 870 { 871 for(i = 0; i < 256; i++) 872 { 873 ((WORD*)rgbQuads)[i] = i; 874 } 875 } 876 else if(bpp > 1 && bpp == BitsPerFormat(psurf->SurfObj.iBitmapFormat)) 877 { 878 /* For color DDBs in native depth (mono DDBs always have 879 a black/white palette): 880 Generate the color map from the selected palette */ 881 PPALETTE pDcPal = PALETTE_ShareLockPalette(pDC->dclevel.hpal); 882 if(!pDcPal) 883 { 884 ScanLines = 0 ; 885 goto done ; 886 } 887 for (i = 0; i < pDcPal->NumColors; i++) 888 { 889 rgbQuads[i].rgbRed = pDcPal->IndexedColors[i].peRed; 890 rgbQuads[i].rgbGreen = pDcPal->IndexedColors[i].peGreen; 891 rgbQuads[i].rgbBlue = pDcPal->IndexedColors[i].peBlue; 892 rgbQuads[i].rgbReserved = 0; 893 } 894 PALETTE_ShareUnlockPalette(pDcPal); 895 } 896 else 897 { 898 switch (bpp) 899 { 900 case 1: 901 rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0; 902 rgbQuads[0].rgbReserved = 0; 903 rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff; 904 rgbQuads[1].rgbReserved = 0; 905 break; 906 907 case 4: 908 /* The EGA palette is the first and last 8 colours of the default palette 909 with the innermost pair swapped */ 910 RtlCopyMemory(rgbQuads, DefLogPaletteQuads, 7 * sizeof(RGBQUAD)); 911 RtlCopyMemory(rgbQuads + 7, DefLogPaletteQuads + 12, 1 * sizeof(RGBQUAD)); 912 RtlCopyMemory(rgbQuads + 8, DefLogPaletteQuads + 7, 1 * sizeof(RGBQUAD)); 913 RtlCopyMemory(rgbQuads + 9, DefLogPaletteQuads + 13, 7 * sizeof(RGBQUAD)); 914 break; 915 916 case 8: 917 { 918 INT i; 919 920 memcpy(rgbQuads, DefLogPaletteQuads, 10 * sizeof(RGBQUAD)); 921 memcpy(rgbQuads + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD)); 922 923 for (i = 10; i < 246; i++) 924 { 925 rgbQuads[i].rgbRed = (i & 0x07) << 5; 926 rgbQuads[i].rgbGreen = (i & 0x38) << 2; 927 rgbQuads[i].rgbBlue = i & 0xc0; 928 rgbQuads[i].rgbReserved = 0; 929 } 930 } 931 } 932 } 933 } 934 break; 935 936 case 15: 937 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 938 { 939 ((PDWORD)Info->bmiColors)[0] = 0x7c00; 940 ((PDWORD)Info->bmiColors)[1] = 0x03e0; 941 ((PDWORD)Info->bmiColors)[2] = 0x001f; 942 } 943 break; 944 945 case 16: 946 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 947 { 948 if (psurf->hSecure) 949 { 950 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask; 951 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask; 952 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask; 953 } 954 else 955 { 956 ((PDWORD)Info->bmiColors)[0] = 0xf800; 957 ((PDWORD)Info->bmiColors)[1] = 0x07e0; 958 ((PDWORD)Info->bmiColors)[2] = 0x001f; 959 } 960 } 961 break; 962 963 case 24: 964 case 32: 965 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 966 { 967 if (psurf->hSecure) 968 { 969 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask; 970 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask; 971 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask; 972 } 973 else 974 { 975 ((PDWORD)Info->bmiColors)[0] = 0xff0000; 976 ((PDWORD)Info->bmiColors)[1] = 0x00ff00; 977 ((PDWORD)Info->bmiColors)[2] = 0x0000ff; 978 } 979 } 980 break; 981 982 default: 983 ScanLines = 0; 984 goto done; 985 } 986 987 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(width, height, bpp); 988 Info->bmiHeader.biPlanes = 1; 989 990 if(Bits && ScanLines) 991 { 992 /* Create a DIBSECTION, blt it, profit */ 993 PVOID pDIBits ; 994 HBITMAP hBmpDest; 995 PSURFACE psurfDest; 996 EXLATEOBJ exlo; 997 RECT rcDest; 998 POINTL srcPoint; 999 BOOL ret ; 1000 int newLines = -1; 1001 1002 if (StartScan >= abs(Info->bmiHeader.biHeight)) 1003 { 1004 ScanLines = 1; 1005 goto done; 1006 } 1007 else 1008 { 1009 ScanLines = min(ScanLines, abs(Info->bmiHeader.biHeight) - StartScan); 1010 } 1011 1012 if (abs(Info->bmiHeader.biHeight) < psurf->SurfObj.sizlBitmap.cy) 1013 { 1014 StartScan += psurf->SurfObj.sizlBitmap.cy - abs(Info->bmiHeader.biHeight); 1015 } 1016 /* Fixup values */ 1017 Info->bmiHeader.biHeight = (height < 0) ? 1018 -(LONG)ScanLines : ScanLines; 1019 /* Create the DIB */ 1020 hBmpDest = DIB_CreateDIBSection(pDC, Info, Usage, &pDIBits, NULL, 0, 0); 1021 /* Restore them */ 1022 Info->bmiHeader.biHeight = height; 1023 1024 if(!hBmpDest) 1025 { 1026 DPRINT1("Unable to create a DIB Section!\n"); 1027 EngSetLastError(ERROR_INVALID_PARAMETER); 1028 ScanLines = 0; 1029 goto done ; 1030 } 1031 1032 psurfDest = SURFACE_ShareLockSurface(hBmpDest); 1033 1034 RECTL_vSetRect(&rcDest, 0, 0, Info->bmiHeader.biWidth, ScanLines); 1035 Info->bmiHeader.biWidth = width; 1036 srcPoint.x = 0; 1037 1038 if (abs(Info->bmiHeader.biHeight) <= psurf->SurfObj.sizlBitmap.cy) 1039 { 1040 srcPoint.y = psurf->SurfObj.sizlBitmap.cy - StartScan - ScanLines; 1041 } 1042 else 1043 { 1044 /* Determine the actual number of lines copied from the */ 1045 /* original bitmap. It might be different from ScanLines. */ 1046 newLines = abs(Info->bmiHeader.biHeight) - psurf->SurfObj.sizlBitmap.cy; 1047 newLines = min((int)(StartScan + ScanLines - newLines), psurf->SurfObj.sizlBitmap.cy); 1048 if (newLines > 0) 1049 { 1050 srcPoint.y = psurf->SurfObj.sizlBitmap.cy - newLines; 1051 if (StartScan > psurf->SurfObj.sizlBitmap.cy) 1052 { 1053 newLines -= (StartScan - psurf->SurfObj.sizlBitmap.cy); 1054 } 1055 } 1056 else 1057 { 1058 newLines = 0; 1059 srcPoint.y = psurf->SurfObj.sizlBitmap.cy; 1060 } 1061 } 1062 1063 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xffffff, 0xffffff, 0); 1064 1065 ret = IntEngCopyBits(&psurfDest->SurfObj, 1066 &psurf->SurfObj, 1067 NULL, 1068 &exlo.xlo, 1069 &rcDest, 1070 &srcPoint); 1071 1072 SURFACE_ShareUnlockSurface(psurfDest); 1073 1074 if(!ret) 1075 ScanLines = 0; 1076 else 1077 { 1078 RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp)); 1079 } 1080 /* Update if line count has changed */ 1081 if (newLines != -1) 1082 { 1083 ScanLines = (UINT)newLines; 1084 } 1085 GreDeleteObject(hBmpDest); 1086 EXLATEOBJ_vCleanup(&exlo); 1087 } 1088 else 1089 { 1090 /* Signals success and not the actual number of scan lines*/ 1091 ScanLines = 1; 1092 } 1093 1094 done: 1095 1096 if (pbmci) 1097 DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci, Usage); 1098 1099 if (psurf) 1100 SURFACE_ShareUnlockSurface(psurf); 1101 1102 if (pDC) 1103 DC_UnlockDc(pDC); 1104 1105 return ScanLines; 1106 } 1107 1108 _Success_(return!=0) 1109 __kernel_entry 1110 INT 1111 APIENTRY 1112 NtGdiGetDIBitsInternal( 1113 _In_ HDC hdc, 1114 _In_ HBITMAP hbm, 1115 _In_ UINT iStartScan, 1116 _In_ UINT cScans, 1117 _Out_writes_bytes_opt_(cjMaxBits) LPBYTE pjBits, 1118 _Inout_ LPBITMAPINFO pbmi, 1119 _In_ UINT iUsage, 1120 _In_ UINT cjMaxBits, 1121 _In_ UINT cjMaxInfo) 1122 { 1123 PBITMAPINFO pbmiSafe; 1124 HANDLE hSecure = NULL; 1125 INT iResult = 0; 1126 UINT cjAlloc; 1127 1128 /* Check for bad iUsage */ 1129 if (iUsage > 2) return 0; 1130 1131 /* Check if the size of the bitmap info is large enough */ 1132 if (cjMaxInfo < sizeof(BITMAPCOREHEADER)) 1133 { 1134 return 0; 1135 } 1136 1137 /* Use maximum size */ 1138 cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)); 1139 1140 // HACK: the underlying code sucks and doesn't care for the size, so we 1141 // give it the maximum ever needed 1142 cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD); 1143 1144 /* Allocate a buffer the bitmapinfo */ 1145 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG'); 1146 if (!pbmiSafe) 1147 { 1148 /* Fail */ 1149 return 0; 1150 } 1151 1152 /* Use SEH */ 1153 _SEH2_TRY 1154 { 1155 /* Probe and copy the BITMAPINFO */ 1156 ProbeForRead(pbmi, cjMaxInfo, 1); 1157 RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo); 1158 } 1159 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1160 { 1161 goto cleanup; 1162 } 1163 _SEH2_END; 1164 1165 /* Check if the header size is large enough */ 1166 if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) || 1167 (pbmiSafe->bmiHeader.biSize > cjMaxInfo)) 1168 { 1169 goto cleanup; 1170 } 1171 1172 /* Check if the caller provided bitmap bits */ 1173 if (pjBits) 1174 { 1175 /* Secure the user mode memory */ 1176 hSecure = EngSecureMem(pjBits, cjMaxBits); 1177 if (!hSecure) 1178 { 1179 goto cleanup; 1180 } 1181 } 1182 1183 /* Now call the internal function */ 1184 iResult = GreGetDIBitsInternal(hdc, 1185 hbm, 1186 iStartScan, 1187 cScans, 1188 pjBits, 1189 pbmiSafe, 1190 iUsage, 1191 cjMaxBits, 1192 cjMaxInfo); 1193 1194 /* Check for success */ 1195 if (iResult) 1196 { 1197 /* Use SEH to copy back to user mode */ 1198 _SEH2_TRY 1199 { 1200 /* Copy the data back */ 1201 cjMaxInfo = min(cjMaxInfo, (UINT)DIB_BitmapInfoSize(pbmiSafe, (WORD)iUsage)); 1202 ProbeForWrite(pbmi, cjMaxInfo, 1); 1203 RtlCopyMemory(pbmi, pbmiSafe, cjMaxInfo); 1204 } 1205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1206 { 1207 /* Ignore */ 1208 (VOID)0; 1209 } 1210 _SEH2_END; 1211 } 1212 1213 cleanup: 1214 if (hSecure) EngUnsecureMem(hSecure); 1215 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1216 1217 return iResult; 1218 } 1219 1220 W32KAPI 1221 INT 1222 APIENTRY 1223 NtGdiStretchDIBitsInternal( 1224 IN HDC hdc, 1225 IN INT xDst, 1226 IN INT yDst, 1227 IN INT cxDst, 1228 IN INT cyDst, 1229 IN INT xSrc, 1230 IN INT ySrc, 1231 IN INT cxSrc, 1232 IN INT cySrc, 1233 IN OPTIONAL LPBYTE pjInit, 1234 IN LPBITMAPINFO pbmi, 1235 IN DWORD dwUsage, 1236 IN DWORD dwRop, // MS ntgdi.h says dwRop4(?) 1237 IN UINT cjMaxInfo, 1238 IN UINT cjMaxBits, 1239 IN HANDLE hcmXform) 1240 { 1241 SIZEL sizel; 1242 RECTL rcSrc, rcDst; 1243 PDC pdc; 1244 HBITMAP hbmTmp = 0; 1245 PSURFACE psurfTmp = 0, psurfDst = 0; 1246 PPALETTE ppalDIB = 0; 1247 EXLATEOBJ exlo; 1248 PBYTE pvBits; 1249 1250 LPBITMAPINFO pbmiSafe; 1251 UINT cjAlloc; 1252 HBITMAP hBitmap, hOldBitmap = NULL; 1253 HDC hdcMem; 1254 HPALETTE hPal = NULL; 1255 ULONG BmpFormat = 0; 1256 INT LinesCopied = 0; 1257 1258 /* Check for bad iUsage */ 1259 if (dwUsage > 2) return 0; 1260 1261 /* We must have LPBITMAPINFO */ 1262 if (!pbmi) 1263 { 1264 DPRINT1("Error, Invalid Parameter.\n"); 1265 EngSetLastError(ERROR_INVALID_PARAMETER); 1266 return 0; 1267 } 1268 1269 /* Check if the size of the bitmap info is large enough */ 1270 if (cjMaxInfo < sizeof(BITMAPCOREHEADER)) 1271 { 1272 return 0; 1273 } 1274 1275 /* Use maximum size */ 1276 cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)); 1277 1278 // HACK: the underlying code sucks and doesn't care for the size, so we 1279 // give it the maximum ever needed 1280 cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD); 1281 1282 /* Allocate a buffer the bitmapinfo */ 1283 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG'); 1284 if (!pbmiSafe) 1285 { 1286 /* Fail */ 1287 return 0; 1288 } 1289 1290 /* Use SEH */ 1291 _SEH2_TRY 1292 { 1293 /* Probe and copy the BITMAPINFO */ 1294 ProbeForRead(pbmi, cjMaxInfo, 1); 1295 RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo); 1296 } 1297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1298 { 1299 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1300 return 0; 1301 } 1302 _SEH2_END; 1303 1304 /* Check if the header size is large enough */ 1305 if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) || 1306 (pbmiSafe->bmiHeader.biSize > cjMaxInfo)) 1307 { 1308 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1309 return 0; 1310 } 1311 1312 if (!(pdc = DC_LockDc(hdc))) 1313 { 1314 EngSetLastError(ERROR_INVALID_HANDLE); 1315 return 0; 1316 } 1317 1318 /* Check for info / mem DC without surface */ 1319 if (!pdc->dclevel.pSurface) 1320 { 1321 DC_UnlockDc(pdc); 1322 // CHECKME 1323 return TRUE; 1324 } 1325 1326 /* Transform dest size */ 1327 sizel.cx = cxDst; 1328 sizel.cy = cyDst; 1329 IntLPtoDP(pdc, (POINTL*)&sizel, 1); 1330 DC_UnlockDc(pdc); 1331 1332 if (pjInit && (cjMaxBits > 0)) 1333 { 1334 pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB); 1335 if (!pvBits) 1336 { 1337 return 0; 1338 } 1339 1340 _SEH2_TRY 1341 { 1342 ProbeForRead(pjInit, cjMaxBits, 1); 1343 RtlCopyMemory(pvBits, pjInit, cjMaxBits); 1344 } 1345 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1346 { 1347 ExFreePoolWithTag(pvBits, TAG_DIB); 1348 return 0; 1349 } 1350 _SEH2_END; 1351 } 1352 else 1353 { 1354 pvBits = NULL; 1355 } 1356 1357 /* Here we select between the dwRop with SRCCOPY or not. */ 1358 if (dwRop == SRCCOPY) 1359 { 1360 hdcMem = NtGdiCreateCompatibleDC(hdc); 1361 if (hdcMem == NULL) 1362 { 1363 DPRINT1("NtGdiCreateCompatibleDC failed to create hdc.\n"); 1364 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 1365 return 0; 1366 } 1367 1368 hBitmap = NtGdiCreateCompatibleBitmap(hdc, 1369 abs(pbmiSafe->bmiHeader.biWidth), 1370 abs(pbmiSafe->bmiHeader.biHeight)); 1371 if (hBitmap == NULL) 1372 { 1373 DPRINT1("NtGdiCreateCompatibleBitmap failed to create bitmap.\n"); 1374 DPRINT1("hdc : 0x%08x \n", hdc); 1375 DPRINT1("width : 0x%08x \n", pbmiSafe->bmiHeader.biWidth); 1376 DPRINT1("height : 0x%08x \n", pbmiSafe->bmiHeader.biHeight); 1377 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 1378 return 0; 1379 } 1380 1381 /* Select the bitmap into hdcMem, and save a handle to the old bitmap */ 1382 hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap); 1383 1384 if (dwUsage == DIB_PAL_COLORS) 1385 { 1386 hPal = NtGdiGetDCObject(hdc, GDI_OBJECT_TYPE_PALETTE); 1387 hPal = GdiSelectPalette(hdcMem, hPal, FALSE); 1388 } 1389 1390 pdc = DC_LockDc(hdcMem); 1391 if (pdc != NULL) 1392 { 1393 IntSetDIBits(pdc, hBitmap, 0, abs(pbmiSafe->bmiHeader.biHeight), pvBits, 1394 cjMaxBits, pbmiSafe, dwUsage); 1395 DC_UnlockDc(pdc); 1396 } 1397 1398 /* Origin for DIBitmap may be bottom left (positive biHeight) or top 1399 left (negative biHeight) */ 1400 if (cxSrc == cxDst && cySrc == cyDst) 1401 { 1402 NtGdiBitBlt(hdc, xDst, yDst, cxDst, cyDst, 1403 hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc - ySrc, 1404 dwRop, 0, 0); 1405 } 1406 else 1407 { 1408 NtGdiStretchBlt(hdc, xDst, yDst, cxDst, cyDst, 1409 hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc - ySrc, 1410 cxSrc, cySrc, dwRop, 0); 1411 } 1412 1413 /* cleanup */ 1414 if (hPal) 1415 GdiSelectPalette(hdcMem, hPal, FALSE); 1416 1417 if (hOldBitmap) 1418 NtGdiSelectBitmap(hdcMem, hOldBitmap); 1419 1420 NtGdiDeleteObjectApp(hdcMem); 1421 GreDeleteObject(hBitmap); 1422 1423 } /* End of dwRop == SRCCOPY */ 1424 else 1425 { /* Start of dwRop != SRCCOPY */ 1426 /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */ 1427 if (!(pdc = DC_LockDc(hdc))) 1428 { 1429 DPRINT1("Could not lock dc\n"); 1430 EngSetLastError(ERROR_INVALID_HANDLE); 1431 goto cleanup; 1432 } 1433 1434 /* Calculate source and destination rect */ 1435 rcSrc.left = xSrc; 1436 rcSrc.top = ySrc; 1437 rcSrc.right = xSrc + abs(cxSrc); 1438 rcSrc.bottom = ySrc + abs(cySrc); 1439 rcDst.left = xDst; 1440 rcDst.top = yDst; 1441 rcDst.right = rcDst.left + cxDst; 1442 rcDst.bottom = rcDst.top + cyDst; 1443 IntLPtoDP(pdc, (POINTL*)&rcDst, 2); 1444 RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); 1445 1446 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 1447 { 1448 IntUpdateBoundsRect(pdc, &rcDst); 1449 } 1450 1451 BmpFormat = BitmapFormat(pbmiSafe->bmiHeader.biBitCount, 1452 pbmiSafe->bmiHeader.biCompression); 1453 1454 hbmTmp = GreCreateBitmapEx(pbmiSafe->bmiHeader.biWidth, 1455 abs(pbmiSafe->bmiHeader.biHeight), 1456 0, 1457 BmpFormat, 1458 pbmiSafe->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, 1459 cjMaxBits, 1460 pvBits, 1461 0); 1462 1463 if (!hbmTmp) 1464 { 1465 goto cleanup; 1466 } 1467 1468 psurfTmp = SURFACE_ShareLockSurface(hbmTmp); 1469 if (!psurfTmp) 1470 { 1471 goto cleanup; 1472 } 1473 1474 /* Create a palette for the DIB */ 1475 ppalDIB = CreateDIBPalette(pbmiSafe, pdc, dwUsage); 1476 if (!ppalDIB) 1477 { 1478 goto cleanup; 1479 } 1480 1481 /* Prepare DC for blit */ 1482 DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL); 1483 1484 psurfDst = pdc->dclevel.pSurface; 1485 1486 /* Initialize XLATEOBJ */ 1487 EXLATEOBJ_vInitialize(&exlo, 1488 ppalDIB, 1489 psurfDst->ppal, 1490 RGB(0xff, 0xff, 0xff), 1491 pdc->pdcattr->crBackgroundClr, 1492 pdc->pdcattr->crForegroundClr); 1493 1494 /* Perform the stretch operation */ 1495 IntEngStretchBlt(&psurfDst->SurfObj, 1496 &psurfTmp->SurfObj, 1497 NULL, 1498 (CLIPOBJ *)&pdc->co, 1499 &exlo.xlo, 1500 &pdc->dclevel.ca, 1501 &rcDst, 1502 &rcSrc, 1503 NULL, 1504 &pdc->eboFill.BrushObject, 1505 NULL, 1506 WIN32_ROP3_TO_ENG_ROP4(dwRop)); 1507 1508 /* Cleanup */ 1509 DC_vFinishBlit(pdc, NULL); 1510 EXLATEOBJ_vCleanup(&exlo); 1511 1512 cleanup: 1513 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB); 1514 if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp); 1515 if (hbmTmp) GreDeleteObject(hbmTmp); 1516 if (pdc) DC_UnlockDc(pdc); 1517 } 1518 1519 if (pvBits) ExFreePoolWithTag(pvBits, TAG_DIB); 1520 1521 /* This is not what MSDN says is returned from this function, but it 1522 * follows Wine's dlls/gdi32/dib.c function nulldrv_StretchDIBits 1523 * and it fixes over 100 gdi32:dib regression tests. */ 1524 if (dwRop == SRCCOPY) 1525 { 1526 LinesCopied = abs(pbmiSafe->bmiHeader.biHeight); 1527 } 1528 else 1529 { 1530 LinesCopied = pbmiSafe->bmiHeader.biHeight; 1531 } 1532 1533 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1534 1535 return LinesCopied; 1536 } 1537 1538 HBITMAP 1539 FASTCALL 1540 IntCreateDIBitmap( 1541 PDC Dc, 1542 INT width, 1543 INT height, 1544 UINT planes, 1545 UINT bpp, 1546 ULONG compression, 1547 DWORD init, 1548 LPBYTE bits, 1549 ULONG cjMaxBits, 1550 PBITMAPINFO data, 1551 DWORD coloruse) 1552 { 1553 HBITMAP handle; 1554 BOOL fColor; 1555 ULONG BmpFormat = 0; 1556 1557 if (planes && bpp) 1558 BmpFormat = BitmapFormat(planes * bpp, compression); 1559 1560 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2 1561 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap. 1562 1563 if (BmpFormat != BMF_1BPP) fColor = TRUE; 1564 else if ((coloruse > DIB_RGB_COLORS) || ((init & CBM_INIT) == 0) || !data) fColor = FALSE; 1565 else 1566 { 1567 const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize); 1568 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue); 1569 1570 // Check if the first color of the colormap is black 1571 if (col == RGB(0, 0, 0)) 1572 { 1573 rgb++; 1574 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue); 1575 1576 // If the second color is white, create a monochrome bitmap 1577 fColor = (col != RGB(0xff,0xff,0xff)); 1578 } 1579 else fColor = TRUE; 1580 } 1581 1582 // Now create the bitmap 1583 if (fColor) 1584 { 1585 if (init & CBM_CREATDIB) 1586 { 1587 PSURFACE Surface; 1588 PPALETTE Palette; 1589 1590 /* Undocumented flag which creates a DDB of the format specified by the bitmap info. */ 1591 handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp); 1592 if (!handle) 1593 { 1594 DPRINT1("IntCreateCompatibleBitmap() failed!\n"); 1595 return NULL; 1596 } 1597 1598 /* The palette must also match the given data */ 1599 Surface = SURFACE_ShareLockSurface(handle); 1600 ASSERT(Surface); 1601 Palette = CreateDIBPalette(data, Dc, coloruse); 1602 if (Palette == NULL) 1603 { 1604 SURFACE_ShareUnlockSurface(Surface); 1605 GreDeleteObject(handle); 1606 return NULL; 1607 } 1608 1609 SURFACE_vSetPalette(Surface, Palette); 1610 1611 PALETTE_ShareUnlockPalette(Palette); 1612 SURFACE_ShareUnlockSurface(Surface); 1613 } 1614 else 1615 { 1616 /* Create a regular compatible bitmap, in the same format as the device */ 1617 handle = IntCreateCompatibleBitmap(Dc, width, height, 0, 0); 1618 } 1619 } 1620 else 1621 { 1622 handle = GreCreateBitmap(width, 1623 abs(height), 1624 1, 1625 1, 1626 NULL); 1627 } 1628 1629 if (height < 0) 1630 height = -height; 1631 1632 if ((NULL != handle) && (CBM_INIT & init)) 1633 { 1634 IntSetDIBits(Dc, handle, 0, height, bits, cjMaxBits, data, coloruse); 1635 } 1636 1637 return handle; 1638 } 1639 1640 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits 1641 // The DDB that is created will be whatever bit depth your reference DC is 1642 HBITMAP 1643 APIENTRY 1644 NtGdiCreateDIBitmapInternal( 1645 IN HDC hDc, 1646 IN INT cx, 1647 IN INT cy, 1648 IN DWORD fInit, 1649 IN OPTIONAL LPBYTE pjInit, 1650 IN OPTIONAL LPBITMAPINFO pbmi, 1651 IN DWORD iUsage, 1652 IN UINT cjMaxInitInfo, 1653 IN UINT cjMaxBits, 1654 IN FLONG fl, 1655 IN HANDLE hcmXform) 1656 { 1657 NTSTATUS Status = STATUS_SUCCESS; 1658 PBYTE safeBits = NULL; 1659 HBITMAP hbmResult = NULL; 1660 1661 if (pjInit == NULL) 1662 { 1663 fInit &= ~CBM_INIT; 1664 } 1665 1666 if(pjInit && (fInit & CBM_INIT)) 1667 { 1668 if (cjMaxBits == 0) return NULL; 1669 safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB); 1670 if(!safeBits) 1671 { 1672 DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits); 1673 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1674 return NULL; 1675 } 1676 } 1677 1678 _SEH2_TRY 1679 { 1680 if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1); 1681 if(pjInit && (fInit & CBM_INIT)) 1682 { 1683 ProbeForRead(pjInit, cjMaxBits, 1); 1684 RtlCopyMemory(safeBits, pjInit, cjMaxBits); 1685 } 1686 } 1687 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1688 { 1689 Status = _SEH2_GetExceptionCode(); 1690 } 1691 _SEH2_END; 1692 1693 if(!NT_SUCCESS(Status)) 1694 { 1695 DPRINT1("Got an exception! pjInit = %p\n", pjInit); 1696 SetLastNtError(Status); 1697 goto cleanup; 1698 } 1699 1700 hbmResult = GreCreateDIBitmapInternal(hDc, 1701 cx, 1702 cy, 1703 fInit, 1704 safeBits, 1705 pbmi, 1706 iUsage, 1707 fl, 1708 cjMaxBits, 1709 hcmXform); 1710 1711 cleanup: 1712 if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB); 1713 return hbmResult; 1714 } 1715 1716 HBITMAP 1717 NTAPI 1718 GreCreateDIBitmapInternal( 1719 IN HDC hDc, 1720 IN INT cx, 1721 IN INT cy, 1722 IN DWORD fInit, 1723 IN OPTIONAL LPBYTE pjInit, 1724 IN OPTIONAL PBITMAPINFO pbmi, 1725 IN DWORD iUsage, 1726 IN FLONG fl, 1727 IN UINT cjMaxBits, 1728 IN HANDLE hcmXform) 1729 { 1730 PDC Dc; 1731 HBITMAP Bmp; 1732 USHORT bpp, planes; 1733 DWORD compression; 1734 HDC hdcDest; 1735 1736 if (!hDc) /* 1bpp monochrome bitmap */ 1737 { 1738 // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this. 1739 hdcDest = NtGdiCreateCompatibleDC(0); 1740 if(!hdcDest) 1741 { 1742 DPRINT1("NtGdiCreateCompatibleDC failed\n"); 1743 return NULL; 1744 } 1745 } 1746 else 1747 { 1748 hdcDest = hDc; 1749 } 1750 1751 Dc = DC_LockDc(hdcDest); 1752 if (!Dc) 1753 { 1754 DPRINT1("Failed to lock hdcDest %p\n", hdcDest); 1755 EngSetLastError(ERROR_INVALID_HANDLE); 1756 return NULL; 1757 } 1758 /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap 1759 * if bpp != 1 and ignore the real value that was passed */ 1760 if (pbmi) 1761 { 1762 if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 1763 { 1764 BITMAPCOREHEADER* CoreHeader = (BITMAPCOREHEADER*)&pbmi->bmiHeader; 1765 bpp = CoreHeader->bcBitCount; 1766 planes = CoreHeader->bcPlanes ? CoreHeader->bcPlanes : 1; 1767 compression = BI_RGB; 1768 } 1769 else 1770 { 1771 bpp = pbmi->bmiHeader.biBitCount; 1772 planes = pbmi->bmiHeader.biPlanes ? pbmi->bmiHeader.biPlanes : 1; 1773 compression = pbmi->bmiHeader.biCompression; 1774 } 1775 } 1776 else 1777 { 1778 bpp = 0; 1779 planes = 0; 1780 compression = 0; 1781 } 1782 Bmp = IntCreateDIBitmap(Dc, cx, cy, planes, bpp, compression, fInit, pjInit, cjMaxBits, pbmi, iUsage); 1783 DC_UnlockDc(Dc); 1784 1785 if(!hDc) 1786 { 1787 NtGdiDeleteObjectApp(hdcDest); 1788 } 1789 return Bmp; 1790 } 1791 1792 HBITMAP 1793 NTAPI 1794 GreCreateDIBitmapFromPackedDIB( 1795 _In_reads_(cjPackedDIB )PVOID pvPackedDIB, 1796 _In_ UINT cjPackedDIB, 1797 _In_ ULONG uUsage) 1798 { 1799 PBITMAPINFO pbmi; 1800 PBYTE pjBits; 1801 UINT cjInfo, cjBits; 1802 HBITMAP hbm; 1803 1804 /* We only support BITMAPINFOHEADER, make sure the size is ok */ 1805 if (cjPackedDIB < sizeof(BITMAPINFOHEADER)) 1806 { 1807 return NULL; 1808 } 1809 1810 /* The packed DIB starts with the BITMAPINFOHEADER */ 1811 pbmi = pvPackedDIB; 1812 1813 if (cjPackedDIB < pbmi->bmiHeader.biSize) 1814 { 1815 return NULL; 1816 } 1817 1818 /* Calculate the info size and make sure the packed DIB is large enough */ 1819 cjInfo = DIB_BitmapInfoSize(pbmi, uUsage); 1820 if (cjPackedDIB <= cjInfo) 1821 { 1822 return NULL; 1823 } 1824 1825 /* The bitmap bits start after the header */ 1826 pjBits = (PBYTE)pvPackedDIB + cjInfo; 1827 cjBits = cjPackedDIB - cjInfo; 1828 1829 hbm = GreCreateDIBitmapInternal(NULL, 1830 pbmi->bmiHeader.biWidth, 1831 abs(pbmi->bmiHeader.biHeight), 1832 CBM_INIT | CBM_CREATDIB, 1833 pjBits, 1834 pbmi, 1835 uUsage, 1836 0, 1837 cjBits, 1838 NULL); 1839 1840 return hbm; 1841 } 1842 1843 HBITMAP 1844 APIENTRY 1845 NtGdiCreateDIBSection( 1846 IN HDC hDC, 1847 IN OPTIONAL HANDLE hSection, 1848 IN DWORD dwOffset, 1849 IN BITMAPINFO* bmi, 1850 IN DWORD Usage, 1851 IN UINT cjHeader, 1852 IN FLONG fl, 1853 IN ULONG_PTR dwColorSpace, 1854 OUT PVOID *Bits) 1855 { 1856 HBITMAP hbitmap = 0; 1857 DC *dc; 1858 BOOL bDesktopDC = FALSE; 1859 NTSTATUS Status = STATUS_SUCCESS; 1860 1861 if (!bmi) return hbitmap; // Make sure. 1862 1863 _SEH2_TRY 1864 { 1865 ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1); 1866 ProbeForRead(bmi, bmi->bmiHeader.biSize, 1); 1867 ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, (WORD)Usage), 1); 1868 } 1869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1870 { 1871 Status = _SEH2_GetExceptionCode(); 1872 } 1873 _SEH2_END; 1874 1875 if(!NT_SUCCESS(Status)) 1876 { 1877 SetLastNtError(Status); 1878 return NULL; 1879 } 1880 1881 // If the reference hdc is null, take the desktop dc 1882 if (hDC == 0) 1883 { 1884 hDC = NtGdiCreateCompatibleDC(0); 1885 bDesktopDC = TRUE; 1886 } 1887 1888 if ((dc = DC_LockDc(hDC))) 1889 { 1890 hbitmap = DIB_CreateDIBSection(dc, 1891 bmi, 1892 Usage, 1893 Bits, 1894 hSection, 1895 dwOffset, 1896 0); 1897 DC_UnlockDc(dc); 1898 } 1899 else 1900 { 1901 EngSetLastError(ERROR_INVALID_HANDLE); 1902 } 1903 1904 if (bDesktopDC) 1905 NtGdiDeleteObjectApp(hDC); 1906 1907 return hbitmap; 1908 } 1909 1910 HBITMAP 1911 APIENTRY 1912 DIB_CreateDIBSection( 1913 PDC dc, 1914 CONST BITMAPINFO *bmi, 1915 UINT usage, 1916 LPVOID *bits, 1917 HANDLE section, 1918 DWORD offset, 1919 DWORD ovr_pitch) 1920 { 1921 HBITMAP res = 0; 1922 SURFACE *bmp = NULL; 1923 void *mapBits = NULL; 1924 PPALETTE ppalDIB = NULL; 1925 1926 // Fill BITMAP32 structure with DIB data 1927 CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader; 1928 INT effHeight; 1929 ULONG totalSize; 1930 BITMAP bm; 1931 //SIZEL Size; 1932 HANDLE hSecure; 1933 1934 DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n", 1935 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount, 1936 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB"); 1937 1938 /* CreateDIBSection should fail for compressed formats */ 1939 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8) 1940 { 1941 DPRINT1("no compressed format allowed\n"); 1942 return (HBITMAP)NULL; 1943 } 1944 1945 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight; 1946 bm.bmType = 0; 1947 bm.bmWidth = bi->biWidth; 1948 bm.bmHeight = effHeight; 1949 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount); 1950 1951 bm.bmPlanes = bi->biPlanes; 1952 bm.bmBitsPixel = bi->biBitCount; 1953 bm.bmBits = NULL; 1954 1955 // Get storage location for DIB bits. Only use biSizeImage if it's valid and 1956 // we're dealing with a compressed bitmap. Otherwise, use width * height. 1957 totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS)) 1958 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight); 1959 1960 if (section) 1961 { 1962 SYSTEM_BASIC_INFORMATION Sbi; 1963 NTSTATUS Status; 1964 DWORD mapOffset; 1965 LARGE_INTEGER SectionOffset; 1966 SIZE_T mapSize; 1967 1968 Status = ZwQuerySystemInformation(SystemBasicInformation, 1969 &Sbi, 1970 sizeof Sbi, 1971 0); 1972 if (!NT_SUCCESS(Status)) 1973 { 1974 DPRINT1("ZwQuerySystemInformation failed (0x%lx)\n", Status); 1975 return NULL; 1976 } 1977 1978 mapOffset = offset - (offset % Sbi.AllocationGranularity); 1979 mapSize = totalSize + (offset - mapOffset); 1980 1981 SectionOffset.LowPart = mapOffset; 1982 SectionOffset.HighPart = 0; 1983 1984 Status = ZwMapViewOfSection(section, 1985 NtCurrentProcess(), 1986 &mapBits, 1987 0, 1988 0, 1989 &SectionOffset, 1990 &mapSize, 1991 ViewShare, 1992 0, 1993 PAGE_READWRITE); 1994 if (!NT_SUCCESS(Status)) 1995 { 1996 DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status); 1997 EngSetLastError(ERROR_INVALID_PARAMETER); 1998 return NULL; 1999 } 2000 2001 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset); 2002 } 2003 else if (ovr_pitch && offset) 2004 bm.bmBits = UlongToPtr(offset); 2005 else 2006 { 2007 offset = 0; 2008 bm.bmBits = EngAllocUserMem(totalSize, 0); 2009 if(!bm.bmBits) 2010 { 2011 DPRINT1("Failed to allocate memory\n"); 2012 goto cleanup; 2013 } 2014 } 2015 2016 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE); 2017 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!! 2018 2019 // Create Device Dependent Bitmap and add DIB pointer 2020 //Size.cx = bm.bmWidth; 2021 //Size.cy = abs(bm.bmHeight); 2022 res = GreCreateBitmapEx(bm.bmWidth, 2023 abs(bm.bmHeight), 2024 bm.bmWidthBytes, 2025 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression), 2026 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT | 2027 ((bi->biHeight < 0) ? BMF_TOPDOWN : 0), 2028 totalSize, 2029 bm.bmBits, 2030 0); 2031 if (!res) 2032 { 2033 DPRINT1("GreCreateBitmapEx failed\n"); 2034 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 2035 goto cleanup; 2036 } 2037 bmp = SURFACE_ShareLockSurface(res); // HACK 2038 if (NULL == bmp) 2039 { 2040 DPRINT1("SURFACE_LockSurface failed\n"); 2041 EngSetLastError(ERROR_INVALID_HANDLE); 2042 goto cleanup; 2043 } 2044 2045 /* WINE NOTE: WINE makes use of a colormap, which is a color translation 2046 table between the DIB and the X physical device. Obviously, 2047 this is left out of the ReactOS implementation. Instead, 2048 we call NtGdiSetDIBColorTable. */ 2049 bmp->hDIBSection = section; 2050 bmp->hSecure = hSecure; 2051 bmp->dwOffset = offset; 2052 bmp->flags = API_BITMAP; 2053 bmp->biClrImportant = bi->biClrImportant; 2054 2055 /* Create a palette for the DIB */ 2056 ppalDIB = CreateDIBPalette(bmi, dc, usage); 2057 2058 // Clean up in case of errors 2059 cleanup: 2060 if (!res || !bmp || !bm.bmBits || !ppalDIB) 2061 { 2062 DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits); 2063 if (bm.bmBits) 2064 { 2065 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this! 2066 if (section) 2067 { 2068 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits); 2069 bm.bmBits = NULL; 2070 } 2071 else if (!offset) 2072 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL; 2073 } 2074 2075 if (bmp) 2076 { 2077 SURFACE_ShareUnlockSurface(bmp); 2078 bmp = NULL; 2079 } 2080 2081 if (res) 2082 { 2083 GreDeleteObject(res); 2084 res = 0; 2085 } 2086 2087 if(ppalDIB) 2088 { 2089 PALETTE_ShareUnlockPalette(ppalDIB); 2090 } 2091 } 2092 2093 if (bmp) 2094 { 2095 /* If we're here, everything went fine */ 2096 SURFACE_vSetPalette(bmp, ppalDIB); 2097 PALETTE_ShareUnlockPalette(ppalDIB); 2098 SURFACE_ShareUnlockSurface(bmp); 2099 } 2100 2101 // Return BITMAP handle and storage location 2102 if (NULL != bm.bmBits && NULL != bits) 2103 { 2104 *bits = bm.bmBits; 2105 } 2106 2107 return res; 2108 } 2109 2110 /*********************************************************************** 2111 * DIB_GetBitmapInfo 2112 * 2113 * Get the info from a bitmap header. 2114 * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error. 2115 */ 2116 int 2117 FASTCALL 2118 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width, 2119 LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size ) 2120 { 2121 if (header->biSize == sizeof(BITMAPCOREHEADER)) 2122 { 2123 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header; 2124 *width = core->bcWidth; 2125 *height = core->bcHeight; 2126 *planes = core->bcPlanes; 2127 *bpp = core->bcBitCount; 2128 *compr = BI_RGB; 2129 *size = 0; 2130 return 0; 2131 } 2132 if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* Assume BITMAPINFOHEADER */ 2133 { 2134 *width = header->biWidth; 2135 *height = header->biHeight; 2136 *planes = header->biPlanes; 2137 *bpp = header->biBitCount; 2138 *compr = header->biCompression; 2139 *size = header->biSizeImage; 2140 return 1; 2141 } 2142 DPRINT1("(%u): unknown/wrong size for header\n", header->biSize ); 2143 return -1; 2144 } 2145 2146 /*********************************************************************** 2147 * DIB_GetDIBImageBytes 2148 * 2149 * Return the number of bytes used to hold the image in a DIB bitmap. 2150 * 11/16/1999 (RJJ) lifted from wine 2151 */ 2152 2153 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth) 2154 { 2155 return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height); 2156 } 2157 2158 /*********************************************************************** 2159 * DIB_BitmapInfoSize 2160 * 2161 * Return the size of the bitmap info structure including color table. 2162 * 11/16/1999 (RJJ) lifted from wine 2163 */ 2164 2165 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse) 2166 { 2167 unsigned int colors, size, masks = 0; 2168 unsigned int colorsize; 2169 2170 colorsize = (coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : 2171 (coloruse == DIB_PAL_INDICES) ? 0 : 2172 sizeof(WORD); 2173 2174 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 2175 { 2176 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info; 2177 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0; 2178 return sizeof(BITMAPCOREHEADER) + colors * colorsize; 2179 } 2180 else /* Assume BITMAPINFOHEADER */ 2181 { 2182 colors = info->bmiHeader.biClrUsed; 2183 if (colors > 256) colors = 256; 2184 if (!colors && (info->bmiHeader.biBitCount <= 8)) 2185 colors = 1 << info->bmiHeader.biBitCount; 2186 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3; 2187 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) ); 2188 return size + colors * colorsize; 2189 } 2190 } 2191 2192 HPALETTE 2193 FASTCALL 2194 DIB_MapPaletteColors(PPALETTE ppalDc, CONST BITMAPINFO* lpbmi) 2195 { 2196 PPALETTE ppalNew; 2197 ULONG nNumColors,i; 2198 USHORT *lpIndex; 2199 HPALETTE hpal; 2200 2201 if (!(ppalDc->flFlags & PAL_INDEXED)) 2202 { 2203 return NULL; 2204 } 2205 2206 nNumColors = 1 << lpbmi->bmiHeader.biBitCount; 2207 if (lpbmi->bmiHeader.biClrUsed) 2208 { 2209 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed); 2210 } 2211 2212 ppalNew = PALETTE_AllocPalWithHandle(PAL_INDEXED, nNumColors, NULL, 0, 0, 0); 2213 if (ppalNew == NULL) 2214 { 2215 DPRINT1("Could not allocate palette\n"); 2216 return NULL; 2217 } 2218 2219 lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize); 2220 2221 for (i = 0; i < nNumColors; i++) 2222 { 2223 ULONG iColorIndex = *lpIndex % ppalDc->NumColors; 2224 ppalNew->IndexedColors[i] = ppalDc->IndexedColors[iColorIndex]; 2225 lpIndex++; 2226 } 2227 2228 hpal = ppalNew->BaseObject.hHmgr; 2229 PALETTE_UnlockPalette(ppalNew); 2230 2231 return hpal; 2232 } 2233 2234 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure, 2235 * or does nothing if it's already a BITMAPINFO (or V4 or V5) */ 2236 BITMAPINFO* 2237 FASTCALL 2238 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage) 2239 { 2240 CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi; 2241 BITMAPINFO* pNewBmi ; 2242 UINT numColors = 0, ColorsSize = 0; 2243 2244 if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi; 2245 if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL; 2246 2247 if(pbmci->bmciHeader.bcBitCount <= 8) 2248 { 2249 numColors = 1 << pbmci->bmciHeader.bcBitCount; 2250 if(Usage == DIB_PAL_COLORS) 2251 { 2252 ColorsSize = numColors * sizeof(WORD); 2253 } 2254 else 2255 { 2256 ColorsSize = numColors * sizeof(RGBQUAD); 2257 } 2258 } 2259 else if (Usage == DIB_PAL_COLORS) 2260 { 2261 /* Invalid at high-res */ 2262 return NULL; 2263 } 2264 2265 pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB); 2266 if(!pNewBmi) return NULL; 2267 2268 RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize); 2269 2270 pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 2271 pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount; 2272 pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth; 2273 pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight; 2274 pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes; 2275 pNewBmi->bmiHeader.biCompression = BI_RGB ; 2276 pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth, 2277 pNewBmi->bmiHeader.biHeight, 2278 pNewBmi->bmiHeader.biBitCount); 2279 pNewBmi->bmiHeader.biClrUsed = numColors; 2280 2281 if(Usage == DIB_PAL_COLORS) 2282 { 2283 RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize); 2284 } 2285 else 2286 { 2287 UINT i; 2288 for(i=0; i<numColors; i++) 2289 { 2290 pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed; 2291 pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen; 2292 pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue; 2293 } 2294 } 2295 2296 return pNewBmi ; 2297 } 2298 2299 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */ 2300 VOID 2301 FASTCALL 2302 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage) 2303 { 2304 BITMAPCOREINFO* pbmci; 2305 if(converted == orig) 2306 return; 2307 2308 if(usage == -1) 2309 { 2310 /* Caller don't want any conversion */ 2311 ExFreePoolWithTag(converted, TAG_DIB); 2312 return; 2313 } 2314 2315 /* Perform inverse conversion */ 2316 pbmci = (BITMAPCOREINFO*)orig; 2317 2318 ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER)); 2319 pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount; 2320 pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth; 2321 pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight; 2322 pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes; 2323 2324 if(pbmci->bmciHeader.bcBitCount <= 8) 2325 { 2326 UINT numColors = converted->bmiHeader.biClrUsed; 2327 if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount; 2328 if(usage == DIB_PAL_COLORS) 2329 { 2330 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD)); 2331 RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD)); 2332 } 2333 else 2334 { 2335 UINT i; 2336 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE)); 2337 for(i=0; i<numColors; i++) 2338 { 2339 pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed; 2340 pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen; 2341 pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue; 2342 } 2343 } 2344 } 2345 /* Now free it, it's not needed anymore */ 2346 ExFreePoolWithTag(converted, TAG_DIB); 2347 } 2348 2349 /* EOF */ 2350