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