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