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