1 #include <precomp.h> 2 3 #include <pseh/pseh2.h> 4 5 #define NDEBUG 6 #include <debug.h> 7 8 /* Copied from win32ss/gdi/eng/surface.c */ 9 ULONG 10 FASTCALL 11 BitmapFormat(ULONG cBits, ULONG iCompression) 12 { 13 switch (iCompression) 14 { 15 case BI_RGB: 16 /* Fall through */ 17 case BI_BITFIELDS: 18 if (cBits <= 1) return BMF_1BPP; 19 if (cBits <= 4) return BMF_4BPP; 20 if (cBits <= 8) return BMF_8BPP; 21 if (cBits <= 16) return BMF_16BPP; 22 if (cBits <= 24) return BMF_24BPP; 23 if (cBits <= 32) return BMF_32BPP; 24 return 0; 25 26 case BI_RLE4: 27 return BMF_4RLE; 28 29 case BI_RLE8: 30 return BMF_8RLE; 31 32 default: 33 return 0; 34 } 35 } 36 37 /* Copied from win32ss/gdi/eng/surface.c */ 38 UCHAR 39 gajBitsPerFormat[11] = 40 { 41 0, /* 0: unused */ 42 1, /* 1: BMF_1BPP */ 43 4, /* 2: BMF_4BPP */ 44 8, /* 3: BMF_8BPP */ 45 16, /* 4: BMF_16BPP */ 46 24, /* 5: BMF_24BPP */ 47 32, /* 6: BMF_32BPP */ 48 4, /* 7: BMF_4RLE */ 49 8, /* 8: BMF_8RLE */ 50 0, /* 9: BMF_JPEG */ 51 0, /* 10: BMF_PNG */ 52 }; 53 54 // From Yuan, ScanLineSize = (Width * bitcount + 31)/32 55 #define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3) 56 57 /* 58 * DIB_BitmapInfoSize 59 * 60 * Return the size of the bitmap info structure including color table. 61 * 11/16/1999 (RJJ) lifted from wine 62 */ 63 64 INT 65 FASTCALL DIB_BitmapInfoSize( 66 const BITMAPINFO * info, 67 WORD coloruse, 68 BOOL max) 69 { 70 unsigned int colors, size, masks = 0; 71 72 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 73 { 74 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *) info; 75 size = sizeof(BITMAPCOREHEADER); 76 if (core->bcBitCount <= 8) 77 { 78 colors = 1 << core->bcBitCount; 79 if (coloruse == DIB_RGB_COLORS) 80 size += colors * sizeof(RGBTRIPLE); 81 else 82 size += colors * sizeof(WORD); 83 } 84 return size; 85 } 86 else /* assume BITMAPINFOHEADER */ 87 { 88 colors = max ? (1 << info->bmiHeader.biBitCount) : info->bmiHeader.biClrUsed; 89 if (colors > 256) 90 colors = 256; 91 if (!colors && (info->bmiHeader.biBitCount <= 8)) 92 colors = 1 << info->bmiHeader.biBitCount; 93 if (info->bmiHeader.biCompression == BI_BITFIELDS) 94 masks = 3; 95 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD)); 96 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD)); 97 } 98 } 99 100 /* 101 * Return the full scan size for a bitmap. 102 * 103 * Based on Wine, Utils.c and Windows Graphics Prog pg 595, SDK amvideo.h. 104 */ 105 UINT 106 FASTCALL 107 DIB_BitmapMaxBitsSize( 108 PBITMAPINFO Info, 109 UINT ScanLines) 110 { 111 UINT Ret; 112 113 if (!Info) 114 return 0; 115 116 if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 117 { 118 PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER) Info; 119 Ret = WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes, 120 Core->bcBitCount) * ScanLines; 121 } 122 else /* assume BITMAPINFOHEADER */ 123 { 124 if ((Info->bmiHeader.biCompression == BI_RGB) || (Info->bmiHeader.biCompression == BI_BITFIELDS)) 125 { 126 Ret = WIDTH_BYTES_ALIGN32( 127 Info->bmiHeader.biWidth * Info->bmiHeader.biPlanes, 128 Info->bmiHeader.biBitCount) * ScanLines; 129 } 130 else 131 { 132 Ret = Info->bmiHeader.biSizeImage; 133 } 134 } 135 return Ret; 136 } 137 138 /* 139 * DIB_GetBitmapInfo is complete copy of wine cvs 2/9-2006 140 * from file dib.c from gdi32.dll or orginal version 141 * did not calc the info right for some headers. 142 */ 143 INT 144 WINAPI 145 DIB_GetBitmapInfo( 146 const BITMAPINFOHEADER *header, 147 PLONG width, 148 PLONG height, 149 PWORD planes, 150 PWORD bpp, 151 PLONG compr, 152 PLONG size) 153 { 154 if (header->biSize == sizeof(BITMAPCOREHEADER)) 155 { 156 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *) header; 157 *width = core->bcWidth; 158 *height = core->bcHeight; 159 *planes = core->bcPlanes; 160 *bpp = core->bcBitCount; 161 *compr = 0; 162 *size = 0; 163 return 0; 164 } 165 166 if (header->biSize == sizeof(BITMAPINFOHEADER)) 167 { 168 *width = header->biWidth; 169 *height = header->biHeight; 170 *planes = header->biPlanes; 171 *bpp = header->biBitCount; 172 *compr = header->biCompression; 173 *size = header->biSizeImage; 174 return 1; 175 } 176 177 if (header->biSize == sizeof(BITMAPV4HEADER)) 178 { 179 BITMAPV4HEADER *v4hdr = (BITMAPV4HEADER *) header; 180 *width = v4hdr->bV4Width; 181 *height = v4hdr->bV4Height; 182 *planes = v4hdr->bV4Planes; 183 *bpp = v4hdr->bV4BitCount; 184 *compr = v4hdr->bV4V4Compression; 185 *size = v4hdr->bV4SizeImage; 186 return 4; 187 } 188 189 if (header->biSize == sizeof(BITMAPV5HEADER)) 190 { 191 BITMAPV5HEADER *v5hdr = (BITMAPV5HEADER *) header; 192 *width = v5hdr->bV5Width; 193 *height = v5hdr->bV5Height; 194 *planes = v5hdr->bV5Planes; 195 *bpp = v5hdr->bV5BitCount; 196 *compr = v5hdr->bV5Compression; 197 *size = v5hdr->bV5SizeImage; 198 return 5; 199 } 200 DPRINT("(%lu): wrong size for header\n", header->biSize); 201 return -1; 202 } 203 204 /* 205 * @implemented 206 */ 207 int 208 WINAPI 209 GdiGetBitmapBitsSize( 210 BITMAPINFO *lpbmi) 211 { 212 UINT Ret; 213 214 if (!lpbmi) 215 return 0; 216 217 if (lpbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 218 { 219 PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER) lpbmi; 220 Ret = 221 WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes, 222 Core->bcBitCount) * Core->bcHeight; 223 } 224 else /* assume BITMAPINFOHEADER */ 225 { 226 if (!(lpbmi->bmiHeader.biCompression) || (lpbmi->bmiHeader.biCompression == BI_BITFIELDS)) 227 { 228 Ret = WIDTH_BYTES_ALIGN32( 229 lpbmi->bmiHeader.biWidth * lpbmi->bmiHeader.biPlanes, 230 lpbmi->bmiHeader.biBitCount) * abs(lpbmi->bmiHeader.biHeight); 231 } 232 else 233 { 234 Ret = lpbmi->bmiHeader.biSizeImage; 235 } 236 } 237 return Ret; 238 } 239 240 /* 241 * @implemented 242 */ 243 HBITMAP 244 WINAPI 245 CreateDIBSection( 246 HDC hDC, 247 CONST BITMAPINFO *BitmapInfo, 248 UINT Usage, 249 VOID **Bits, 250 HANDLE hSection, 251 DWORD dwOffset) 252 { 253 PBITMAPINFO pConvertedInfo; 254 UINT ConvertedInfoSize; 255 HBITMAP hBitmap = NULL; 256 PVOID bmBits = NULL; 257 258 pConvertedInfo = ConvertBitmapInfo(BitmapInfo, 259 Usage, 260 &ConvertedInfoSize, 261 FALSE); 262 if (pConvertedInfo) 263 { 264 // Verify header due to converted may == info. 265 if (pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) 266 { 267 if (pConvertedInfo->bmiHeader.biCompression == BI_JPEG || 268 pConvertedInfo->bmiHeader.biCompression == BI_PNG) 269 { 270 SetLastError(ERROR_INVALID_PARAMETER); 271 return NULL; 272 } 273 } 274 hBitmap = NtGdiCreateDIBSection(hDC, 275 hSection, 276 dwOffset, 277 pConvertedInfo, 278 Usage, 279 ConvertedInfoSize, 280 0, // fl 281 0, // dwColorSpace 282 &bmBits); 283 if (!hBitmap) 284 bmBits = NULL; 285 286 if (BitmapInfo != pConvertedInfo) 287 RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); 288 } 289 290 if (Bits) 291 *Bits = bmBits; 292 293 return hBitmap; 294 } 295 296 297 /* 298 * @implemented 299 */ 300 HBITMAP 301 WINAPI 302 CreateBitmap( 303 INT Width, 304 INT Height, 305 UINT Planes, 306 UINT BitsPixel, 307 CONST VOID* pUnsafeBits) 308 { 309 if (Width && Height) 310 { 311 return NtGdiCreateBitmap(Width, Height, Planes, BitsPixel, (LPBYTE) pUnsafeBits); 312 } 313 else 314 { 315 /* Return 1x1 bitmap */ 316 return GetStockObject(DEFAULT_BITMAP); 317 } 318 } 319 320 /* 321 * @implemented 322 */ 323 HBITMAP 324 WINAPI 325 CreateBitmapIndirect( 326 const BITMAP *pbm) 327 { 328 HBITMAP bitmap = NULL; 329 330 /* Note windows xp/2003 does not check if pbm is NULL or not */ 331 if ((pbm->bmWidthBytes != 0) && (!(pbm->bmWidthBytes & 1))) 332 333 { 334 bitmap = CreateBitmap(pbm->bmWidth, pbm->bmHeight, pbm->bmPlanes, pbm->bmBitsPixel, 335 pbm->bmBits); 336 } 337 else 338 { 339 SetLastError(ERROR_INVALID_PARAMETER); 340 } 341 342 return bitmap; 343 } 344 345 HBITMAP 346 WINAPI 347 CreateDiscardableBitmap( 348 HDC hDC, 349 INT Width, 350 INT Height) 351 { 352 return CreateCompatibleBitmap(hDC, Width, Height); 353 } 354 355 HBITMAP 356 WINAPI 357 CreateCompatibleBitmap( 358 HDC hDC, 359 INT Width, 360 INT Height) 361 { 362 PDC_ATTR pDc_Attr; 363 364 if (!GdiGetHandleUserData(hDC, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr)) 365 return NULL; 366 367 if (!Width || !Height) 368 return GetStockObject(DEFAULT_BITMAP); 369 370 if (!(pDc_Attr->ulDirty_ & DC_DIBSECTION)) 371 { 372 return NtGdiCreateCompatibleBitmap(hDC, Width, Height); 373 } 374 else 375 { 376 HBITMAP hBmp = NULL; 377 struct 378 { 379 BITMAP bitmap; 380 BITMAPINFOHEADER bmih; 381 RGBQUAD rgbquad[256]; 382 } buffer; 383 DIBSECTION* pDIBs = (DIBSECTION*) &buffer; 384 BITMAPINFO* pbmi = (BITMAPINFO*) &buffer.bmih; 385 386 hBmp = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_BITMAP); 387 388 if (GetObjectA(hBmp, sizeof(DIBSECTION), pDIBs) != sizeof(DIBSECTION)) 389 return NULL; 390 391 if (pDIBs->dsBm.bmBitsPixel <= 8) 392 GetDIBColorTable(hDC, 0, 256, buffer.rgbquad); 393 394 pDIBs->dsBmih.biWidth = Width; 395 pDIBs->dsBmih.biHeight = Height; 396 397 return CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, NULL, NULL, 0); 398 } 399 return NULL; 400 } 401 402 INT 403 WINAPI 404 GetDIBits( 405 HDC hDC, 406 HBITMAP hbmp, 407 UINT uStartScan, 408 UINT cScanLines, 409 LPVOID lpvBits, 410 LPBITMAPINFO lpbmi, 411 UINT uUsage) 412 { 413 UINT cjBmpScanSize; 414 UINT cjInfoSize; 415 416 if (!hDC || !GdiValidateHandle((HGDIOBJ) hDC) || !lpbmi) 417 { 418 GdiSetLastError(ERROR_INVALID_PARAMETER); 419 return 0; 420 } 421 422 cjBmpScanSize = DIB_BitmapMaxBitsSize(lpbmi, cScanLines); 423 /* Caller must provide maximum size possible */ 424 cjInfoSize = DIB_BitmapInfoSize(lpbmi, uUsage, TRUE); 425 426 if (lpvBits) 427 { 428 if (lpbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) 429 { 430 if (lpbmi->bmiHeader.biCompression == BI_JPEG 431 || lpbmi->bmiHeader.biCompression == BI_PNG) 432 { 433 SetLastError(ERROR_INVALID_PARAMETER); 434 return 0; 435 } 436 } 437 } 438 439 return NtGdiGetDIBitsInternal(hDC, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, uUsage, 440 cjBmpScanSize, cjInfoSize); 441 } 442 443 /* 444 * @implemented 445 */ 446 HBITMAP 447 WINAPI 448 CreateDIBitmap( 449 HDC hDC, 450 const BITMAPINFOHEADER *Header, 451 DWORD Init, 452 LPCVOID Bits, 453 const BITMAPINFO *Data, 454 UINT ColorUse) 455 { 456 LONG Width, Height, Compression, DibSize; 457 WORD Planes, BitsPerPixel; 458 // PDC_ATTR pDc_Attr; 459 UINT cjBmpScanSize = 0; 460 HBITMAP hBitmap = NULL; 461 PBITMAPINFO pbmiConverted; 462 UINT cjInfoSize; 463 464 /* Convert the BITMAPINFO if it is a COREINFO */ 465 pbmiConverted = ConvertBitmapInfo(Data, ColorUse, &cjInfoSize, FALSE); 466 467 /* Check for CBM_CREATDIB */ 468 if (Init & CBM_CREATDIB) 469 { 470 if (cjInfoSize == 0) 471 { 472 goto Exit; 473 } 474 else if (Init & CBM_INIT) 475 { 476 if (Bits == NULL) 477 { 478 goto Exit; 479 } 480 } 481 else 482 { 483 Bits = NULL; 484 } 485 486 /* CBM_CREATDIB needs Data. */ 487 if (pbmiConverted == NULL) 488 { 489 DPRINT1("CBM_CREATDIB needs a BITMAPINFO!\n"); 490 goto Exit; 491 } 492 493 /* It only works with PAL or RGB */ 494 if (ColorUse > DIB_PAL_COLORS) 495 { 496 DPRINT1("Invalid ColorUse: %lu\n", ColorUse); 497 GdiSetLastError(ERROR_INVALID_PARAMETER); 498 goto Exit; 499 } 500 501 /* Use the header from the data */ 502 Header = &Data->bmiHeader; 503 } 504 else 505 { 506 if (Init & CBM_INIT) 507 { 508 if (Bits != NULL) 509 { 510 if (cjInfoSize == 0) 511 { 512 goto Exit; 513 } 514 } 515 else 516 { 517 Init &= ~CBM_INIT; 518 } 519 } 520 } 521 522 /* Header is required */ 523 if (!Header) 524 { 525 DPRINT1("Header is NULL\n"); 526 GdiSetLastError(ERROR_INVALID_PARAMETER); 527 goto Exit; 528 } 529 530 /* Get the bitmap format and dimensions */ 531 if (DIB_GetBitmapInfo(Header, &Width, &Height, &Planes, &BitsPerPixel, &Compression, &DibSize) == -1) 532 { 533 DPRINT1("DIB_GetBitmapInfo failed!\n"); 534 GdiSetLastError(ERROR_INVALID_PARAMETER); 535 goto Exit; 536 } 537 538 /* Check if the Compr is incompatible */ 539 if ((Compression == BI_JPEG) || (Compression == BI_PNG)) 540 { 541 DPRINT1("Invalid compression: %lu!\n", Compression); 542 goto Exit; 543 } 544 545 /* Only DIB_RGB_COLORS (0), DIB_PAL_COLORS (1) and 2 are valid. */ 546 if (ColorUse > DIB_PAL_COLORS + 1) 547 { 548 DPRINT1("Invalid compression: %lu!\n", Compression); 549 GdiSetLastError(ERROR_INVALID_PARAMETER); 550 goto Exit; 551 } 552 553 /* If some Bits are given, only DIB_PAL_COLORS and DIB_RGB_COLORS are valid */ 554 if (Bits && (ColorUse > DIB_PAL_COLORS)) 555 { 556 DPRINT1("Invalid ColorUse: %lu\n", ColorUse); 557 GdiSetLastError(ERROR_INVALID_PARAMETER); 558 goto Exit; 559 } 560 561 /* Negative width is not allowed */ 562 if (Width < 0) 563 { 564 DPRINT1("Negative width: %li\n", Width); 565 goto Exit; 566 } 567 568 /* Top-down DIBs have a negative height. */ 569 Height = abs(Height); 570 571 // For Icm support. 572 // GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr)) 573 574 cjBmpScanSize = GdiGetBitmapBitsSize(pbmiConverted); 575 576 DPRINT("pBMI %p, Size bpp %u, dibsize %d, Conv %u, BSS %u\n", 577 Data, BitsPerPixel, DibSize, cjInfoSize, cjBmpScanSize); 578 579 if (!Width || !Height) 580 { 581 hBitmap = GetStockObject(DEFAULT_BITMAP); 582 } 583 else 584 { 585 hBitmap = NtGdiCreateDIBitmapInternal(hDC, 586 Width, 587 Height, 588 Init, 589 (LPBYTE)Bits, 590 (LPBITMAPINFO)pbmiConverted, 591 ColorUse, 592 cjInfoSize, 593 cjBmpScanSize, 594 0, 0); 595 } 596 597 Exit: 598 /* Cleanup converted BITMAPINFO */ 599 if ((pbmiConverted != NULL) && (pbmiConverted != Data)) 600 { 601 RtlFreeHeap(RtlGetProcessHeap(), 0, pbmiConverted); 602 } 603 604 return hBitmap; 605 } 606 607 /* 608 * @implemented 609 */ 610 INT 611 WINAPI 612 SetDIBits( 613 HDC hDC, 614 HBITMAP hBitmap, 615 UINT uStartScan, 616 UINT cScanLines, 617 CONST VOID *lpvBits, 618 CONST BITMAPINFO *lpbmi, 619 UINT fuColorUse) 620 { 621 HDC hDCc, SavehDC, nhDC; 622 DWORD dwWidth, dwHeight; 623 HGDIOBJ hOldBitmap; 624 HPALETTE hPal = NULL; 625 INT LinesCopied = 0; 626 BOOL newDC = FALSE; 627 628 if (fuColorUse != DIB_RGB_COLORS && fuColorUse != DIB_PAL_COLORS) 629 return 0; 630 631 if (!lpvBits || (GDI_HANDLE_GET_TYPE(hBitmap) != GDI_OBJECT_TYPE_BITMAP)) 632 return 0; 633 634 if (lpbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) 635 { 636 if (lpbmi->bmiHeader.biCompression == BI_JPEG 637 || lpbmi->bmiHeader.biCompression == BI_PNG) 638 { 639 SetLastError(ERROR_INVALID_PARAMETER); 640 return 0; 641 } 642 } 643 644 if (lpbmi->bmiHeader.biCompression == BI_BITFIELDS) 645 { 646 DWORD *masks = (DWORD *)lpbmi->bmiColors; 647 if (!masks[0] || !masks[1] || !masks[2]) 648 { 649 SetLastError(ERROR_INVALID_PARAMETER); 650 return 0; 651 } 652 } 653 654 hDCc = NtGdiGetDCforBitmap(hBitmap); // hDC can be NULL, so, get it from the bitmap. 655 SavehDC = hDCc; 656 if (!hDCc) // No DC associated with bitmap, Clone or Create one. 657 { 658 nhDC = CreateCompatibleDC(hDC); 659 if (!nhDC) 660 return 0; 661 newDC = TRUE; 662 SavehDC = nhDC; 663 } 664 else if (!SaveDC(hDCc)) 665 return 0; 666 667 hOldBitmap = SelectObject(SavehDC, hBitmap); 668 669 if (hOldBitmap) 670 { 671 if (hDC) 672 hPal = SelectPalette(SavehDC, (HPALETTE) GetCurrentObject(hDC, OBJ_PAL), FALSE); 673 674 if (lpbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER)) 675 { 676 PBITMAPCOREINFO pbci = (PBITMAPCOREINFO) lpbmi; 677 dwWidth = pbci->bmciHeader.bcWidth; 678 dwHeight = pbci->bmciHeader.bcHeight; 679 } 680 else 681 { 682 dwWidth = lpbmi->bmiHeader.biWidth; 683 dwHeight = abs(lpbmi->bmiHeader.biHeight); 684 } 685 686 LinesCopied = SetDIBitsToDevice(SavehDC, 0, 0, dwWidth, dwHeight, 0, 0, uStartScan, 687 cScanLines, (void *) lpvBits, (LPBITMAPINFO) lpbmi, fuColorUse); 688 689 if (hDC) 690 SelectPalette(SavehDC, hPal, FALSE); 691 692 SelectObject(SavehDC, hOldBitmap); 693 } 694 695 if (newDC) 696 DeleteDC(SavehDC); 697 else 698 RestoreDC(SavehDC, -1); 699 700 return LinesCopied; 701 } 702 703 /* 704 * @implemented 705 * 706 */ 707 INT 708 WINAPI 709 SetDIBitsToDevice( 710 HDC hdc, 711 int XDest, 712 int YDest, 713 DWORD Width, 714 DWORD Height, 715 int XSrc, 716 int YSrc, 717 UINT StartScan, 718 UINT ScanLines, 719 CONST VOID *Bits, 720 CONST BITMAPINFO *lpbmi, 721 UINT ColorUse) 722 { 723 PDC_ATTR pDc_Attr; 724 PBITMAPINFO pConvertedInfo; 725 UINT ConvertedInfoSize; 726 INT LinesCopied = 0; 727 UINT cjBmpScanSize = 0; 728 BOOL Hit = FALSE; 729 PVOID pvSafeBits = (PVOID) Bits; 730 UINT bmiHeight; 731 BOOL top_down; 732 INT src_y = 0; 733 ULONG iFormat, cBitsPixel, cjBits, cjWidth; 734 735 #define MaxScanLines 1000 736 #define MaxHeight 2000 737 #define MaxSourceHeight 2000 738 #define IS_ALIGNED(Pointer, Alignment) \ 739 (((ULONG_PTR)(void *)(Pointer)) % (Alignment) == 0) 740 741 if (!ScanLines || !lpbmi || !Bits) 742 return 0; 743 744 DPRINT("ScanLines %d Height %d Width %d biHeight %d biWidth %d\n" 745 " lpbmi '%p' ColorUse '%d' SizeImage '%d' StartScan %d\n" 746 " biCompression '%d' biBitCount '%d'\n", 747 ScanLines, Height, Width, lpbmi->bmiHeader.biHeight, 748 lpbmi->bmiHeader.biWidth, lpbmi, ColorUse, 749 lpbmi->bmiHeader.biSizeImage, StartScan, 750 lpbmi->bmiHeader.biCompression, lpbmi->bmiHeader.biBitCount); 751 752 if (lpbmi->bmiHeader.biWidth < 0) 753 return 0; 754 755 if (ColorUse && ColorUse != DIB_PAL_COLORS && ColorUse != DIB_PAL_COLORS + 1) 756 return 0; 757 758 pConvertedInfo = ConvertBitmapInfo(lpbmi, ColorUse, &ConvertedInfoSize, FALSE); 759 if (!pConvertedInfo) 760 return 0; 761 762 if (ScanLines > MaxScanLines) 763 { 764 LinesCopied = 0; 765 goto Exit; 766 } 767 768 bmiHeight = abs(pConvertedInfo->bmiHeader.biHeight); 769 top_down = (pConvertedInfo->bmiHeader.biHeight < 0); 770 if ((StartScan > bmiHeight) && (ScanLines > bmiHeight)) 771 { 772 DPRINT("Returning ScanLines of '%d'\n", ScanLines); 773 LinesCopied = ScanLines; 774 goto Exit; 775 } 776 777 if (pConvertedInfo->bmiHeader.biHeight == 0) 778 { 779 LinesCopied = 0; 780 goto Exit; 781 } 782 783 if (!IS_ALIGNED(Bits, 2) && (ScanLines > Height)) 784 { 785 LinesCopied = 0; 786 goto Exit; 787 } 788 789 /* Below code modeled after Wine's nulldrv_SetDIBitsToDevice */ 790 if (StartScan <= YSrc + bmiHeight) 791 { 792 if ((pConvertedInfo->bmiHeader.biCompression == BI_RLE8) || 793 (pConvertedInfo->bmiHeader.biCompression == BI_RLE4)) 794 { 795 StartScan = 0; 796 ScanLines = bmiHeight; 797 } 798 else 799 { 800 if (StartScan >= bmiHeight) 801 { 802 LinesCopied = 0; 803 goto Exit; 804 } 805 if (!top_down && ScanLines > bmiHeight - StartScan) 806 { 807 ScanLines = bmiHeight - StartScan; 808 } 809 src_y = StartScan + ScanLines - (YSrc + Height); 810 if (!top_down) 811 { 812 /* get rid of unnecessary lines */ 813 if ((src_y < 0 || src_y >= (INT)ScanLines) && 814 pConvertedInfo->bmiHeader.biCompression != BI_BITFIELDS) 815 { 816 LinesCopied = ScanLines; 817 goto Exit; 818 } 819 if (YDest >= 0) 820 { 821 LinesCopied = ScanLines + StartScan; 822 ScanLines -= src_y; 823 } 824 else 825 { 826 LinesCopied = ScanLines - src_y; 827 } 828 } 829 else if (src_y < 0 || src_y >= (INT)ScanLines) 830 { 831 if (lpbmi->bmiHeader.biHeight < 0 && 832 StartScan > MaxScanLines) 833 { 834 ScanLines = lpbmi->bmiHeader.biHeight - StartScan; 835 } 836 DPRINT("Returning ScanLines of '%d'\n", ScanLines); 837 LinesCopied = ScanLines; 838 goto Exit; 839 } 840 else 841 { 842 LinesCopied = ScanLines; 843 } 844 } 845 } 846 847 HANDLE_METADC(INT, 848 SetDIBitsToDevice, 849 0, 850 hdc, 851 XDest, 852 YDest, 853 Width, 854 Height, 855 XSrc, 856 YSrc, 857 StartScan, 858 ScanLines, 859 Bits, 860 lpbmi, 861 ColorUse); 862 863 // Handle the "Special Case"! 864 { 865 PLDC pldc; 866 ULONG hType = GDI_HANDLE_GET_TYPE(hdc); 867 if (hType != GDILoObjType_LO_DC_TYPE && hType != GDILoObjType_LO_METADC16_TYPE) 868 { 869 pldc = GdiGetLDC(hdc); 870 if (pldc) 871 { 872 if (pldc->Flags & LDC_STARTPAGE) StartPage(hdc); 873 874 if (pldc->Flags & LDC_SAPCALLBACK) GdiSAPCallback(pldc); 875 876 if (pldc->Flags & LDC_KILL_DOCUMENT) 877 { 878 LinesCopied = 0; 879 goto Exit; 880 } 881 } 882 else 883 { 884 SetLastError(ERROR_INVALID_HANDLE); 885 LinesCopied = 0; 886 goto Exit; 887 } 888 } 889 } 890 891 if ((pConvertedInfo->bmiHeader.biCompression == BI_RLE8) || 892 (pConvertedInfo->bmiHeader.biCompression == BI_RLE4)) 893 { 894 /* For compressed data, we must set the whole thing */ 895 StartScan = 0; 896 ScanLines = pConvertedInfo->bmiHeader.biHeight; 897 } 898 899 cjBmpScanSize = DIB_BitmapMaxBitsSize((LPBITMAPINFO) lpbmi, ScanLines); 900 901 pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize); 902 if (pvSafeBits) 903 { 904 _SEH2_TRY 905 { 906 RtlCopyMemory(pvSafeBits, Bits, cjBmpScanSize); 907 } 908 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 909 { 910 Hit = TRUE; 911 } 912 _SEH2_END; 913 914 if (Hit) 915 { 916 // We don't die, we continue on with a allocated safe pointer to kernel 917 // space..... 918 919 if (!IS_ALIGNED(Bits, 2)) // If both Read Exception and mis-aligned 920 { 921 LinesCopied = 0; 922 goto Exit; 923 } 924 925 DPRINT1("SetDIBitsToDevice fail to read BitMapInfo: %p or Bits: %p & Size: %u\n", 926 pConvertedInfo, Bits, cjBmpScanSize); 927 } 928 DPRINT("SetDIBitsToDevice Allocate Bits %u!!!\n", cjBmpScanSize); 929 } 930 931 if (!GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr)) 932 { 933 DPRINT1("SetDIBitsToDevice called on invalid DC %p (not owned?)\n", hdc); 934 SetLastError(ERROR_INVALID_PARAMETER); 935 LinesCopied = 0; 936 goto Exit; 937 } 938 939 /* Calculation of ScanLines for NtGdiSetDIBitsToDeviceInternal */ 940 if (YDest >= 0) 941 { 942 ScanLines = min(abs(Height), ScanLines); 943 if (YSrc > 0) 944 ScanLines += YSrc; 945 } 946 else 947 { 948 ScanLines = min(ScanLines, 949 abs(pConvertedInfo->bmiHeader.biHeight) - StartScan); 950 } 951 952 if (YDest >= 0 && YSrc > 0 && bmiHeight <= MaxHeight) 953 { 954 ScanLines += YSrc; 955 } 956 957 /* Find Format from lpbmi which is now pConvertedInfo */ 958 iFormat = BitmapFormat(pConvertedInfo->bmiHeader.biBitCount, 959 pConvertedInfo->bmiHeader.biCompression); 960 961 /* Get bits per pixel from the format */ 962 cBitsPixel = gajBitsPerFormat[iFormat]; 963 964 cjWidth = WIDTH_BYTES_ALIGN32(pConvertedInfo->bmiHeader.biWidth, cBitsPixel); 965 966 /* Calculate the correct bitmap size in bytes */ 967 if (!NT_SUCCESS(RtlULongMult(cjWidth, max(ScanLines, LinesCopied), &cjBits))) 968 { 969 DPRINT1("Overflow calculating size: cjWidth %lu, ScanLines %lu\n", 970 cjWidth, max(ScanLines, LinesCopied)); 971 goto Exit; 972 } 973 974 /* Make sure the buffer is large enough */ 975 if (pConvertedInfo->bmiHeader.biSizeImage < cjBits) 976 { 977 DPRINT("Buffer is too small, required: %lu, got %lu\n", 978 cjBits, pConvertedInfo->bmiHeader.biSizeImage); 979 if (pConvertedInfo->bmiHeader.biCompression == BI_RGB) 980 { 981 pConvertedInfo->bmiHeader.biSizeImage = cjBits; 982 } 983 } 984 985 /* 986 if ( !pDc_Attr || // DC is Public 987 ColorUse == DIB_PAL_COLORS || 988 ((pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && 989 (pConvertedInfo->bmiHeader.biCompression == BI_JPEG || 990 pConvertedInfo->bmiHeader.biCompression == BI_PNG )) )*/ 991 { 992 LinesCopied = NtGdiSetDIBitsToDeviceInternal(hdc, XDest, YDest, 993 Width, Height, XSrc, YSrc, 994 StartScan, ScanLines, (LPBYTE) pvSafeBits, 995 (LPBITMAPINFO) pConvertedInfo, ColorUse, 996 cjBmpScanSize, ConvertedInfoSize, 997 TRUE, 998 NULL); 999 } 1000 1001 if (bmiHeight > MaxScanLines) 1002 { 1003 LinesCopied = ScanLines; 1004 } 1005 1006 if (YDest < 0) 1007 { 1008 if (top_down) 1009 LinesCopied = ScanLines; 1010 else 1011 LinesCopied = ScanLines - src_y; 1012 } 1013 1014 if (pConvertedInfo->bmiHeader.biCompression == BI_RLE8 || 1015 pConvertedInfo->bmiHeader.biCompression == BI_RLE4) 1016 { 1017 LinesCopied = bmiHeight; 1018 } 1019 1020 if (pConvertedInfo->bmiHeader.biHeight < 0) 1021 { 1022 if (pConvertedInfo->bmiHeader.biHeight < -MaxSourceHeight || 1023 (YDest >= 0 && src_y < -ScanLines)) 1024 { 1025 LinesCopied = ScanLines + src_y; 1026 } 1027 else 1028 { 1029 LinesCopied = ScanLines; 1030 } 1031 } 1032 1033 Exit: 1034 if (Bits != pvSafeBits) 1035 RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits); 1036 if (lpbmi != pConvertedInfo) 1037 RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); 1038 1039 return LinesCopied; 1040 } 1041 1042 /* 1043 * @unimplemented 1044 */ 1045 int 1046 WINAPI 1047 StretchDIBits( 1048 HDC hdc, 1049 int XDest, 1050 int YDest, 1051 int nDestWidth, 1052 int nDestHeight, 1053 int XSrc, 1054 int YSrc, 1055 int nSrcWidth, 1056 int nSrcHeight, 1057 CONST VOID *lpBits, 1058 CONST BITMAPINFO *lpBitsInfo, 1059 UINT iUsage, 1060 DWORD dwRop) 1061 1062 { 1063 PDC_ATTR pDc_Attr; 1064 PBITMAPINFO pConvertedInfo = NULL; 1065 UINT ConvertedInfoSize = 0; 1066 INT LinesCopied = 0; 1067 UINT cjBmpScanSize = 0; 1068 PVOID pvSafeBits = NULL; 1069 BOOL Hit = FALSE; 1070 1071 DPRINT("StretchDIBits %p : %p : %u\n", lpBits, lpBitsInfo, iUsage); 1072 1073 HANDLE_METADC( int, 1074 StretchDIBits, 1075 0, 1076 hdc, 1077 XDest, 1078 YDest, 1079 nDestWidth, 1080 nDestHeight, 1081 XSrc, 1082 YSrc, 1083 nSrcWidth, 1084 nSrcHeight, 1085 lpBits, 1086 lpBitsInfo, 1087 iUsage, 1088 dwRop ); 1089 1090 if ( GdiConvertAndCheckDC(hdc) == NULL ) return 0; 1091 1092 pConvertedInfo = ConvertBitmapInfo(lpBitsInfo, iUsage, &ConvertedInfoSize, FALSE); 1093 if (!pConvertedInfo) 1094 { 1095 return 0; 1096 } 1097 1098 cjBmpScanSize = GdiGetBitmapBitsSize((BITMAPINFO *) pConvertedInfo); 1099 1100 if (lpBits) 1101 { 1102 pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize); 1103 if (pvSafeBits) 1104 { 1105 _SEH2_TRY 1106 { 1107 RtlCopyMemory(pvSafeBits, lpBits, cjBmpScanSize); 1108 } 1109 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1110 { 1111 Hit = TRUE; 1112 } 1113 _SEH2_END 1114 1115 if (Hit) 1116 { 1117 // We don't die, we continue on with a allocated safe pointer to kernel 1118 // space..... 1119 DPRINT1("StretchDIBits fail to read BitMapInfo: %p or Bits: %p & Size: %u\n", 1120 pConvertedInfo, lpBits, cjBmpScanSize); 1121 } 1122 DPRINT("StretchDIBits Allocate Bits %u!!!\n", cjBmpScanSize); 1123 } 1124 } 1125 1126 if (!GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr)) 1127 { 1128 DPRINT1("StretchDIBits called on invalid DC %p (not owned?)\n", hdc); 1129 SetLastError(ERROR_INVALID_PARAMETER); 1130 LinesCopied = 0; 1131 goto Exit; 1132 } 1133 /* 1134 if ( !pDc_Attr || 1135 iUsage == DIB_PAL_COLORS || 1136 ((pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && 1137 (pConvertedInfo->bmiHeader.biCompression == BI_JPEG || 1138 pConvertedInfo->bmiHeader.biCompression == BI_PNG )) )*/ 1139 { 1140 LinesCopied = NtGdiStretchDIBitsInternal( hdc, 1141 XDest, 1142 YDest, 1143 nDestWidth, 1144 nDestHeight, 1145 XSrc, 1146 YSrc, 1147 nSrcWidth, 1148 nSrcHeight, 1149 pvSafeBits, 1150 pConvertedInfo, 1151 (DWORD) iUsage, 1152 dwRop, 1153 ConvertedInfoSize, 1154 cjBmpScanSize, 1155 NULL ); 1156 } 1157 Exit: 1158 if (pvSafeBits) 1159 RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits); 1160 if (lpBitsInfo != pConvertedInfo) 1161 RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); 1162 1163 return LinesCopied; 1164 } 1165 1166 /* 1167 * @implemented 1168 */ 1169 DWORD 1170 WINAPI 1171 GetBitmapAttributes(HBITMAP hbm) 1172 { 1173 if ( GDI_HANDLE_IS_STOCKOBJ(hbm) ) 1174 { 1175 return SC_BB_STOCKOBJ; 1176 } 1177 return 0; 1178 } 1179 1180 /* 1181 * @implemented 1182 */ 1183 HBITMAP 1184 WINAPI 1185 SetBitmapAttributes(HBITMAP hbm, DWORD dwFlags) 1186 { 1187 if ( dwFlags & ~SC_BB_STOCKOBJ ) 1188 { 1189 return NULL; 1190 } 1191 return NtGdiSetBitmapAttributes( hbm, dwFlags ); 1192 } 1193 1194 /* 1195 * @implemented 1196 */ 1197 HBITMAP 1198 WINAPI 1199 ClearBitmapAttributes(HBITMAP hbm, DWORD dwFlags) 1200 { 1201 if ( dwFlags & ~SC_BB_STOCKOBJ ) 1202 { 1203 return NULL; 1204 } 1205 return NtGdiClearBitmapAttributes( hbm, dwFlags );; 1206 } 1207 1208 1209