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