e003640e9eea1afb5fad3f5f643cc22034e1bb42
[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 ProbeForRead(pUnsafeBits, Bytes, sizeof(WORD));
646 ret = UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
647 }
648 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
649 {
650 ret = 0;
651 }
652 _SEH2_END
653
654 SURFACE_ShareUnlockSurface(psurf);
655
656 return ret;
657 }
658
659 BOOL APIENTRY
660 NtGdiSetBitmapDimension(
661 HBITMAP hBitmap,
662 INT Width,
663 INT Height,
664 LPSIZE Size)
665 {
666 PSURFACE psurf;
667 BOOL Ret = TRUE;
668
669 if (hBitmap == NULL)
670 return FALSE;
671
672 psurf = SURFACE_ShareLockSurface(hBitmap);
673 if (psurf == NULL)
674 {
675 EngSetLastError(ERROR_INVALID_HANDLE);
676 return FALSE;
677 }
678
679 if (Size)
680 {
681 _SEH2_TRY
682 {
683 ProbeForWrite(Size, sizeof(SIZE), 1);
684 *Size = psurf->sizlDim;
685 }
686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
687 {
688 Ret = FALSE;
689 }
690 _SEH2_END
691 }
692
693 /* The dimension is changed even if writing the old value failed */
694 psurf->sizlDim.cx = Width;
695 psurf->sizlDim.cy = Height;
696
697 SURFACE_ShareUnlockSurface(psurf);
698
699 return Ret;
700 }
701
702 /* Internal Functions */
703
704 HBITMAP
705 FASTCALL
706 BITMAP_CopyBitmap(HBITMAP hBitmap)
707 {
708 HBITMAP hbmNew;
709 SURFACE *psurfSrc, *psurfNew;
710
711 /* Fail, if no source bitmap is given */
712 if (hBitmap == NULL) return 0;
713
714 /* Lock the source bitmap */
715 psurfSrc = SURFACE_ShareLockSurface(hBitmap);
716 if (psurfSrc == NULL)
717 {
718 return 0;
719 }
720
721 /* Allocate a new bitmap with the same dimensions as the source bmp */
722 hbmNew = GreCreateBitmapEx(psurfSrc->SurfObj.sizlBitmap.cx,
723 psurfSrc->SurfObj.sizlBitmap.cy,
724 abs(psurfSrc->SurfObj.lDelta),
725 psurfSrc->SurfObj.iBitmapFormat,
726 psurfSrc->SurfObj.fjBitmap & BMF_TOPDOWN,
727 psurfSrc->SurfObj.cjBits,
728 NULL,
729 psurfSrc->flags);
730
731 if (hbmNew)
732 {
733 /* Lock the new bitmap */
734 psurfNew = SURFACE_ShareLockSurface(hbmNew);
735 if (psurfNew)
736 {
737 /* Copy the bitmap bits to the new bitmap buffer */
738 RtlCopyMemory(psurfNew->SurfObj.pvBits,
739 psurfSrc->SurfObj.pvBits,
740 psurfNew->SurfObj.cjBits);
741
742
743 /* Reference the palette of the source bitmap and use it */
744 SURFACE_vSetPalette(psurfNew, psurfSrc->ppal);
745
746 /* Unlock the new surface */
747 SURFACE_ShareUnlockSurface(psurfNew);
748 }
749 else
750 {
751 /* Failed to lock the bitmap, shouldn't happen */
752 GreDeleteObject(hbmNew);
753 hbmNew = NULL;
754 }
755 }
756
757 /* Unlock the source bitmap and return the handle of the new bitmap */
758 SURFACE_ShareUnlockSurface(psurfSrc);
759 return hbmNew;
760 }
761
762 INT APIENTRY
763 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
764 {
765 PBITMAP pBitmap;
766
767 if (!buffer) return sizeof(BITMAP);
768 if ((UINT)Count < sizeof(BITMAP)) return 0;
769
770 /* Always fill a basic BITMAP structure */
771 pBitmap = buffer;
772 pBitmap->bmType = 0;
773 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
774 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
775 pBitmap->bmPlanes = 1;
776 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
777 pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN16(pBitmap->bmWidth, pBitmap->bmBitsPixel);
778
779 /* Check for DIB section */
780 if (psurf->hSecure)
781 {
782 /* Set bmBits in this case */
783 pBitmap->bmBits = psurf->SurfObj.pvBits;
784 /* DIBs data are 32 bits aligned */
785 pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN32(pBitmap->bmWidth, pBitmap->bmBitsPixel);
786
787 if (Count >= sizeof(DIBSECTION))
788 {
789 /* Fill rest of DIBSECTION */
790 PDIBSECTION pds = buffer;
791
792 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
793 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
794 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
795 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
796 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
797
798 switch (psurf->SurfObj.iBitmapFormat)
799 {
800 case BMF_1BPP:
801 case BMF_4BPP:
802 case BMF_8BPP:
803 pds->dsBmih.biCompression = BI_RGB;
804 break;
805
806 case BMF_16BPP:
807 if (psurf->ppal->flFlags & PAL_RGB16_555)
808 pds->dsBmih.biCompression = BI_RGB;
809 else
810 pds->dsBmih.biCompression = BI_BITFIELDS;
811 break;
812
813 case BMF_24BPP:
814 case BMF_32BPP:
815 /* 24/32bpp BI_RGB is actually BGR format */
816 if (psurf->ppal->flFlags & PAL_BGR)
817 pds->dsBmih.biCompression = BI_RGB;
818 else
819 pds->dsBmih.biCompression = BI_BITFIELDS;
820 break;
821
822 case BMF_4RLE:
823 pds->dsBmih.biCompression = BI_RLE4;
824 break;
825 case BMF_8RLE:
826 pds->dsBmih.biCompression = BI_RLE8;
827 break;
828 case BMF_JPEG:
829 pds->dsBmih.biCompression = BI_JPEG;
830 break;
831 case BMF_PNG:
832 pds->dsBmih.biCompression = BI_PNG;
833 break;
834 default:
835 ASSERT(FALSE); /* This shouldn't happen */
836 }
837
838 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
839 pds->dsBmih.biXPelsPerMeter = 0;
840 pds->dsBmih.biYPelsPerMeter = 0;
841 pds->dsBmih.biClrUsed = psurf->ppal->NumColors;
842 pds->dsBmih.biClrImportant = psurf->biClrImportant;
843 pds->dsBitfields[0] = psurf->ppal->RedMask;
844 pds->dsBitfields[1] = psurf->ppal->GreenMask;
845 pds->dsBitfields[2] = psurf->ppal->BlueMask;
846 pds->dshSection = psurf->hDIBSection;
847 pds->dsOffset = psurf->dwOffset;
848
849 return sizeof(DIBSECTION);
850 }
851 }
852 else
853 {
854 /* Not set according to wine test, confirmed in win2k */
855 pBitmap->bmBits = NULL;
856 }
857
858 return sizeof(BITMAP);
859 }
860
861 /*
862 * @implemented
863 */
864 HDC
865 APIENTRY
866 NtGdiGetDCforBitmap(
867 IN HBITMAP hsurf)
868 {
869 HDC hdc = NULL;
870 PSURFACE psurf = SURFACE_ShareLockSurface(hsurf);
871 if (psurf)
872 {
873 hdc = psurf->hdc;
874 SURFACE_ShareUnlockSurface(psurf);
875 }
876 return hdc;
877 }
878
879
880 /* EOF */