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