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