xref: /reactos/win32ss/gdi/ntgdi/dibobj.c (revision b3194e32)
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
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
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!");
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
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
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 
715 /* Converts a device-dependent bitmap to a DIB */
716 INT
717 APIENTRY
718 GreGetDIBitsInternal(
719     HDC hDC,
720     HBITMAP hBitmap,
721     UINT StartScan,
722     UINT ScanLines,
723     LPBYTE Bits,
724     LPBITMAPINFO Info,
725     UINT Usage,
726     UINT MaxBits,
727     UINT MaxInfo)
728 {
729     BITMAPCOREINFO* pbmci = NULL;
730     PSURFACE psurf = NULL;
731     PDC pDC;
732     LONG width, height;
733     WORD planes, bpp;
734     DWORD compr, size ;
735     USHORT i;
736     int bitmap_type;
737     RGBQUAD* rgbQuads;
738     VOID* colorPtr;
739 
740     DPRINT("Entered GreGetDIBitsInternal()\n");
741 
742     if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap)
743         return 0;
744 
745     pDC = DC_LockDc(hDC);
746     if (pDC == NULL || pDC->dctype == DCTYPE_INFO)
747     {
748         ScanLines = 0;
749         goto done;
750     }
751 
752     /* Get a pointer to the source bitmap object */
753     psurf = SURFACE_ShareLockSurface(hBitmap);
754     if (psurf == NULL)
755     {
756         ScanLines = 0;
757         goto done;
758     }
759 
760     colorPtr = (LPBYTE)Info + Info->bmiHeader.biSize;
761     rgbQuads = colorPtr;
762 
763     bitmap_type = DIB_GetBitmapInfo(&Info->bmiHeader,
764                                     &width,
765                                     &height,
766                                     &planes,
767                                     &bpp,
768                                     &compr,
769                                     &size);
770     if(bitmap_type == -1)
771     {
772         DPRINT1("Wrong bitmap format\n");
773         EngSetLastError(ERROR_INVALID_PARAMETER);
774         ScanLines = 0;
775         goto done;
776     }
777     else if(bitmap_type == 0)
778     {
779         /* We need a BITMAPINFO to create a DIB, but we have to fill
780          * the BITMAPCOREINFO we're provided */
781         pbmci = (BITMAPCOREINFO*)Info;
782         /* fill in the the bit count, so we can calculate the right ColorsSize during the conversion */
783         pbmci->bmciHeader.bcBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
784         Info = DIB_ConvertBitmapInfo((BITMAPINFO*)pbmci, Usage);
785         if(Info == NULL)
786         {
787             DPRINT1("Error, could not convert the BITMAPCOREINFO!\n");
788             ScanLines = 0;
789             goto done;
790         }
791         rgbQuads = Info->bmiColors;
792     }
793 
794     /* Validate input:
795        - negative width is always an invalid value
796        - non-null Bits and zero bpp is an invalid combination
797        - only check the rest of the input params if either bpp is non-zero or Bits are set */
798     if (width < 0 || (bpp == 0 && Bits))
799     {
800         ScanLines = 0;
801         goto done;
802     }
803 
804     if (Bits || bpp)
805     {
806         if ((height == 0 || width == 0) || (compr && compr != BI_BITFIELDS && compr != BI_RGB))
807         {
808             ScanLines = 0;
809             goto done;
810         }
811     }
812 
813     Info->bmiHeader.biClrUsed = 0;
814     Info->bmiHeader.biClrImportant = 0;
815 
816     /* Fill in the structure */
817     switch(bpp)
818     {
819     case 0: /* Only info */
820         Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx;
821         Info->bmiHeader.biHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ?
822                                    -psurf->SurfObj.sizlBitmap.cy :
823                                    psurf->SurfObj.sizlBitmap.cy;
824         Info->bmiHeader.biPlanes = 1;
825         Info->bmiHeader.biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
826         Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( Info->bmiHeader.biWidth,
827                                       Info->bmiHeader.biHeight,
828                                       Info->bmiHeader.biBitCount);
829         Info->bmiHeader.biCompression = (Info->bmiHeader.biBitCount == 16 || Info->bmiHeader.biBitCount == 32) ?
830                                         BI_BITFIELDS : BI_RGB;
831         Info->bmiHeader.biXPelsPerMeter = 0;
832         Info->bmiHeader.biYPelsPerMeter = 0;
833 
834         if (Info->bmiHeader.biBitCount <= 8 && Info->bmiHeader.biClrUsed == 0)
835             Info->bmiHeader.biClrUsed = 1 << Info->bmiHeader.biBitCount;
836 
837         ScanLines = 1;
838         goto done;
839 
840     case 1:
841     case 4:
842     case 8:
843         Info->bmiHeader.biClrUsed = 1 << bpp;
844 
845         /* If the bitmap is a DIB section and has the same format as what
846          * is requested, go ahead! */
847         if((psurf->hSecure) &&
848                 (BitsPerFormat(psurf->SurfObj.iBitmapFormat) == bpp))
849         {
850             if(Usage == DIB_RGB_COLORS)
851             {
852                 ULONG colors = min(psurf->ppal->NumColors, 256);
853                 if(colors != 256) Info->bmiHeader.biClrUsed = colors;
854                 for(i = 0; i < colors; i++)
855                 {
856                     rgbQuads[i].rgbRed = psurf->ppal->IndexedColors[i].peRed;
857                     rgbQuads[i].rgbGreen = psurf->ppal->IndexedColors[i].peGreen;
858                     rgbQuads[i].rgbBlue = psurf->ppal->IndexedColors[i].peBlue;
859                     rgbQuads[i].rgbReserved = 0;
860                 }
861             }
862             else
863             {
864                 for(i = 0; i < 256; i++)
865                     ((WORD*)rgbQuads)[i] = i;
866             }
867         }
868         else
869         {
870             if(Usage == DIB_PAL_COLORS)
871             {
872                 for(i = 0; i < 256; i++)
873                 {
874                     ((WORD*)rgbQuads)[i] = i;
875                 }
876             }
877             else if(bpp > 1 && bpp == BitsPerFormat(psurf->SurfObj.iBitmapFormat))
878             {
879                 /* For color DDBs in native depth (mono DDBs always have
880                    a black/white palette):
881                    Generate the color map from the selected palette */
882                 PPALETTE pDcPal = PALETTE_ShareLockPalette(pDC->dclevel.hpal);
883                 if(!pDcPal)
884                 {
885                     ScanLines = 0 ;
886                     goto done ;
887                 }
888                 for (i = 0; i < pDcPal->NumColors; i++)
889                 {
890                     rgbQuads[i].rgbRed      = pDcPal->IndexedColors[i].peRed;
891                     rgbQuads[i].rgbGreen    = pDcPal->IndexedColors[i].peGreen;
892                     rgbQuads[i].rgbBlue     = pDcPal->IndexedColors[i].peBlue;
893                     rgbQuads[i].rgbReserved = 0;
894                 }
895                 PALETTE_ShareUnlockPalette(pDcPal);
896             }
897             else
898             {
899                 switch (bpp)
900                 {
901                 case 1:
902                     rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0;
903                     rgbQuads[0].rgbReserved = 0;
904                     rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff;
905                     rgbQuads[1].rgbReserved = 0;
906                     break;
907 
908                 case 4:
909                     /* The EGA palette is the first and last 8 colours of the default palette
910                        with the innermost pair swapped */
911                     RtlCopyMemory(rgbQuads,     DefLogPaletteQuads,      7 * sizeof(RGBQUAD));
912                     RtlCopyMemory(rgbQuads + 7, DefLogPaletteQuads + 12, 1 * sizeof(RGBQUAD));
913                     RtlCopyMemory(rgbQuads + 8, DefLogPaletteQuads +  7, 1 * sizeof(RGBQUAD));
914                     RtlCopyMemory(rgbQuads + 9, DefLogPaletteQuads + 13, 7 * sizeof(RGBQUAD));
915                     break;
916 
917                 case 8:
918                 {
919                     INT i;
920 
921                     memcpy(rgbQuads, DefLogPaletteQuads, 10 * sizeof(RGBQUAD));
922                     memcpy(rgbQuads + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD));
923 
924                     for (i = 10; i < 246; i++)
925                     {
926                         rgbQuads[i].rgbRed = (i & 0x07) << 5;
927                         rgbQuads[i].rgbGreen = (i & 0x38) << 2;
928                         rgbQuads[i].rgbBlue = i & 0xc0;
929                         rgbQuads[i].rgbReserved = 0;
930                     }
931                 }
932                 }
933             }
934         }
935         break;
936 
937     case 15:
938         if (Info->bmiHeader.biCompression == BI_BITFIELDS)
939         {
940             ((PDWORD)Info->bmiColors)[0] = 0x7c00;
941             ((PDWORD)Info->bmiColors)[1] = 0x03e0;
942             ((PDWORD)Info->bmiColors)[2] = 0x001f;
943         }
944         break;
945 
946     case 16:
947         if (Info->bmiHeader.biCompression == BI_BITFIELDS)
948         {
949             if (psurf->hSecure)
950             {
951                 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask;
952                 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask;
953                 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask;
954             }
955             else
956             {
957                 ((PDWORD)Info->bmiColors)[0] = 0xf800;
958                 ((PDWORD)Info->bmiColors)[1] = 0x07e0;
959                 ((PDWORD)Info->bmiColors)[2] = 0x001f;
960             }
961         }
962         break;
963 
964     case 24:
965     case 32:
966         if (Info->bmiHeader.biCompression == BI_BITFIELDS)
967         {
968             if (psurf->hSecure)
969             {
970                 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask;
971                 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask;
972                 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask;
973             }
974             else
975             {
976                 ((PDWORD)Info->bmiColors)[0] = 0xff0000;
977                 ((PDWORD)Info->bmiColors)[1] = 0x00ff00;
978                 ((PDWORD)Info->bmiColors)[2] = 0x0000ff;
979             }
980         }
981         break;
982 
983     default:
984         ScanLines = 0;
985         goto done;
986     }
987 
988     Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(width, height, bpp);
989     Info->bmiHeader.biPlanes = 1;
990 
991     if(Bits && ScanLines)
992     {
993         /* Create a DIBSECTION, blt it, profit */
994         PVOID pDIBits ;
995         HBITMAP hBmpDest;
996         PSURFACE psurfDest;
997         EXLATEOBJ exlo;
998         RECT rcDest;
999         POINTL srcPoint;
1000         BOOL ret ;
1001         int newLines = -1;
1002 
1003         if (StartScan >= abs(Info->bmiHeader.biHeight))
1004         {
1005             ScanLines = 1;
1006             goto done;
1007         }
1008         else
1009         {
1010             ScanLines = min(ScanLines, abs(Info->bmiHeader.biHeight) - StartScan);
1011         }
1012 
1013         if (abs(Info->bmiHeader.biHeight) < psurf->SurfObj.sizlBitmap.cy)
1014         {
1015             StartScan += psurf->SurfObj.sizlBitmap.cy - abs(Info->bmiHeader.biHeight);
1016         }
1017         /* Fixup values */
1018         Info->bmiHeader.biHeight = (height < 0) ?
1019                                    -(LONG)ScanLines : ScanLines;
1020         /* Create the DIB */
1021         hBmpDest = DIB_CreateDIBSection(pDC, Info, Usage, &pDIBits, NULL, 0, 0);
1022         /* Restore them */
1023         Info->bmiHeader.biHeight = height;
1024 
1025         if(!hBmpDest)
1026         {
1027             DPRINT1("Unable to create a DIB Section!\n");
1028             EngSetLastError(ERROR_INVALID_PARAMETER);
1029             ScanLines = 0;
1030             goto done ;
1031         }
1032 
1033         psurfDest = SURFACE_ShareLockSurface(hBmpDest);
1034 
1035         RECTL_vSetRect(&rcDest, 0, 0, Info->bmiHeader.biWidth, ScanLines);
1036         Info->bmiHeader.biWidth = width;
1037         srcPoint.x = 0;
1038 
1039         if (abs(Info->bmiHeader.biHeight) <= psurf->SurfObj.sizlBitmap.cy)
1040         {
1041             srcPoint.y = psurf->SurfObj.sizlBitmap.cy - StartScan - ScanLines;
1042         }
1043         else
1044         {
1045             /*  Determine the actual number of lines copied from the  */
1046             /*  original bitmap. It might be different from ScanLines. */
1047             newLines = abs(Info->bmiHeader.biHeight) - psurf->SurfObj.sizlBitmap.cy;
1048             newLines = min((int)(StartScan + ScanLines - newLines), psurf->SurfObj.sizlBitmap.cy);
1049             if (newLines > 0)
1050             {
1051                 srcPoint.y = psurf->SurfObj.sizlBitmap.cy - newLines;
1052                 if (StartScan > psurf->SurfObj.sizlBitmap.cy)
1053                 {
1054                     newLines -= (StartScan - psurf->SurfObj.sizlBitmap.cy);
1055                 }
1056             }
1057             else
1058             {
1059                 newLines = 0;
1060                 srcPoint.y = psurf->SurfObj.sizlBitmap.cy;
1061             }
1062         }
1063 
1064         EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xffffff, 0xffffff, 0);
1065 
1066         ret = IntEngCopyBits(&psurfDest->SurfObj,
1067                              &psurf->SurfObj,
1068                              NULL,
1069                              &exlo.xlo,
1070                              &rcDest,
1071                              &srcPoint);
1072 
1073         SURFACE_ShareUnlockSurface(psurfDest);
1074 
1075         if(!ret)
1076             ScanLines = 0;
1077         else
1078         {
1079             RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp));
1080         }
1081         /* Update if line count has changed */
1082         if (newLines != -1)
1083         {
1084             ScanLines = (UINT)newLines;
1085         }
1086         GreDeleteObject(hBmpDest);
1087         EXLATEOBJ_vCleanup(&exlo);
1088     }
1089     else
1090     {
1091         /* Signals success and not the actual number of scan lines*/
1092         ScanLines = 1;
1093     }
1094 
1095 done:
1096 
1097     if (pbmci)
1098         DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci, Usage);
1099 
1100     if (psurf)
1101         SURFACE_ShareUnlockSurface(psurf);
1102 
1103     if (pDC)
1104         DC_UnlockDc(pDC);
1105 
1106     return ScanLines;
1107 }
1108 
1109 _Success_(return!=0)
1110 __kernel_entry
1111 INT
1112 APIENTRY
1113 NtGdiGetDIBitsInternal(
1114     _In_ HDC hdc,
1115     _In_ HBITMAP hbm,
1116     _In_ UINT iStartScan,
1117     _In_ UINT cScans,
1118     _Out_writes_bytes_opt_(cjMaxBits) LPBYTE pjBits,
1119     _Inout_ LPBITMAPINFO pbmi,
1120     _In_ UINT iUsage,
1121     _In_ UINT cjMaxBits,
1122     _In_ UINT cjMaxInfo)
1123 {
1124     PBITMAPINFO pbmiSafe;
1125     HANDLE hSecure = NULL;
1126     INT iResult = 0;
1127     UINT cjAlloc;
1128 
1129     /* Check for bad iUsage */
1130     if (iUsage > 2) return 0;
1131 
1132     /* Check if the size of the bitmap info is large enough */
1133     if (cjMaxInfo < sizeof(BITMAPCOREHEADER))
1134     {
1135         return 0;
1136     }
1137 
1138     /* Use maximum size */
1139     cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD));
1140 
1141     // HACK: the underlying code sucks and doesn't care for the size, so we
1142     // give it the maximum ever needed
1143     cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD);
1144 
1145     /* Allocate a buffer the bitmapinfo */
1146     pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
1147     if (!pbmiSafe)
1148     {
1149         /* Fail */
1150         return 0;
1151     }
1152 
1153     /* Use SEH */
1154     _SEH2_TRY
1155     {
1156         /* Probe and copy the BITMAPINFO */
1157         ProbeForRead(pbmi, cjMaxInfo, 1);
1158         RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo);
1159     }
1160     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1161     {
1162         goto cleanup;
1163     }
1164     _SEH2_END;
1165 
1166     /* Check if the header size is large enough */
1167     if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
1168         (pbmiSafe->bmiHeader.biSize > cjMaxInfo))
1169     {
1170         goto cleanup;
1171     }
1172 
1173     /* Check if the caller provided bitmap bits */
1174     if (pjBits)
1175     {
1176         /* Secure the user mode memory */
1177         hSecure = EngSecureMem(pjBits, cjMaxBits);
1178         if (!hSecure)
1179         {
1180             goto cleanup;
1181         }
1182     }
1183 
1184     /* Now call the internal function */
1185     iResult = GreGetDIBitsInternal(hdc,
1186                                    hbm,
1187                                    iStartScan,
1188                                    cScans,
1189                                    pjBits,
1190                                    pbmiSafe,
1191                                    iUsage,
1192                                    cjMaxBits,
1193                                    cjMaxInfo);
1194 
1195     /* Check for success */
1196     if (iResult)
1197     {
1198         /* Use SEH to copy back to user mode */
1199         _SEH2_TRY
1200         {
1201             /* Copy the data back */
1202             cjMaxInfo = min(cjMaxInfo, (UINT)DIB_BitmapInfoSize(pbmiSafe, (WORD)iUsage));
1203             ProbeForWrite(pbmi, cjMaxInfo, 1);
1204             RtlCopyMemory(pbmi, pbmiSafe, cjMaxInfo);
1205         }
1206         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1207         {
1208             /* Ignore */
1209             (VOID)0;
1210         }
1211         _SEH2_END;
1212     }
1213 
1214 cleanup:
1215     if (hSecure) EngUnsecureMem(hSecure);
1216     ExFreePoolWithTag(pbmiSafe, 'imBG');
1217 
1218     return iResult;
1219 }
1220 
1221 
1222 W32KAPI
1223 INT
1224 APIENTRY
1225 NtGdiStretchDIBitsInternal(
1226     IN HDC hdc,
1227     IN INT xDst,
1228     IN INT yDst,
1229     IN INT cxDst,
1230     IN INT cyDst,
1231     IN INT xSrc,
1232     IN INT ySrc,
1233     IN INT cxSrc,
1234     IN INT cySrc,
1235     IN OPTIONAL LPBYTE pjInit,
1236     IN LPBITMAPINFO pbmi,
1237     IN DWORD dwUsage,
1238     IN DWORD dwRop, // MS ntgdi.h says dwRop4(?)
1239     IN UINT cjMaxInfo,
1240     IN UINT cjMaxBits,
1241     IN HANDLE hcmXform)
1242 {
1243     SIZEL sizel;
1244     RECTL rcSrc, rcDst;
1245     PDC pdc;
1246     HBITMAP hbmTmp = 0;
1247     PSURFACE psurfTmp = 0, psurfDst = 0;
1248     PPALETTE ppalDIB = 0;
1249     EXLATEOBJ exlo;
1250     PBYTE pvBits;
1251 
1252     LPBITMAPINFO pbmiSafe;
1253     UINT cjAlloc;
1254     HBITMAP hBitmap, hOldBitmap = NULL;
1255     HDC hdcMem;
1256     HPALETTE hPal = NULL;
1257     ULONG BmpFormat = 0;
1258     INT LinesCopied = 0;
1259 
1260     /* Check for bad iUsage */
1261     if (dwUsage > 2) return 0;
1262 
1263     /* We must have LPBITMAPINFO */
1264     if (!pbmi)
1265     {
1266         DPRINT1("Error, Invalid Parameter.\n");
1267         EngSetLastError(ERROR_INVALID_PARAMETER);
1268         return 0;
1269     }
1270 
1271     /* Check if the size of the bitmap info is large enough */
1272     if (cjMaxInfo < sizeof(BITMAPCOREHEADER))
1273     {
1274         return 0;
1275     }
1276 
1277     /* Use maximum size */
1278     cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD));
1279 
1280     // HACK: the underlying code sucks and doesn't care for the size, so we
1281     // give it the maximum ever needed
1282     cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD);
1283 
1284     /* Allocate a buffer the bitmapinfo */
1285     pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
1286     if (!pbmiSafe)
1287     {
1288         /* Fail */
1289         return 0;
1290     }
1291 
1292     /* Use SEH */
1293     _SEH2_TRY
1294     {
1295         /* Probe and copy the BITMAPINFO */
1296         ProbeForRead(pbmi, cjMaxInfo, 1);
1297         RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo);
1298     }
1299     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1300     {
1301         ExFreePoolWithTag(pbmiSafe, 'imBG');
1302         return 0;
1303     }
1304     _SEH2_END;
1305 
1306     /* Check if the header size is large enough */
1307     if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
1308         (pbmiSafe->bmiHeader.biSize > cjMaxInfo))
1309     {
1310         ExFreePoolWithTag(pbmiSafe, 'imBG');
1311         return 0;
1312     }
1313 
1314     if (!(pdc = DC_LockDc(hdc)))
1315     {
1316         EngSetLastError(ERROR_INVALID_HANDLE);
1317         return 0;
1318     }
1319 
1320     /* Check for info / mem DC without surface */
1321     if (!pdc->dclevel.pSurface)
1322     {
1323         DC_UnlockDc(pdc);
1324         // CHECKME
1325         return TRUE;
1326     }
1327 
1328     /* Transform dest size */
1329     sizel.cx = cxDst;
1330     sizel.cy = cyDst;
1331     IntLPtoDP(pdc, (POINTL*)&sizel, 1);
1332     DC_UnlockDc(pdc);
1333 
1334     if (pjInit && (cjMaxBits > 0))
1335     {
1336         pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
1337         if (!pvBits)
1338         {
1339             return 0;
1340         }
1341 
1342         _SEH2_TRY
1343         {
1344             ProbeForRead(pjInit, cjMaxBits, 1);
1345             RtlCopyMemory(pvBits, pjInit, cjMaxBits);
1346         }
1347         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1348         {
1349             ExFreePoolWithTag(pvBits, TAG_DIB);
1350             return 0;
1351         }
1352         _SEH2_END;
1353     }
1354     else
1355     {
1356         pvBits = NULL;
1357     }
1358 
1359     /* Here we select between the dwRop with SRCCOPY or not. */
1360     if (dwRop == SRCCOPY)
1361     {
1362         hdcMem = NtGdiCreateCompatibleDC(hdc);
1363         if (hdcMem == NULL)
1364         {
1365             DPRINT1("NtGdiCreateCompatibleDC failed to create hdc.\n");
1366             EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
1367             return 0;
1368         }
1369 
1370         hBitmap = NtGdiCreateCompatibleBitmap(hdc,
1371                                               abs(pbmiSafe->bmiHeader.biWidth),
1372                                               abs(pbmiSafe->bmiHeader.biHeight));
1373         if (hBitmap == NULL)
1374         {
1375             DPRINT1("NtGdiCreateCompatibleBitmap failed to create bitmap.\n");
1376             DPRINT1("hdc : 0x%08x \n", hdc);
1377             DPRINT1("width : 0x%08x \n", pbmiSafe->bmiHeader.biWidth);
1378             DPRINT1("height : 0x%08x \n", pbmiSafe->bmiHeader.biHeight);
1379             EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
1380             return 0;
1381         }
1382 
1383         /* Select the bitmap into hdcMem, and save a handle to the old bitmap */
1384         hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap);
1385 
1386         if (dwUsage == DIB_PAL_COLORS)
1387         {
1388             hPal = NtGdiGetDCObject(hdc, GDI_OBJECT_TYPE_PALETTE);
1389             hPal = GdiSelectPalette(hdcMem, hPal, FALSE);
1390         }
1391 
1392         pdc = DC_LockDc(hdcMem);
1393         if (pdc != NULL)
1394         {
1395             IntSetDIBits(pdc, hBitmap, 0, abs(pbmiSafe->bmiHeader.biHeight), pvBits,
1396                          cjMaxBits, pbmiSafe, dwUsage);
1397             DC_UnlockDc(pdc);
1398         }
1399 
1400         /* Origin for DIBitmap may be bottom left (positive biHeight) or top
1401            left (negative biHeight) */
1402         if (cxSrc == cxDst && cySrc == cyDst)
1403         {
1404             NtGdiBitBlt(hdc, xDst, yDst, cxDst, cyDst,
1405                         hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc - ySrc,
1406                         dwRop, 0, 0);
1407         }
1408         else
1409         {
1410             NtGdiStretchBlt(hdc, xDst, yDst, cxDst, cyDst,
1411                             hdcMem, xSrc, abs(pbmiSafe->bmiHeader.biHeight) - cySrc - ySrc,
1412                             cxSrc, cySrc, dwRop, 0);
1413         }
1414 
1415         /* cleanup */
1416         if (hPal)
1417             GdiSelectPalette(hdcMem, hPal, FALSE);
1418 
1419         if (hOldBitmap)
1420             NtGdiSelectBitmap(hdcMem, hOldBitmap);
1421 
1422         NtGdiDeleteObjectApp(hdcMem);
1423         GreDeleteObject(hBitmap);
1424 
1425     } /* End of dwRop == SRCCOPY */
1426     else
1427     { /* Start of dwRop != SRCCOPY */
1428         /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */
1429         if (!(pdc = DC_LockDc(hdc)))
1430         {
1431             DPRINT1("Could not lock dc\n");
1432             EngSetLastError(ERROR_INVALID_HANDLE);
1433             goto cleanup;
1434         }
1435 
1436         /* Calculate source and destination rect */
1437         rcSrc.left = xSrc;
1438         rcSrc.top = ySrc;
1439         rcSrc.right = xSrc + abs(cxSrc);
1440         rcSrc.bottom = ySrc + abs(cySrc);
1441         rcDst.left = xDst;
1442         rcDst.top = yDst;
1443         rcDst.right = rcDst.left + cxDst;
1444         rcDst.bottom = rcDst.top + cyDst;
1445         IntLPtoDP(pdc, (POINTL*)&rcDst, 2);
1446         RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1447 
1448         if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1449         {
1450            IntUpdateBoundsRect(pdc, &rcDst);
1451         }
1452 
1453         BmpFormat = BitmapFormat(pbmiSafe->bmiHeader.biBitCount,
1454                                  pbmiSafe->bmiHeader.biCompression);
1455 
1456         hbmTmp = GreCreateBitmapEx(pbmiSafe->bmiHeader.biWidth,
1457                                    abs(pbmiSafe->bmiHeader.biHeight),
1458                                    0,
1459                                    BmpFormat,
1460                                    pbmiSafe->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
1461                                    cjMaxBits,
1462                                    pvBits,
1463                                    0);
1464 
1465         if (!hbmTmp)
1466         {
1467             goto cleanup;
1468         }
1469 
1470         psurfTmp = SURFACE_ShareLockSurface(hbmTmp);
1471         if (!psurfTmp)
1472         {
1473             goto cleanup;
1474         }
1475 
1476         /* Create a palette for the DIB */
1477         ppalDIB = CreateDIBPalette(pbmiSafe, pdc, dwUsage);
1478         if (!ppalDIB)
1479         {
1480             goto cleanup;
1481         }
1482 
1483         /* Prepare DC for blit */
1484         DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL);
1485 
1486         psurfDst = pdc->dclevel.pSurface;
1487 
1488         /* Initialize XLATEOBJ */
1489         EXLATEOBJ_vInitialize(&exlo,
1490                               ppalDIB,
1491                               psurfDst->ppal,
1492                               RGB(0xff, 0xff, 0xff),
1493                               pdc->pdcattr->crBackgroundClr,
1494                               pdc->pdcattr->crForegroundClr);
1495 
1496         /* Perform the stretch operation */
1497         IntEngStretchBlt(&psurfDst->SurfObj,
1498                          &psurfTmp->SurfObj,
1499                          NULL,
1500                          (CLIPOBJ *)&pdc->co,
1501                          &exlo.xlo,
1502                          &pdc->dclevel.ca,
1503                          &rcDst,
1504                          &rcSrc,
1505                          NULL,
1506                          &pdc->eboFill.BrushObject,
1507                          NULL,
1508                          WIN32_ROP3_TO_ENG_ROP4(dwRop));
1509 
1510         /* Cleanup */
1511         DC_vFinishBlit(pdc, NULL);
1512         EXLATEOBJ_vCleanup(&exlo);
1513 
1514     cleanup:
1515         if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
1516         if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp);
1517         if (hbmTmp) GreDeleteObject(hbmTmp);
1518         if (pdc) DC_UnlockDc(pdc);
1519     }
1520 
1521     if (pvBits) ExFreePoolWithTag(pvBits, TAG_DIB);
1522 
1523     /* This is not what MSDN says is returned from this function, but it
1524      * follows Wine's dlls/gdi32/dib.c function nulldrv_StretchDIBits
1525      * and it fixes over 100 gdi32:dib regression tests. */
1526     if (dwRop == SRCCOPY)
1527     {
1528         LinesCopied = abs(pbmiSafe->bmiHeader.biHeight);
1529     }
1530     else
1531     {
1532         LinesCopied = pbmiSafe->bmiHeader.biHeight;
1533     }
1534 
1535     ExFreePoolWithTag(pbmiSafe, 'imBG');
1536 
1537     return LinesCopied;
1538 }
1539 
1540 
1541 HBITMAP
1542 FASTCALL
1543 IntCreateDIBitmap(
1544     PDC Dc,
1545     INT width,
1546     INT height,
1547     UINT planes,
1548     UINT bpp,
1549     ULONG compression,
1550     DWORD init,
1551     LPBYTE bits,
1552     ULONG cjMaxBits,
1553     PBITMAPINFO data,
1554     DWORD coloruse)
1555 {
1556     HBITMAP handle;
1557     BOOL fColor;
1558     ULONG BmpFormat = 0;
1559 
1560     if (planes && bpp)
1561         BmpFormat = BitmapFormat(planes * bpp, compression);
1562 
1563     // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
1564     // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
1565 
1566     if (BmpFormat != BMF_1BPP) fColor = TRUE;
1567     else if ((coloruse > DIB_RGB_COLORS) || ((init & CBM_INIT) == 0) || !data) fColor = FALSE;
1568     else
1569     {
1570         const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize);
1571         DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1572 
1573         // Check if the first color of the colormap is black
1574         if (col == RGB(0, 0, 0))
1575         {
1576             rgb++;
1577             col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1578 
1579             // If the second color is white, create a monochrome bitmap
1580             fColor = (col != RGB(0xff,0xff,0xff));
1581         }
1582         else fColor = TRUE;
1583     }
1584 
1585     // Now create the bitmap
1586     if (fColor)
1587     {
1588         if (init & CBM_CREATDIB)
1589         {
1590             PSURFACE Surface;
1591             PPALETTE Palette;
1592 
1593             /* Undocumented flag which creates a DDB of the format specified by the bitmap info. */
1594             handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp);
1595             if (!handle)
1596             {
1597                 DPRINT1("IntCreateCompatibleBitmap() failed!\n");
1598                 return NULL;
1599             }
1600 
1601             /* The palette must also match the given data */
1602             Surface = SURFACE_ShareLockSurface(handle);
1603             ASSERT(Surface);
1604             Palette = CreateDIBPalette(data, Dc, coloruse);
1605             if (Palette == NULL)
1606             {
1607                 SURFACE_ShareUnlockSurface(Surface);
1608                 GreDeleteObject(handle);
1609                 return NULL;
1610             }
1611 
1612             SURFACE_vSetPalette(Surface, Palette);
1613 
1614             PALETTE_ShareUnlockPalette(Palette);
1615             SURFACE_ShareUnlockSurface(Surface);
1616         }
1617         else
1618         {
1619             /* Create a regular compatible bitmap, in the same format as the device */
1620             handle = IntCreateCompatibleBitmap(Dc, width, height, 0, 0);
1621         }
1622     }
1623     else
1624     {
1625         handle = GreCreateBitmap(width,
1626                                  abs(height),
1627                                  1,
1628                                  1,
1629                                  NULL);
1630     }
1631 
1632     if (height < 0)
1633         height = -height;
1634 
1635     if ((NULL != handle) && (CBM_INIT & init))
1636     {
1637         IntSetDIBits(Dc, handle, 0, height, bits, cjMaxBits, data, coloruse);
1638     }
1639 
1640     return handle;
1641 }
1642 
1643 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
1644 // The DDB that is created will be whatever bit depth your reference DC is
1645 HBITMAP
1646 APIENTRY
1647 NtGdiCreateDIBitmapInternal(
1648     IN HDC hDc,
1649     IN INT cx,
1650     IN INT cy,
1651     IN DWORD fInit,
1652     IN OPTIONAL LPBYTE pjInit,
1653     IN OPTIONAL LPBITMAPINFO pbmi,
1654     IN DWORD iUsage,
1655     IN UINT cjMaxInitInfo,
1656     IN UINT cjMaxBits,
1657     IN FLONG fl,
1658     IN HANDLE hcmXform)
1659 {
1660     NTSTATUS Status = STATUS_SUCCESS;
1661     PBYTE safeBits = NULL;
1662     HBITMAP hbmResult = NULL;
1663 
1664     if (pjInit == NULL)
1665     {
1666         fInit &= ~CBM_INIT;
1667     }
1668 
1669     if(pjInit && (fInit & CBM_INIT))
1670     {
1671         if (cjMaxBits == 0) return NULL;
1672         safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
1673         if(!safeBits)
1674         {
1675             DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits);
1676             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1677             return NULL;
1678         }
1679     }
1680 
1681     _SEH2_TRY
1682     {
1683         if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1);
1684         if(pjInit && (fInit & CBM_INIT))
1685         {
1686             ProbeForRead(pjInit, cjMaxBits, 1);
1687             RtlCopyMemory(safeBits, pjInit, cjMaxBits);
1688         }
1689     }
1690     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1691     {
1692         Status = _SEH2_GetExceptionCode();
1693     }
1694     _SEH2_END;
1695 
1696     if(!NT_SUCCESS(Status))
1697     {
1698         DPRINT1("Got an exception! pjInit = %p\n", pjInit);
1699         SetLastNtError(Status);
1700         goto cleanup;
1701     }
1702 
1703     hbmResult =  GreCreateDIBitmapInternal(hDc,
1704                                            cx,
1705                                            cy,
1706                                            fInit,
1707                                            safeBits,
1708                                            pbmi,
1709                                            iUsage,
1710                                            fl,
1711                                            cjMaxBits,
1712                                            hcmXform);
1713 
1714 cleanup:
1715     if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB);
1716     return hbmResult;
1717 }
1718 
1719 HBITMAP
1720 NTAPI
1721 GreCreateDIBitmapInternal(
1722     IN HDC hDc,
1723     IN INT cx,
1724     IN INT cy,
1725     IN DWORD fInit,
1726     IN OPTIONAL LPBYTE pjInit,
1727     IN OPTIONAL PBITMAPINFO pbmi,
1728     IN DWORD iUsage,
1729     IN FLONG fl,
1730     IN UINT cjMaxBits,
1731     IN HANDLE hcmXform)
1732 {
1733     PDC Dc;
1734     HBITMAP Bmp;
1735     USHORT bpp, planes;
1736     DWORD compression;
1737     HDC hdcDest;
1738 
1739     if (!hDc) /* 1bpp monochrome bitmap */
1740     {
1741         // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
1742         hdcDest = NtGdiCreateCompatibleDC(0);
1743         if(!hdcDest)
1744         {
1745             DPRINT1("NtGdiCreateCompatibleDC failed\n");
1746             return NULL;
1747         }
1748     }
1749     else
1750     {
1751         hdcDest = hDc;
1752     }
1753 
1754     Dc = DC_LockDc(hdcDest);
1755     if (!Dc)
1756     {
1757         DPRINT1("Failed to lock hdcDest %p\n", hdcDest);
1758         EngSetLastError(ERROR_INVALID_HANDLE);
1759         return NULL;
1760     }
1761     /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap
1762      * if bpp != 1 and ignore the real value that was passed */
1763     if (pbmi)
1764     {
1765         if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1766         {
1767             BITMAPCOREHEADER* CoreHeader = (BITMAPCOREHEADER*)&pbmi->bmiHeader;
1768             bpp = CoreHeader->bcBitCount;
1769             planes = CoreHeader->bcPlanes ? CoreHeader->bcPlanes : 1;
1770             compression = BI_RGB;
1771         }
1772         else
1773         {
1774             bpp = pbmi->bmiHeader.biBitCount;
1775             planes = pbmi->bmiHeader.biPlanes ? pbmi->bmiHeader.biPlanes : 1;
1776             compression = pbmi->bmiHeader.biCompression;
1777         }
1778     }
1779     else
1780     {
1781         bpp = 0;
1782         planes = 0;
1783         compression = 0;
1784     }
1785     Bmp = IntCreateDIBitmap(Dc, cx, cy, planes, bpp, compression, fInit, pjInit, cjMaxBits, pbmi, iUsage);
1786     DC_UnlockDc(Dc);
1787 
1788     if(!hDc)
1789     {
1790         NtGdiDeleteObjectApp(hdcDest);
1791     }
1792     return Bmp;
1793 }
1794 
1795 HBITMAP
1796 NTAPI
1797 GreCreateDIBitmapFromPackedDIB(
1798     _In_reads_(cjPackedDIB )PVOID pvPackedDIB,
1799     _In_ UINT cjPackedDIB,
1800     _In_ ULONG uUsage)
1801 {
1802     PBITMAPINFO pbmi;
1803     PBYTE pjBits;
1804     UINT cjInfo, cjBits;
1805     HBITMAP hbm;
1806 
1807     /* We only support BITMAPINFOHEADER, make sure the size is ok */
1808     if (cjPackedDIB < sizeof(BITMAPINFOHEADER))
1809     {
1810         return NULL;
1811     }
1812 
1813     /* The packed DIB starts with the BITMAPINFOHEADER */
1814     pbmi = pvPackedDIB;
1815 
1816     if (cjPackedDIB < pbmi->bmiHeader.biSize)
1817     {
1818         return NULL;
1819     }
1820 
1821     /* Calculate the info size and make sure the packed DIB is large enough */
1822     cjInfo = DIB_BitmapInfoSize(pbmi, uUsage);
1823     if (cjPackedDIB <= cjInfo)
1824     {
1825         return NULL;
1826     }
1827 
1828     /* The bitmap bits start after the header */
1829     pjBits = (PBYTE)pvPackedDIB + cjInfo;
1830     cjBits = cjPackedDIB - cjInfo;
1831 
1832     hbm = GreCreateDIBitmapInternal(NULL,
1833                                     pbmi->bmiHeader.biWidth,
1834                                     abs(pbmi->bmiHeader.biHeight),
1835                                     CBM_INIT | CBM_CREATDIB,
1836                                     pjBits,
1837                                     pbmi,
1838                                     uUsage,
1839                                     0,
1840                                     cjBits,
1841                                     NULL);
1842 
1843     return hbm;
1844 }
1845 
1846 HBITMAP
1847 APIENTRY
1848 NtGdiCreateDIBSection(
1849     IN HDC hDC,
1850     IN OPTIONAL HANDLE hSection,
1851     IN DWORD dwOffset,
1852     IN BITMAPINFO* bmi,
1853     IN DWORD Usage,
1854     IN UINT cjHeader,
1855     IN FLONG fl,
1856     IN ULONG_PTR dwColorSpace,
1857     OUT PVOID *Bits)
1858 {
1859     HBITMAP hbitmap = 0;
1860     DC *dc;
1861     BOOL bDesktopDC = FALSE;
1862     NTSTATUS Status = STATUS_SUCCESS;
1863 
1864     if (!bmi) return hbitmap; // Make sure.
1865 
1866     _SEH2_TRY
1867     {
1868         ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1);
1869         ProbeForRead(bmi, bmi->bmiHeader.biSize, 1);
1870         ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, (WORD)Usage), 1);
1871     }
1872     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1873     {
1874         Status = _SEH2_GetExceptionCode();
1875     }
1876     _SEH2_END;
1877 
1878     if(!NT_SUCCESS(Status))
1879     {
1880         SetLastNtError(Status);
1881         return NULL;
1882     }
1883 
1884     // If the reference hdc is null, take the desktop dc
1885     if (hDC == 0)
1886     {
1887         hDC = NtGdiCreateCompatibleDC(0);
1888         bDesktopDC = TRUE;
1889     }
1890 
1891     if ((dc = DC_LockDc(hDC)))
1892     {
1893         hbitmap = DIB_CreateDIBSection(dc,
1894                                        bmi,
1895                                        Usage,
1896                                        Bits,
1897                                        hSection,
1898                                        dwOffset,
1899                                        0);
1900         DC_UnlockDc(dc);
1901     }
1902     else
1903     {
1904         EngSetLastError(ERROR_INVALID_HANDLE);
1905     }
1906 
1907     if (bDesktopDC)
1908         NtGdiDeleteObjectApp(hDC);
1909 
1910     return hbitmap;
1911 }
1912 
1913 HBITMAP
1914 APIENTRY
1915 DIB_CreateDIBSection(
1916     PDC dc,
1917     CONST BITMAPINFO *bmi,
1918     UINT usage,
1919     LPVOID *bits,
1920     HANDLE section,
1921     DWORD offset,
1922     DWORD ovr_pitch)
1923 {
1924     HBITMAP res = 0;
1925     SURFACE *bmp = NULL;
1926     void *mapBits = NULL;
1927     PPALETTE ppalDIB = NULL;
1928 
1929     // Fill BITMAP32 structure with DIB data
1930     CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1931     INT effHeight;
1932     ULONG totalSize;
1933     BITMAP bm;
1934     //SIZEL Size;
1935     HANDLE hSecure;
1936 
1937     DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n",
1938            bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1939            bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1940 
1941     /* CreateDIBSection should fail for compressed formats */
1942     if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
1943     {
1944         DPRINT1("no compressed format allowed\n");
1945         return (HBITMAP)NULL;
1946     }
1947 
1948     effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1949     bm.bmType = 0;
1950     bm.bmWidth = bi->biWidth;
1951     bm.bmHeight = effHeight;
1952     bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount);
1953 
1954     bm.bmPlanes = bi->biPlanes;
1955     bm.bmBitsPixel = bi->biBitCount;
1956     bm.bmBits = NULL;
1957 
1958     // Get storage location for DIB bits.  Only use biSizeImage if it's valid and
1959     // we're dealing with a compressed bitmap.  Otherwise, use width * height.
1960     totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS))
1961                 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
1962 
1963     if (section)
1964     {
1965         SYSTEM_BASIC_INFORMATION Sbi;
1966         NTSTATUS Status;
1967         DWORD mapOffset;
1968         LARGE_INTEGER SectionOffset;
1969         SIZE_T mapSize;
1970 
1971         Status = ZwQuerySystemInformation(SystemBasicInformation,
1972                                           &Sbi,
1973                                           sizeof Sbi,
1974                                           0);
1975         if (!NT_SUCCESS(Status))
1976         {
1977             DPRINT1("ZwQuerySystemInformation failed (0x%lx)\n", Status);
1978             return NULL;
1979         }
1980 
1981         mapOffset = offset - (offset % Sbi.AllocationGranularity);
1982         mapSize = totalSize + (offset - mapOffset);
1983 
1984         SectionOffset.LowPart  = mapOffset;
1985         SectionOffset.HighPart = 0;
1986 
1987         Status = ZwMapViewOfSection(section,
1988                                     NtCurrentProcess(),
1989                                     &mapBits,
1990                                     0,
1991                                     0,
1992                                     &SectionOffset,
1993                                     &mapSize,
1994                                     ViewShare,
1995                                     0,
1996                                     PAGE_READWRITE);
1997         if (!NT_SUCCESS(Status))
1998         {
1999             DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status);
2000             EngSetLastError(ERROR_INVALID_PARAMETER);
2001             return NULL;
2002         }
2003 
2004         if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
2005     }
2006     else if (ovr_pitch && offset)
2007         bm.bmBits = UlongToPtr(offset);
2008     else
2009     {
2010         offset = 0;
2011         bm.bmBits = EngAllocUserMem(totalSize, 0);
2012         if(!bm.bmBits)
2013         {
2014             DPRINT1("Failed to allocate memory\n");
2015             goto cleanup;
2016         }
2017     }
2018 
2019 //  hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
2020     hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
2021 
2022 
2023     // Create Device Dependent Bitmap and add DIB pointer
2024     //Size.cx = bm.bmWidth;
2025     //Size.cy = abs(bm.bmHeight);
2026     res = GreCreateBitmapEx(bm.bmWidth,
2027                             abs(bm.bmHeight),
2028                             bm.bmWidthBytes,
2029                             BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
2030                             BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
2031                             ((bi->biHeight < 0) ? BMF_TOPDOWN : 0),
2032                             totalSize,
2033                             bm.bmBits,
2034                             0);
2035     if (!res)
2036     {
2037         DPRINT1("GreCreateBitmapEx failed\n");
2038         EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
2039         goto cleanup;
2040     }
2041     bmp = SURFACE_ShareLockSurface(res); // HACK
2042     if (NULL == bmp)
2043     {
2044         DPRINT1("SURFACE_LockSurface failed\n");
2045         EngSetLastError(ERROR_INVALID_HANDLE);
2046         goto cleanup;
2047     }
2048 
2049     /* WINE NOTE: WINE makes use of a colormap, which is a color translation
2050                   table between the DIB and the X physical device. Obviously,
2051                   this is left out of the ReactOS implementation. Instead,
2052                   we call NtGdiSetDIBColorTable. */
2053     bmp->hDIBSection = section;
2054     bmp->hSecure = hSecure;
2055     bmp->dwOffset = offset;
2056     bmp->flags = API_BITMAP;
2057     bmp->biClrImportant = bi->biClrImportant;
2058 
2059     /* Create a palette for the DIB */
2060     ppalDIB = CreateDIBPalette(bmi, dc, usage);
2061 
2062     // Clean up in case of errors
2063 cleanup:
2064     if (!res || !bmp || !bm.bmBits || !ppalDIB)
2065     {
2066         DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
2067         if (bm.bmBits)
2068         {
2069             // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
2070             if (section)
2071             {
2072                 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
2073                 bm.bmBits = NULL;
2074             }
2075             else if (!offset)
2076                 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
2077         }
2078 
2079         if (bmp)
2080         {
2081             SURFACE_ShareUnlockSurface(bmp);
2082             bmp = NULL;
2083         }
2084 
2085         if (res)
2086         {
2087             GreDeleteObject(res);
2088             res = 0;
2089         }
2090 
2091         if(ppalDIB)
2092         {
2093             PALETTE_ShareUnlockPalette(ppalDIB);
2094         }
2095     }
2096 
2097     if (bmp)
2098     {
2099         /* If we're here, everything went fine */
2100         SURFACE_vSetPalette(bmp, ppalDIB);
2101         PALETTE_ShareUnlockPalette(ppalDIB);
2102         SURFACE_ShareUnlockSurface(bmp);
2103     }
2104 
2105     // Return BITMAP handle and storage location
2106     if (NULL != bm.bmBits && NULL != bits)
2107     {
2108         *bits = bm.bmBits;
2109     }
2110 
2111     return res;
2112 }
2113 
2114 /***********************************************************************
2115  *           DIB_GetBitmapInfo
2116  *
2117  * Get the info from a bitmap header.
2118  * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error.
2119  */
2120 int
2121 FASTCALL
2122 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
2123                    LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size )
2124 {
2125     if (header->biSize == sizeof(BITMAPCOREHEADER))
2126     {
2127         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
2128         *width  = core->bcWidth;
2129         *height = core->bcHeight;
2130         *planes = core->bcPlanes;
2131         *bpp    = core->bcBitCount;
2132         *compr  = BI_RGB;
2133         *size   = 0;
2134         return 0;
2135     }
2136     if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* Assume BITMAPINFOHEADER */
2137     {
2138         *width  = header->biWidth;
2139         *height = header->biHeight;
2140         *planes = header->biPlanes;
2141         *bpp    = header->biBitCount;
2142         *compr  = header->biCompression;
2143         *size   = header->biSizeImage;
2144         return 1;
2145     }
2146     DPRINT1("(%u): unknown/wrong size for header\n", header->biSize );
2147     return -1;
2148 }
2149 
2150 /***********************************************************************
2151  *           DIB_GetDIBImageBytes
2152  *
2153  * Return the number of bytes used to hold the image in a DIB bitmap.
2154  * 11/16/1999 (RJJ) lifted from wine
2155  */
2156 
2157 INT APIENTRY DIB_GetDIBImageBytes(INT  width, INT height, INT depth)
2158 {
2159     return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height);
2160 }
2161 
2162 /***********************************************************************
2163  *           DIB_BitmapInfoSize
2164  *
2165  * Return the size of the bitmap info structure including color table.
2166  * 11/16/1999 (RJJ) lifted from wine
2167  */
2168 
2169 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
2170 {
2171     unsigned int colors, size, masks = 0;
2172     unsigned int colorsize;
2173 
2174     colorsize = (coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) :
2175                 (coloruse == DIB_PAL_INDICES) ? 0 :
2176                 sizeof(WORD);
2177 
2178     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
2179     {
2180         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
2181         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
2182         return sizeof(BITMAPCOREHEADER) + colors * colorsize;
2183     }
2184     else  /* Assume BITMAPINFOHEADER */
2185     {
2186         colors = info->bmiHeader.biClrUsed;
2187         if (colors > 256) colors = 256;
2188         if (!colors && (info->bmiHeader.biBitCount <= 8))
2189             colors = 1 << info->bmiHeader.biBitCount;
2190         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
2191         size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
2192         return size + colors * colorsize;
2193     }
2194 }
2195 
2196 HPALETTE
2197 FASTCALL
2198 DIB_MapPaletteColors(PPALETTE ppalDc, CONST BITMAPINFO* lpbmi)
2199 {
2200     PPALETTE ppalNew;
2201     ULONG nNumColors,i;
2202     USHORT *lpIndex;
2203     HPALETTE hpal;
2204 
2205     if (!(ppalDc->flFlags & PAL_INDEXED))
2206     {
2207         return NULL;
2208     }
2209 
2210     nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
2211     if (lpbmi->bmiHeader.biClrUsed)
2212     {
2213         nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
2214     }
2215 
2216     ppalNew = PALETTE_AllocPalWithHandle(PAL_INDEXED, nNumColors, NULL, 0, 0, 0);
2217     if (ppalNew == NULL)
2218     {
2219         DPRINT1("Could not allocate palette\n");
2220         return NULL;
2221     }
2222 
2223     lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize);
2224 
2225     for (i = 0; i < nNumColors; i++)
2226     {
2227         ULONG iColorIndex = *lpIndex % ppalDc->NumColors;
2228         ppalNew->IndexedColors[i] = ppalDc->IndexedColors[iColorIndex];
2229         lpIndex++;
2230     }
2231 
2232     hpal = ppalNew->BaseObject.hHmgr;
2233     PALETTE_UnlockPalette(ppalNew);
2234 
2235     return hpal;
2236 }
2237 
2238 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure,
2239  * or does nothing if it's already a BITMAPINFO (or V4 or V5) */
2240 BITMAPINFO*
2241 FASTCALL
2242 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage)
2243 {
2244     CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi;
2245     BITMAPINFO* pNewBmi ;
2246     UINT numColors = 0, ColorsSize = 0;
2247 
2248     if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi;
2249     if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL;
2250 
2251     if(pbmci->bmciHeader.bcBitCount <= 8)
2252     {
2253         numColors = 1 << pbmci->bmciHeader.bcBitCount;
2254         if(Usage == DIB_PAL_COLORS)
2255         {
2256             ColorsSize = numColors * sizeof(WORD);
2257         }
2258         else
2259         {
2260             ColorsSize = numColors * sizeof(RGBQUAD);
2261         }
2262     }
2263     else if (Usage == DIB_PAL_COLORS)
2264     {
2265         /* Invalid at high-res */
2266         return NULL;
2267     }
2268 
2269     pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB);
2270     if(!pNewBmi) return NULL;
2271 
2272     RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize);
2273 
2274     pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2275     pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount;
2276     pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth;
2277     pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight;
2278     pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes;
2279     pNewBmi->bmiHeader.biCompression = BI_RGB ;
2280     pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth,
2281                                      pNewBmi->bmiHeader.biHeight,
2282                                      pNewBmi->bmiHeader.biBitCount);
2283     pNewBmi->bmiHeader.biClrUsed = numColors;
2284 
2285     if(Usage == DIB_PAL_COLORS)
2286     {
2287         RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize);
2288     }
2289     else
2290     {
2291         UINT i;
2292         for(i=0; i<numColors; i++)
2293         {
2294             pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed;
2295             pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen;
2296             pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue;
2297         }
2298     }
2299 
2300     return pNewBmi ;
2301 }
2302 
2303 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */
2304 VOID
2305 FASTCALL
2306 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage)
2307 {
2308     BITMAPCOREINFO* pbmci;
2309     if(converted == orig)
2310         return;
2311 
2312     if(usage == -1)
2313     {
2314         /* Caller don't want any conversion */
2315         ExFreePoolWithTag(converted, TAG_DIB);
2316         return;
2317     }
2318 
2319     /* Perform inverse conversion */
2320     pbmci = (BITMAPCOREINFO*)orig;
2321 
2322     ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER));
2323     pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount;
2324     pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth;
2325     pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight;
2326     pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes;
2327 
2328     if(pbmci->bmciHeader.bcBitCount <= 8)
2329     {
2330         UINT numColors = converted->bmiHeader.biClrUsed;
2331         if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount;
2332         if(usage == DIB_PAL_COLORS)
2333         {
2334             RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD));
2335             RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD));
2336         }
2337         else
2338         {
2339             UINT i;
2340             RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE));
2341             for(i=0; i<numColors; i++)
2342             {
2343                 pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed;
2344                 pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen;
2345                 pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue;
2346             }
2347         }
2348     }
2349     /* Now free it, it's not needed anymore */
2350     ExFreePoolWithTag(converted, TAG_DIB);
2351 }
2352 
2353 /* EOF */
2354