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