Merge from amd64-branch:
[reactos.git] / reactos / subsystems / win32 / win32k / objects / bitmaps.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$ */
20
21 #include <w32k.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 HBITMAP APIENTRY
27 IntGdiCreateBitmap(
28 INT Width,
29 INT Height,
30 UINT Planes,
31 UINT BitsPixel,
32 IN OPTIONAL LPBYTE pBits)
33 {
34 HBITMAP hBitmap;
35 SIZEL Size;
36 LONG WidthBytes;
37 PSURFACE psurfBmp;
38
39 /* NOTE: Windows also doesn't store nr. of planes separately! */
40 BitsPixel = BITMAP_GetRealBitsPixel(BitsPixel * Planes);
41
42 /* Check parameters */
43 if (BitsPixel == 0 || Width <= 0 || Width >= 0x8000000 || Height == 0)
44 {
45 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
46 Width, Height, BitsPixel);
47 SetLastWin32Error(ERROR_INVALID_PARAMETER);
48 return 0;
49 }
50
51 WidthBytes = BITMAP_GetWidthBytes(Width, BitsPixel);
52
53 Size.cx = Width;
54 Size.cy = abs(Height);
55
56 /* Make sure that cjBits will not overflow */
57 if ((ULONGLONG)WidthBytes * Size.cy >= 0x100000000ULL)
58 {
59 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
60 Width, Height, BitsPixel);
61 SetLastWin32Error(ERROR_INVALID_PARAMETER);
62 return 0;
63 }
64
65 /* Create the bitmap object. */
66 hBitmap = IntCreateBitmap(Size, WidthBytes,
67 BitmapFormat(BitsPixel, BI_RGB),
68 (Height < 0 ? BMF_TOPDOWN : 0) |
69 (NULL == pBits ? 0 : BMF_NOZEROINIT), NULL);
70 if (!hBitmap)
71 {
72 DPRINT("IntGdiCreateBitmap: returned 0\n");
73 return 0;
74 }
75
76 psurfBmp = SURFACE_LockSurface(hBitmap);
77 if (psurfBmp == NULL)
78 {
79 GreDeleteObject(hBitmap);
80 return NULL;
81 }
82
83 psurfBmp->flFlags = BITMAPOBJ_IS_APIBITMAP;
84 psurfBmp->hDC = NULL; // Fixme
85
86 if (NULL != pBits)
87 {
88 IntSetBitmapBits(psurfBmp, psurfBmp->SurfObj.cjBits, pBits);
89 }
90
91 SURFACE_UnlockSurface(psurfBmp);
92
93 DPRINT("IntGdiCreateBitmap : %dx%d, %d BPP colors, topdown %d, returning %08x\n",
94 Size.cx, Size.cy, BitsPixel, (Height < 0 ? 1 : 0), hBitmap);
95
96 return hBitmap;
97 }
98
99
100 HBITMAP APIENTRY
101 NtGdiCreateBitmap(
102 INT Width,
103 INT Height,
104 UINT Planes,
105 UINT BitsPixel,
106 IN OPTIONAL LPBYTE pUnsafeBits)
107 {
108 if (pUnsafeBits)
109 {
110 BOOL Hit = FALSE;
111 UINT cjBits = BITMAP_GetWidthBytes(Width, BitsPixel) * abs(Height);
112
113 // FIXME: Use MmSecureVirtualMemory
114 _SEH2_TRY
115 {
116 ProbeForRead(pUnsafeBits, cjBits, 1);
117 }
118 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
119 {
120 Hit = TRUE;
121 }
122 _SEH2_END
123
124 if (Hit) return 0;
125 }
126
127 return IntGdiCreateBitmap(Width, Height, Planes, BitsPixel, pUnsafeBits);
128 }
129
130 HBITMAP FASTCALL
131 IntCreateCompatibleBitmap(
132 PDC Dc,
133 INT Width,
134 INT Height)
135 {
136 HBITMAP Bmp = NULL;
137
138 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
139 if (0 == Width || 0 == Height)
140 {
141 Bmp = NtGdiGetStockObject(DEFAULT_BITMAP);
142 }
143 else
144 {
145 if (Dc->dctype != DC_TYPE_MEMORY)
146 {
147 Bmp = IntGdiCreateBitmap(abs(Width),
148 abs(Height),
149 IntGdiGetDeviceCaps(Dc,PLANES),
150 IntGdiGetDeviceCaps(Dc,BITSPIXEL),
151 NULL);
152 }
153 else
154 {
155 DIBSECTION dibs;
156 INT Count;
157 PSURFACE psurf = Dc->dclevel.pSurface;
158 Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
159
160 if (Count)
161 {
162 if (Count == sizeof(BITMAP))
163 {
164 /* We have a bitmap bug!!! W/O the HACK, we have white icons.
165
166 MSDN Note: When a memory device context is created, it initially
167 has a 1-by-1 monochrome bitmap selected into it. If this memory
168 device context is used in CreateCompatibleBitmap, the bitmap that
169 is created is a monochrome bitmap. To create a color bitmap, use
170 the hDC that was used to create the memory device context, as
171 shown in the following code:
172
173 HDC memDC = CreateCompatibleDC(hDC);
174 HBITMAP memBM = CreateCompatibleBitmap(hDC, nWidth, nHeight);
175 SelectObject(memDC, memBM);
176 */
177 Bmp = IntGdiCreateBitmap(abs(Width),
178 abs(Height),
179 dibs.dsBm.bmPlanes,
180 IntGdiGetDeviceCaps(Dc,BITSPIXEL),//<-- HACK! dibs.dsBm.bmBitsPixel, // <-- Correct!
181 NULL);
182 }
183 else
184 {
185 /* A DIB section is selected in the DC */
186 BITMAPINFO *bi;
187 PVOID Bits;
188
189 /* Allocate memory for a BITMAPINFOHEADER structure and a
190 color table. The maximum number of colors in a color table
191 is 256 which corresponds to a bitmap with depth 8.
192 Bitmaps with higher depths don't have color tables. */
193 bi = ExAllocatePoolWithTag(PagedPool,
194 sizeof(BITMAPINFOHEADER) +
195 256 * sizeof(RGBQUAD),
196 TAG_TEMP);
197
198 if (bi)
199 {
200 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
201 bi->bmiHeader.biWidth = Width;
202 bi->bmiHeader.biHeight = Height;
203 bi->bmiHeader.biPlanes = dibs.dsBmih.biPlanes;
204 bi->bmiHeader.biBitCount = dibs.dsBmih.biBitCount;
205 bi->bmiHeader.biCompression = dibs.dsBmih.biCompression;
206 bi->bmiHeader.biSizeImage = 0;
207 bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
208 bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
209 bi->bmiHeader.biClrUsed = dibs.dsBmih.biClrUsed;
210 bi->bmiHeader.biClrImportant = dibs.dsBmih.biClrImportant;
211
212 if (bi->bmiHeader.biCompression == BI_BITFIELDS)
213 {
214 /* Copy the color masks */
215 RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3 * sizeof(DWORD));
216 }
217 else if (bi->bmiHeader.biBitCount <= 8)
218 {
219 /* Copy the color table */
220 UINT Index;
221 PPALETTE PalGDI = PALETTE_LockPalette(psurf->hDIBPalette);
222
223 if (!PalGDI)
224 {
225 ExFreePoolWithTag(bi, TAG_TEMP);
226 SetLastWin32Error(ERROR_INVALID_HANDLE);
227 return 0;
228 }
229
230 for (Index = 0;
231 Index < 256 && Index < PalGDI->NumColors;
232 Index++)
233 {
234 bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
235 bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
236 bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
237 bi->bmiColors[Index].rgbReserved = 0;
238 }
239 PALETTE_UnlockPalette(PalGDI);
240 }
241
242 Bmp = DIB_CreateDIBSection(Dc,
243 bi,
244 DIB_RGB_COLORS,
245 &Bits,
246 NULL,
247 0,
248 0);
249
250 ExFreePoolWithTag(bi, TAG_TEMP);
251 return Bmp;
252 }
253 }
254 }
255 }
256 }
257 return Bmp;
258 }
259
260 HBITMAP APIENTRY
261 NtGdiCreateCompatibleBitmap(
262 HDC hDC,
263 INT Width,
264 INT Height)
265 {
266 HBITMAP Bmp;
267 PDC Dc;
268
269 if (Width <= 0 || Height <= 0 || (Width * Height) > 0x3FFFFFFF)
270 {
271 SetLastWin32Error(ERROR_INVALID_PARAMETER);
272 return NULL;
273 }
274
275 if (!hDC)
276 return IntGdiCreateBitmap(Width, Height, 1, 1, 0);
277
278 Dc = DC_LockDc(hDC);
279
280 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n",
281 hDC, Width, Height, Dc->ppdev->GDIInfo.cBitsPixel);
282
283 if (NULL == Dc)
284 {
285 SetLastWin32Error(ERROR_INVALID_HANDLE);
286 return NULL;
287 }
288
289 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
290
291 DPRINT("\t\t%04x\n", Bmp);
292 DC_UnlockDc(Dc);
293 return Bmp;
294 }
295
296 BOOL APIENTRY
297 NtGdiGetBitmapDimension(
298 HBITMAP hBitmap,
299 LPSIZE Dimension)
300 {
301 PSURFACE psurfBmp;
302 BOOL Ret = TRUE;
303
304 if (hBitmap == NULL)
305 return FALSE;
306
307 psurfBmp = SURFACE_LockSurface(hBitmap);
308 if (psurfBmp == NULL)
309 {
310 SetLastWin32Error(ERROR_INVALID_HANDLE);
311 return FALSE;
312 }
313
314 _SEH2_TRY
315 {
316 ProbeForWrite(Dimension, sizeof(SIZE), 1);
317 *Dimension = psurfBmp->dimension;
318 }
319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
320 {
321 Ret = FALSE;
322 }
323 _SEH2_END
324
325 SURFACE_UnlockSurface(psurfBmp);
326
327 return Ret;
328 }
329
330 COLORREF APIENTRY
331 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
332 {
333 PDC dc = NULL;
334 COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
335 BOOL bInRect = FALSE;
336 SURFACE *psurf;
337 SURFOBJ *pso;
338 HPALETTE Pal = 0;
339 XLATEOBJ *XlateObj;
340 HBITMAP hBmpTmp;
341
342 dc = DC_LockDc(hDC);
343
344 if (!dc)
345 {
346 SetLastWin32Error(ERROR_INVALID_HANDLE);
347 return Result;
348 }
349
350 if (dc->dctype == DC_TYPE_INFO)
351 {
352 DC_UnlockDc(dc);
353 return Result;
354 }
355
356 XPos += dc->ptlDCOrig.x;
357 YPos += dc->ptlDCOrig.y;
358 if (RECTL_bPointInRect(&dc->rosdc.CombinedClip->rclBounds, XPos, YPos))
359 {
360 bInRect = TRUE;
361 psurf = dc->dclevel.pSurface;
362 pso = &psurf->SurfObj;
363 if (psurf)
364 {
365 Pal = psurf->hDIBPalette;
366 if (!Pal) Pal = pPrimarySurface->DevInfo.hpalDefault;
367
368 /* FIXME: Verify if it shouldn't be PAL_BGR! */
369 XlateObj = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, 0, NULL, Pal);
370 if (XlateObj)
371 {
372 // check if this DC has a DIB behind it...
373 if (pso->pvScan0) // STYPE_BITMAP == pso->iType
374 {
375 ASSERT(pso->lDelta);
376 Result = XLATEOBJ_iXlate(XlateObj,
377 DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_GetPixel(pso, XPos, YPos));
378 }
379 EngDeleteXlate(XlateObj);
380 }
381 }
382 }
383 DC_UnlockDc(dc);
384
385 // if Result is still CLR_INVALID, then the "quick" method above didn't work
386 if (bInRect && Result == CLR_INVALID)
387 {
388 // FIXME: create a 1x1 32BPP DIB, and blit to it
389 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
390 if (hDCTmp)
391 {
392 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
393 BITMAPINFO bi;
394 RtlMoveMemory(&(bi.bmiHeader), &bih, sizeof(bih));
395 hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
396 bi.bmiHeader.biWidth,
397 bi.bmiHeader.biHeight,
398 0,
399 NULL,
400 &bi,
401 DIB_RGB_COLORS,
402 bi.bmiHeader.biBitCount,
403 bi.bmiHeader.biSizeImage,
404 0,
405 0);
406
407 //HBITMAP hBmpTmp = IntGdiCreateBitmap(1, 1, 1, 32, NULL);
408 if (hBmpTmp)
409 {
410 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap(hDCTmp, hBmpTmp);
411 if (hBmpOld)
412 {
413 PSURFACE psurf;
414
415 NtGdiBitBlt(hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0);
416 NtGdiSelectBitmap(hDCTmp, hBmpOld);
417
418 // our bitmap is no longer selected, so we can access it's stuff...
419 psurf = SURFACE_LockSurface(hBmpTmp);
420 if (psurf)
421 {
422 // Dont you need to convert something here?
423 Result = *(COLORREF*)psurf->SurfObj.pvScan0;
424 SURFACE_UnlockSurface(psurf);
425 }
426 }
427 GreDeleteObject(hBmpTmp);
428 }
429 NtGdiDeleteObjectApp(hDCTmp);
430 }
431 }
432
433 return Result;
434 }
435
436
437 LONG APIENTRY
438 IntGetBitmapBits(
439 PSURFACE psurf,
440 DWORD Bytes,
441 OUT PBYTE Bits)
442 {
443 LONG ret;
444
445 ASSERT(Bits);
446
447 /* Don't copy more bytes than the buffer has */
448 Bytes = min(Bytes, psurf->SurfObj.cjBits);
449
450 #if 0
451 /* FIXME: Call DDI CopyBits here if available */
452 if (psurf->DDBitmap)
453 {
454 DPRINT("Calling device specific BitmapBits\n");
455 if (psurf->DDBitmap->funcs->pBitmapBits)
456 {
457 ret = psurf->DDBitmap->funcs->pBitmapBits(hbitmap,
458 bits,
459 count,
460 DDB_GET);
461 }
462 else
463 {
464 ERR_(bitmap)("BitmapBits == NULL??\n");
465 ret = 0;
466 }
467 }
468 else
469 #endif
470 {
471 RtlCopyMemory(Bits, psurf->SurfObj.pvBits, Bytes);
472 ret = Bytes;
473 }
474 return ret;
475 }
476
477 LONG APIENTRY
478 NtGdiGetBitmapBits(
479 HBITMAP hBitmap,
480 ULONG Bytes,
481 OUT OPTIONAL PBYTE pUnsafeBits)
482 {
483 PSURFACE psurf;
484 LONG bmSize, ret;
485
486 if (pUnsafeBits != NULL && Bytes == 0)
487 {
488 return 0;
489 }
490
491 psurf = SURFACE_LockSurface(hBitmap);
492 if (!psurf)
493 {
494 SetLastWin32Error(ERROR_INVALID_HANDLE);
495 return 0;
496 }
497
498 bmSize = BITMAP_GetWidthBytes(psurf->SurfObj.sizlBitmap.cx,
499 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
500 abs(psurf->SurfObj.sizlBitmap.cy);
501
502 /* If the bits vector is null, the function should return the read size */
503 if (pUnsafeBits == NULL)
504 {
505 SURFACE_UnlockSurface(psurf);
506 return bmSize;
507 }
508
509 /* Don't copy more bytes than the buffer has */
510 Bytes = min(Bytes, bmSize);
511
512 // FIXME: use MmSecureVirtualMemory
513 _SEH2_TRY
514 {
515 ProbeForWrite(pUnsafeBits, Bytes, 1);
516 ret = IntGetBitmapBits(psurf, Bytes, pUnsafeBits);
517 }
518 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
519 {
520 ret = 0;
521 }
522 _SEH2_END
523
524 SURFACE_UnlockSurface(psurf);
525
526 return ret;
527 }
528
529
530 LONG APIENTRY
531 IntSetBitmapBits(
532 PSURFACE psurf,
533 DWORD Bytes,
534 IN PBYTE Bits)
535 {
536 LONG ret;
537
538 /* Don't copy more bytes than the buffer has */
539 Bytes = min(Bytes, psurf->SurfObj.cjBits);
540
541 #if 0
542 /* FIXME: call DDI specific function here if available */
543 if (psurf->DDBitmap)
544 {
545 DPRINT("Calling device specific BitmapBits\n");
546 if (psurf->DDBitmap->funcs->pBitmapBits)
547 {
548 ret = psurf->DDBitmap->funcs->pBitmapBits(hBitmap,
549 (void *)Bits,
550 Bytes,
551 DDB_SET);
552 }
553 else
554 {
555 DPRINT("BitmapBits == NULL??\n");
556 ret = 0;
557 }
558 }
559 else
560 #endif
561 {
562 RtlCopyMemory(psurf->SurfObj.pvBits, Bits, Bytes);
563 ret = Bytes;
564 }
565
566 return ret;
567 }
568
569
570 LONG APIENTRY
571 NtGdiSetBitmapBits(
572 HBITMAP hBitmap,
573 DWORD Bytes,
574 IN PBYTE pUnsafeBits)
575 {
576 LONG ret;
577 PSURFACE psurf;
578
579 if (pUnsafeBits == NULL || Bytes == 0)
580 {
581 return 0;
582 }
583
584 psurf = SURFACE_LockSurface(hBitmap);
585 if (psurf == NULL)
586 {
587 SetLastWin32Error(ERROR_INVALID_HANDLE);
588 return 0;
589 }
590
591 _SEH2_TRY
592 {
593 ProbeForRead(pUnsafeBits, Bytes, 1);
594 ret = IntSetBitmapBits(psurf, Bytes, pUnsafeBits);
595 }
596 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
597 {
598 ret = 0;
599 }
600 _SEH2_END
601
602 SURFACE_UnlockSurface(psurf);
603
604 return ret;
605 }
606
607 BOOL APIENTRY
608 NtGdiSetBitmapDimension(
609 HBITMAP hBitmap,
610 INT Width,
611 INT Height,
612 LPSIZE Size)
613 {
614 PSURFACE psurf;
615 BOOL Ret = TRUE;
616
617 if (hBitmap == NULL)
618 return FALSE;
619
620 psurf = SURFACE_LockSurface(hBitmap);
621 if (psurf == NULL)
622 {
623 SetLastWin32Error(ERROR_INVALID_HANDLE);
624 return FALSE;
625 }
626
627 if (Size)
628 {
629 _SEH2_TRY
630 {
631 ProbeForWrite(Size, sizeof(SIZE), 1);
632 *Size = psurf->dimension;
633 }
634 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
635 {
636 Ret = FALSE;
637 }
638 _SEH2_END
639 }
640
641 /* The dimension is changed even if writing the old value failed */
642 psurf->dimension.cx = Width;
643 psurf->dimension.cy = Height;
644
645 SURFACE_UnlockSurface(psurf);
646
647 return Ret;
648 }
649
650 BOOL APIENTRY
651 GdiSetPixelV(
652 HDC hDC,
653 INT X,
654 INT Y,
655 COLORREF Color)
656 {
657 HBRUSH hbrush = NtGdiCreateSolidBrush(Color, NULL);
658 HGDIOBJ OldBrush;
659
660 if (hbrush == NULL)
661 return(FALSE);
662
663 OldBrush = NtGdiSelectBrush(hDC, hbrush);
664 if (OldBrush == NULL)
665 {
666 GreDeleteObject(hbrush);
667 return(FALSE);
668 }
669
670 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
671 NtGdiSelectBrush(hDC, OldBrush);
672 GreDeleteObject(hbrush);
673
674 return TRUE;
675 }
676
677 COLORREF APIENTRY
678 NtGdiSetPixel(
679 HDC hDC,
680 INT X,
681 INT Y,
682 COLORREF Color)
683 {
684 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
685
686 if (GdiSetPixelV(hDC,X,Y,Color))
687 {
688 Color = NtGdiGetPixel(hDC,X,Y);
689 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
690 return Color;
691 }
692
693 Color = (COLORREF)CLR_INVALID;
694 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
695 return Color;
696 }
697
698
699 /* Internal Functions */
700
701 UINT FASTCALL
702 BITMAP_GetRealBitsPixel(UINT nBitsPixel)
703 {
704 if (nBitsPixel <= 1)
705 return 1;
706 if (nBitsPixel <= 4)
707 return 4;
708 if (nBitsPixel <= 8)
709 return 8;
710 if (nBitsPixel <= 16)
711 return 16;
712 if (nBitsPixel <= 24)
713 return 24;
714 if (nBitsPixel <= 32)
715 return 32;
716
717 return 0;
718 }
719
720 INT FASTCALL
721 BITMAP_GetWidthBytes(INT bmWidth, INT bpp)
722 {
723 #if 0
724 switch (bpp)
725 {
726 case 1:
727 return 2 * ((bmWidth+15) >> 4);
728
729 case 24:
730 bmWidth *= 3; /* fall through */
731 case 8:
732 return bmWidth + (bmWidth & 1);
733
734 case 32:
735 return bmWidth * 4;
736
737 case 16:
738 case 15:
739 return bmWidth * 2;
740
741 case 4:
742 return 2 * ((bmWidth+3) >> 2);
743
744 default:
745 DPRINT ("stub");
746 }
747
748 return -1;
749 #endif
750
751 return ((bmWidth * bpp + 15) & ~15) >> 3;
752 }
753
754 HBITMAP FASTCALL
755 BITMAP_CopyBitmap(HBITMAP hBitmap)
756 {
757 HBITMAP res;
758 BITMAP bm;
759 SURFACE *Bitmap, *resBitmap;
760 SIZEL Size;
761
762 if (hBitmap == NULL)
763 {
764 return 0;
765 }
766
767 Bitmap = GDIOBJ_LockObj(hBitmap, GDI_OBJECT_TYPE_BITMAP);
768 if (Bitmap == NULL)
769 {
770 return 0;
771 }
772
773 BITMAP_GetObject(Bitmap, sizeof(BITMAP), (PVOID)&bm);
774 bm.bmBits = NULL;
775 if (Bitmap->SurfObj.lDelta >= 0)
776 bm.bmHeight = -bm.bmHeight;
777
778 Size.cx = abs(bm.bmWidth);
779 Size.cy = abs(bm.bmHeight);
780 res = IntCreateBitmap(Size,
781 bm.bmWidthBytes,
782 BitmapFormat(bm.bmBitsPixel * bm.bmPlanes, BI_RGB),
783 (bm.bmHeight < 0 ? BMF_TOPDOWN : 0) | BMF_NOZEROINIT,
784 NULL);
785
786 if (res)
787 {
788 PBYTE buf;
789
790 resBitmap = GDIOBJ_LockObj(res, GDI_OBJECT_TYPE_BITMAP);
791 if (resBitmap)
792 {
793 buf = ExAllocatePoolWithTag(PagedPool,
794 bm.bmWidthBytes * abs(bm.bmHeight),
795 TAG_BITMAP);
796 if (buf == NULL)
797 {
798 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
799 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
800 GreDeleteObject(res);
801 return 0;
802 }
803 IntGetBitmapBits(Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
804 IntSetBitmapBits(resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
805 ExFreePoolWithTag(buf,TAG_BITMAP);
806 resBitmap->flFlags = Bitmap->flFlags;
807 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
808 }
809 else
810 {
811 GreDeleteObject(res);
812 res = NULL;
813 }
814 }
815
816 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
817
818 return res;
819 }
820
821 INT APIENTRY
822 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
823 {
824 PBITMAP pBitmap;
825
826 if (!buffer) return sizeof(BITMAP);
827 if ((UINT)Count < sizeof(BITMAP)) return 0;
828
829 /* always fill a basic BITMAP structure */
830 pBitmap = buffer;
831 pBitmap->bmType = 0;
832 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
833 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
834 pBitmap->bmWidthBytes = abs(psurf->SurfObj.lDelta);
835 pBitmap->bmPlanes = 1;
836 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
837
838 /* Check for DIB section */
839 if (psurf->hSecure)
840 {
841 /* Set bmBits in this case */
842 pBitmap->bmBits = psurf->SurfObj.pvBits;
843
844 if (Count >= sizeof(DIBSECTION))
845 {
846 /* Fill rest of DIBSECTION */
847 PDIBSECTION pds = buffer;
848
849 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
850 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
851 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
852 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
853 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
854 switch (psurf->SurfObj.iBitmapFormat)
855 {
856 /* FIXME: What about BI_BITFIELDS? */
857 case BMF_1BPP:
858 case BMF_4BPP:
859 case BMF_8BPP:
860 case BMF_16BPP:
861 case BMF_24BPP:
862 case BMF_32BPP:
863 pds->dsBmih.biCompression = BI_RGB;
864 break;
865 case BMF_4RLE:
866 pds->dsBmih.biCompression = BI_RLE4;
867 break;
868 case BMF_8RLE:
869 pds->dsBmih.biCompression = BI_RLE8;
870 break;
871 case BMF_JPEG:
872 pds->dsBmih.biCompression = BI_JPEG;
873 break;
874 case BMF_PNG:
875 pds->dsBmih.biCompression = BI_PNG;
876 break;
877 }
878 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
879 pds->dsBmih.biXPelsPerMeter = 0;
880 pds->dsBmih.biYPelsPerMeter = 0;
881 pds->dsBmih.biClrUsed = psurf->biClrUsed;
882 pds->dsBmih.biClrImportant = psurf->biClrImportant;
883 pds->dsBitfields[0] = psurf->dsBitfields[0];
884 pds->dsBitfields[1] = psurf->dsBitfields[1];
885 pds->dsBitfields[2] = psurf->dsBitfields[2];
886 pds->dshSection = psurf->hDIBSection;
887 pds->dsOffset = psurf->dwOffset;
888
889 return sizeof(DIBSECTION);
890 }
891 }
892 else
893 {
894 /* not set according to wine test, confirmed in win2k */
895 pBitmap->bmBits = NULL;
896 }
897
898 return sizeof(BITMAP);
899 }
900
901 /*
902 * @implemented
903 */
904 HDC
905 APIENTRY
906 NtGdiGetDCforBitmap(
907 IN HBITMAP hsurf)
908 {
909 HDC hDC = NULL;
910 PSURFACE psurf = SURFACE_LockSurface(hsurf);
911 if (psurf)
912 {
913 hDC = psurf->hDC;
914 SURFACE_UnlockSurface(psurf);
915 }
916 return hDC;
917 }
918
919 /* EOF */