1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/dibobj.c
5 * PURPOSE: Dib object functions
6 * PROGRAMMER:
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 static const RGBQUAD DefLogPaletteQuads[20] = /* Copy of Default Logical Palette */
15 {
16 /* rgbBlue, rgbGreen, rgbRed, rgbReserved */
17 { 0x00, 0x00, 0x00, 0x00 },
18 { 0x00, 0x00, 0x80, 0x00 },
19 { 0x00, 0x80, 0x00, 0x00 },
20 { 0x00, 0x80, 0x80, 0x00 },
21 { 0x80, 0x00, 0x00, 0x00 },
22 { 0x80, 0x00, 0x80, 0x00 },
23 { 0x80, 0x80, 0x00, 0x00 },
24 { 0xc0, 0xc0, 0xc0, 0x00 },
25 { 0xc0, 0xdc, 0xc0, 0x00 },
26 { 0xf0, 0xca, 0xa6, 0x00 },
27 { 0xf0, 0xfb, 0xff, 0x00 },
28 { 0xa4, 0xa0, 0xa0, 0x00 },
29 { 0x80, 0x80, 0x80, 0x00 },
30 { 0x00, 0x00, 0xff, 0x00 },
31 { 0x00, 0xff, 0x00, 0x00 },
32 { 0x00, 0xff, 0xff, 0x00 },
33 { 0xff, 0x00, 0x00, 0x00 },
34 { 0xff, 0x00, 0xff, 0x00 },
35 { 0xff, 0xff, 0x00, 0x00 },
36 { 0xff, 0xff, 0xff, 0x00 }
37 };
38
39 PPALETTE
40 NTAPI
CreateDIBPalette(_In_ const BITMAPINFO * pbmi,_In_ PDC pdc,_In_ ULONG iUsage)41 CreateDIBPalette(
42 _In_ const BITMAPINFO *pbmi,
43 _In_ PDC pdc,
44 _In_ ULONG iUsage)
45 {
46 PPALETTE ppal;
47 ULONG i, cBitsPixel, cColors;
48
49 if (pbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
50 {
51 PBITMAPCOREINFO pbci = (PBITMAPCOREINFO)pbmi;
52 cBitsPixel = pbci->bmciHeader.bcBitCount;
53 }
54 else
55 {
56 cBitsPixel = pbmi->bmiHeader.biBitCount;
57 }
58
59 /* Check if the colors are indexed */
60 if (cBitsPixel <= 8)
61 {
62 /* We create a "full" palette */
63 cColors = 1 << cBitsPixel;
64
65 /* Allocate the palette */
66 ppal = PALETTE_AllocPalette(PAL_INDEXED,
67 cColors,
68 NULL,
69 0,
70 0,
71 0);
72 if (ppal == NULL)
73 {
74 DPRINT1("Failed to allocate palette.\n");
75 return NULL;
76 }
77
78 /* Check if the BITMAPINFO specifies how many colors to use */
79 if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
80 (pbmi->bmiHeader.biClrUsed != 0))
81 {
82 /* This is how many colors we can actually process */
83 cColors = min(cColors, pbmi->bmiHeader.biClrUsed);
84 }
85
86 /* Check how to use the colors */
87 if (iUsage == DIB_PAL_COLORS)
88 {
89 COLORREF crColor;
90
91 /* The colors are an array of WORD indices into the DC palette */
92 PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
93
94 /* Use the DCs palette or, if no DC is given, the default one */
95 PPALETTE ppalDC = pdc ? pdc->dclevel.ppal : gppalDefault;
96
97 /* Loop all color indices in the DIB */
98 for (i = 0; i < cColors; i++)
99 {
100 /* Get the palette index and handle wraparound when exceeding
101 the number of colors in the DC palette */
102 WORD wIndex = pwColors[i] % ppalDC->NumColors;
103
104 /* USe the RGB value from the DC palette */
105 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, wIndex);
106 PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
107 }
108 }
109 else if (iUsage == DIB_PAL_BRUSHHACK)
110 {
111 /* The colors are an array of WORD indices into the DC palette */
112 PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
113
114 /* Loop all color indices in the DIB */
115 for (i = 0; i < cColors; i++)
116 {
117 /* Set the index directly as the RGB color, the real palette
118 containing RGB values will be calculated when the brush is
119 realized */
120 PALETTE_vSetRGBColorForIndex(ppal, i, pwColors[i]);
121 }
122
123 /* Mark the palette as a brush hack palette */
124 ppal->flFlags |= PAL_BRUSHHACK;
125 }
126 // else if (iUsage == 2)
127 // {
128 // FIXME: this one is undocumented
129 // ASSERT(FALSE);
130 // }
131 else if (pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
132 {
133 /* The colors are an array of RGBQUAD values */
134 RGBQUAD *prgb = (RGBQUAD*)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
135 RGBQUAD colors[256] = {{0}};
136
137 // FIXME: do we need to handle PALETTEINDEX / PALETTERGB macro?
138
139 /* Use SEH to verify we can READ prgb[] succesfully */
140 _SEH2_TRY
141 {
142 RtlCopyMemory(colors, prgb, cColors * sizeof(colors[0]));
143 }
144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
145 {
146 /* Do Nothing */
147 }
148 _SEH2_END;
149
150 for (i = 0; i < cColors; ++i)
151 {
152 /* Get the color value and translate it to a COLORREF */
153 COLORREF crColor = RGB(colors[i].rgbRed, colors[i].rgbGreen, colors[i].rgbBlue);
154
155 /* Set the RGB value in the palette */
156 PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
157 }
158 }
159 else
160 {
161 /* The colors are an array of RGBTRIPLE values */
162 RGBTRIPLE *prgb = (RGBTRIPLE*)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
163
164 /* Loop all color indices in the DIB */
165 for (i = 0; i < cColors; i++)
166 {
167 /* Get the color value and translate it to a COLORREF */
168 RGBTRIPLE rgb = prgb[i];
169 COLORREF crColor = RGB(rgb.rgbtRed, rgb.rgbtGreen, rgb.rgbtBlue);
170
171 /* Set the RGB value in the palette */
172 PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
173 }
174 }
175 }
176 else
177 {
178 /* This is a bitfield / RGB palette */
179 ULONG flRedMask, flGreenMask, flBlueMask;
180
181 /* Check if the DIB contains bitfield values */
182 if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
183 (pbmi->bmiHeader.biCompression == BI_BITFIELDS))
184 {
185 /* Check if we have a v4/v5 header */
186 if (pbmi->bmiHeader.biSize >= sizeof(BITMAPV4HEADER))
187 {
188 /* The masks are dedicated fields in the header */
189 PBITMAPV4HEADER pbmV4Header = (PBITMAPV4HEADER)&pbmi->bmiHeader;
190 flRedMask = pbmV4Header->bV4RedMask;
191 flGreenMask = pbmV4Header->bV4GreenMask;
192 flBlueMask = pbmV4Header->bV4BlueMask;
193 }
194 else
195 {
196 /* The masks are the first 3 values in the DIB color table */
197 PDWORD pdwColors = (PVOID)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
198 flRedMask = pdwColors[0];
199 flGreenMask = pdwColors[1];
200 flBlueMask = pdwColors[2];
201 }
202 }
203 else
204 {
205 /* Check what bit depth we have. Note: optimization flags are
206 calculated in PALETTE_AllocPalette() */
207 if (cBitsPixel == 16)
208 {
209 /* This is an RGB 555 palette */
210 flRedMask = 0x7C00;
211 flGreenMask = 0x03E0;
212 flBlueMask = 0x001F;
213 }
214 else
215 {
216 /* This is an RGB 888 palette */
217 flRedMask = 0xFF0000;
218 flGreenMask = 0x00FF00;
219 flBlueMask = 0x0000FF;
220 }
221 }
222
223 /* Allocate the bitfield palette */
224 ppal = PALETTE_AllocPalette(PAL_BITFIELDS,
225 0,
226 NULL,
227 flRedMask,
228 flGreenMask,
229 flBlueMask);
230 }
231
232 /* We're done, return the palette */
233 return ppal;
234 }
235
236 // Converts a DIB to a device-dependent bitmap
237 static INT
238 FASTCALL
IntSetDIBits(PDC DC,HBITMAP hBitmap,UINT StartScan,UINT ScanLines,CONST VOID * Bits,ULONG cjMaxBits,CONST BITMAPINFO * bmi,UINT ColorUse)239 IntSetDIBits(
240 PDC DC,
241 HBITMAP hBitmap,
242 UINT StartScan,
243 UINT ScanLines,
244 CONST VOID *Bits,
245 ULONG cjMaxBits,
246 CONST BITMAPINFO *bmi,
247 UINT ColorUse)
248 {
249 HBITMAP SourceBitmap;
250 PSURFACE psurfDst, psurfSrc;
251 INT result = 0;
252 RECT rcDst;
253 POINTL ptSrc;
254 EXLATEOBJ exlo;
255 PPALETTE ppalDIB = 0;
256 ULONG cjSizeImage;
257
258 if (!bmi || !Bits) return 0;
259
260 /* Check for uncompressed formats */
261 if ((bmi->bmiHeader.biCompression == BI_RGB) ||
262 (bmi->bmiHeader.biCompression == BI_BITFIELDS))
263 {
264 /* Calculate the image size */
265 cjSizeImage = DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
266 ScanLines,
267 bmi->bmiHeader.biBitCount);
268 }
269 /* Check if the header provided an image size */
270 else if (bmi->bmiHeader.biSizeImage != 0)
271 {
272 /* Use the given size */
273 cjSizeImage = bmi->bmiHeader.biSizeImage;
274 }
275 else
276 {
277 /* Compressed format without a size. This is invalid. */
278 DPRINT1("Compressed format without a size\n");
279 return 0;
280 }
281
282 /* Check if the size that we have is ok */
283 if ((cjSizeImage > cjMaxBits) || (cjSizeImage == 0))
284 {
285 DPRINT1("Invalid bitmap size! cjSizeImage = %lu, cjMaxBits = %lu\n",
286 cjSizeImage, cjMaxBits);
287 return 0;
288 }
289
290 SourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth,
291 ScanLines,
292 0,
293 BitmapFormat(bmi->bmiHeader.biBitCount,
294 bmi->bmiHeader.biCompression),
295 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
296 cjSizeImage,
297 (PVOID)Bits,
298 0);
299 if (!SourceBitmap)
300 {
301 DPRINT1("Error: Could not create a bitmap.\n");
302 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
303 return 0;
304 }
305
306 psurfDst = SURFACE_ShareLockSurface(hBitmap);
307 psurfSrc = SURFACE_ShareLockSurface(SourceBitmap);
308
309 if(!(psurfSrc && psurfDst))
310 {
311 DPRINT1("Error: Could not lock surfaces\n");
312 goto cleanup;
313 }
314
315 /* Create a palette for the DIB */
316 ppalDIB = CreateDIBPalette(bmi, DC, ColorUse);
317 if (!ppalDIB)
318 {
319 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
320 goto cleanup;
321 }
322
323 /* Initialize EXLATEOBJ */
324 EXLATEOBJ_vInitialize(&exlo,
325 ppalDIB,
326 psurfDst->ppal,
327 RGB(0xff, 0xff, 0xff),
328 RGB(0xff, 0xff, 0xff), //DC->pdcattr->crBackgroundClr,
329 0); // DC->pdcattr->crForegroundClr);
330
331 rcDst.top = StartScan;
332 rcDst.left = 0;
333 rcDst.bottom = rcDst.top + ScanLines;
334 rcDst.right = psurfDst->SurfObj.sizlBitmap.cx;
335 ptSrc.x = 0;
336 ptSrc.y = 0;
337
338 result = IntEngCopyBits(&psurfDst->SurfObj,
339 &psurfSrc->SurfObj,
340 NULL,
341 &exlo.xlo,
342 &rcDst,
343 &ptSrc);
344 if(result)
345 result = ScanLines;
346
347 EXLATEOBJ_vCleanup(&exlo);
348
349 cleanup:
350 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
351 if(psurfSrc) SURFACE_ShareUnlockSurface(psurfSrc);
352 if(psurfDst) SURFACE_ShareUnlockSurface(psurfDst);
353 GreDeleteObject(SourceBitmap);
354
355 return result;
356 }
357
358 static
359 HBITMAP
IntGdiCreateMaskFromRLE(DWORD Width,DWORD Height,ULONG Compression,const BYTE * Bits,DWORD BitsSize)360 IntGdiCreateMaskFromRLE(
361 DWORD Width,
362 DWORD Height,
363 ULONG Compression,
364 const BYTE* Bits,
365 DWORD BitsSize)
366 {
367 HBITMAP Mask;
368 DWORD x, y;
369 SURFOBJ* SurfObj;
370 UINT i = 0;
371 BYTE Data, NumPixels, ToSkip;
372
373 ASSERT((Compression == BI_RLE8) || (Compression == BI_RLE4));
374
375 /* Create the bitmap */
376 Mask = GreCreateBitmapEx(Width, Height, 0, BMF_1BPP, 0, 0, NULL, 0);
377 if (!Mask)
378 return NULL;
379
380 SurfObj = EngLockSurface((HSURF)Mask);
381 if (!SurfObj)
382 {
383 GreDeleteObject(Mask);
384 return NULL;
385 }
386 ASSERT(SurfObj->pvBits != NULL);
387
388 x = y = 0;
389
390 while (i < BitsSize)
391 {
392 NumPixels = Bits[i];
393 Data = Bits[i + 1];
394 i += 2;
395
396 if (NumPixels != 0)
397 {
398 if ((x + NumPixels) > Width)
399 NumPixels = Width - x;
400
401 if (NumPixels == 0)
402 continue;
403
404 DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1);
405 x += NumPixels;
406 continue;
407 }
408
409 if (Data < 3)
410 {
411 switch (Data)
412 {
413 case 0:
414 /* End of line */
415 y++;
416 if (y == Height)
417 goto done;
418 x = 0;
419 break;
420 case 1:
421 /* End of file */
422 goto done;
423 case 2:
424 /* Jump */
425 if (i >= (BitsSize - 1))
426 goto done;
427 x += Bits[i];
428 if (x > Width)
429 x = Width;
430 y += Bits[i + 1];
431 if (y >= Height)
432 goto done;
433 i += 2;
434 break;
435 }
436 /* Done for this run */
437 continue;
438 }
439
440 /* Embedded data into the RLE */
441 NumPixels = Data;
442 if (Compression == BI_RLE8)
443 ToSkip = NumPixels;
444 else
445 ToSkip = (NumPixels / 2) + (NumPixels & 1);
446
447 if ((i + ToSkip) > BitsSize)
448 goto done;
449 ToSkip = (ToSkip + 1) & ~1;
450
451 if ((x + NumPixels) > Width)
452 NumPixels = Width - x;
453
454 if (NumPixels != 0)
455 {
456 DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1);
457 x += NumPixels;
458 }
459 i += ToSkip;
460 }
461
462 done:
463 EngUnlockSurface(SurfObj);
464 return Mask;
465 }
466
467 W32KAPI
468 INT
469 APIENTRY
NtGdiSetDIBitsToDeviceInternal(IN HDC hDC,IN INT XDest,IN INT YDest,IN DWORD Width,IN DWORD Height,IN INT XSrc,IN INT YSrc,IN DWORD StartScan,IN DWORD ScanLines,IN LPBYTE Bits,IN LPBITMAPINFO bmi,IN DWORD ColorUse,IN UINT cjMaxBits,IN UINT cjMaxInfo,IN BOOL bTransformCoordinates,IN OPTIONAL HANDLE hcmXform)470 NtGdiSetDIBitsToDeviceInternal(
471 IN HDC hDC,
472 IN INT XDest,
473 IN INT YDest,
474 IN DWORD Width,
475 IN DWORD Height,
476 IN INT XSrc,
477 IN INT YSrc,
478 IN DWORD StartScan,
479 IN DWORD ScanLines,
480 IN LPBYTE Bits,
481 IN LPBITMAPINFO bmi,
482 IN DWORD ColorUse,
483 IN UINT cjMaxBits,
484 IN UINT cjMaxInfo,
485 IN BOOL bTransformCoordinates,
486 IN OPTIONAL HANDLE hcmXform)
487 {
488 INT ret;
489 PDC pDC = NULL;
490 HBITMAP hSourceBitmap = NULL, hMaskBitmap = NULL;
491 SURFOBJ *pDestSurf, *pSourceSurf = NULL, *pMaskSurf = NULL;
492 SURFACE *pSurf;
493 RECTL rcDest;
494 POINTL ptSource;
495 //INT DIBWidth;
496 SIZEL SourceSize;
497 EXLATEOBJ exlo;
498 PPALETTE ppalDIB = NULL;
499 LPBITMAPINFO pbmiSafe;
500 BOOL bResult;
501
502 if (!Bits) return 0;
503
504 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjMaxInfo, 'pmTG');
505 if (!pbmiSafe) return 0;
506
507 _SEH2_TRY
508 {
509 ProbeForRead(bmi, cjMaxInfo, 1);
510 ProbeForRead(Bits, cjMaxBits, 1);
511 RtlCopyMemory(pbmiSafe, bmi, cjMaxInfo);
512 bmi = pbmiSafe;
513 }
514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
515 {
516 ret = 0;
517 goto Exit;
518 }
519 _SEH2_END;
520
521 DPRINT("StartScan %d ScanLines %d Bits %p bmi %p ColorUse %d\n"
522 " Height %d Width %d SizeImage %d\n"
523 " biHeight %d biWidth %d biBitCount %d\n"
524 " XSrc %d YSrc %d xDext %d yDest %d\n",
525 StartScan, ScanLines, Bits, bmi, ColorUse,
526 Height, Width, bmi->bmiHeader.biSizeImage,
527 bmi->bmiHeader.biHeight, bmi->bmiHeader.biWidth,
528 bmi->bmiHeader.biBitCount,
529 XSrc, YSrc, XDest, YDest);
530
531 if (YDest >= 0)
532 {
533 ScanLines = min(abs(Height), ScanLines);
534 if (YSrc > 0)
535 ScanLines += YSrc;
536 }
537 else
538 {
539 ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan);
540 }
541
542 if (ScanLines == 0)
543 {
544 DPRINT1("ScanLines == 0\n");
545 ret = 0;
546 goto Exit;
547 }
548
549 pDC = DC_LockDc(hDC);
550 if (!pDC)
551 {
552 EngSetLastError(ERROR_INVALID_HANDLE);
553 ret = 0;
554 goto Exit;
555 }
556
557 if (pDC->dctype == DCTYPE_INFO)
558 {
559 ret = 0;
560 goto Exit;
561 }
562
563 rcDest.left = XDest;
564 rcDest.top = YDest;
565 if (bTransformCoordinates)
566 {
567 IntLPtoDP(pDC, (LPPOINT)&rcDest, 2);
568 }
569 rcDest.left += pDC->ptlDCOrig.x;
570 rcDest.top += pDC->ptlDCOrig.y;
571 rcDest.right = rcDest.left + Width;
572 rcDest.bottom = rcDest.top + Height;
573 rcDest.top += StartScan;
574
575 if (pDC->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
576 {
577 IntUpdateBoundsRect(pDC, &rcDest);
578 }
579
580 ptSource.x = XSrc;
581 ptSource.y = YSrc;
582
583 SourceSize.cx = bmi->bmiHeader.biWidth;
584 SourceSize.cy = ScanLines;
585 if (YDest >= 0 && YSrc > 0)
586 {
587 ScanLines += YSrc;
588 }
589
590 //DIBWidth = WIDTH_BYTES_ALIGN32(SourceSize.cx, bmi->bmiHeader.biBitCount);
591
592 hSourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth,
593 ScanLines,
594 0,
595 BitmapFormat(bmi->bmiHeader.biBitCount,
596 bmi->bmiHeader.biCompression),
597 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
598 bmi->bmiHeader.biSizeImage,
599 Bits,
600 0);
601
602 if (!hSourceBitmap)
603 {
604 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
605 ret = 0;
606 goto Exit;
607 }
608
609 pSourceSurf = EngLockSurface((HSURF)hSourceBitmap);
610 if (!pSourceSurf)
611 {
612 ret = 0;
613 goto Exit;
614 }
615
616 /* HACK: If this is a RLE bitmap, only the relevant pixels must be set. */
617 if ((bmi->bmiHeader.biCompression == BI_RLE8) || (bmi->bmiHeader.biCompression == BI_RLE4))
618 {
619 hMaskBitmap = IntGdiCreateMaskFromRLE(bmi->bmiHeader.biWidth,
620 ScanLines,
621 bmi->bmiHeader.biCompression,
622 Bits,
623 cjMaxBits);
624 if (!hMaskBitmap)
625 {
626 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
627 ret = 0;
628 goto Exit;
629 }
630 pMaskSurf = EngLockSurface((HSURF)hMaskBitmap);
631 if (!pMaskSurf)
632 {
633 ret = 0;
634 goto Exit;
635 }
636 }
637
638 /* Create a palette for the DIB */
639 ppalDIB = CreateDIBPalette(bmi, pDC, ColorUse);
640 if (!ppalDIB)
641 {
642 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
643 ret = 0;
644 goto Exit;
645 }
646
647 /* This is actually a blit */
648 DC_vPrepareDCsForBlit(pDC, &rcDest, NULL, NULL);
649 pSurf = pDC->dclevel.pSurface;
650 if (!pSurf)
651 {
652 DC_vFinishBlit(pDC, NULL);
653 ret = ScanLines;
654 goto Exit;
655 }
656
657 ASSERT(pSurf->ppal);
658
659 /* Initialize EXLATEOBJ */
660 EXLATEOBJ_vInitialize(&exlo,
661 ppalDIB,
662 pSurf->ppal,
663 RGB(0xff, 0xff, 0xff),
664 pDC->pdcattr->crBackgroundClr,
665 pDC->pdcattr->crForegroundClr);
666
667 pDestSurf = &pSurf->SurfObj;
668
669 /* Copy the bits */
670 DPRINT("BitsToDev with rcDest=(%d|%d) (%d|%d), ptSource=(%d|%d) w=%d h=%d\n",
671 rcDest.left, rcDest.top, rcDest.right, rcDest.bottom,
672 ptSource.x, ptSource.y, SourceSize.cx, SourceSize.cy);
673
674 /* This fixes the large Google text on Google.com from being upside down */
675 if (rcDest.top > rcDest.bottom)
676 {
677 RECTL_vMakeWellOrdered(&rcDest);
678 ptSource.y -= SourceSize.cy;
679 }
680
681 bResult = IntEngBitBlt(pDestSurf,
682 pSourceSurf,
683 pMaskSurf,
684 (CLIPOBJ *)&pDC->co,
685 &exlo.xlo,
686 &rcDest,
687 &ptSource,
688 pMaskSurf ? &ptSource : NULL,
689 NULL,
690 NULL,
691 pMaskSurf ? ROP4_MASK : ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
692
693 /* Cleanup EXLATEOBJ */
694 EXLATEOBJ_vCleanup(&exlo);
695
696 /* We're done */
697 DC_vFinishBlit(pDC, NULL);
698
699 ret = bResult ? ScanLines : 0;
700
701 Exit:
702
703 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
704 if (pSourceSurf) EngUnlockSurface(pSourceSurf);
705 if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap);
706 if (pMaskSurf) EngUnlockSurface(pMaskSurf);
707 if (hMaskBitmap) EngDeleteSurface((HSURF)hMaskBitmap);
708 if (pDC) DC_UnlockDc(pDC);
709 ExFreePoolWithTag(pbmiSafe, 'pmTG');
710
711 return ret;
712 }
713
714 /* Converts a device-dependent bitmap to a DIB */
715 INT
716 APIENTRY
GreGetDIBitsInternal(HDC hDC,HBITMAP hBitmap,UINT StartScan,UINT ScanLines,LPBYTE Bits,LPBITMAPINFO Info,UINT Usage,UINT MaxBits,UINT MaxInfo)717 GreGetDIBitsInternal(
718 HDC hDC,
719 HBITMAP hBitmap,
720 UINT StartScan,
721 UINT ScanLines,
722 LPBYTE Bits,
723 LPBITMAPINFO Info,
724 UINT Usage,
725 UINT MaxBits,
726 UINT MaxInfo)
727 {
728 BITMAPCOREINFO* pbmci = NULL;
729 PSURFACE psurf = NULL;
730 PDC pDC;
731 LONG width, height;
732 WORD planes, bpp;
733 DWORD compr, size ;
734 USHORT i;
735 int bitmap_type;
736 RGBQUAD* rgbQuads;
737 VOID* colorPtr;
738
739 DPRINT("Entered GreGetDIBitsInternal()\n");
740
741 if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap)
742 return 0;
743
744 pDC = DC_LockDc(hDC);
745 if (pDC == NULL || pDC->dctype == DCTYPE_INFO)
746 {
747 ScanLines = 0;
748 goto done;
749 }
750
751 /* Get a pointer to the source bitmap object */
752 psurf = SURFACE_ShareLockSurface(hBitmap);
753 if (psurf == NULL)
754 {
755 ScanLines = 0;
756 goto done;
757 }
758
759 colorPtr = (LPBYTE)Info + Info->bmiHeader.biSize;
760 rgbQuads = colorPtr;
761
762 bitmap_type = DIB_GetBitmapInfo(&Info->bmiHeader,
763 &width,
764 &height,
765 &planes,
766 &bpp,
767 &compr,
768 &size);
769 if(bitmap_type == -1)
770 {
771 DPRINT1("Wrong bitmap format\n");
772 EngSetLastError(ERROR_INVALID_PARAMETER);
773 ScanLines = 0;
774 goto done;
775 }
776 else if(bitmap_type == 0)
777 {
778 /* We need a BITMAPINFO to create a DIB, but we have to fill
779 * the BITMAPCOREINFO we're provided */
780 pbmci = (BITMAPCOREINFO*)Info;
781 /* fill in the the bit count, so we can calculate the right ColorsSize during the conversion */
782 pbmci->bmciHeader.bcBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
783 Info = DIB_ConvertBitmapInfo((BITMAPINFO*)pbmci, Usage);
784 if(Info == NULL)
785 {
786 DPRINT1("Error, could not convert the BITMAPCOREINFO!\n");
787 ScanLines = 0;
788 goto done;
789 }
790 rgbQuads = Info->bmiColors;
791 }
792
793 /* Validate input:
794 - negative width is always an invalid value
795 - non-null Bits and zero bpp is an invalid combination
796 - only check the rest of the input params if either bpp is non-zero or Bits are set */
797 if (width < 0 || (bpp == 0 && Bits))
798 {
799 ScanLines = 0;
800 goto done;
801 }
802
803 if (Bits || bpp)
804 {
805 if ((height == 0 || width == 0) || (compr && compr != BI_BITFIELDS && compr != BI_RGB))
806 {
807 ScanLines = 0;
808 goto done;
809 }
810 }
811
812 Info->bmiHeader.biClrUsed = 0;
813 Info->bmiHeader.biClrImportant = 0;
814
815 /* Fill in the structure */
816 switch(bpp)
817 {
818 case 0: /* Only info */
819 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx;
820 Info->bmiHeader.biHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ?
821 -psurf->SurfObj.sizlBitmap.cy :
822 psurf->SurfObj.sizlBitmap.cy;
823 Info->bmiHeader.biPlanes = 1;
824 Info->bmiHeader.biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
825 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( Info->bmiHeader.biWidth,
826 Info->bmiHeader.biHeight,
827 Info->bmiHeader.biBitCount);
828 Info->bmiHeader.biCompression = (Info->bmiHeader.biBitCount == 16 || Info->bmiHeader.biBitCount == 32) ?
829 BI_BITFIELDS : BI_RGB;
830 Info->bmiHeader.biXPelsPerMeter = 0;
831 Info->bmiHeader.biYPelsPerMeter = 0;
832
833 if (Info->bmiHeader.biBitCount <= 8 && Info->bmiHeader.biClrUsed == 0)
834 Info->bmiHeader.biClrUsed = 1 << Info->bmiHeader.biBitCount;
835
836 ScanLines = 1;
837 goto done;
838
839 case 1:
840 case 4:
841 case 8:
842 Info->bmiHeader.biClrUsed = 1 << bpp;
843
844 /* If the bitmap is a DIB section and has the same format as what
845 * is requested, go ahead! */
846 if((psurf->hSecure) &&
847 (BitsPerFormat(psurf->SurfObj.iBitmapFormat) == bpp))
848 {
849 if(Usage == DIB_RGB_COLORS)
850 {
851 ULONG colors = min(psurf->ppal->NumColors, 256);
852 if(colors != 256) Info->bmiHeader.biClrUsed = colors;
853 for(i = 0; i < colors; i++)
854 {
855 rgbQuads[i].rgbRed = psurf->ppal->IndexedColors[i].peRed;
856 rgbQuads[i].rgbGreen = psurf->ppal->IndexedColors[i].peGreen;
857 rgbQuads[i].rgbBlue = psurf->ppal->IndexedColors[i].peBlue;
858 rgbQuads[i].rgbReserved = 0;
859 }
860 }
861 else
862 {
863 for(i = 0; i < 256; i++)
864 ((WORD*)rgbQuads)[i] = i;
865 }
866 }
867 else
868 {
869 if(Usage == DIB_PAL_COLORS)
870 {
871 for(i = 0; i < 256; i++)
872 {
873 ((WORD*)rgbQuads)[i] = i;
874 }
875 }
876 else if(bpp > 1 && bpp == BitsPerFormat(psurf->SurfObj.iBitmapFormat))
877 {
878 /* For color DDBs in native depth (mono DDBs always have
879 a black/white palette):
880 Generate the color map from the selected palette */
881 PPALETTE pDcPal = PALETTE_ShareLockPalette(pDC->dclevel.hpal);
882 if(!pDcPal)
883 {
884 ScanLines = 0 ;
885 goto done ;
886 }
887 for (i = 0; i < pDcPal->NumColors; i++)
888 {
889 rgbQuads[i].rgbRed = pDcPal->IndexedColors[i].peRed;
890 rgbQuads[i].rgbGreen = pDcPal->IndexedColors[i].peGreen;
891 rgbQuads[i].rgbBlue = pDcPal->IndexedColors[i].peBlue;
892 rgbQuads[i].rgbReserved = 0;
893 }
894 PALETTE_ShareUnlockPalette(pDcPal);
895 }
896 else
897 {
898 switch (bpp)
899 {
900 case 1:
901 rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0;
902 rgbQuads[0].rgbReserved = 0;
903 rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff;
904 rgbQuads[1].rgbReserved = 0;
905 break;
906
907 case 4:
908 /* The EGA palette is the first and last 8 colours of the default palette
909 with the innermost pair swapped */
910 RtlCopyMemory(rgbQuads, DefLogPaletteQuads, 7 * sizeof(RGBQUAD));
911 RtlCopyMemory(rgbQuads + 7, DefLogPaletteQuads + 12, 1 * sizeof(RGBQUAD));
912 RtlCopyMemory(rgbQuads + 8, DefLogPaletteQuads + 7, 1 * sizeof(RGBQUAD));
913 RtlCopyMemory(rgbQuads + 9, DefLogPaletteQuads + 13, 7 * sizeof(RGBQUAD));
914 break;
915
916 case 8:
917 {
918 INT i;
919
920 memcpy(rgbQuads, DefLogPaletteQuads, 10 * sizeof(RGBQUAD));
921 memcpy(rgbQuads + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD));
922
923 for (i = 10; i < 246; i++)
924 {
925 rgbQuads[i].rgbRed = (i & 0x07) << 5;
926 rgbQuads[i].rgbGreen = (i & 0x38) << 2;
927 rgbQuads[i].rgbBlue = i & 0xc0;
928 rgbQuads[i].rgbReserved = 0;
929 }
930 }
931 }
932 }
933 }
934 break;
935
936 case 15:
937 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
938 {
939 ((PDWORD)Info->bmiColors)[0] = 0x7c00;
940 ((PDWORD)Info->bmiColors)[1] = 0x03e0;
941 ((PDWORD)Info->bmiColors)[2] = 0x001f;
942 }
943 break;
944
945 case 16:
946 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
947 {
948 if (psurf->hSecure)
949 {
950 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask;
951 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask;
952 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask;
953 }
954 else
955 {
956 ((PDWORD)Info->bmiColors)[0] = 0xf800;
957 ((PDWORD)Info->bmiColors)[1] = 0x07e0;
958 ((PDWORD)Info->bmiColors)[2] = 0x001f;
959 }
960 }
961 break;
962
963 case 24:
964 case 32:
965 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
966 {
967 if (psurf->hSecure)
968 {
969 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask;
970 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask;
971 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask;
972 }
973 else
974 {
975 ((PDWORD)Info->bmiColors)[0] = 0xff0000;
976 ((PDWORD)Info->bmiColors)[1] = 0x00ff00;
977 ((PDWORD)Info->bmiColors)[2] = 0x0000ff;
978 }
979 }
980 break;
981
982 default:
983 ScanLines = 0;
984 goto done;
985 }
986
987 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(width, height, bpp);
988 Info->bmiHeader.biPlanes = 1;
989
990 if(Bits && ScanLines)
991 {
992 /* Create a DIBSECTION, blt it, profit */
993 PVOID pDIBits ;
994 HBITMAP hBmpDest;
995 PSURFACE psurfDest;
996 EXLATEOBJ exlo;
997 RECT rcDest;
998 POINTL srcPoint;
999 BOOL ret ;
1000 int newLines = -1;
1001
1002 if (StartScan >= abs(Info->bmiHeader.biHeight))
1003 {
1004 ScanLines = 1;
1005 goto done;
1006 }
1007 else
1008 {
1009 ScanLines = min(ScanLines, abs(Info->bmiHeader.biHeight) - StartScan);
1010 }
1011
1012 if (abs(Info->bmiHeader.biHeight) < psurf->SurfObj.sizlBitmap.cy)
1013 {
1014 StartScan += psurf->SurfObj.sizlBitmap.cy - abs(Info->bmiHeader.biHeight);
1015 }
1016 /* Fixup values */
1017 Info->bmiHeader.biHeight = (height < 0) ?
1018 -(LONG)ScanLines : ScanLines;
1019 /* Create the DIB */
1020 hBmpDest = DIB_CreateDIBSection(pDC, Info, Usage, &pDIBits, NULL, 0, 0);
1021 /* Restore them */
1022 Info->bmiHeader.biHeight = height;
1023
1024 if(!hBmpDest)
1025 {
1026 DPRINT1("Unable to create a DIB Section!\n");
1027 EngSetLastError(ERROR_INVALID_PARAMETER);
1028 ScanLines = 0;
1029 goto done ;
1030 }
1031
1032 psurfDest = SURFACE_ShareLockSurface(hBmpDest);
1033
1034 RECTL_vSetRect(&rcDest, 0, 0, Info->bmiHeader.biWidth, ScanLines);
1035 Info->bmiHeader.biWidth = width;
1036 srcPoint.x = 0;
1037
1038 if (abs(Info->bmiHeader.biHeight) <= psurf->SurfObj.sizlBitmap.cy)
1039 {
1040 srcPoint.y = psurf->SurfObj.sizlBitmap.cy - StartScan - ScanLines;
1041 }
1042 else
1043 {
1044 /* Determine the actual number of lines copied from the */
1045 /* original bitmap. It might be different from ScanLines. */
1046 newLines = abs(Info->bmiHeader.biHeight) - psurf->SurfObj.sizlBitmap.cy;
1047 newLines = min((int)(StartScan + ScanLines - newLines), psurf->SurfObj.sizlBitmap.cy);
1048 if (newLines > 0)
1049 {
1050 srcPoint.y = psurf->SurfObj.sizlBitmap.cy - newLines;
1051 if (StartScan > psurf->SurfObj.sizlBitmap.cy)
1052 {
1053 newLines -= (StartScan - psurf->SurfObj.sizlBitmap.cy);
1054 }
1055 }
1056 else
1057 {
1058 newLines = 0;
1059 srcPoint.y = psurf->SurfObj.sizlBitmap.cy;
1060 }
1061 }
1062
1063 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xffffff, 0xffffff, 0);
1064
1065 ret = IntEngCopyBits(&psurfDest->SurfObj,
1066 &psurf->SurfObj,
1067 NULL,
1068 &exlo.xlo,
1069 &rcDest,
1070 &srcPoint);
1071
1072 SURFACE_ShareUnlockSurface(psurfDest);
1073
1074 if(!ret)
1075 ScanLines = 0;
1076 else
1077 {
1078 RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp));
1079 }
1080 /* Update if line count has changed */
1081 if (newLines != -1)
1082 {
1083 ScanLines = (UINT)newLines;
1084 }
1085 GreDeleteObject(hBmpDest);
1086 EXLATEOBJ_vCleanup(&exlo);
1087 }
1088 else
1089 {
1090 /* Signals success and not the actual number of scan lines*/
1091 ScanLines = 1;
1092 }
1093
1094 done:
1095
1096 if (pbmci)
1097 DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci, Usage);
1098
1099 if (psurf)
1100 SURFACE_ShareUnlockSurface(psurf);
1101
1102 if (pDC)
1103 DC_UnlockDc(pDC);
1104
1105 return ScanLines;
1106 }
1107
1108 _Success_(return!=0)
1109 __kernel_entry
1110 INT
1111 APIENTRY
NtGdiGetDIBitsInternal(_In_ HDC hdc,_In_ HBITMAP hbm,_In_ UINT iStartScan,_In_ UINT cScans,_Out_writes_bytes_opt_ (cjMaxBits)LPBYTE pjBits,_Inout_ LPBITMAPINFO pbmi,_In_ UINT iUsage,_In_ UINT cjMaxBits,_In_ UINT cjMaxInfo)1112 NtGdiGetDIBitsInternal(
1113 _In_ HDC hdc,
1114 _In_ HBITMAP hbm,
1115 _In_ UINT iStartScan,
1116 _In_ UINT cScans,
1117 _Out_writes_bytes_opt_(cjMaxBits) LPBYTE pjBits,
1118 _Inout_ LPBITMAPINFO pbmi,
1119 _In_ UINT iUsage,
1120 _In_ UINT cjMaxBits,
1121 _In_ UINT cjMaxInfo)
1122 {
1123 PBITMAPINFO pbmiSafe;
1124 HANDLE hSecure = NULL;
1125 INT iResult = 0;
1126 UINT cjAlloc;
1127
1128 /* Check for bad iUsage */
1129 if (iUsage > 2) return 0;
1130
1131 /* Check if the size of the bitmap info is large enough */
1132 if (cjMaxInfo < sizeof(BITMAPCOREHEADER))
1133 {
1134 return 0;
1135 }
1136
1137 /* Use maximum size */
1138 cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD));
1139
1140 // HACK: the underlying code sucks and doesn't care for the size, so we
1141 // give it the maximum ever needed
1142 cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD);
1143
1144 /* Allocate a buffer the bitmapinfo */
1145 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
1146 if (!pbmiSafe)
1147 {
1148 /* Fail */
1149 return 0;
1150 }
1151
1152 /* Use SEH */
1153 _SEH2_TRY
1154 {
1155 /* Probe and copy the BITMAPINFO */
1156 ProbeForRead(pbmi, cjMaxInfo, 1);
1157 RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo);
1158 }
1159 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1160 {
1161 goto cleanup;
1162 }
1163 _SEH2_END;
1164
1165 /* Check if the header size is large enough */
1166 if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
1167 (pbmiSafe->bmiHeader.biSize > cjMaxInfo))
1168 {
1169 goto cleanup;
1170 }
1171
1172 /* Check if the caller provided bitmap bits */
1173 if (pjBits)
1174 {
1175 /* Secure the user mode memory */
1176 hSecure = EngSecureMem(pjBits, cjMaxBits);
1177 if (!hSecure)
1178 {
1179 goto cleanup;
1180 }
1181 }
1182
1183 /* Now call the internal function */
1184 iResult = GreGetDIBitsInternal(hdc,
1185 hbm,
1186 iStartScan,
1187 cScans,
1188 pjBits,
1189 pbmiSafe,
1190 iUsage,
1191 cjMaxBits,
1192 cjMaxInfo);
1193
1194 /* Check for success */
1195 if (iResult)
1196 {
1197 /* Use SEH to copy back to user mode */
1198 _SEH2_TRY
1199 {
1200 /* Copy the data back */
1201 cjMaxInfo = min(cjMaxInfo, (UINT)DIB_BitmapInfoSize(pbmiSafe, (WORD)iUsage));
1202 ProbeForWrite(pbmi, cjMaxInfo, 1);
1203 RtlCopyMemory(pbmi, pbmiSafe, cjMaxInfo);
1204 }
1205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1206 {
1207 /* Ignore */
1208 (VOID)0;
1209 }
1210 _SEH2_END;
1211 }
1212
1213 cleanup:
1214 if (hSecure) EngUnsecureMem(hSecure);
1215 ExFreePoolWithTag(pbmiSafe, 'imBG');
1216
1217 return iResult;
1218 }
1219
1220 W32KAPI
1221 INT
1222 APIENTRY
NtGdiStretchDIBitsInternal(IN HDC hdc,IN INT xDst,IN INT yDst,IN INT cxDst,IN INT cyDst,IN INT xSrc,IN INT ySrc,IN INT cxSrc,IN INT cySrc,IN OPTIONAL LPBYTE pjInit,IN LPBITMAPINFO pbmi,IN DWORD dwUsage,IN DWORD dwRop,IN UINT cjMaxInfo,IN UINT cjMaxBits,IN HANDLE hcmXform)1223 NtGdiStretchDIBitsInternal(
1224 IN HDC hdc,
1225 IN INT xDst,
1226 IN INT yDst,
1227 IN INT cxDst,
1228 IN INT cyDst,
1229 IN INT xSrc,
1230 IN INT ySrc,
1231 IN INT cxSrc,
1232 IN INT cySrc,
1233 IN OPTIONAL LPBYTE pjInit,
1234 IN LPBITMAPINFO pbmi,
1235 IN DWORD dwUsage,
1236 IN DWORD dwRop, // MS ntgdi.h says dwRop4(?)
1237 IN UINT cjMaxInfo,
1238 IN UINT cjMaxBits,
1239 IN HANDLE hcmXform)
1240 {
1241 SIZEL sizel;
1242 RECTL rcSrc, rcDst;
1243 PDC pdc;
1244 HBITMAP hbmTmp = 0;
1245 PSURFACE psurfTmp = 0, psurfDst = 0;
1246 PPALETTE ppalDIB = 0;
1247 EXLATEOBJ exlo;
1248 PBYTE pvBits;
1249
1250 LPBITMAPINFO pbmiSafe;
1251 UINT cjAlloc;
1252 HBITMAP hBitmap, hOldBitmap = NULL;
1253 HDC hdcMem;
1254 HPALETTE hPal = NULL;
1255 ULONG BmpFormat = 0;
1256 INT LinesCopied = 0;
1257
1258 /* Check for bad iUsage */
1259 if (dwUsage > 2) return 0;
1260
1261 /* We must have LPBITMAPINFO */
1262 if (!pbmi)
1263 {
1264 DPRINT1("Error, Invalid Parameter.\n");
1265 EngSetLastError(ERROR_INVALID_PARAMETER);
1266 return 0;
1267 }
1268
1269 /* Check if the size of the bitmap info is large enough */
1270 if (cjMaxInfo < sizeof(BITMAPCOREHEADER))
1271 {
1272 return 0;
1273 }
1274
1275 /* Use maximum size */
1276 cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD));
1277
1278 // HACK: the underlying code sucks and doesn't care for the size, so we
1279 // give it the maximum ever needed
1280 cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD);
1281
1282 /* Allocate a buffer the bitmapinfo */
1283 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
1284 if (!pbmiSafe)
1285 {
1286 /* Fail */
1287 return 0;
1288 }
1289
1290 /* Use SEH */
1291 _SEH2_TRY
1292 {
1293 /* Probe and copy the BITMAPINFO */
1294 ProbeForRead(pbmi, cjMaxInfo, 1);
1295 RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo);
1296 }
1297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1298 {
1299 ExFreePoolWithTag(pbmiSafe, 'imBG');
1300 return 0;
1301 }
1302 _SEH2_END;
1303
1304 /* Check if the header size is large enough */
1305 if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
1306 (pbmiSafe->bmiHeader.biSize > cjMaxInfo))
1307 {
1308 ExFreePoolWithTag(pbmiSafe, 'imBG');
1309 return 0;
1310 }
1311
1312 if (!(pdc = DC_LockDc(hdc)))
1313 {
1314 EngSetLastError(ERROR_INVALID_HANDLE);
1315 return 0;
1316 }
1317
1318 /* Check for info / mem DC without surface */
1319 if (!pdc->dclevel.pSurface)
1320 {
1321 DC_UnlockDc(pdc);
1322 // CHECKME
1323 return TRUE;
1324 }
1325
1326 /* Transform dest size */
1327 sizel.cx = cxDst;
1328 sizel.cy = cyDst;
1329 IntLPtoDP(pdc, (POINTL*)&sizel, 1);
1330 DC_UnlockDc(pdc);
1331
1332 if (pjInit && (cjMaxBits > 0))
1333 {
1334 pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
1335 if (!pvBits)
1336 {
1337 return 0;
1338 }
1339
1340 _SEH2_TRY
1341 {
1342 ProbeForRead(pjInit, cjMaxBits, 1);
1343 RtlCopyMemory(pvBits, pjInit, cjMaxBits);
1344 }
1345 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1346 {
1347 ExFreePoolWithTag(pvBits, TAG_DIB);
1348 return 0;
1349 }
1350 _SEH2_END;
1351 }
1352 else
1353 {
1354 pvBits = NULL;
1355 }
1356
1357 /* Here we select between the dwRop with SRCCOPY or not. */
1358 if (dwRop == SRCCOPY)
1359 {
1360 hdcMem = NtGdiCreateCompatibleDC(hdc);
1361 if (hdcMem == NULL)
1362 {
1363 DPRINT1("NtGdiCreateCompatibleDC failed to create hdc.\n");
1364 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
1365 return 0;
1366 }
1367
1368 hBitmap = NtGdiCreateCompatibleBitmap(hdc,
1369 abs(pbmiSafe->bmiHeader.biWidth),
1370 abs(pbmiSafe->bmiHeader.biHeight));
1371 if (hBitmap == NULL)
1372 {
1373 DPRINT1("NtGdiCreateCompatibleBitmap failed to create bitmap.\n");
1374 DPRINT1("hdc : 0x%08x \n", hdc);
1375 DPRINT1("width : 0x%08x \n", pbmiSafe->bmiHeader.biWidth);
1376 DPRINT1("height : 0x%08x \n", pbmiSafe->bmiHeader.biHeight);
1377 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
1378 return 0;
1379 }
1380
1381 /* Select the bitmap into hdcMem, and save a handle to the old bitmap */
1382 hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap);
1383
1384 if (dwUsage == DIB_PAL_COLORS)
1385 {
1386 hPal = NtGdiGetDCObject(hdc, GDI_OBJECT_TYPE_PALETTE);
1387 hPal = GdiSelectPalette(hdcMem, hPal, FALSE);
1388 }
1389
1390 pdc = DC_LockDc(hdcMem);
1391 if (pdc != NULL)
1392 {
1393 IntSetDIBits(pdc, hBitmap, 0, abs(pbmiSafe->bmiHeader.biHeight), pvBits,
1394 cjMaxBits, pbmiSafe, dwUsage);
1395 DC_UnlockDc(pdc);
1396 }
1397
1398 /* Origin for DIBitmap may be bottom left (positive biHeight) or top
1399 left (negative biHeight) */
1400 if (cxSrc == cxDst && cySrc == cyDst)
1401 {
1402 NtGdiBitBlt(hdc, xDst, yDst, cxDst, cyDst,
1403 hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc - ySrc,
1404 dwRop, 0, 0);
1405 }
1406 else
1407 {
1408 NtGdiStretchBlt(hdc, xDst, yDst, cxDst, cyDst,
1409 hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc - ySrc,
1410 cxSrc, cySrc, dwRop, 0);
1411 }
1412
1413 /* cleanup */
1414 if (hPal)
1415 GdiSelectPalette(hdcMem, hPal, FALSE);
1416
1417 if (hOldBitmap)
1418 NtGdiSelectBitmap(hdcMem, hOldBitmap);
1419
1420 NtGdiDeleteObjectApp(hdcMem);
1421 GreDeleteObject(hBitmap);
1422
1423 } /* End of dwRop == SRCCOPY */
1424 else
1425 { /* Start of dwRop != SRCCOPY */
1426 /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */
1427 if (!(pdc = DC_LockDc(hdc)))
1428 {
1429 DPRINT1("Could not lock dc\n");
1430 EngSetLastError(ERROR_INVALID_HANDLE);
1431 goto cleanup;
1432 }
1433
1434 /* Calculate source and destination rect */
1435 rcSrc.left = xSrc;
1436 rcSrc.top = ySrc;
1437 rcSrc.right = xSrc + abs(cxSrc);
1438 rcSrc.bottom = ySrc + abs(cySrc);
1439 rcDst.left = xDst;
1440 rcDst.top = yDst;
1441 rcDst.right = rcDst.left + cxDst;
1442 rcDst.bottom = rcDst.top + cyDst;
1443 IntLPtoDP(pdc, (POINTL*)&rcDst, 2);
1444 RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1445
1446 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1447 {
1448 IntUpdateBoundsRect(pdc, &rcDst);
1449 }
1450
1451 BmpFormat = BitmapFormat(pbmiSafe->bmiHeader.biBitCount,
1452 pbmiSafe->bmiHeader.biCompression);
1453
1454 hbmTmp = GreCreateBitmapEx(pbmiSafe->bmiHeader.biWidth,
1455 abs(pbmiSafe->bmiHeader.biHeight),
1456 0,
1457 BmpFormat,
1458 pbmiSafe->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
1459 cjMaxBits,
1460 pvBits,
1461 0);
1462
1463 if (!hbmTmp)
1464 {
1465 goto cleanup;
1466 }
1467
1468 psurfTmp = SURFACE_ShareLockSurface(hbmTmp);
1469 if (!psurfTmp)
1470 {
1471 goto cleanup;
1472 }
1473
1474 /* Create a palette for the DIB */
1475 ppalDIB = CreateDIBPalette(pbmiSafe, pdc, dwUsage);
1476 if (!ppalDIB)
1477 {
1478 goto cleanup;
1479 }
1480
1481 /* Prepare DC for blit */
1482 DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL);
1483
1484 psurfDst = pdc->dclevel.pSurface;
1485
1486 /* Initialize XLATEOBJ */
1487 EXLATEOBJ_vInitialize(&exlo,
1488 ppalDIB,
1489 psurfDst->ppal,
1490 RGB(0xff, 0xff, 0xff),
1491 pdc->pdcattr->crBackgroundClr,
1492 pdc->pdcattr->crForegroundClr);
1493
1494 /* Perform the stretch operation */
1495 IntEngStretchBlt(&psurfDst->SurfObj,
1496 &psurfTmp->SurfObj,
1497 NULL,
1498 (CLIPOBJ *)&pdc->co,
1499 &exlo.xlo,
1500 &pdc->dclevel.ca,
1501 &rcDst,
1502 &rcSrc,
1503 NULL,
1504 &pdc->eboFill.BrushObject,
1505 NULL,
1506 WIN32_ROP3_TO_ENG_ROP4(dwRop));
1507
1508 /* Cleanup */
1509 DC_vFinishBlit(pdc, NULL);
1510 EXLATEOBJ_vCleanup(&exlo);
1511
1512 cleanup:
1513 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
1514 if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp);
1515 if (hbmTmp) GreDeleteObject(hbmTmp);
1516 if (pdc) DC_UnlockDc(pdc);
1517 }
1518
1519 if (pvBits) ExFreePoolWithTag(pvBits, TAG_DIB);
1520
1521 /* This is not what MSDN says is returned from this function, but it
1522 * follows Wine's dlls/gdi32/dib.c function nulldrv_StretchDIBits
1523 * and it fixes over 100 gdi32:dib regression tests. */
1524 if (dwRop == SRCCOPY)
1525 {
1526 LinesCopied = abs(pbmiSafe->bmiHeader.biHeight);
1527 }
1528 else
1529 {
1530 LinesCopied = pbmiSafe->bmiHeader.biHeight;
1531 }
1532
1533 ExFreePoolWithTag(pbmiSafe, 'imBG');
1534
1535 return LinesCopied;
1536 }
1537
1538 HBITMAP
1539 FASTCALL
IntCreateDIBitmap(PDC Dc,INT width,INT height,UINT planes,UINT bpp,ULONG compression,DWORD init,LPBYTE bits,ULONG cjMaxBits,PBITMAPINFO data,DWORD coloruse)1540 IntCreateDIBitmap(
1541 PDC Dc,
1542 INT width,
1543 INT height,
1544 UINT planes,
1545 UINT bpp,
1546 ULONG compression,
1547 DWORD init,
1548 LPBYTE bits,
1549 ULONG cjMaxBits,
1550 PBITMAPINFO data,
1551 DWORD coloruse)
1552 {
1553 HBITMAP handle;
1554 BOOL fColor;
1555 ULONG BmpFormat = 0;
1556
1557 if (planes && bpp)
1558 BmpFormat = BitmapFormat(planes * bpp, compression);
1559
1560 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
1561 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
1562
1563 if (BmpFormat != BMF_1BPP) fColor = TRUE;
1564 else if ((coloruse > DIB_RGB_COLORS) || ((init & CBM_INIT) == 0) || !data) fColor = FALSE;
1565 else
1566 {
1567 const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize);
1568 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1569
1570 // Check if the first color of the colormap is black
1571 if (col == RGB(0, 0, 0))
1572 {
1573 rgb++;
1574 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1575
1576 // If the second color is white, create a monochrome bitmap
1577 fColor = (col != RGB(0xff,0xff,0xff));
1578 }
1579 else fColor = TRUE;
1580 }
1581
1582 // Now create the bitmap
1583 if (fColor)
1584 {
1585 if (init & CBM_CREATDIB)
1586 {
1587 PSURFACE Surface;
1588 PPALETTE Palette;
1589
1590 /* Undocumented flag which creates a DDB of the format specified by the bitmap info. */
1591 handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp);
1592 if (!handle)
1593 {
1594 DPRINT1("IntCreateCompatibleBitmap() failed!\n");
1595 return NULL;
1596 }
1597
1598 /* The palette must also match the given data */
1599 Surface = SURFACE_ShareLockSurface(handle);
1600 ASSERT(Surface);
1601 Palette = CreateDIBPalette(data, Dc, coloruse);
1602 if (Palette == NULL)
1603 {
1604 SURFACE_ShareUnlockSurface(Surface);
1605 GreDeleteObject(handle);
1606 return NULL;
1607 }
1608
1609 SURFACE_vSetPalette(Surface, Palette);
1610
1611 PALETTE_ShareUnlockPalette(Palette);
1612 SURFACE_ShareUnlockSurface(Surface);
1613 }
1614 else
1615 {
1616 /* Create a regular compatible bitmap, in the same format as the device */
1617 handle = IntCreateCompatibleBitmap(Dc, width, height, 0, 0);
1618 }
1619 }
1620 else
1621 {
1622 handle = GreCreateBitmap(width,
1623 abs(height),
1624 1,
1625 1,
1626 NULL);
1627 }
1628
1629 if (height < 0)
1630 height = -height;
1631
1632 if ((NULL != handle) && (CBM_INIT & init))
1633 {
1634 IntSetDIBits(Dc, handle, 0, height, bits, cjMaxBits, data, coloruse);
1635 }
1636
1637 return handle;
1638 }
1639
1640 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
1641 // The DDB that is created will be whatever bit depth your reference DC is
1642 HBITMAP
1643 APIENTRY
NtGdiCreateDIBitmapInternal(IN HDC hDc,IN INT cx,IN INT cy,IN DWORD fInit,IN OPTIONAL LPBYTE pjInit,IN OPTIONAL LPBITMAPINFO pbmi,IN DWORD iUsage,IN UINT cjMaxInitInfo,IN UINT cjMaxBits,IN FLONG fl,IN HANDLE hcmXform)1644 NtGdiCreateDIBitmapInternal(
1645 IN HDC hDc,
1646 IN INT cx,
1647 IN INT cy,
1648 IN DWORD fInit,
1649 IN OPTIONAL LPBYTE pjInit,
1650 IN OPTIONAL LPBITMAPINFO pbmi,
1651 IN DWORD iUsage,
1652 IN UINT cjMaxInitInfo,
1653 IN UINT cjMaxBits,
1654 IN FLONG fl,
1655 IN HANDLE hcmXform)
1656 {
1657 NTSTATUS Status = STATUS_SUCCESS;
1658 PBYTE safeBits = NULL;
1659 HBITMAP hbmResult = NULL;
1660
1661 if (pjInit == NULL)
1662 {
1663 fInit &= ~CBM_INIT;
1664 }
1665
1666 if(pjInit && (fInit & CBM_INIT))
1667 {
1668 if (cjMaxBits == 0) return NULL;
1669 safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
1670 if(!safeBits)
1671 {
1672 DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits);
1673 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1674 return NULL;
1675 }
1676 }
1677
1678 _SEH2_TRY
1679 {
1680 if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1);
1681 if(pjInit && (fInit & CBM_INIT))
1682 {
1683 ProbeForRead(pjInit, cjMaxBits, 1);
1684 RtlCopyMemory(safeBits, pjInit, cjMaxBits);
1685 }
1686 }
1687 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1688 {
1689 Status = _SEH2_GetExceptionCode();
1690 }
1691 _SEH2_END;
1692
1693 if(!NT_SUCCESS(Status))
1694 {
1695 DPRINT1("Got an exception! pjInit = %p\n", pjInit);
1696 SetLastNtError(Status);
1697 goto cleanup;
1698 }
1699
1700 hbmResult = GreCreateDIBitmapInternal(hDc,
1701 cx,
1702 cy,
1703 fInit,
1704 safeBits,
1705 pbmi,
1706 iUsage,
1707 fl,
1708 cjMaxBits,
1709 hcmXform);
1710
1711 cleanup:
1712 if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB);
1713 return hbmResult;
1714 }
1715
1716 HBITMAP
1717 NTAPI
GreCreateDIBitmapInternal(IN HDC hDc,IN INT cx,IN INT cy,IN DWORD fInit,IN OPTIONAL LPBYTE pjInit,IN OPTIONAL PBITMAPINFO pbmi,IN DWORD iUsage,IN FLONG fl,IN UINT cjMaxBits,IN HANDLE hcmXform)1718 GreCreateDIBitmapInternal(
1719 IN HDC hDc,
1720 IN INT cx,
1721 IN INT cy,
1722 IN DWORD fInit,
1723 IN OPTIONAL LPBYTE pjInit,
1724 IN OPTIONAL PBITMAPINFO pbmi,
1725 IN DWORD iUsage,
1726 IN FLONG fl,
1727 IN UINT cjMaxBits,
1728 IN HANDLE hcmXform)
1729 {
1730 PDC Dc;
1731 HBITMAP Bmp;
1732 USHORT bpp, planes;
1733 DWORD compression;
1734 HDC hdcDest;
1735
1736 if (!hDc) /* 1bpp monochrome bitmap */
1737 {
1738 // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
1739 hdcDest = NtGdiCreateCompatibleDC(0);
1740 if(!hdcDest)
1741 {
1742 DPRINT1("NtGdiCreateCompatibleDC failed\n");
1743 return NULL;
1744 }
1745 }
1746 else
1747 {
1748 hdcDest = hDc;
1749 }
1750
1751 Dc = DC_LockDc(hdcDest);
1752 if (!Dc)
1753 {
1754 DPRINT1("Failed to lock hdcDest %p\n", hdcDest);
1755 EngSetLastError(ERROR_INVALID_HANDLE);
1756 return NULL;
1757 }
1758 /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap
1759 * if bpp != 1 and ignore the real value that was passed */
1760 if (pbmi)
1761 {
1762 if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1763 {
1764 BITMAPCOREHEADER* CoreHeader = (BITMAPCOREHEADER*)&pbmi->bmiHeader;
1765 bpp = CoreHeader->bcBitCount;
1766 planes = CoreHeader->bcPlanes ? CoreHeader->bcPlanes : 1;
1767 compression = BI_RGB;
1768 }
1769 else
1770 {
1771 bpp = pbmi->bmiHeader.biBitCount;
1772 planes = pbmi->bmiHeader.biPlanes ? pbmi->bmiHeader.biPlanes : 1;
1773 compression = pbmi->bmiHeader.biCompression;
1774 }
1775 }
1776 else
1777 {
1778 bpp = 0;
1779 planes = 0;
1780 compression = 0;
1781 }
1782 Bmp = IntCreateDIBitmap(Dc, cx, cy, planes, bpp, compression, fInit, pjInit, cjMaxBits, pbmi, iUsage);
1783 DC_UnlockDc(Dc);
1784
1785 if(!hDc)
1786 {
1787 NtGdiDeleteObjectApp(hdcDest);
1788 }
1789 return Bmp;
1790 }
1791
1792 HBITMAP
1793 NTAPI
GreCreateDIBitmapFromPackedDIB(_In_reads_ (cjPackedDIB)PVOID pvPackedDIB,_In_ UINT cjPackedDIB,_In_ ULONG uUsage)1794 GreCreateDIBitmapFromPackedDIB(
1795 _In_reads_(cjPackedDIB )PVOID pvPackedDIB,
1796 _In_ UINT cjPackedDIB,
1797 _In_ ULONG uUsage)
1798 {
1799 PBITMAPINFO pbmi;
1800 PBYTE pjBits;
1801 UINT cjInfo, cjBits;
1802 HBITMAP hbm;
1803
1804 /* We only support BITMAPINFOHEADER, make sure the size is ok */
1805 if (cjPackedDIB < sizeof(BITMAPINFOHEADER))
1806 {
1807 return NULL;
1808 }
1809
1810 /* The packed DIB starts with the BITMAPINFOHEADER */
1811 pbmi = pvPackedDIB;
1812
1813 if (cjPackedDIB < pbmi->bmiHeader.biSize)
1814 {
1815 return NULL;
1816 }
1817
1818 /* Calculate the info size and make sure the packed DIB is large enough */
1819 cjInfo = DIB_BitmapInfoSize(pbmi, uUsage);
1820 if (cjPackedDIB <= cjInfo)
1821 {
1822 return NULL;
1823 }
1824
1825 /* The bitmap bits start after the header */
1826 pjBits = (PBYTE)pvPackedDIB + cjInfo;
1827 cjBits = cjPackedDIB - cjInfo;
1828
1829 hbm = GreCreateDIBitmapInternal(NULL,
1830 pbmi->bmiHeader.biWidth,
1831 abs(pbmi->bmiHeader.biHeight),
1832 CBM_INIT | CBM_CREATDIB,
1833 pjBits,
1834 pbmi,
1835 uUsage,
1836 0,
1837 cjBits,
1838 NULL);
1839
1840 return hbm;
1841 }
1842
1843 HBITMAP
1844 APIENTRY
NtGdiCreateDIBSection(IN HDC hDC,IN OPTIONAL HANDLE hSection,IN DWORD dwOffset,IN BITMAPINFO * bmi,IN DWORD Usage,IN UINT cjHeader,IN FLONG fl,IN ULONG_PTR dwColorSpace,OUT PVOID * Bits)1845 NtGdiCreateDIBSection(
1846 IN HDC hDC,
1847 IN OPTIONAL HANDLE hSection,
1848 IN DWORD dwOffset,
1849 IN BITMAPINFO* bmi,
1850 IN DWORD Usage,
1851 IN UINT cjHeader,
1852 IN FLONG fl,
1853 IN ULONG_PTR dwColorSpace,
1854 OUT PVOID *Bits)
1855 {
1856 HBITMAP hbitmap = 0;
1857 DC *dc;
1858 BOOL bDesktopDC = FALSE;
1859 NTSTATUS Status = STATUS_SUCCESS;
1860
1861 if (!bmi) return hbitmap; // Make sure.
1862
1863 _SEH2_TRY
1864 {
1865 ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1);
1866 ProbeForRead(bmi, bmi->bmiHeader.biSize, 1);
1867 ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, (WORD)Usage), 1);
1868 }
1869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1870 {
1871 Status = _SEH2_GetExceptionCode();
1872 }
1873 _SEH2_END;
1874
1875 if(!NT_SUCCESS(Status))
1876 {
1877 SetLastNtError(Status);
1878 return NULL;
1879 }
1880
1881 // If the reference hdc is null, take the desktop dc
1882 if (hDC == 0)
1883 {
1884 hDC = NtGdiCreateCompatibleDC(0);
1885 bDesktopDC = TRUE;
1886 }
1887
1888 if ((dc = DC_LockDc(hDC)))
1889 {
1890 hbitmap = DIB_CreateDIBSection(dc,
1891 bmi,
1892 Usage,
1893 Bits,
1894 hSection,
1895 dwOffset,
1896 0);
1897 DC_UnlockDc(dc);
1898 }
1899 else
1900 {
1901 EngSetLastError(ERROR_INVALID_HANDLE);
1902 }
1903
1904 if (bDesktopDC)
1905 NtGdiDeleteObjectApp(hDC);
1906
1907 return hbitmap;
1908 }
1909
1910 HBITMAP
1911 APIENTRY
DIB_CreateDIBSection(PDC dc,CONST BITMAPINFO * bmi,UINT usage,LPVOID * bits,HANDLE section,DWORD offset,DWORD ovr_pitch)1912 DIB_CreateDIBSection(
1913 PDC dc,
1914 CONST BITMAPINFO *bmi,
1915 UINT usage,
1916 LPVOID *bits,
1917 HANDLE section,
1918 DWORD offset,
1919 DWORD ovr_pitch)
1920 {
1921 HBITMAP res = 0;
1922 SURFACE *bmp = NULL;
1923 void *mapBits = NULL;
1924 PPALETTE ppalDIB = NULL;
1925
1926 // Fill BITMAP32 structure with DIB data
1927 CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1928 INT effHeight;
1929 ULONG totalSize;
1930 BITMAP bm;
1931 //SIZEL Size;
1932 HANDLE hSecure;
1933
1934 DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n",
1935 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1936 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1937
1938 /* CreateDIBSection should fail for compressed formats */
1939 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
1940 {
1941 DPRINT1("no compressed format allowed\n");
1942 return (HBITMAP)NULL;
1943 }
1944
1945 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1946 bm.bmType = 0;
1947 bm.bmWidth = bi->biWidth;
1948 bm.bmHeight = effHeight;
1949 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount);
1950
1951 bm.bmPlanes = bi->biPlanes;
1952 bm.bmBitsPixel = bi->biBitCount;
1953 bm.bmBits = NULL;
1954
1955 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
1956 // we're dealing with a compressed bitmap. Otherwise, use width * height.
1957 totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS))
1958 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
1959
1960 if (section)
1961 {
1962 SYSTEM_BASIC_INFORMATION Sbi;
1963 NTSTATUS Status;
1964 DWORD mapOffset;
1965 LARGE_INTEGER SectionOffset;
1966 SIZE_T mapSize;
1967
1968 Status = ZwQuerySystemInformation(SystemBasicInformation,
1969 &Sbi,
1970 sizeof Sbi,
1971 0);
1972 if (!NT_SUCCESS(Status))
1973 {
1974 DPRINT1("ZwQuerySystemInformation failed (0x%lx)\n", Status);
1975 return NULL;
1976 }
1977
1978 mapOffset = offset - (offset % Sbi.AllocationGranularity);
1979 mapSize = totalSize + (offset - mapOffset);
1980
1981 SectionOffset.LowPart = mapOffset;
1982 SectionOffset.HighPart = 0;
1983
1984 Status = ZwMapViewOfSection(section,
1985 NtCurrentProcess(),
1986 &mapBits,
1987 0,
1988 0,
1989 &SectionOffset,
1990 &mapSize,
1991 ViewShare,
1992 0,
1993 PAGE_READWRITE);
1994 if (!NT_SUCCESS(Status))
1995 {
1996 DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status);
1997 EngSetLastError(ERROR_INVALID_PARAMETER);
1998 return NULL;
1999 }
2000
2001 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
2002 }
2003 else if (ovr_pitch && offset)
2004 bm.bmBits = UlongToPtr(offset);
2005 else
2006 {
2007 offset = 0;
2008 bm.bmBits = EngAllocUserMem(totalSize, 0);
2009 if(!bm.bmBits)
2010 {
2011 DPRINT1("Failed to allocate memory\n");
2012 goto cleanup;
2013 }
2014 }
2015
2016 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
2017 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
2018
2019 // Create Device Dependent Bitmap and add DIB pointer
2020 //Size.cx = bm.bmWidth;
2021 //Size.cy = abs(bm.bmHeight);
2022 res = GreCreateBitmapEx(bm.bmWidth,
2023 abs(bm.bmHeight),
2024 bm.bmWidthBytes,
2025 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
2026 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
2027 ((bi->biHeight < 0) ? BMF_TOPDOWN : 0),
2028 totalSize,
2029 bm.bmBits,
2030 0);
2031 if (!res)
2032 {
2033 DPRINT1("GreCreateBitmapEx failed\n");
2034 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
2035 goto cleanup;
2036 }
2037 bmp = SURFACE_ShareLockSurface(res); // HACK
2038 if (NULL == bmp)
2039 {
2040 DPRINT1("SURFACE_LockSurface failed\n");
2041 EngSetLastError(ERROR_INVALID_HANDLE);
2042 goto cleanup;
2043 }
2044
2045 /* WINE NOTE: WINE makes use of a colormap, which is a color translation
2046 table between the DIB and the X physical device. Obviously,
2047 this is left out of the ReactOS implementation. Instead,
2048 we call NtGdiSetDIBColorTable. */
2049 bmp->hDIBSection = section;
2050 bmp->hSecure = hSecure;
2051 bmp->dwOffset = offset;
2052 bmp->flags = API_BITMAP;
2053 bmp->biClrImportant = bi->biClrImportant;
2054
2055 /* Create a palette for the DIB */
2056 ppalDIB = CreateDIBPalette(bmi, dc, usage);
2057
2058 // Clean up in case of errors
2059 cleanup:
2060 if (!res || !bmp || !bm.bmBits || !ppalDIB)
2061 {
2062 DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
2063 if (bm.bmBits)
2064 {
2065 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
2066 if (section)
2067 {
2068 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
2069 bm.bmBits = NULL;
2070 }
2071 else if (!offset)
2072 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
2073 }
2074
2075 if (bmp)
2076 {
2077 SURFACE_ShareUnlockSurface(bmp);
2078 bmp = NULL;
2079 }
2080
2081 if (res)
2082 {
2083 GreDeleteObject(res);
2084 res = 0;
2085 }
2086
2087 if(ppalDIB)
2088 {
2089 PALETTE_ShareUnlockPalette(ppalDIB);
2090 }
2091 }
2092
2093 if (bmp)
2094 {
2095 /* If we're here, everything went fine */
2096 SURFACE_vSetPalette(bmp, ppalDIB);
2097 PALETTE_ShareUnlockPalette(ppalDIB);
2098 SURFACE_ShareUnlockSurface(bmp);
2099 }
2100
2101 // Return BITMAP handle and storage location
2102 if (NULL != bm.bmBits && NULL != bits)
2103 {
2104 *bits = bm.bmBits;
2105 }
2106
2107 return res;
2108 }
2109
2110 /***********************************************************************
2111 * DIB_GetBitmapInfo
2112 *
2113 * Get the info from a bitmap header.
2114 * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error.
2115 */
2116 int
2117 FASTCALL
DIB_GetBitmapInfo(const BITMAPINFOHEADER * header,LONG * width,LONG * height,WORD * planes,WORD * bpp,DWORD * compr,DWORD * size)2118 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
2119 LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size )
2120 {
2121 if (header->biSize == sizeof(BITMAPCOREHEADER))
2122 {
2123 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
2124 *width = core->bcWidth;
2125 *height = core->bcHeight;
2126 *planes = core->bcPlanes;
2127 *bpp = core->bcBitCount;
2128 *compr = BI_RGB;
2129 *size = 0;
2130 return 0;
2131 }
2132 if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* Assume BITMAPINFOHEADER */
2133 {
2134 *width = header->biWidth;
2135 *height = header->biHeight;
2136 *planes = header->biPlanes;
2137 *bpp = header->biBitCount;
2138 *compr = header->biCompression;
2139 *size = header->biSizeImage;
2140 return 1;
2141 }
2142 DPRINT1("(%u): unknown/wrong size for header\n", header->biSize );
2143 return -1;
2144 }
2145
2146 /***********************************************************************
2147 * DIB_GetDIBImageBytes
2148 *
2149 * Return the number of bytes used to hold the image in a DIB bitmap.
2150 * 11/16/1999 (RJJ) lifted from wine
2151 */
2152
DIB_GetDIBImageBytes(INT width,INT height,INT depth)2153 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth)
2154 {
2155 return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height);
2156 }
2157
2158 /***********************************************************************
2159 * DIB_BitmapInfoSize
2160 *
2161 * Return the size of the bitmap info structure including color table.
2162 * 11/16/1999 (RJJ) lifted from wine
2163 */
2164
DIB_BitmapInfoSize(const BITMAPINFO * info,WORD coloruse)2165 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
2166 {
2167 unsigned int colors, size, masks = 0;
2168 unsigned int colorsize;
2169
2170 colorsize = (coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) :
2171 (coloruse == DIB_PAL_INDICES) ? 0 :
2172 sizeof(WORD);
2173
2174 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
2175 {
2176 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
2177 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
2178 return sizeof(BITMAPCOREHEADER) + colors * colorsize;
2179 }
2180 else /* Assume BITMAPINFOHEADER */
2181 {
2182 colors = info->bmiHeader.biClrUsed;
2183 if (colors > 256) colors = 256;
2184 if (!colors && (info->bmiHeader.biBitCount <= 8))
2185 colors = 1 << info->bmiHeader.biBitCount;
2186 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
2187 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
2188 return size + colors * colorsize;
2189 }
2190 }
2191
2192 HPALETTE
2193 FASTCALL
DIB_MapPaletteColors(PPALETTE ppalDc,CONST BITMAPINFO * lpbmi)2194 DIB_MapPaletteColors(PPALETTE ppalDc, CONST BITMAPINFO* lpbmi)
2195 {
2196 PPALETTE ppalNew;
2197 ULONG nNumColors,i;
2198 USHORT *lpIndex;
2199 HPALETTE hpal;
2200
2201 if (!(ppalDc->flFlags & PAL_INDEXED))
2202 {
2203 return NULL;
2204 }
2205
2206 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
2207 if (lpbmi->bmiHeader.biClrUsed)
2208 {
2209 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
2210 }
2211
2212 ppalNew = PALETTE_AllocPalWithHandle(PAL_INDEXED, nNumColors, NULL, 0, 0, 0);
2213 if (ppalNew == NULL)
2214 {
2215 DPRINT1("Could not allocate palette\n");
2216 return NULL;
2217 }
2218
2219 lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize);
2220
2221 for (i = 0; i < nNumColors; i++)
2222 {
2223 ULONG iColorIndex = *lpIndex % ppalDc->NumColors;
2224 ppalNew->IndexedColors[i] = ppalDc->IndexedColors[iColorIndex];
2225 lpIndex++;
2226 }
2227
2228 hpal = ppalNew->BaseObject.hHmgr;
2229 PALETTE_UnlockPalette(ppalNew);
2230
2231 return hpal;
2232 }
2233
2234 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure,
2235 * or does nothing if it's already a BITMAPINFO (or V4 or V5) */
2236 BITMAPINFO*
2237 FASTCALL
DIB_ConvertBitmapInfo(CONST BITMAPINFO * pbmi,DWORD Usage)2238 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage)
2239 {
2240 CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi;
2241 BITMAPINFO* pNewBmi ;
2242 UINT numColors = 0, ColorsSize = 0;
2243
2244 if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi;
2245 if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL;
2246
2247 if(pbmci->bmciHeader.bcBitCount <= 8)
2248 {
2249 numColors = 1 << pbmci->bmciHeader.bcBitCount;
2250 if(Usage == DIB_PAL_COLORS)
2251 {
2252 ColorsSize = numColors * sizeof(WORD);
2253 }
2254 else
2255 {
2256 ColorsSize = numColors * sizeof(RGBQUAD);
2257 }
2258 }
2259 else if (Usage == DIB_PAL_COLORS)
2260 {
2261 /* Invalid at high-res */
2262 return NULL;
2263 }
2264
2265 pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB);
2266 if(!pNewBmi) return NULL;
2267
2268 RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize);
2269
2270 pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2271 pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount;
2272 pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth;
2273 pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight;
2274 pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes;
2275 pNewBmi->bmiHeader.biCompression = BI_RGB ;
2276 pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth,
2277 pNewBmi->bmiHeader.biHeight,
2278 pNewBmi->bmiHeader.biBitCount);
2279 pNewBmi->bmiHeader.biClrUsed = numColors;
2280
2281 if(Usage == DIB_PAL_COLORS)
2282 {
2283 RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize);
2284 }
2285 else
2286 {
2287 UINT i;
2288 for(i=0; i<numColors; i++)
2289 {
2290 pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed;
2291 pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen;
2292 pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue;
2293 }
2294 }
2295
2296 return pNewBmi ;
2297 }
2298
2299 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */
2300 VOID
2301 FASTCALL
DIB_FreeConvertedBitmapInfo(BITMAPINFO * converted,BITMAPINFO * orig,DWORD usage)2302 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage)
2303 {
2304 BITMAPCOREINFO* pbmci;
2305 if(converted == orig)
2306 return;
2307
2308 if(usage == -1)
2309 {
2310 /* Caller don't want any conversion */
2311 ExFreePoolWithTag(converted, TAG_DIB);
2312 return;
2313 }
2314
2315 /* Perform inverse conversion */
2316 pbmci = (BITMAPCOREINFO*)orig;
2317
2318 ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER));
2319 pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount;
2320 pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth;
2321 pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight;
2322 pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes;
2323
2324 if(pbmci->bmciHeader.bcBitCount <= 8)
2325 {
2326 UINT numColors = converted->bmiHeader.biClrUsed;
2327 if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount;
2328 if(usage == DIB_PAL_COLORS)
2329 {
2330 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD));
2331 RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD));
2332 }
2333 else
2334 {
2335 UINT i;
2336 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE));
2337 for(i=0; i<numColors; i++)
2338 {
2339 pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed;
2340 pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen;
2341 pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue;
2342 }
2343 }
2344 }
2345 /* Now free it, it's not needed anymore */
2346 ExFreePoolWithTag(converted, TAG_DIB);
2347 }
2348
2349 /* EOF */
2350