[WIN32SS][NTGDI] Alignment probe change in NtGdiSetBitmapBits (#1309)
[reactos.git] / win32ss / gdi / ntgdi / bitmaps.c
1 /*
2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Bitmap functions
5 * FILE: win32ss/gdi/ntgdi/bitmaps.c
6 * PROGRAMERS: Timo Kreuzer <timo.kreuzer@reactos.org>
7 * Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
8 */
9
10 #include <win32k.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 BOOL
16 NTAPI
17 GreSetBitmapOwner(
18 _In_ HBITMAP hbmp,
19 _In_ ULONG ulOwner)
20 {
21 /* Check if we have the correct object type */
22 if (GDI_HANDLE_GET_TYPE(hbmp) != GDILoObjType_LO_BITMAP_TYPE)
23 {
24 DPRINT1("Incorrect type for hbmp: %p\n", hbmp);
25 return FALSE;
26 }
27
28 /// FIXME: this is a hack and doesn't handle a race condition properly.
29 /// It needs to be done in GDIOBJ_vSetObjectOwner atomically.
30
31 /* Check if we set public or none */
32 if ((ulOwner == GDI_OBJ_HMGR_PUBLIC) ||
33 (ulOwner == GDI_OBJ_HMGR_NONE))
34 {
35 /* Only allow this for owned objects */
36 if (GreGetObjectOwner(hbmp) != GDI_OBJ_HMGR_POWNED)
37 {
38 DPRINT1("Cannot change owner for non-powned hbmp\n");
39 return FALSE;
40 }
41 }
42
43 return GreSetObjectOwner(hbmp, ulOwner);
44 }
45
46 LONG
47 NTAPI
48 UnsafeSetBitmapBits(
49 _Inout_ PSURFACE psurf,
50 _In_ ULONG cjBits,
51 _In_ const VOID *pvBits)
52 {
53 PUCHAR pjDst;
54 const UCHAR *pjSrc;
55 LONG lDeltaDst, lDeltaSrc;
56 ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
57
58 NT_ASSERT(psurf->flags & API_BITMAP);
59 NT_ASSERT(psurf->SurfObj.iBitmapFormat <= BMF_32BPP);
60
61 nWidth = psurf->SurfObj.sizlBitmap.cx;
62 nHeight = labs(psurf->SurfObj.sizlBitmap.cy);
63 cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
64
65 pjDst = psurf->SurfObj.pvScan0;
66 pjSrc = pvBits;
67 lDeltaDst = psurf->SurfObj.lDelta;
68 lDeltaSrc = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
69 NT_ASSERT(lDeltaSrc <= labs(lDeltaDst));
70
71 cbDst = labs(lDeltaDst) * nHeight;
72 cbSrc = lDeltaSrc * nHeight;
73 cjBits = min(cjBits, cbSrc);
74
75 iSrc = iDst = 0;
76 for (Y = 0; Y < nHeight; Y++)
77 {
78 if (iSrc + lDeltaSrc > cjBits || iDst + labs(lDeltaDst) > cbDst)
79 {
80 LONG lDelta = min(cjBits - iSrc, cbDst - iDst);
81 NT_ASSERT(lDelta >= 0);
82 RtlCopyMemory(pjDst, pjSrc, lDelta);
83 iSrc += lDelta;
84 break;
85 }
86
87 /* Copy one line */
88 RtlCopyMemory(pjDst, pjSrc, lDeltaSrc);
89 pjSrc += lDeltaSrc;
90 pjDst += lDeltaDst;
91 iSrc += lDeltaSrc;
92 iDst += labs(lDeltaDst);
93 }
94
95 return iSrc;
96 }
97
98 HBITMAP
99 NTAPI
100 GreCreateBitmapEx(
101 _In_ ULONG nWidth,
102 _In_ ULONG nHeight,
103 _In_ ULONG cjWidthBytes,
104 _In_ ULONG iFormat,
105 _In_ USHORT fjBitmap,
106 _In_ ULONG cjSizeImage,
107 _In_opt_ PVOID pvBits,
108 _In_ FLONG flags)
109 {
110 PSURFACE psurf;
111 HBITMAP hbmp;
112 PVOID pvCompressedBits = NULL;
113
114 /* Verify format */
115 if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL;
116
117 /* The infamous RLE hack */
118 if ((iFormat == BMF_4RLE) || (iFormat == BMF_8RLE))
119 {
120 pvCompressedBits = pvBits;
121 pvBits = NULL;
122 iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP;
123 }
124
125 /* Allocate a surface */
126 psurf = SURFACE_AllocSurface(STYPE_BITMAP,
127 nWidth,
128 nHeight,
129 iFormat,
130 fjBitmap,
131 cjWidthBytes,
132 pvCompressedBits ? 0 : cjSizeImage,
133 pvBits);
134 if (!psurf)
135 {
136 DPRINT1("SURFACE_AllocSurface failed.\n");
137 return NULL;
138 }
139
140 /* The infamous RLE hack */
141 if (pvCompressedBits)
142 {
143 SIZEL sizl;
144 LONG lDelta;
145
146 sizl.cx = nWidth;
147 sizl.cy = nHeight;
148 lDelta = WIDTH_BYTES_ALIGN32(nWidth, gajBitsPerFormat[iFormat]);
149
150 pvBits = psurf->SurfObj.pvBits;
151 DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat, cjSizeImage);
152 }
153
154 /* Get the handle for the bitmap */
155 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
156
157 /* Mark as API bitmap */
158 psurf->flags |= (flags | API_BITMAP);
159
160 /* Unlock the surface and return */
161 SURFACE_UnlockSurface(psurf);
162 return hbmp;
163 }
164
165 /* Creates a DDB surface,
166 * as in CreateCompatibleBitmap or CreateBitmap.
167 * Note that each scanline must be 32bit aligned!
168 */
169 HBITMAP
170 NTAPI
171 GreCreateBitmap(
172 _In_ ULONG nWidth,
173 _In_ ULONG nHeight,
174 _In_ ULONG cPlanes,
175 _In_ ULONG cBitsPixel,
176 _In_opt_ PVOID pvBits)
177 {
178 /* Call the extended function */
179 return GreCreateBitmapEx(nWidth,
180 nHeight,
181 0, /* Auto width */
182 BitmapFormat(cBitsPixel * cPlanes, BI_RGB),
183 0, /* No bitmap flags */
184 0, /* Auto size */
185 pvBits,
186 DDB_SURFACE /* DDB */);
187 }
188
189 HBITMAP
190 APIENTRY
191 NtGdiCreateBitmap(
192 IN INT nWidth,
193 IN INT nHeight,
194 IN UINT cPlanes,
195 IN UINT cBitsPixel,
196 IN OPTIONAL LPBYTE pUnsafeBits)
197 {
198 HBITMAP hbmp;
199 ULONG cRealBpp, cjWidthBytes, iFormat;
200 ULONGLONG cjSize;
201 PSURFACE psurf;
202
203 /* Calculate bitmap format and real bits per pixel. */
204 iFormat = BitmapFormat(cBitsPixel * cPlanes, BI_RGB);
205 cRealBpp = gajBitsPerFormat[iFormat];
206
207 /* Calculate width and image size in bytes */
208 cjWidthBytes = WIDTH_BYTES_ALIGN16(nWidth, cRealBpp);
209 cjSize = (ULONGLONG)cjWidthBytes * nHeight;
210
211 /* Check parameters (possible overflow of cjSize!) */
212 if ((iFormat == 0) || (nWidth <= 0) || (nWidth >= 0x8000000) || (nHeight <= 0) ||
213 (cBitsPixel > 32) || (cPlanes > 32) || (cjSize >= 0x100000000ULL))
214 {
215 DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%u, Planes=%u\n",
216 nWidth, nHeight, cBitsPixel, cPlanes);
217 EngSetLastError(ERROR_INVALID_PARAMETER);
218 return NULL;
219 }
220
221 /* Allocate the surface (but don't set the bits) */
222 psurf = SURFACE_AllocSurface(STYPE_BITMAP,
223 nWidth,
224 nHeight,
225 iFormat,
226 0,
227 0,
228 0,
229 NULL);
230 if (!psurf)
231 {
232 DPRINT1("SURFACE_AllocSurface failed.\n");
233 return NULL;
234 }
235
236 /* Mark as API and DDB bitmap */
237 psurf->flags |= (API_BITMAP | DDB_SURFACE);
238
239 /* Check if we have bits to set */
240 if (pUnsafeBits)
241 {
242 /* Protect with SEH and copy the bits */
243 _SEH2_TRY
244 {
245 ProbeForRead(pUnsafeBits, (SIZE_T)cjSize, 1);
246 UnsafeSetBitmapBits(psurf, cjSize, pUnsafeBits);
247 }
248 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
249 {
250 GDIOBJ_vDeleteObject(&psurf->BaseObject);
251 _SEH2_YIELD(return NULL;)
252 }
253 _SEH2_END
254 }
255 else
256 {
257 /* Zero the bits */
258 RtlZeroMemory(psurf->SurfObj.pvBits, psurf->SurfObj.cjBits);
259 }
260
261 /* Get the handle for the bitmap */
262 hbmp = (HBITMAP)psurf->SurfObj.hsurf;
263
264 /* Unlock the surface */
265 SURFACE_UnlockSurface(psurf);
266
267 return hbmp;
268 }
269
270
271 HBITMAP FASTCALL
272 IntCreateCompatibleBitmap(
273 PDC Dc,
274 INT Width,
275 INT Height,
276 UINT Planes,
277 UINT Bpp)
278 {
279 HBITMAP Bmp = NULL;
280 PPALETTE ppal;
281
282 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
283 if (0 == Width || 0 == Height)
284 {
285 return NtGdiGetStockObject(DEFAULT_BITMAP);
286 }
287
288 if (Dc->dctype != DC_TYPE_MEMORY)
289 {
290 PSURFACE psurf;
291
292 Bmp = GreCreateBitmap(abs(Width),
293 abs(Height),
294 Planes ? Planes : 1,
295 Bpp ? Bpp : Dc->ppdev->gdiinfo.cBitsPixel,
296 NULL);
297 if (Bmp == NULL)
298 {
299 DPRINT1("Failed to allocate a bitmap!\n");
300 return NULL;
301 }
302
303 psurf = SURFACE_ShareLockSurface(Bmp);
304 ASSERT(psurf);
305
306 /* Dereference old palette and set new palette */
307 ppal = PALETTE_ShareLockPalette(Dc->ppdev->devinfo.hpalDefault);
308 ASSERT(ppal);
309 SURFACE_vSetPalette(psurf, ppal);
310 PALETTE_ShareUnlockPalette(ppal);
311
312 /* Set flags */
313 psurf->flags = API_BITMAP;
314 psurf->hdc = NULL; // FIXME:
315 psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
316 SURFACE_ShareUnlockSurface(psurf);
317 }
318 else
319 {
320 DIBSECTION dibs;
321 INT Count;
322 PSURFACE psurf = Dc->dclevel.pSurface;
323 if(!psurf) psurf = psurfDefaultBitmap;
324 Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
325
326 if (Count == sizeof(BITMAP))
327 {
328 PSURFACE psurfBmp;
329
330 Bmp = GreCreateBitmap(abs(Width),
331 abs(Height),
332 Planes ? Planes : 1,
333 Bpp ? Bpp : dibs.dsBm.bmBitsPixel,
334 NULL);
335 psurfBmp = SURFACE_ShareLockSurface(Bmp);
336 ASSERT(psurfBmp);
337
338 /* Dereference old palette and set new palette */
339 SURFACE_vSetPalette(psurfBmp, psurf->ppal);
340
341 /* Set flags */
342 psurfBmp->flags = API_BITMAP;
343 psurfBmp->hdc = NULL; // FIXME:
344 psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
345 SURFACE_ShareUnlockSurface(psurfBmp);
346 }
347 else if (Count == sizeof(DIBSECTION))
348 {
349 /* A DIB section is selected in the DC */
350 BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0};
351 PVOID Bits;
352 BITMAPINFO* bi = (BITMAPINFO*)buf;
353
354 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
355 bi->bmiHeader.biWidth = Width;
356 bi->bmiHeader.biHeight = Height;
357 bi->bmiHeader.biPlanes = Planes ? Planes : dibs.dsBmih.biPlanes;
358 bi->bmiHeader.biBitCount = Bpp ? Bpp : dibs.dsBmih.biBitCount;
359 bi->bmiHeader.biCompression = dibs.dsBmih.biCompression;
360 bi->bmiHeader.biSizeImage = 0;
361 bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
362 bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
363 bi->bmiHeader.biClrUsed = dibs.dsBmih.biClrUsed;
364 bi->bmiHeader.biClrImportant = dibs.dsBmih.biClrImportant;
365
366 if (bi->bmiHeader.biCompression == BI_BITFIELDS)
367 {
368 /* Copy the color masks */
369 RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD));
370 }
371 else if (bi->bmiHeader.biBitCount <= 8)
372 {
373 /* Copy the color table */
374 UINT Index;
375 PPALETTE PalGDI;
376
377 if (!psurf->ppal)
378 {
379 EngSetLastError(ERROR_INVALID_HANDLE);
380 return 0;
381 }
382
383 PalGDI = psurf->ppal;
384
385 for (Index = 0;
386 Index < 256 && Index < PalGDI->NumColors;
387 Index++)
388 {
389 bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
390 bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
391 bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
392 bi->bmiColors[Index].rgbReserved = 0;
393 }
394 }
395
396 Bmp = DIB_CreateDIBSection(Dc,
397 bi,
398 DIB_RGB_COLORS,
399 &Bits,
400 NULL,
401 0,
402 0);
403 return Bmp;
404 }
405 }
406 return Bmp;
407 }
408
409 HBITMAP APIENTRY
410 NtGdiCreateCompatibleBitmap(
411 HDC hDC,
412 INT Width,
413 INT Height)
414 {
415 HBITMAP Bmp;
416 PDC Dc;
417
418 /* Check parameters */
419 if ((Width <= 0) || (Height <= 0) || ((Width * Height) > 0x3FFFFFFF))
420 {
421 EngSetLastError(ERROR_INVALID_PARAMETER);
422 return NULL;
423 }
424
425 if (!hDC)
426 return GreCreateBitmap(Width, Height, 1, 1, 0);
427
428 Dc = DC_LockDc(hDC);
429
430 DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
431 hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
432
433 if (NULL == Dc)
434 {
435 EngSetLastError(ERROR_INVALID_HANDLE);
436 return NULL;
437 }
438
439 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height, 0, 0);
440
441 DC_UnlockDc(Dc);
442 return Bmp;
443 }
444
445 BOOL
446 NTAPI
447 GreGetBitmapDimension(
448 _In_ HBITMAP hBitmap,
449 _Out_ LPSIZE psizDim)
450 {
451 PSURFACE psurfBmp;
452
453 if (hBitmap == NULL)
454 return FALSE;
455
456 /* Lock the bitmap */
457 psurfBmp = SURFACE_ShareLockSurface(hBitmap);
458 if (psurfBmp == NULL)
459 {
460 EngSetLastError(ERROR_INVALID_HANDLE);
461 return FALSE;
462 }
463
464 *psizDim = psurfBmp->sizlDim;
465
466 /* Unlock the bitmap */
467 SURFACE_ShareUnlockSurface(psurfBmp);
468
469 return TRUE;
470 }
471
472 BOOL
473 APIENTRY
474 NtGdiGetBitmapDimension(
475 HBITMAP hBitmap,
476 LPSIZE psizDim)
477 {
478 SIZE dim;
479
480 if (!GreGetBitmapDimension(hBitmap, &dim))
481 return FALSE;
482
483 /* Use SEH to copy the data to the caller */
484 _SEH2_TRY
485 {
486 ProbeForWrite(psizDim, sizeof(*psizDim), 1);
487 *psizDim = dim;
488 }
489 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
490 {
491 _SEH2_YIELD(return FALSE);
492 }
493 _SEH2_END
494
495 return TRUE;
496 }
497
498
499 LONG
500 FASTCALL
501 UnsafeGetBitmapBits(
502 PSURFACE psurf,
503 DWORD Bytes,
504 OUT PBYTE pvBits)
505 {
506 PUCHAR pjDst, pjSrc;
507 LONG lDeltaDst, lDeltaSrc;
508 ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
509
510 nWidth = psurf->SurfObj.sizlBitmap.cx;
511 nHeight = labs(psurf->SurfObj.sizlBitmap.cy);
512 cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
513
514 /* Get pointers */
515 pjSrc = psurf->SurfObj.pvScan0;
516 pjDst = pvBits;
517 lDeltaSrc = psurf->SurfObj.lDelta;
518 lDeltaDst = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
519 NT_ASSERT(labs(lDeltaSrc) >= lDeltaDst);
520
521 cbSrc = nHeight * labs(lDeltaSrc);
522 cbDst = nHeight * lDeltaDst;
523 Bytes = min(Bytes, cbDst);
524
525 iSrc = iDst = 0;
526 for (Y = 0; Y < nHeight; Y++)
527 {
528 if (iSrc + labs(lDeltaSrc) > cbSrc || iDst + lDeltaDst > Bytes)
529 {
530 LONG lDelta = min(cbSrc - iSrc, Bytes - iDst);
531 NT_ASSERT(lDelta >= 0);
532 RtlCopyMemory(pjDst, pjSrc, lDelta);
533 iDst += lDelta;
534 break;
535 }
536
537 /* Copy one line */
538 RtlCopyMemory(pjDst, pjSrc, lDeltaDst);
539 pjSrc += lDeltaSrc;
540 pjDst += lDeltaDst;
541 iSrc += labs(lDeltaSrc);
542 iDst += lDeltaDst;
543 }
544
545 return iDst;
546 }
547
548 LONG
549 APIENTRY
550 NtGdiGetBitmapBits(
551 HBITMAP hBitmap,
552 ULONG cjBuffer,
553 OUT OPTIONAL PBYTE pUnsafeBits)
554 {
555 PSURFACE psurf;
556 ULONG cjSize;
557 LONG ret;
558
559 /* Check parameters */
560 if (pUnsafeBits != NULL && cjBuffer == 0)
561 {
562 return 0;
563 }
564
565 /* Lock the bitmap */
566 psurf = SURFACE_ShareLockSurface(hBitmap);
567 if (!psurf)
568 {
569 EngSetLastError(ERROR_INVALID_HANDLE);
570 return 0;
571 }
572
573 /* Calculate the size of the bitmap in bytes */
574 cjSize = WIDTH_BYTES_ALIGN16(psurf->SurfObj.sizlBitmap.cx,
575 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
576 abs(psurf->SurfObj.sizlBitmap.cy);
577
578 /* If the bits vector is null, the function should return the read size */
579 if (pUnsafeBits == NULL)
580 {
581 SURFACE_ShareUnlockSurface(psurf);
582 return cjSize;
583 }
584
585 /* Don't copy more bytes than the buffer has */
586 cjBuffer = min(cjBuffer, cjSize);
587
588 // FIXME: Use MmSecureVirtualMemory
589 _SEH2_TRY
590 {
591 ProbeForWrite(pUnsafeBits, cjBuffer, 1);
592 ret = UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits);
593 }
594 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
595 {
596 ret = 0;
597 }
598 _SEH2_END
599
600 SURFACE_ShareUnlockSurface(psurf);
601
602 return ret;
603 }
604
605
606 LONG APIENTRY
607 NtGdiSetBitmapBits(
608 HBITMAP hBitmap,
609 DWORD Bytes,
610 IN PBYTE pUnsafeBits)
611 {
612 LONG ret;
613 PSURFACE psurf;
614
615 if (pUnsafeBits == NULL || Bytes == 0)
616 {
617 return 0;
618 }
619
620 if (GDI_HANDLE_IS_STOCKOBJ(hBitmap))
621 {
622 return 0;
623 }
624
625 psurf = SURFACE_ShareLockSurface(hBitmap);
626 if (psurf == NULL)
627 {
628 EngSetLastError(ERROR_INVALID_HANDLE);
629 return 0;
630 }
631
632 if (((psurf->flags & API_BITMAP) == 0) ||
633 (psurf->SurfObj.iBitmapFormat > BMF_32BPP))
634 {
635 DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n",
636 psurf->SurfObj.iBitmapFormat,
637 psurf->flags);
638 EngSetLastError(ERROR_INVALID_HANDLE);
639 SURFACE_ShareUnlockSurface(psurf);
640 return 0;
641 }
642
643 _SEH2_TRY
644 {
645 /* NOTE: Win2k3 doesn't check WORD alignment here. */
646 ProbeForRead(pUnsafeBits, Bytes, 1);
647 ret = UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
648 }
649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
650 {
651 ret = 0;
652 }
653 _SEH2_END
654
655 SURFACE_ShareUnlockSurface(psurf);
656
657 return ret;
658 }
659
660 BOOL APIENTRY
661 NtGdiSetBitmapDimension(
662 HBITMAP hBitmap,
663 INT Width,
664 INT Height,
665 LPSIZE Size)
666 {
667 PSURFACE psurf;
668 BOOL Ret = TRUE;
669
670 if (hBitmap == NULL)
671 return FALSE;
672
673 psurf = SURFACE_ShareLockSurface(hBitmap);
674 if (psurf == NULL)
675 {
676 EngSetLastError(ERROR_INVALID_HANDLE);
677 return FALSE;
678 }
679
680 if (Size)
681 {
682 _SEH2_TRY
683 {
684 ProbeForWrite(Size, sizeof(SIZE), 1);
685 *Size = psurf->sizlDim;
686 }
687 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
688 {
689 Ret = FALSE;
690 }
691 _SEH2_END
692 }
693
694 /* The dimension is changed even if writing the old value failed */
695 psurf->sizlDim.cx = Width;
696 psurf->sizlDim.cy = Height;
697
698 SURFACE_ShareUnlockSurface(psurf);
699
700 return Ret;
701 }
702
703 /* Internal Functions */
704
705 HBITMAP
706 FASTCALL
707 BITMAP_CopyBitmap(HBITMAP hBitmap)
708 {
709 HBITMAP hbmNew;
710 SURFACE *psurfSrc, *psurfNew;
711
712 /* Fail, if no source bitmap is given */
713 if (hBitmap == NULL) return 0;
714
715 /* Lock the source bitmap */
716 psurfSrc = SURFACE_ShareLockSurface(hBitmap);
717 if (psurfSrc == NULL)
718 {
719 return 0;
720 }
721
722 /* Allocate a new bitmap with the same dimensions as the source bmp */
723 hbmNew = GreCreateBitmapEx(psurfSrc->SurfObj.sizlBitmap.cx,
724 psurfSrc->SurfObj.sizlBitmap.cy,
725 abs(psurfSrc->SurfObj.lDelta),
726 psurfSrc->SurfObj.iBitmapFormat,
727 psurfSrc->SurfObj.fjBitmap & BMF_TOPDOWN,
728 psurfSrc->SurfObj.cjBits,
729 NULL,
730 psurfSrc->flags);
731
732 if (hbmNew)
733 {
734 /* Lock the new bitmap */
735 psurfNew = SURFACE_ShareLockSurface(hbmNew);
736 if (psurfNew)
737 {
738 /* Copy the bitmap bits to the new bitmap buffer */
739 RtlCopyMemory(psurfNew->SurfObj.pvBits,
740 psurfSrc->SurfObj.pvBits,
741 psurfNew->SurfObj.cjBits);
742
743
744 /* Reference the palette of the source bitmap and use it */
745 SURFACE_vSetPalette(psurfNew, psurfSrc->ppal);
746
747 /* Unlock the new surface */
748 SURFACE_ShareUnlockSurface(psurfNew);
749 }
750 else
751 {
752 /* Failed to lock the bitmap, shouldn't happen */
753 GreDeleteObject(hbmNew);
754 hbmNew = NULL;
755 }
756 }
757
758 /* Unlock the source bitmap and return the handle of the new bitmap */
759 SURFACE_ShareUnlockSurface(psurfSrc);
760 return hbmNew;
761 }
762
763 INT APIENTRY
764 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
765 {
766 PBITMAP pBitmap;
767
768 if (!buffer) return sizeof(BITMAP);
769 if ((UINT)Count < sizeof(BITMAP)) return 0;
770
771 /* Always fill a basic BITMAP structure */
772 pBitmap = buffer;
773 pBitmap->bmType = 0;
774 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
775 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
776 pBitmap->bmPlanes = 1;
777 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
778 pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN16(pBitmap->bmWidth, pBitmap->bmBitsPixel);
779
780 /* Check for DIB section */
781 if (psurf->hSecure)
782 {
783 /* Set bmBits in this case */
784 pBitmap->bmBits = psurf->SurfObj.pvBits;
785 /* DIBs data are 32 bits aligned */
786 pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN32(pBitmap->bmWidth, pBitmap->bmBitsPixel);
787
788 if (Count >= sizeof(DIBSECTION))
789 {
790 /* Fill rest of DIBSECTION */
791 PDIBSECTION pds = buffer;
792
793 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
794 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
795 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
796 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
797 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
798
799 switch (psurf->SurfObj.iBitmapFormat)
800 {
801 case BMF_1BPP:
802 case BMF_4BPP:
803 case BMF_8BPP:
804 pds->dsBmih.biCompression = BI_RGB;
805 break;
806
807 case BMF_16BPP:
808 if (psurf->ppal->flFlags & PAL_RGB16_555)
809 pds->dsBmih.biCompression = BI_RGB;
810 else
811 pds->dsBmih.biCompression = BI_BITFIELDS;
812 break;
813
814 case BMF_24BPP:
815 case BMF_32BPP:
816 /* 24/32bpp BI_RGB is actually BGR format */
817 if (psurf->ppal->flFlags & PAL_BGR)
818 pds->dsBmih.biCompression = BI_RGB;
819 else
820 pds->dsBmih.biCompression = BI_BITFIELDS;
821 break;
822
823 case BMF_4RLE:
824 pds->dsBmih.biCompression = BI_RLE4;
825 break;
826 case BMF_8RLE:
827 pds->dsBmih.biCompression = BI_RLE8;
828 break;
829 case BMF_JPEG:
830 pds->dsBmih.biCompression = BI_JPEG;
831 break;
832 case BMF_PNG:
833 pds->dsBmih.biCompression = BI_PNG;
834 break;
835 default:
836 ASSERT(FALSE); /* This shouldn't happen */
837 }
838
839 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
840 pds->dsBmih.biXPelsPerMeter = 0;
841 pds->dsBmih.biYPelsPerMeter = 0;
842 pds->dsBmih.biClrUsed = psurf->ppal->NumColors;
843 pds->dsBmih.biClrImportant = psurf->biClrImportant;
844 pds->dsBitfields[0] = psurf->ppal->RedMask;
845 pds->dsBitfields[1] = psurf->ppal->GreenMask;
846 pds->dsBitfields[2] = psurf->ppal->BlueMask;
847 pds->dshSection = psurf->hDIBSection;
848 pds->dsOffset = psurf->dwOffset;
849
850 return sizeof(DIBSECTION);
851 }
852 }
853 else
854 {
855 /* Not set according to wine test, confirmed in win2k */
856 pBitmap->bmBits = NULL;
857 }
858
859 return sizeof(BITMAP);
860 }
861
862 /*
863 * @implemented
864 */
865 HDC
866 APIENTRY
867 NtGdiGetDCforBitmap(
868 IN HBITMAP hsurf)
869 {
870 HDC hdc = NULL;
871 PSURFACE psurf = SURFACE_ShareLockSurface(hsurf);
872 if (psurf)
873 {
874 hdc = psurf->hdc;
875 SURFACE_ShareUnlockSurface(psurf);
876 }
877 return hdc;
878 }
879
880
881 /* EOF */