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