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