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