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