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