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