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
BitmapFormat(ULONG cBits,ULONG iCompression)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
DIB_BitmapInfoSize(const BITMAPINFO * info,WORD coloruse,BOOL max)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
DIB_BitmapMaxBitsSize(PBITMAPINFO Info,UINT ScanLines)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
DIB_GetBitmapInfo(const BITMAPINFOHEADER * header,PLONG width,PLONG height,PWORD planes,PWORD bpp,PLONG compr,PLONG size)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
GdiGetBitmapBitsSize(BITMAPINFO * lpbmi)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
CreateDIBSection(HDC hDC,CONST BITMAPINFO * BitmapInfo,UINT Usage,VOID ** Bits,HANDLE hSection,DWORD dwOffset)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
CreateBitmap(INT Width,INT Height,UINT Planes,UINT BitsPixel,CONST VOID * pUnsafeBits)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
CreateBitmapIndirect(const BITMAP * pbm)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
CreateDiscardableBitmap(HDC hDC,INT Width,INT Height)347 CreateDiscardableBitmap(
348 HDC hDC,
349 INT Width,
350 INT Height)
351 {
352 return CreateCompatibleBitmap(hDC, Width, Height);
353 }
354
355 HBITMAP
356 WINAPI
CreateCompatibleBitmap(HDC hDC,INT Width,INT Height)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
GetDIBits(HDC hDC,HBITMAP hbmp,UINT uStartScan,UINT cScanLines,LPVOID lpvBits,LPBITMAPINFO lpbmi,UINT uUsage)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
CreateDIBitmap(HDC hDC,const BITMAPINFOHEADER * Header,DWORD Init,LPCVOID Bits,const BITMAPINFO * Data,UINT ColorUse)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
SetDIBits(HDC hDC,HBITMAP hBitmap,UINT uStartScan,UINT cScanLines,CONST VOID * lpvBits,CONST BITMAPINFO * lpbmi,UINT fuColorUse)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
SetDIBitsToDevice(HDC hdc,int XDest,int YDest,DWORD Width,DWORD Height,int XSrc,int YSrc,UINT StartScan,UINT ScanLines,CONST VOID * Bits,CONST BITMAPINFO * lpbmi,UINT ColorUse)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
StretchDIBits(HDC hdc,int XDest,int YDest,int nDestWidth,int nDestHeight,int XSrc,int YSrc,int nSrcWidth,int nSrcHeight,CONST VOID * lpBits,CONST BITMAPINFO * lpBitsInfo,UINT iUsage,DWORD dwRop)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
GetBitmapAttributes(HBITMAP hbm)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
SetBitmapAttributes(HBITMAP hbm,DWORD dwFlags)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
ClearBitmapAttributes(HBITMAP hbm,DWORD dwFlags)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