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