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