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