xref: /reactos/win32ss/gdi/ntgdi/dibobj.c (revision 1734f297)
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             if (Palette == NULL)
1582             {
1583                 SURFACE_ShareUnlockSurface(Surface);
1584                 GreDeleteObject(handle);
1585                 return NULL;
1586             }
1587 
1588             SURFACE_vSetPalette(Surface, Palette);
1589 
1590             PALETTE_ShareUnlockPalette(Palette);
1591             SURFACE_ShareUnlockSurface(Surface);
1592         }
1593         else
1594         {
1595             /* Create a regular compatible bitmap, in the same format as the device */
1596             handle = IntCreateCompatibleBitmap(Dc, width, height, 0, 0);
1597         }
1598     }
1599     else
1600     {
1601         handle = GreCreateBitmap(width,
1602                                  abs(height),
1603                                  1,
1604                                  1,
1605                                  NULL);
1606     }
1607 
1608     if (height < 0)
1609         height = -height;
1610 
1611     if ((NULL != handle) && (CBM_INIT & init))
1612     {
1613         IntSetDIBits(Dc, handle, 0, height, bits, cjMaxBits, data, coloruse);
1614     }
1615 
1616     return handle;
1617 }
1618 
1619 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
1620 // The DDB that is created will be whatever bit depth your reference DC is
1621 HBITMAP
1622 APIENTRY
1623 NtGdiCreateDIBitmapInternal(
1624     IN HDC hDc,
1625     IN INT cx,
1626     IN INT cy,
1627     IN DWORD fInit,
1628     IN OPTIONAL LPBYTE pjInit,
1629     IN OPTIONAL LPBITMAPINFO pbmi,
1630     IN DWORD iUsage,
1631     IN UINT cjMaxInitInfo,
1632     IN UINT cjMaxBits,
1633     IN FLONG fl,
1634     IN HANDLE hcmXform)
1635 {
1636     NTSTATUS Status = STATUS_SUCCESS;
1637     PBYTE safeBits = NULL;
1638     HBITMAP hbmResult = NULL;
1639 
1640     if (pjInit == NULL)
1641     {
1642         fInit &= ~CBM_INIT;
1643     }
1644 
1645     if(pjInit && (fInit & CBM_INIT))
1646     {
1647         if (cjMaxBits == 0) return NULL;
1648         safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
1649         if(!safeBits)
1650         {
1651             DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits);
1652             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1653             return NULL;
1654         }
1655     }
1656 
1657     _SEH2_TRY
1658     {
1659         if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1);
1660         if(pjInit && (fInit & CBM_INIT))
1661         {
1662             ProbeForRead(pjInit, cjMaxBits, 1);
1663             RtlCopyMemory(safeBits, pjInit, cjMaxBits);
1664         }
1665     }
1666     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1667     {
1668         Status = _SEH2_GetExceptionCode();
1669     }
1670     _SEH2_END;
1671 
1672     if(!NT_SUCCESS(Status))
1673     {
1674         DPRINT1("Got an exception! pjInit = %p\n", pjInit);
1675         SetLastNtError(Status);
1676         goto cleanup;
1677     }
1678 
1679     hbmResult =  GreCreateDIBitmapInternal(hDc,
1680                                            cx,
1681                                            cy,
1682                                            fInit,
1683                                            safeBits,
1684                                            pbmi,
1685                                            iUsage,
1686                                            fl,
1687                                            cjMaxBits,
1688                                            hcmXform);
1689 
1690 cleanup:
1691     if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB);
1692     return hbmResult;
1693 }
1694 
1695 HBITMAP
1696 NTAPI
1697 GreCreateDIBitmapInternal(
1698     IN HDC hDc,
1699     IN INT cx,
1700     IN INT cy,
1701     IN DWORD fInit,
1702     IN OPTIONAL LPBYTE pjInit,
1703     IN OPTIONAL PBITMAPINFO pbmi,
1704     IN DWORD iUsage,
1705     IN FLONG fl,
1706     IN UINT cjMaxBits,
1707     IN HANDLE hcmXform)
1708 {
1709     PDC Dc;
1710     HBITMAP Bmp;
1711     USHORT bpp, planes;
1712     DWORD compression;
1713     HDC hdcDest;
1714 
1715     if (!hDc) /* 1bpp monochrome bitmap */
1716     {
1717         // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
1718         hdcDest = NtGdiCreateCompatibleDC(0);
1719         if(!hdcDest)
1720         {
1721             DPRINT1("NtGdiCreateCompatibleDC failed\n");
1722             return NULL;
1723         }
1724     }
1725     else
1726     {
1727         hdcDest = hDc;
1728     }
1729 
1730     Dc = DC_LockDc(hdcDest);
1731     if (!Dc)
1732     {
1733         DPRINT1("Failed to lock hdcDest %p\n", hdcDest);
1734         EngSetLastError(ERROR_INVALID_HANDLE);
1735         return NULL;
1736     }
1737     /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap
1738      * if bpp != 1 and ignore the real value that was passed */
1739     if (pbmi)
1740     {
1741         if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1742         {
1743             BITMAPCOREHEADER* CoreHeader = (BITMAPCOREHEADER*)&pbmi->bmiHeader;
1744             bpp = CoreHeader->bcBitCount;
1745             planes = CoreHeader->bcPlanes ? CoreHeader->bcPlanes : 1;
1746             compression = BI_RGB;
1747         }
1748         else
1749         {
1750             bpp = pbmi->bmiHeader.biBitCount;
1751             planes = pbmi->bmiHeader.biPlanes ? pbmi->bmiHeader.biPlanes : 1;
1752             compression = pbmi->bmiHeader.biCompression;
1753         }
1754     }
1755     else
1756     {
1757         bpp = 0;
1758         planes = 0;
1759         compression = 0;
1760     }
1761     Bmp = IntCreateDIBitmap(Dc, cx, cy, planes, bpp, compression, fInit, pjInit, cjMaxBits, pbmi, iUsage);
1762     DC_UnlockDc(Dc);
1763 
1764     if(!hDc)
1765     {
1766         NtGdiDeleteObjectApp(hdcDest);
1767     }
1768     return Bmp;
1769 }
1770 
1771 HBITMAP
1772 NTAPI
1773 GreCreateDIBitmapFromPackedDIB(
1774     _In_reads_(cjPackedDIB )PVOID pvPackedDIB,
1775     _In_ UINT cjPackedDIB,
1776     _In_ ULONG uUsage)
1777 {
1778     PBITMAPINFO pbmi;
1779     PBYTE pjBits;
1780     UINT cjInfo, cjBits;
1781     HBITMAP hbm;
1782 
1783     /* We only support BITMAPINFOHEADER, make sure the size is ok */
1784     if (cjPackedDIB < sizeof(BITMAPINFOHEADER))
1785     {
1786         return NULL;
1787     }
1788 
1789     /* The packed DIB starts with the BITMAPINFOHEADER */
1790     pbmi = pvPackedDIB;
1791 
1792     if (cjPackedDIB < pbmi->bmiHeader.biSize)
1793     {
1794         return NULL;
1795     }
1796 
1797     /* Calculate the info size and make sure the packed DIB is large enough */
1798     cjInfo = DIB_BitmapInfoSize(pbmi, uUsage);
1799     if (cjPackedDIB <= cjInfo)
1800     {
1801         return NULL;
1802     }
1803 
1804     /* The bitmap bits start after the header */
1805     pjBits = (PBYTE)pvPackedDIB + cjInfo;
1806     cjBits = cjPackedDIB - cjInfo;
1807 
1808     hbm = GreCreateDIBitmapInternal(NULL,
1809                                     pbmi->bmiHeader.biWidth,
1810                                     abs(pbmi->bmiHeader.biHeight),
1811                                     CBM_INIT | CBM_CREATDIB,
1812                                     pjBits,
1813                                     pbmi,
1814                                     uUsage,
1815                                     0,
1816                                     cjBits,
1817                                     NULL);
1818 
1819     return hbm;
1820 }
1821 
1822 HBITMAP
1823 APIENTRY
1824 NtGdiCreateDIBSection(
1825     IN HDC hDC,
1826     IN OPTIONAL HANDLE hSection,
1827     IN DWORD dwOffset,
1828     IN BITMAPINFO* bmi,
1829     IN DWORD Usage,
1830     IN UINT cjHeader,
1831     IN FLONG fl,
1832     IN ULONG_PTR dwColorSpace,
1833     OUT PVOID *Bits)
1834 {
1835     HBITMAP hbitmap = 0;
1836     DC *dc;
1837     BOOL bDesktopDC = FALSE;
1838     NTSTATUS Status = STATUS_SUCCESS;
1839 
1840     if (!bmi) return hbitmap; // Make sure.
1841 
1842     _SEH2_TRY
1843     {
1844         ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1);
1845         ProbeForRead(bmi, bmi->bmiHeader.biSize, 1);
1846         ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, (WORD)Usage), 1);
1847     }
1848     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1849     {
1850         Status = _SEH2_GetExceptionCode();
1851     }
1852     _SEH2_END;
1853 
1854     if(!NT_SUCCESS(Status))
1855     {
1856         SetLastNtError(Status);
1857         return NULL;
1858     }
1859 
1860     // If the reference hdc is null, take the desktop dc
1861     if (hDC == 0)
1862     {
1863         hDC = NtGdiCreateCompatibleDC(0);
1864         bDesktopDC = TRUE;
1865     }
1866 
1867     if ((dc = DC_LockDc(hDC)))
1868     {
1869         hbitmap = DIB_CreateDIBSection(dc,
1870                                        bmi,
1871                                        Usage,
1872                                        Bits,
1873                                        hSection,
1874                                        dwOffset,
1875                                        0);
1876         DC_UnlockDc(dc);
1877     }
1878     else
1879     {
1880         EngSetLastError(ERROR_INVALID_HANDLE);
1881     }
1882 
1883     if (bDesktopDC)
1884         NtGdiDeleteObjectApp(hDC);
1885 
1886     return hbitmap;
1887 }
1888 
1889 HBITMAP
1890 APIENTRY
1891 DIB_CreateDIBSection(
1892     PDC dc,
1893     CONST BITMAPINFO *bmi,
1894     UINT usage,
1895     LPVOID *bits,
1896     HANDLE section,
1897     DWORD offset,
1898     DWORD ovr_pitch)
1899 {
1900     HBITMAP res = 0;
1901     SURFACE *bmp = NULL;
1902     void *mapBits = NULL;
1903     PPALETTE ppalDIB = NULL;
1904 
1905     // Fill BITMAP32 structure with DIB data
1906     CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1907     INT effHeight;
1908     ULONG totalSize;
1909     BITMAP bm;
1910     //SIZEL Size;
1911     HANDLE hSecure;
1912 
1913     DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n",
1914            bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1915            bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1916 
1917     /* CreateDIBSection should fail for compressed formats */
1918     if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
1919     {
1920         DPRINT1("no compressed format allowed\n");
1921         return (HBITMAP)NULL;
1922     }
1923 
1924     effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1925     bm.bmType = 0;
1926     bm.bmWidth = bi->biWidth;
1927     bm.bmHeight = effHeight;
1928     bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount);
1929 
1930     bm.bmPlanes = bi->biPlanes;
1931     bm.bmBitsPixel = bi->biBitCount;
1932     bm.bmBits = NULL;
1933 
1934     // Get storage location for DIB bits.  Only use biSizeImage if it's valid and
1935     // we're dealing with a compressed bitmap.  Otherwise, use width * height.
1936     totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS))
1937                 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
1938 
1939     if (section)
1940     {
1941         SYSTEM_BASIC_INFORMATION Sbi;
1942         NTSTATUS Status;
1943         DWORD mapOffset;
1944         LARGE_INTEGER SectionOffset;
1945         SIZE_T mapSize;
1946 
1947         Status = ZwQuerySystemInformation(SystemBasicInformation,
1948                                           &Sbi,
1949                                           sizeof Sbi,
1950                                           0);
1951         if (!NT_SUCCESS(Status))
1952         {
1953             DPRINT1("ZwQuerySystemInformation failed (0x%lx)\n", Status);
1954             return NULL;
1955         }
1956 
1957         mapOffset = offset - (offset % Sbi.AllocationGranularity);
1958         mapSize = totalSize + (offset - mapOffset);
1959 
1960         SectionOffset.LowPart  = mapOffset;
1961         SectionOffset.HighPart = 0;
1962 
1963         Status = ZwMapViewOfSection(section,
1964                                     NtCurrentProcess(),
1965                                     &mapBits,
1966                                     0,
1967                                     0,
1968                                     &SectionOffset,
1969                                     &mapSize,
1970                                     ViewShare,
1971                                     0,
1972                                     PAGE_READWRITE);
1973         if (!NT_SUCCESS(Status))
1974         {
1975             DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status);
1976             EngSetLastError(ERROR_INVALID_PARAMETER);
1977             return NULL;
1978         }
1979 
1980         if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
1981     }
1982     else if (ovr_pitch && offset)
1983         bm.bmBits = UlongToPtr(offset);
1984     else
1985     {
1986         offset = 0;
1987         bm.bmBits = EngAllocUserMem(totalSize, 0);
1988         if(!bm.bmBits)
1989         {
1990             DPRINT1("Failed to allocate memory\n");
1991             goto cleanup;
1992         }
1993     }
1994 
1995 //  hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
1996     hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
1997 
1998 
1999     // Create Device Dependent Bitmap and add DIB pointer
2000     //Size.cx = bm.bmWidth;
2001     //Size.cy = abs(bm.bmHeight);
2002     res = GreCreateBitmapEx(bm.bmWidth,
2003                             abs(bm.bmHeight),
2004                             bm.bmWidthBytes,
2005                             BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
2006                             BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
2007                             ((bi->biHeight < 0) ? BMF_TOPDOWN : 0),
2008                             totalSize,
2009                             bm.bmBits,
2010                             0);
2011     if (!res)
2012     {
2013         DPRINT1("GreCreateBitmapEx failed\n");
2014         EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
2015         goto cleanup;
2016     }
2017     bmp = SURFACE_ShareLockSurface(res); // HACK
2018     if (NULL == bmp)
2019     {
2020         DPRINT1("SURFACE_LockSurface failed\n");
2021         EngSetLastError(ERROR_INVALID_HANDLE);
2022         goto cleanup;
2023     }
2024 
2025     /* WINE NOTE: WINE makes use of a colormap, which is a color translation
2026                   table between the DIB and the X physical device. Obviously,
2027                   this is left out of the ReactOS implementation. Instead,
2028                   we call NtGdiSetDIBColorTable. */
2029     bmp->hDIBSection = section;
2030     bmp->hSecure = hSecure;
2031     bmp->dwOffset = offset;
2032     bmp->flags = API_BITMAP;
2033     bmp->biClrImportant = bi->biClrImportant;
2034 
2035     /* Create a palette for the DIB */
2036     ppalDIB = CreateDIBPalette(bmi, dc, usage);
2037 
2038     // Clean up in case of errors
2039 cleanup:
2040     if (!res || !bmp || !bm.bmBits || !ppalDIB)
2041     {
2042         DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
2043         if (bm.bmBits)
2044         {
2045             // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
2046             if (section)
2047             {
2048                 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
2049                 bm.bmBits = NULL;
2050             }
2051             else if (!offset)
2052                 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
2053         }
2054 
2055         if (bmp)
2056         {
2057             SURFACE_ShareUnlockSurface(bmp);
2058             bmp = NULL;
2059         }
2060 
2061         if (res)
2062         {
2063             GreDeleteObject(res);
2064             res = 0;
2065         }
2066 
2067         if(ppalDIB)
2068         {
2069             PALETTE_ShareUnlockPalette(ppalDIB);
2070         }
2071     }
2072 
2073     if (bmp)
2074     {
2075         /* If we're here, everything went fine */
2076         SURFACE_vSetPalette(bmp, ppalDIB);
2077         PALETTE_ShareUnlockPalette(ppalDIB);
2078         SURFACE_ShareUnlockSurface(bmp);
2079     }
2080 
2081     // Return BITMAP handle and storage location
2082     if (NULL != bm.bmBits && NULL != bits)
2083     {
2084         *bits = bm.bmBits;
2085     }
2086 
2087     return res;
2088 }
2089 
2090 /***********************************************************************
2091  *           DIB_GetBitmapInfo
2092  *
2093  * Get the info from a bitmap header.
2094  * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error.
2095  */
2096 int
2097 FASTCALL
2098 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
2099                    LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size )
2100 {
2101     if (header->biSize == sizeof(BITMAPCOREHEADER))
2102     {
2103         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
2104         *width  = core->bcWidth;
2105         *height = core->bcHeight;
2106         *planes = core->bcPlanes;
2107         *bpp    = core->bcBitCount;
2108         *compr  = BI_RGB;
2109         *size   = 0;
2110         return 0;
2111     }
2112     if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* Assume BITMAPINFOHEADER */
2113     {
2114         *width  = header->biWidth;
2115         *height = header->biHeight;
2116         *planes = header->biPlanes;
2117         *bpp    = header->biBitCount;
2118         *compr  = header->biCompression;
2119         *size   = header->biSizeImage;
2120         return 1;
2121     }
2122     DPRINT1("(%u): unknown/wrong size for header\n", header->biSize );
2123     return -1;
2124 }
2125 
2126 /***********************************************************************
2127  *           DIB_GetDIBImageBytes
2128  *
2129  * Return the number of bytes used to hold the image in a DIB bitmap.
2130  * 11/16/1999 (RJJ) lifted from wine
2131  */
2132 
2133 INT APIENTRY DIB_GetDIBImageBytes(INT  width, INT height, INT depth)
2134 {
2135     return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height);
2136 }
2137 
2138 /***********************************************************************
2139  *           DIB_BitmapInfoSize
2140  *
2141  * Return the size of the bitmap info structure including color table.
2142  * 11/16/1999 (RJJ) lifted from wine
2143  */
2144 
2145 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
2146 {
2147     unsigned int colors, size, masks = 0;
2148     unsigned int colorsize;
2149 
2150     colorsize = (coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) :
2151                 (coloruse == DIB_PAL_INDICES) ? 0 :
2152                 sizeof(WORD);
2153 
2154     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
2155     {
2156         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
2157         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
2158         return sizeof(BITMAPCOREHEADER) + colors * colorsize;
2159     }
2160     else  /* Assume BITMAPINFOHEADER */
2161     {
2162         colors = info->bmiHeader.biClrUsed;
2163         if (colors > 256) colors = 256;
2164         if (!colors && (info->bmiHeader.biBitCount <= 8))
2165             colors = 1 << info->bmiHeader.biBitCount;
2166         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
2167         size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
2168         return size + colors * colorsize;
2169     }
2170 }
2171 
2172 HPALETTE
2173 FASTCALL
2174 DIB_MapPaletteColors(PPALETTE ppalDc, CONST BITMAPINFO* lpbmi)
2175 {
2176     PPALETTE ppalNew;
2177     ULONG nNumColors,i;
2178     USHORT *lpIndex;
2179     HPALETTE hpal;
2180 
2181     if (!(ppalDc->flFlags & PAL_INDEXED))
2182     {
2183         return NULL;
2184     }
2185 
2186     nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
2187     if (lpbmi->bmiHeader.biClrUsed)
2188     {
2189         nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
2190     }
2191 
2192     ppalNew = PALETTE_AllocPalWithHandle(PAL_INDEXED, nNumColors, NULL, 0, 0, 0);
2193     if (ppalNew == NULL)
2194     {
2195         DPRINT1("Could not allocate palette\n");
2196         return NULL;
2197     }
2198 
2199     lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize);
2200 
2201     for (i = 0; i < nNumColors; i++)
2202     {
2203         ULONG iColorIndex = *lpIndex % ppalDc->NumColors;
2204         ppalNew->IndexedColors[i] = ppalDc->IndexedColors[iColorIndex];
2205         lpIndex++;
2206     }
2207 
2208     hpal = ppalNew->BaseObject.hHmgr;
2209     PALETTE_UnlockPalette(ppalNew);
2210 
2211     return hpal;
2212 }
2213 
2214 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure,
2215  * or does nothing if it's already a BITMAPINFO (or V4 or V5) */
2216 BITMAPINFO*
2217 FASTCALL
2218 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage)
2219 {
2220     CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi;
2221     BITMAPINFO* pNewBmi ;
2222     UINT numColors = 0, ColorsSize = 0;
2223 
2224     if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi;
2225     if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL;
2226 
2227     if(pbmci->bmciHeader.bcBitCount <= 8)
2228     {
2229         numColors = 1 << pbmci->bmciHeader.bcBitCount;
2230         if(Usage == DIB_PAL_COLORS)
2231         {
2232             ColorsSize = numColors * sizeof(WORD);
2233         }
2234         else
2235         {
2236             ColorsSize = numColors * sizeof(RGBQUAD);
2237         }
2238     }
2239     else if (Usage == DIB_PAL_COLORS)
2240     {
2241         /* Invalid at high-res */
2242         return NULL;
2243     }
2244 
2245     pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB);
2246     if(!pNewBmi) return NULL;
2247 
2248     RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize);
2249 
2250     pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2251     pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount;
2252     pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth;
2253     pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight;
2254     pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes;
2255     pNewBmi->bmiHeader.biCompression = BI_RGB ;
2256     pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth,
2257                                      pNewBmi->bmiHeader.biHeight,
2258                                      pNewBmi->bmiHeader.biBitCount);
2259     pNewBmi->bmiHeader.biClrUsed = numColors;
2260 
2261     if(Usage == DIB_PAL_COLORS)
2262     {
2263         RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize);
2264     }
2265     else
2266     {
2267         UINT i;
2268         for(i=0; i<numColors; i++)
2269         {
2270             pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed;
2271             pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen;
2272             pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue;
2273         }
2274     }
2275 
2276     return pNewBmi ;
2277 }
2278 
2279 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */
2280 VOID
2281 FASTCALL
2282 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage)
2283 {
2284     BITMAPCOREINFO* pbmci;
2285     if(converted == orig)
2286         return;
2287 
2288     if(usage == -1)
2289     {
2290         /* Caller don't want any conversion */
2291         ExFreePoolWithTag(converted, TAG_DIB);
2292         return;
2293     }
2294 
2295     /* Perform inverse conversion */
2296     pbmci = (BITMAPCOREINFO*)orig;
2297 
2298     ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER));
2299     pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount;
2300     pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth;
2301     pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight;
2302     pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes;
2303 
2304     if(pbmci->bmciHeader.bcBitCount <= 8)
2305     {
2306         UINT numColors = converted->bmiHeader.biClrUsed;
2307         if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount;
2308         if(usage == DIB_PAL_COLORS)
2309         {
2310             RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD));
2311             RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD));
2312         }
2313         else
2314         {
2315             UINT i;
2316             RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE));
2317             for(i=0; i<numColors; i++)
2318             {
2319                 pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed;
2320                 pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen;
2321                 pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue;
2322             }
2323         }
2324     }
2325     /* Now free it, it's not needed anymore */
2326     ExFreePoolWithTag(converted, TAG_DIB);
2327 }
2328 
2329 /* EOF */
2330