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