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