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