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