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