Update PDEVOBJ and GRAPHICS_DEVICE fields
[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 hpal = 0;
339 PPALETTE ppal;
340 EXLATEOBJ exlo;
341 HBITMAP hBmpTmp;
342
343 dc = DC_LockDc(hDC);
344
345 if (!dc)
346 {
347 SetLastWin32Error(ERROR_INVALID_HANDLE);
348 return Result;
349 }
350
351 if (dc->dctype == DC_TYPE_INFO)
352 {
353 DC_UnlockDc(dc);
354 return Result;
355 }
356
357 XPos += dc->ptlDCOrig.x;
358 YPos += dc->ptlDCOrig.y;
359 if (RECTL_bPointInRect(&dc->rosdc.CombinedClip->rclBounds, XPos, YPos))
360 {
361 bInRect = TRUE;
362 psurf = dc->dclevel.pSurface;
363 if (psurf)
364 {
365 pso = &psurf->SurfObj;
366 hpal = psurf->hDIBPalette;
367 if (!hpal) hpal = pPrimarySurface->devinfo.hpalDefault;
368 ppal = PALETTE_ShareLockPalette(hpal);
369
370 if (psurf->SurfObj.iBitmapFormat == BMF_1BPP && !psurf->hSecure)
371 {
372 /* FIXME: palette should be gpalMono already ! */
373 EXLATEOBJ_vInitialize(&exlo, &gpalMono, &gpalRGB, 0, 0xffffff, 0);
374 }
375 else
376 {
377 EXLATEOBJ_vInitialize(&exlo, ppal, &gpalRGB, 0, 0xffffff, 0);
378 }
379
380 // check if this DC has a DIB behind it...
381 if (pso->pvScan0) // STYPE_BITMAP == pso->iType
382 {
383 ASSERT(pso->lDelta);
384 Result = XLATEOBJ_iXlate(&exlo.xlo,
385 DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_GetPixel(pso, XPos, YPos));
386 }
387
388 EXLATEOBJ_vCleanup(&exlo);
389 PALETTE_ShareUnlockPalette(ppal);
390 }
391 }
392 DC_UnlockDc(dc);
393
394 // if Result is still CLR_INVALID, then the "quick" method above didn't work
395 if (bInRect && Result == CLR_INVALID)
396 {
397 // FIXME: create a 1x1 32BPP DIB, and blit to it
398 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
399 if (hDCTmp)
400 {
401 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
402 BITMAPINFO bi;
403 RtlMoveMemory(&(bi.bmiHeader), &bih, sizeof(bih));
404 hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
405 bi.bmiHeader.biWidth,
406 bi.bmiHeader.biHeight,
407 0,
408 NULL,
409 &bi,
410 DIB_RGB_COLORS,
411 bi.bmiHeader.biBitCount,
412 bi.bmiHeader.biSizeImage,
413 0,
414 0);
415
416 //HBITMAP hBmpTmp = IntGdiCreateBitmap(1, 1, 1, 32, NULL);
417 if (hBmpTmp)
418 {
419 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap(hDCTmp, hBmpTmp);
420 if (hBmpOld)
421 {
422 PSURFACE psurf;
423
424 NtGdiBitBlt(hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0);
425 NtGdiSelectBitmap(hDCTmp, hBmpOld);
426
427 // our bitmap is no longer selected, so we can access it's stuff...
428 psurf = SURFACE_LockSurface(hBmpTmp);
429 if (psurf)
430 {
431 // Dont you need to convert something here?
432 Result = *(COLORREF*)psurf->SurfObj.pvScan0;
433 SURFACE_UnlockSurface(psurf);
434 }
435 }
436 GreDeleteObject(hBmpTmp);
437 }
438 NtGdiDeleteObjectApp(hDCTmp);
439 }
440 }
441
442 return Result;
443 }
444
445
446 LONG APIENTRY
447 IntGetBitmapBits(
448 PSURFACE psurf,
449 DWORD Bytes,
450 OUT PBYTE Bits)
451 {
452 LONG ret;
453
454 ASSERT(Bits);
455
456 /* Don't copy more bytes than the buffer has */
457 Bytes = min(Bytes, psurf->SurfObj.cjBits);
458
459 #if 0
460 /* FIXME: Call DDI CopyBits here if available */
461 if (psurf->DDBitmap)
462 {
463 DPRINT("Calling device specific BitmapBits\n");
464 if (psurf->DDBitmap->funcs->pBitmapBits)
465 {
466 ret = psurf->DDBitmap->funcs->pBitmapBits(hbitmap,
467 bits,
468 count,
469 DDB_GET);
470 }
471 else
472 {
473 ERR_(bitmap)("BitmapBits == NULL??\n");
474 ret = 0;
475 }
476 }
477 else
478 #endif
479 {
480 RtlCopyMemory(Bits, psurf->SurfObj.pvBits, Bytes);
481 ret = Bytes;
482 }
483 return ret;
484 }
485
486 LONG APIENTRY
487 NtGdiGetBitmapBits(
488 HBITMAP hBitmap,
489 ULONG Bytes,
490 OUT OPTIONAL PBYTE pUnsafeBits)
491 {
492 PSURFACE psurf;
493 LONG bmSize, ret;
494
495 if (pUnsafeBits != NULL && Bytes == 0)
496 {
497 return 0;
498 }
499
500 psurf = SURFACE_LockSurface(hBitmap);
501 if (!psurf)
502 {
503 SetLastWin32Error(ERROR_INVALID_HANDLE);
504 return 0;
505 }
506
507 bmSize = BITMAP_GetWidthBytes(psurf->SurfObj.sizlBitmap.cx,
508 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
509 abs(psurf->SurfObj.sizlBitmap.cy);
510
511 /* If the bits vector is null, the function should return the read size */
512 if (pUnsafeBits == NULL)
513 {
514 SURFACE_UnlockSurface(psurf);
515 return bmSize;
516 }
517
518 /* Don't copy more bytes than the buffer has */
519 Bytes = min(Bytes, bmSize);
520
521 // FIXME: use MmSecureVirtualMemory
522 _SEH2_TRY
523 {
524 ProbeForWrite(pUnsafeBits, Bytes, 1);
525 ret = IntGetBitmapBits(psurf, Bytes, pUnsafeBits);
526 }
527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
528 {
529 ret = 0;
530 }
531 _SEH2_END
532
533 SURFACE_UnlockSurface(psurf);
534
535 return ret;
536 }
537
538
539 LONG APIENTRY
540 IntSetBitmapBits(
541 PSURFACE psurf,
542 DWORD Bytes,
543 IN PBYTE Bits)
544 {
545 LONG ret;
546
547 /* Don't copy more bytes than the buffer has */
548 Bytes = min(Bytes, psurf->SurfObj.cjBits);
549
550 #if 0
551 /* FIXME: call DDI specific function here if available */
552 if (psurf->DDBitmap)
553 {
554 DPRINT("Calling device specific BitmapBits\n");
555 if (psurf->DDBitmap->funcs->pBitmapBits)
556 {
557 ret = psurf->DDBitmap->funcs->pBitmapBits(hBitmap,
558 (void *)Bits,
559 Bytes,
560 DDB_SET);
561 }
562 else
563 {
564 DPRINT("BitmapBits == NULL??\n");
565 ret = 0;
566 }
567 }
568 else
569 #endif
570 {
571 RtlCopyMemory(psurf->SurfObj.pvBits, Bits, Bytes);
572 ret = Bytes;
573 }
574
575 return ret;
576 }
577
578
579 LONG APIENTRY
580 NtGdiSetBitmapBits(
581 HBITMAP hBitmap,
582 DWORD Bytes,
583 IN PBYTE pUnsafeBits)
584 {
585 LONG ret;
586 PSURFACE psurf;
587
588 if (pUnsafeBits == NULL || Bytes == 0)
589 {
590 return 0;
591 }
592
593 psurf = SURFACE_LockSurface(hBitmap);
594 if (psurf == NULL)
595 {
596 SetLastWin32Error(ERROR_INVALID_HANDLE);
597 return 0;
598 }
599
600 _SEH2_TRY
601 {
602 ProbeForRead(pUnsafeBits, Bytes, 1);
603 ret = IntSetBitmapBits(psurf, Bytes, pUnsafeBits);
604 }
605 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
606 {
607 ret = 0;
608 }
609 _SEH2_END
610
611 SURFACE_UnlockSurface(psurf);
612
613 return ret;
614 }
615
616 BOOL APIENTRY
617 NtGdiSetBitmapDimension(
618 HBITMAP hBitmap,
619 INT Width,
620 INT Height,
621 LPSIZE Size)
622 {
623 PSURFACE psurf;
624 BOOL Ret = TRUE;
625
626 if (hBitmap == NULL)
627 return FALSE;
628
629 psurf = SURFACE_LockSurface(hBitmap);
630 if (psurf == NULL)
631 {
632 SetLastWin32Error(ERROR_INVALID_HANDLE);
633 return FALSE;
634 }
635
636 if (Size)
637 {
638 _SEH2_TRY
639 {
640 ProbeForWrite(Size, sizeof(SIZE), 1);
641 *Size = psurf->dimension;
642 }
643 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
644 {
645 Ret = FALSE;
646 }
647 _SEH2_END
648 }
649
650 /* The dimension is changed even if writing the old value failed */
651 psurf->dimension.cx = Width;
652 psurf->dimension.cy = Height;
653
654 SURFACE_UnlockSurface(psurf);
655
656 return Ret;
657 }
658
659 BOOL APIENTRY
660 GdiSetPixelV(
661 HDC hDC,
662 INT X,
663 INT Y,
664 COLORREF Color)
665 {
666 HBRUSH hbrush = NtGdiCreateSolidBrush(Color, NULL);
667 HGDIOBJ OldBrush;
668
669 if (hbrush == NULL)
670 return(FALSE);
671
672 OldBrush = NtGdiSelectBrush(hDC, hbrush);
673 if (OldBrush == NULL)
674 {
675 GreDeleteObject(hbrush);
676 return(FALSE);
677 }
678
679 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
680 NtGdiSelectBrush(hDC, OldBrush);
681 GreDeleteObject(hbrush);
682
683 return TRUE;
684 }
685
686 COLORREF APIENTRY
687 NtGdiSetPixel(
688 HDC hDC,
689 INT X,
690 INT Y,
691 COLORREF Color)
692 {
693 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
694
695 if (GdiSetPixelV(hDC,X,Y,Color))
696 {
697 Color = NtGdiGetPixel(hDC,X,Y);
698 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
699 return Color;
700 }
701
702 Color = (COLORREF)CLR_INVALID;
703 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
704 return Color;
705 }
706
707
708 /* Internal Functions */
709
710 UINT FASTCALL
711 BITMAP_GetRealBitsPixel(UINT nBitsPixel)
712 {
713 if (nBitsPixel <= 1)
714 return 1;
715 if (nBitsPixel <= 4)
716 return 4;
717 if (nBitsPixel <= 8)
718 return 8;
719 if (nBitsPixel <= 16)
720 return 16;
721 if (nBitsPixel <= 24)
722 return 24;
723 if (nBitsPixel <= 32)
724 return 32;
725
726 return 0;
727 }
728
729 INT FASTCALL
730 BITMAP_GetWidthBytes(INT bmWidth, INT bpp)
731 {
732 #if 0
733 switch (bpp)
734 {
735 case 1:
736 return 2 * ((bmWidth+15) >> 4);
737
738 case 24:
739 bmWidth *= 3; /* fall through */
740 case 8:
741 return bmWidth + (bmWidth & 1);
742
743 case 32:
744 return bmWidth * 4;
745
746 case 16:
747 case 15:
748 return bmWidth * 2;
749
750 case 4:
751 return 2 * ((bmWidth+3) >> 2);
752
753 default:
754 DPRINT ("stub");
755 }
756
757 return -1;
758 #endif
759
760 return ((bmWidth * bpp + 15) & ~15) >> 3;
761 }
762
763 HBITMAP FASTCALL
764 BITMAP_CopyBitmap(HBITMAP hBitmap)
765 {
766 HBITMAP res;
767 BITMAP bm;
768 SURFACE *Bitmap, *resBitmap;
769 SIZEL Size;
770
771 if (hBitmap == NULL)
772 {
773 return 0;
774 }
775
776 Bitmap = GDIOBJ_LockObj(hBitmap, GDI_OBJECT_TYPE_BITMAP);
777 if (Bitmap == NULL)
778 {
779 return 0;
780 }
781
782 BITMAP_GetObject(Bitmap, sizeof(BITMAP), (PVOID)&bm);
783 bm.bmBits = NULL;
784 if (Bitmap->SurfObj.lDelta >= 0)
785 bm.bmHeight = -bm.bmHeight;
786
787 Size.cx = abs(bm.bmWidth);
788 Size.cy = abs(bm.bmHeight);
789 res = IntCreateBitmap(Size,
790 bm.bmWidthBytes,
791 BitmapFormat(bm.bmBitsPixel * bm.bmPlanes, BI_RGB),
792 (bm.bmHeight < 0 ? BMF_TOPDOWN : 0) | BMF_NOZEROINIT,
793 NULL);
794
795 if (res)
796 {
797 PBYTE buf;
798
799 resBitmap = GDIOBJ_LockObj(res, GDI_OBJECT_TYPE_BITMAP);
800 if (resBitmap)
801 {
802 buf = ExAllocatePoolWithTag(PagedPool,
803 bm.bmWidthBytes * abs(bm.bmHeight),
804 TAG_BITMAP);
805 if (buf == NULL)
806 {
807 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
808 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
809 GreDeleteObject(res);
810 return 0;
811 }
812 IntGetBitmapBits(Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
813 IntSetBitmapBits(resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
814 ExFreePoolWithTag(buf,TAG_BITMAP);
815 resBitmap->flFlags = Bitmap->flFlags;
816 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
817 }
818 else
819 {
820 GreDeleteObject(res);
821 res = NULL;
822 }
823 }
824
825 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
826
827 return res;
828 }
829
830 INT APIENTRY
831 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
832 {
833 PBITMAP pBitmap;
834
835 if (!buffer) return sizeof(BITMAP);
836 if ((UINT)Count < sizeof(BITMAP)) return 0;
837
838 /* always fill a basic BITMAP structure */
839 pBitmap = buffer;
840 pBitmap->bmType = 0;
841 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
842 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
843 pBitmap->bmWidthBytes = abs(psurf->SurfObj.lDelta);
844 pBitmap->bmPlanes = 1;
845 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
846
847 /* Check for DIB section */
848 if (psurf->hSecure)
849 {
850 /* Set bmBits in this case */
851 pBitmap->bmBits = psurf->SurfObj.pvBits;
852
853 if (Count >= sizeof(DIBSECTION))
854 {
855 /* Fill rest of DIBSECTION */
856 PDIBSECTION pds = buffer;
857
858 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
859 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
860 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
861 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
862 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
863 switch (psurf->SurfObj.iBitmapFormat)
864 {
865 /* FIXME: What about BI_BITFIELDS? */
866 case BMF_1BPP:
867 case BMF_4BPP:
868 case BMF_8BPP:
869 case BMF_16BPP:
870 case BMF_24BPP:
871 case BMF_32BPP:
872 pds->dsBmih.biCompression = BI_RGB;
873 break;
874 case BMF_4RLE:
875 pds->dsBmih.biCompression = BI_RLE4;
876 break;
877 case BMF_8RLE:
878 pds->dsBmih.biCompression = BI_RLE8;
879 break;
880 case BMF_JPEG:
881 pds->dsBmih.biCompression = BI_JPEG;
882 break;
883 case BMF_PNG:
884 pds->dsBmih.biCompression = BI_PNG;
885 break;
886 }
887 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
888 pds->dsBmih.biXPelsPerMeter = 0;
889 pds->dsBmih.biYPelsPerMeter = 0;
890 pds->dsBmih.biClrUsed = psurf->biClrUsed;
891 pds->dsBmih.biClrImportant = psurf->biClrImportant;
892 pds->dsBitfields[0] = psurf->dsBitfields[0];
893 pds->dsBitfields[1] = psurf->dsBitfields[1];
894 pds->dsBitfields[2] = psurf->dsBitfields[2];
895 pds->dshSection = psurf->hDIBSection;
896 pds->dsOffset = psurf->dwOffset;
897
898 return sizeof(DIBSECTION);
899 }
900 }
901 else
902 {
903 /* not set according to wine test, confirmed in win2k */
904 pBitmap->bmBits = NULL;
905 }
906
907 return sizeof(BITMAP);
908 }
909
910 /*
911 * @implemented
912 */
913 HDC
914 APIENTRY
915 NtGdiGetDCforBitmap(
916 IN HBITMAP hsurf)
917 {
918 HDC hDC = NULL;
919 PSURFACE psurf = SURFACE_LockSurface(hsurf);
920 if (psurf)
921 {
922 hDC = psurf->hDC;
923 SURFACE_UnlockSurface(psurf);
924 }
925 return hDC;
926 }
927
928 /* EOF */