xref: /reactos/win32ss/gdi/ntgdi/dibobj.c (revision 24757e30)
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