[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / dibobj.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: 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, rcDest);
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->rosdc.CombinedClip,
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, ScanLines, psurf->SurfObj.sizlBitmap.cx);
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 /* Transform dest size */
1075 sizel.cx = cxDst;
1076 sizel.cy = cyDst;
1077 IntLPtoDP(pdc, (POINTL*)&sizel, 1);
1078 DC_UnlockDc(pdc);
1079
1080 /* Check if we can use NtGdiSetDIBitsToDeviceInternal */
1081 if (sizel.cx == cxSrc && sizel.cy == cySrc && dwRop == SRCCOPY)
1082 {
1083 /* Yes, we can! */
1084 return NtGdiSetDIBitsToDeviceInternal(hdc,
1085 xDst,
1086 yDst,
1087 cxDst,
1088 cyDst,
1089 xSrc,
1090 ySrc,
1091 0,
1092 cySrc,
1093 pjInit,
1094 pbmi,
1095 dwUsage,
1096 cjMaxBits,
1097 cjMaxInfo,
1098 TRUE,
1099 hcmXform);
1100 }
1101
1102 pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, 'pmeT');
1103 if (!pvBits)
1104 {
1105 return 0;
1106 }
1107
1108 _SEH2_TRY
1109 {
1110 ProbeForRead(pjInit, cjMaxBits, 1);
1111 RtlCopyMemory(pvBits, pjInit, cjMaxBits);
1112 }
1113 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1114 {
1115 _SEH2_YIELD(return 0);
1116 }
1117 _SEH2_END
1118
1119 /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */
1120 if (!(pdc = DC_LockDc(hdc)))
1121 {
1122 DPRINT1("Could not lock dc\n");
1123 EngSetLastError(ERROR_INVALID_HANDLE);
1124 goto cleanup;
1125 }
1126
1127 /* Calculate source and destination rect */
1128 rcSrc.left = xSrc;
1129 rcSrc.top = ySrc;
1130 rcSrc.right = xSrc + abs(cxSrc);
1131 rcSrc.bottom = ySrc + abs(cySrc);
1132 rcDst.left = xDst;
1133 rcDst.top = yDst;
1134 rcDst.right = rcDst.left + cxDst;
1135 rcDst.bottom = rcDst.top + cyDst;
1136 IntLPtoDP(pdc, (POINTL*)&rcDst, 2);
1137 RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1138
1139 hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth,
1140 pbmi->bmiHeader.biHeight,
1141 0,
1142 BitmapFormat(pbmi->bmiHeader.biBitCount,
1143 pbmi->bmiHeader.biCompression),
1144 pbmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
1145 pbmi->bmiHeader.biSizeImage,
1146 pvBits,
1147 0);
1148
1149 if (!hbmTmp)
1150 {
1151 bResult = FALSE;
1152 goto cleanup;
1153 }
1154
1155 psurfTmp = SURFACE_ShareLockSurface(hbmTmp);
1156 if (!psurfTmp)
1157 {
1158 bResult = FALSE;
1159 goto cleanup;
1160 }
1161
1162 /* Create a palette for the DIB */
1163 ppalDIB = CreateDIBPalette(pbmi, pdc, dwUsage);
1164 if (!ppalDIB)
1165 {
1166 bResult = FALSE;
1167 goto cleanup;
1168 }
1169
1170 /* Prepare DC for blit */
1171 DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcSrc);
1172
1173 psurfDst = pdc->dclevel.pSurface;
1174 if (!psurfDst)
1175 {
1176 DC_vFinishBlit(pdc, NULL);
1177 // CHECKME
1178 bResult = TRUE;
1179 goto cleanup;
1180 }
1181
1182 /* Initialize XLATEOBJ */
1183 EXLATEOBJ_vInitialize(&exlo,
1184 ppalDIB,
1185 psurfDst->ppal,
1186 RGB(0xff, 0xff, 0xff),
1187 pdc->pdcattr->crBackgroundClr,
1188 pdc->pdcattr->crForegroundClr);
1189
1190 /* Perform the stretch operation */
1191 bResult = IntEngStretchBlt(&psurfDst->SurfObj,
1192 &psurfTmp->SurfObj,
1193 NULL,
1194 pdc->rosdc.CombinedClip,
1195 &exlo.xlo,
1196 &pdc->dclevel.ca,
1197 &rcDst,
1198 &rcSrc,
1199 NULL,
1200 &pdc->eboFill.BrushObject,
1201 NULL,
1202 ROP_TO_ROP4(dwRop));
1203
1204 /* Cleanup */
1205 DC_vFinishBlit(pdc, NULL);
1206 EXLATEOBJ_vCleanup(&exlo);
1207 cleanup:
1208 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
1209 if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp);
1210 if (hbmTmp) GreDeleteObject(hbmTmp);
1211 if (pdc) DC_UnlockDc(pdc);
1212 ExFreePoolWithTag(pvBits, 'pmeT');
1213
1214 return bResult;
1215 }
1216
1217
1218 HBITMAP
1219 FASTCALL
1220 IntCreateDIBitmap(
1221 PDC Dc,
1222 INT width,
1223 INT height,
1224 UINT bpp,
1225 DWORD init,
1226 LPBYTE bits,
1227 PBITMAPINFO data,
1228 DWORD coloruse)
1229 {
1230 HBITMAP handle;
1231 BOOL fColor;
1232
1233 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
1234 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
1235
1236 if (bpp != 1) fColor = TRUE;
1237 else if ((coloruse != DIB_RGB_COLORS) || (init != CBM_INIT) || !data) fColor = FALSE;
1238 else
1239 {
1240 const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize);
1241 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1242
1243 // Check if the first color of the colormap is black
1244 if ((col == RGB(0, 0, 0)))
1245 {
1246 rgb++;
1247 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1248
1249 // If the second color is white, create a monochrome bitmap
1250 fColor = (col != RGB(0xff,0xff,0xff));
1251 }
1252 else fColor = TRUE;
1253 }
1254
1255 // Now create the bitmap
1256 if (fColor)
1257 {
1258 handle = IntCreateCompatibleBitmap(Dc, width, height);
1259 }
1260 else
1261 {
1262 handle = GreCreateBitmap(width,
1263 height,
1264 1,
1265 1,
1266 NULL);
1267 }
1268
1269 if (height < 0)
1270 height = -height;
1271
1272 if (NULL != handle && CBM_INIT == init)
1273 {
1274 IntSetDIBits(Dc, handle, 0, height, bits, data, coloruse);
1275 }
1276
1277 return handle;
1278 }
1279
1280 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
1281 // The DDB that is created will be whatever bit depth your reference DC is
1282 HBITMAP
1283 APIENTRY
1284 NtGdiCreateDIBitmapInternal(
1285 IN HDC hDc,
1286 IN INT cx,
1287 IN INT cy,
1288 IN DWORD fInit,
1289 IN OPTIONAL LPBYTE pjInit,
1290 IN OPTIONAL LPBITMAPINFO pbmi,
1291 IN DWORD iUsage,
1292 IN UINT cjMaxInitInfo,
1293 IN UINT cjMaxBits,
1294 IN FLONG fl,
1295 IN HANDLE hcmXform)
1296 {
1297 NTSTATUS Status = STATUS_SUCCESS;
1298 PBYTE safeBits = NULL;
1299 HBITMAP hbmResult = NULL;
1300
1301 if(pjInit && (fInit == CBM_INIT))
1302 {
1303 if (cjMaxBits == 0) return NULL;
1304 safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
1305 if(!safeBits)
1306 {
1307 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1308 return NULL;
1309 }
1310 }
1311
1312 _SEH2_TRY
1313 {
1314 if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1);
1315 if(pjInit && (fInit == CBM_INIT))
1316 {
1317 ProbeForRead(pjInit, cjMaxBits, 1);
1318 RtlCopyMemory(safeBits, pjInit, cjMaxBits);
1319 }
1320 }
1321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1322 {
1323 Status = _SEH2_GetExceptionCode();
1324 }
1325 _SEH2_END
1326
1327 if(!NT_SUCCESS(Status))
1328 {
1329 SetLastNtError(Status);
1330 goto cleanup;
1331 }
1332
1333 hbmResult = GreCreateDIBitmapInternal(hDc,
1334 cx,
1335 cy,
1336 fInit,
1337 safeBits,
1338 pbmi,
1339 iUsage,
1340 fl,
1341 cjMaxBits,
1342 hcmXform);
1343
1344 cleanup:
1345 if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB);
1346 return hbmResult;
1347 }
1348
1349 HBITMAP
1350 NTAPI
1351 GreCreateDIBitmapInternal(
1352 IN HDC hDc,
1353 IN INT cx,
1354 IN INT cy,
1355 IN DWORD fInit,
1356 IN OPTIONAL LPBYTE pjInit,
1357 IN OPTIONAL PBITMAPINFO pbmi,
1358 IN DWORD iUsage,
1359 IN FLONG fl,
1360 IN UINT cjMaxBits,
1361 IN HANDLE hcmXform)
1362 {
1363 PDC Dc;
1364 HBITMAP Bmp;
1365 WORD bpp;
1366 HDC hdcDest;
1367
1368 if (!hDc) /* 1bpp monochrome bitmap */
1369 {
1370 // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
1371 hdcDest = NtGdiCreateCompatibleDC(0);
1372 if(!hdcDest)
1373 {
1374 return NULL;
1375 }
1376 }
1377 else
1378 {
1379 hdcDest = hDc;
1380 }
1381
1382 Dc = DC_LockDc(hdcDest);
1383 if (!Dc)
1384 {
1385 EngSetLastError(ERROR_INVALID_HANDLE);
1386 return NULL;
1387 }
1388 /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap
1389 * if bpp != 1 and ignore the real value that was passed */
1390 if (pbmi)
1391 bpp = pbmi->bmiHeader.biBitCount;
1392 else
1393 bpp = 0;
1394 Bmp = IntCreateDIBitmap(Dc, cx, cy, bpp, fInit, pjInit, pbmi, iUsage);
1395 DC_UnlockDc(Dc);
1396
1397 if(!hDc)
1398 {
1399 NtGdiDeleteObjectApp(hdcDest);
1400 }
1401 return Bmp;
1402 }
1403
1404
1405 HBITMAP
1406 APIENTRY
1407 NtGdiCreateDIBSection(
1408 IN HDC hDC,
1409 IN OPTIONAL HANDLE hSection,
1410 IN DWORD dwOffset,
1411 IN BITMAPINFO* bmi,
1412 IN DWORD Usage,
1413 IN UINT cjHeader,
1414 IN FLONG fl,
1415 IN ULONG_PTR dwColorSpace,
1416 OUT PVOID *Bits)
1417 {
1418 HBITMAP hbitmap = 0;
1419 DC *dc;
1420 BOOL bDesktopDC = FALSE;
1421 NTSTATUS Status = STATUS_SUCCESS;
1422
1423 if (!bmi) return hbitmap; // Make sure.
1424
1425 _SEH2_TRY
1426 {
1427 ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1);
1428 ProbeForRead(bmi, bmi->bmiHeader.biSize, 1);
1429 ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, (WORD)Usage), 1);
1430 }
1431 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1432 {
1433 Status = _SEH2_GetExceptionCode();
1434 }
1435 _SEH2_END
1436
1437 if(!NT_SUCCESS(Status))
1438 {
1439 SetLastNtError(Status);
1440 return NULL;
1441 }
1442
1443 // If the reference hdc is null, take the desktop dc
1444 if (hDC == 0)
1445 {
1446 hDC = NtGdiCreateCompatibleDC(0);
1447 bDesktopDC = TRUE;
1448 }
1449
1450 if ((dc = DC_LockDc(hDC)))
1451 {
1452 hbitmap = DIB_CreateDIBSection(dc,
1453 bmi,
1454 Usage,
1455 Bits,
1456 hSection,
1457 dwOffset,
1458 0);
1459 DC_UnlockDc(dc);
1460 }
1461 else
1462 {
1463 EngSetLastError(ERROR_INVALID_HANDLE);
1464 }
1465
1466 if (bDesktopDC)
1467 NtGdiDeleteObjectApp(hDC);
1468
1469 return hbitmap;
1470 }
1471
1472 HBITMAP
1473 APIENTRY
1474 DIB_CreateDIBSection(
1475 PDC dc,
1476 CONST BITMAPINFO *bmi,
1477 UINT usage,
1478 LPVOID *bits,
1479 HANDLE section,
1480 DWORD offset,
1481 DWORD ovr_pitch)
1482 {
1483 HBITMAP res = 0;
1484 SURFACE *bmp = NULL;
1485 void *mapBits = NULL;
1486 PPALETTE ppalDIB = NULL;
1487
1488 // Fill BITMAP32 structure with DIB data
1489 CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1490 INT effHeight;
1491 ULONG totalSize;
1492 BITMAP bm;
1493 //SIZEL Size;
1494 HANDLE hSecure;
1495
1496 DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n",
1497 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1498 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1499
1500 /* CreateDIBSection should fail for compressed formats */
1501 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
1502 {
1503 DPRINT1("no compressed format allowed\n");
1504 return (HBITMAP)NULL;
1505 }
1506
1507 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1508 bm.bmType = 0;
1509 bm.bmWidth = bi->biWidth;
1510 bm.bmHeight = effHeight;
1511 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount);
1512
1513 bm.bmPlanes = bi->biPlanes;
1514 bm.bmBitsPixel = bi->biBitCount;
1515 bm.bmBits = NULL;
1516
1517 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
1518 // we're dealing with a compressed bitmap. Otherwise, use width * height.
1519 totalSize = bi->biSizeImage && bi->biCompression != BI_RGB && bi->biCompression != BI_BITFIELDS
1520 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
1521
1522 if (section)
1523 {
1524 SYSTEM_BASIC_INFORMATION Sbi;
1525 NTSTATUS Status;
1526 DWORD mapOffset;
1527 LARGE_INTEGER SectionOffset;
1528 SIZE_T mapSize;
1529
1530 Status = ZwQuerySystemInformation(SystemBasicInformation,
1531 &Sbi,
1532 sizeof Sbi,
1533 0);
1534 if (!NT_SUCCESS(Status))
1535 {
1536 DPRINT1("ZwQuerySystemInformation failed (0x%lx)\n", Status);
1537 return NULL;
1538 }
1539
1540 mapOffset = offset - (offset % Sbi.AllocationGranularity);
1541 mapSize = bi->biSizeImage + (offset - mapOffset);
1542
1543 SectionOffset.LowPart = mapOffset;
1544 SectionOffset.HighPart = 0;
1545
1546 Status = ZwMapViewOfSection(section,
1547 NtCurrentProcess(),
1548 &mapBits,
1549 0,
1550 0,
1551 &SectionOffset,
1552 &mapSize,
1553 ViewShare,
1554 0,
1555 PAGE_READWRITE);
1556 if (!NT_SUCCESS(Status))
1557 {
1558 DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status);
1559 EngSetLastError(ERROR_INVALID_PARAMETER);
1560 return NULL;
1561 }
1562
1563 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
1564 }
1565 else if (ovr_pitch && offset)
1566 bm.bmBits = (LPVOID) offset;
1567 else
1568 {
1569 offset = 0;
1570 bm.bmBits = EngAllocUserMem(totalSize, 0);
1571 if(!bm.bmBits)
1572 {
1573 DPRINT1("Failed to allocate memory\n");
1574 goto cleanup;
1575 }
1576 }
1577
1578 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
1579 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
1580
1581
1582 // Create Device Dependent Bitmap and add DIB pointer
1583 //Size.cx = bm.bmWidth;
1584 //Size.cy = abs(bm.bmHeight);
1585 res = GreCreateBitmapEx(bm.bmWidth,
1586 abs(bm.bmHeight),
1587 bm.bmWidthBytes,
1588 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
1589 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
1590 ((bi->biHeight < 0) ? BMF_TOPDOWN : 0),
1591 bi->biSizeImage,
1592 bm.bmBits,
1593 0);
1594 if (!res)
1595 {
1596 DPRINT1("GreCreateBitmapEx failed\n");
1597 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
1598 goto cleanup;
1599 }
1600 bmp = SURFACE_ShareLockSurface(res); // HACK
1601 if (NULL == bmp)
1602 {
1603 DPRINT1("SURFACE_LockSurface failed\n");
1604 EngSetLastError(ERROR_INVALID_HANDLE);
1605 goto cleanup;
1606 }
1607
1608 /* WINE NOTE: WINE makes use of a colormap, which is a color translation
1609 table between the DIB and the X physical device. Obviously,
1610 this is left out of the ReactOS implementation. Instead,
1611 we call NtGdiSetDIBColorTable. */
1612 bmp->hDIBSection = section;
1613 bmp->hSecure = hSecure;
1614 bmp->dwOffset = offset;
1615 bmp->flags = API_BITMAP;
1616 bmp->biClrImportant = bi->biClrImportant;
1617
1618 /* Create a palette for the DIB */
1619 ppalDIB = CreateDIBPalette(bmi, dc, usage);
1620
1621 // Clean up in case of errors
1622 cleanup:
1623 if (!res || !bmp || !bm.bmBits || !ppalDIB)
1624 {
1625 DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
1626 if (bm.bmBits)
1627 {
1628 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
1629 if (section)
1630 {
1631 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
1632 bm.bmBits = NULL;
1633 }
1634 else if (!offset)
1635 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
1636 }
1637
1638 if (bmp)
1639 {
1640 SURFACE_ShareUnlockSurface(bmp);
1641 bmp = NULL;
1642 }
1643
1644 if (res)
1645 {
1646 GreDeleteObject(res);
1647 res = 0;
1648 }
1649
1650 if(ppalDIB)
1651 {
1652 PALETTE_ShareUnlockPalette(ppalDIB);
1653 }
1654 }
1655
1656 if (bmp)
1657 {
1658 /* If we're here, everything went fine */
1659 SURFACE_vSetPalette(bmp, ppalDIB);
1660 PALETTE_ShareUnlockPalette(ppalDIB);
1661 SURFACE_ShareUnlockSurface(bmp);
1662 }
1663
1664 // Return BITMAP handle and storage location
1665 if (NULL != bm.bmBits && NULL != bits)
1666 {
1667 *bits = bm.bmBits;
1668 }
1669
1670 return res;
1671 }
1672
1673 /***********************************************************************
1674 * DIB_GetBitmapInfo
1675 *
1676 * Get the info from a bitmap header.
1677 * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error.
1678 */
1679 int
1680 FASTCALL
1681 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
1682 LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size )
1683 {
1684 if (header->biSize == sizeof(BITMAPCOREHEADER))
1685 {
1686 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
1687 *width = core->bcWidth;
1688 *height = core->bcHeight;
1689 *planes = core->bcPlanes;
1690 *bpp = core->bcBitCount;
1691 *compr = BI_RGB;
1692 *size = 0;
1693 return 0;
1694 }
1695 if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* Assume BITMAPINFOHEADER */
1696 {
1697 *width = header->biWidth;
1698 *height = header->biHeight;
1699 *planes = header->biPlanes;
1700 *bpp = header->biBitCount;
1701 *compr = header->biCompression;
1702 *size = header->biSizeImage;
1703 return 1;
1704 }
1705 DPRINT1("(%u): unknown/wrong size for header\n", header->biSize );
1706 return -1;
1707 }
1708
1709 /***********************************************************************
1710 * DIB_GetDIBImageBytes
1711 *
1712 * Return the number of bytes used to hold the image in a DIB bitmap.
1713 * 11/16/1999 (RJJ) lifted from wine
1714 */
1715
1716 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth)
1717 {
1718 return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height);
1719 }
1720
1721 /***********************************************************************
1722 * DIB_BitmapInfoSize
1723 *
1724 * Return the size of the bitmap info structure including color table.
1725 * 11/16/1999 (RJJ) lifted from wine
1726 */
1727
1728 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
1729 {
1730 unsigned int colors, size, masks = 0;
1731
1732 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1733 {
1734 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
1735 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
1736 return sizeof(BITMAPCOREHEADER) + colors *
1737 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
1738 }
1739 else /* Assume BITMAPINFOHEADER */
1740 {
1741 colors = info->bmiHeader.biClrUsed;
1742 if (colors > 256) colors = 256;
1743 if (!colors && (info->bmiHeader.biBitCount <= 8))
1744 colors = 1 << info->bmiHeader.biBitCount;
1745 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
1746 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
1747 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
1748 }
1749 }
1750
1751 HPALETTE
1752 FASTCALL
1753 DIB_MapPaletteColors(PPALETTE ppalDc, CONST BITMAPINFO* lpbmi)
1754 {
1755 PPALETTE ppalNew;
1756 ULONG nNumColors,i;
1757 USHORT *lpIndex;
1758 HPALETTE hpal;
1759
1760 if (!(ppalDc->flFlags & PAL_INDEXED))
1761 {
1762 return NULL;
1763 }
1764
1765 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
1766 if (lpbmi->bmiHeader.biClrUsed)
1767 {
1768 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
1769 }
1770
1771 ppalNew = PALETTE_AllocPalWithHandle(PAL_INDEXED, nNumColors, NULL, 0, 0, 0);
1772 if (ppalNew == NULL)
1773 {
1774 DPRINT1("Could not allocate palette\n");
1775 return NULL;
1776 }
1777
1778 lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize);
1779
1780 for (i = 0; i < nNumColors; i++)
1781 {
1782 ULONG iColorIndex = *lpIndex % ppalDc->NumColors;
1783 ppalNew->IndexedColors[i] = ppalDc->IndexedColors[iColorIndex];
1784 lpIndex++;
1785 }
1786
1787 hpal = ppalNew->BaseObject.hHmgr;
1788 PALETTE_UnlockPalette(ppalNew);
1789
1790 return hpal;
1791 }
1792
1793 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure,
1794 * or does nothing if it's already a BITMAPINFO (or V4 or V5) */
1795 BITMAPINFO*
1796 FASTCALL
1797 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage)
1798 {
1799 CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi;
1800 BITMAPINFO* pNewBmi ;
1801 UINT numColors = 0, ColorsSize = 0;
1802
1803 if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi;
1804 if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL;
1805
1806 if(pbmci->bmciHeader.bcBitCount <= 8)
1807 {
1808 numColors = 1 << pbmci->bmciHeader.bcBitCount;
1809 if(Usage == DIB_PAL_COLORS)
1810 {
1811 ColorsSize = numColors * sizeof(WORD);
1812 }
1813 else
1814 {
1815 ColorsSize = numColors * sizeof(RGBQUAD);
1816 }
1817 }
1818 else if (Usage == DIB_PAL_COLORS)
1819 {
1820 /* Invalid at high-res */
1821 return NULL;
1822 }
1823
1824 pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB);
1825 if(!pNewBmi) return NULL;
1826
1827 RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize);
1828
1829 pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1830 pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount;
1831 pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth;
1832 pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight;
1833 pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes;
1834 pNewBmi->bmiHeader.biCompression = BI_RGB ;
1835 pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth,
1836 pNewBmi->bmiHeader.biHeight,
1837 pNewBmi->bmiHeader.biBitCount);
1838
1839 if(Usage == DIB_PAL_COLORS)
1840 {
1841 RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize);
1842 }
1843 else
1844 {
1845 UINT i;
1846 for(i=0; i<numColors; i++)
1847 {
1848 pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed;
1849 pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen;
1850 pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue;
1851 }
1852 }
1853
1854 return pNewBmi ;
1855 }
1856
1857 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */
1858 VOID
1859 FASTCALL
1860 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage)
1861 {
1862 BITMAPCOREINFO* pbmci;
1863 if(converted == orig)
1864 return;
1865
1866 if(usage == -1)
1867 {
1868 /* Caller don't want any conversion */
1869 ExFreePoolWithTag(converted, TAG_DIB);
1870 return;
1871 }
1872
1873 /* Perform inverse conversion */
1874 pbmci = (BITMAPCOREINFO*)orig;
1875
1876 ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER));
1877 pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount;
1878 pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth;
1879 pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight;
1880 pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes;
1881
1882 if(pbmci->bmciHeader.bcBitCount <= 8)
1883 {
1884 UINT numColors = converted->bmiHeader.biClrUsed;
1885 if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount;
1886 if(usage == DIB_PAL_COLORS)
1887 {
1888 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD));
1889 RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD));
1890 }
1891 else
1892 {
1893 UINT i;
1894 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE));
1895 for(i=0; i<numColors; i++)
1896 {
1897 pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed;
1898 pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen;
1899 pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue;
1900 }
1901 }
1902 }
1903 /* Now free it, it's not needed anymore */
1904 ExFreePoolWithTag(converted, TAG_DIB);
1905 }
1906
1907 /* EOF */