- GetBitmapBits: This function should return DDB size since it's for 16 bit win only...
[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 NtGdiDeleteObject(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 = SURFACE_LockSurface(Dc->rosdc.hBitmap);
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 PPALGDI PalGDI = PALETTE_LockPalette(psurf->hDIBPalette);
222
223 if (!PalGDI)
224 {
225 ExFreePoolWithTag(bi, TAG_TEMP);
226 SURFACE_UnlockSurface(psurf);
227 SetLastWin32Error(ERROR_INVALID_HANDLE);
228 return 0;
229 }
230
231 for (Index = 0;
232 Index < 256 && Index < PalGDI->NumColors;
233 Index++)
234 {
235 bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
236 bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
237 bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
238 bi->bmiColors[Index].rgbReserved = 0;
239 }
240 PALETTE_UnlockPalette(PalGDI);
241 }
242 SURFACE_UnlockSurface(psurf);
243
244 Bmp = DIB_CreateDIBSection(Dc,
245 bi,
246 DIB_RGB_COLORS,
247 &Bits,
248 NULL,
249 0,
250 0);
251
252 ExFreePoolWithTag(bi, TAG_TEMP);
253 return Bmp;
254 }
255 }
256 }
257 SURFACE_UnlockSurface(psurf);
258 }
259 }
260 return Bmp;
261 }
262
263 HBITMAP APIENTRY
264 NtGdiCreateCompatibleBitmap(
265 HDC hDC,
266 INT Width,
267 INT Height)
268 {
269 HBITMAP Bmp;
270 PDC Dc;
271
272 if (Width <= 0 || Height <= 0 || (Width * Height) > 0x3FFFFFFF)
273 {
274 SetLastWin32Error(ERROR_INVALID_PARAMETER);
275 return NULL;
276 }
277
278 if (!hDC)
279 return IntGdiCreateBitmap(Width, Height, 1, 1, 0);
280
281 Dc = DC_LockDc(hDC);
282
283 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n",
284 hDC, Width, Height, Dc->ppdev->GDIInfo.cBitsPixel);
285
286 if (NULL == Dc)
287 {
288 SetLastWin32Error(ERROR_INVALID_HANDLE);
289 return NULL;
290 }
291
292 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
293
294 DPRINT("\t\t%04x\n", Bmp);
295 DC_UnlockDc(Dc);
296 return Bmp;
297 }
298
299 BOOL APIENTRY
300 NtGdiGetBitmapDimension(
301 HBITMAP hBitmap,
302 LPSIZE Dimension)
303 {
304 PSURFACE psurfBmp;
305 BOOL Ret = TRUE;
306
307 if (hBitmap == NULL)
308 return FALSE;
309
310 psurfBmp = SURFACE_LockSurface(hBitmap);
311 if (psurfBmp == NULL)
312 {
313 SetLastWin32Error(ERROR_INVALID_HANDLE);
314 return FALSE;
315 }
316
317 _SEH2_TRY
318 {
319 ProbeForWrite(Dimension, sizeof(SIZE), 1);
320 *Dimension = psurfBmp->dimension;
321 }
322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
323 {
324 Ret = FALSE;
325 }
326 _SEH2_END
327
328 SURFACE_UnlockSurface(psurfBmp);
329
330 return Ret;
331 }
332
333 COLORREF APIENTRY
334 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
335 {
336 PDC dc = NULL;
337 COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
338 BOOL bInRect = FALSE;
339 SURFACE *psurf;
340 SURFOBJ *pso;
341 HPALETTE Pal = 0;
342 XLATEOBJ *XlateObj;
343 HBITMAP hBmpTmp;
344
345 dc = DC_LockDc(hDC);
346
347 if (!dc)
348 {
349 SetLastWin32Error(ERROR_INVALID_HANDLE);
350 return Result;
351 }
352
353 if (dc->dctype == DC_TYPE_INFO)
354 {
355 DC_UnlockDc(dc);
356 return Result;
357 }
358
359 XPos += dc->ptlDCOrig.x;
360 YPos += dc->ptlDCOrig.y;
361 if (RECTL_bPointInRect(&dc->rosdc.CombinedClip->rclBounds, XPos, YPos))
362 {
363 bInRect = TRUE;
364 psurf = SURFACE_LockSurface(dc->rosdc.hBitmap);
365 pso = &psurf->SurfObj;
366 if (psurf)
367 {
368 Pal = psurf->hDIBPalette;
369 if (!Pal) Pal = pPrimarySurface->DevInfo.hpalDefault;
370
371 /* FIXME: Verify if it shouldn't be PAL_BGR! */
372 XlateObj = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, 0, NULL, Pal);
373 if (XlateObj)
374 {
375 // check if this DC has a DIB behind it...
376 if (pso->pvScan0) // STYPE_BITMAP == pso->iType
377 {
378 ASSERT(pso->lDelta);
379 Result = XLATEOBJ_iXlate(XlateObj,
380 DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_GetPixel(pso, XPos, YPos));
381 }
382 EngDeleteXlate(XlateObj);
383 }
384 SURFACE_UnlockSurface(psurf);
385 }
386 }
387 DC_UnlockDc(dc);
388
389 // if Result is still CLR_INVALID, then the "quick" method above didn't work
390 if (bInRect && Result == CLR_INVALID)
391 {
392 // FIXME: create a 1x1 32BPP DIB, and blit to it
393 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
394 if (hDCTmp)
395 {
396 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
397 BITMAPINFO bi;
398 RtlMoveMemory(&(bi.bmiHeader), &bih, sizeof(bih));
399 hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
400 bi.bmiHeader.biWidth,
401 bi.bmiHeader.biHeight,
402 0,
403 NULL,
404 &bi,
405 DIB_RGB_COLORS,
406 bi.bmiHeader.biBitCount,
407 bi.bmiHeader.biSizeImage,
408 0,
409 0);
410
411 //HBITMAP hBmpTmp = IntGdiCreateBitmap(1, 1, 1, 32, NULL);
412 if (hBmpTmp)
413 {
414 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap(hDCTmp, hBmpTmp);
415 if (hBmpOld)
416 {
417 PSURFACE psurf;
418
419 NtGdiBitBlt(hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0);
420 NtGdiSelectBitmap(hDCTmp, hBmpOld);
421
422 // our bitmap is no longer selected, so we can access it's stuff...
423 psurf = SURFACE_LockSurface(hBmpTmp);
424 if (psurf)
425 {
426 // Dont you need to convert something here?
427 Result = *(COLORREF*)psurf->SurfObj.pvScan0;
428 SURFACE_UnlockSurface(psurf);
429 }
430 }
431 NtGdiDeleteObject(hBmpTmp);
432 }
433 NtGdiDeleteObjectApp(hDCTmp);
434 }
435 }
436
437 return Result;
438 }
439
440
441 LONG APIENTRY
442 IntGetBitmapBits(
443 PSURFACE psurf,
444 DWORD Bytes,
445 OUT PBYTE Bits)
446 {
447 LONG ret;
448
449 ASSERT(Bits);
450
451 /* Don't copy more bytes than the buffer has */
452 Bytes = min(Bytes, psurf->SurfObj.cjBits);
453
454 #if 0
455 /* FIXME: Call DDI CopyBits here if available */
456 if (psurf->DDBitmap)
457 {
458 DPRINT("Calling device specific BitmapBits\n");
459 if (psurf->DDBitmap->funcs->pBitmapBits)
460 {
461 ret = psurf->DDBitmap->funcs->pBitmapBits(hbitmap,
462 bits,
463 count,
464 DDB_GET);
465 }
466 else
467 {
468 ERR_(bitmap)("BitmapBits == NULL??\n");
469 ret = 0;
470 }
471 }
472 else
473 #endif
474 {
475 RtlCopyMemory(Bits, psurf->SurfObj.pvBits, Bytes);
476 ret = Bytes;
477 }
478 return ret;
479 }
480
481 LONG APIENTRY
482 NtGdiGetBitmapBits(
483 HBITMAP hBitmap,
484 ULONG Bytes,
485 OUT OPTIONAL PBYTE pUnsafeBits)
486 {
487 PSURFACE psurf;
488 LONG bmSize, ret;
489
490 if (pUnsafeBits != NULL && Bytes == 0)
491 {
492 return 0;
493 }
494
495 psurf = SURFACE_LockSurface(hBitmap);
496 if (!psurf)
497 {
498 SetLastWin32Error(ERROR_INVALID_HANDLE);
499 return 0;
500 }
501
502 bmSize = BITMAP_GetWidthBytes(psurf->SurfObj.sizlBitmap.cx,
503 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
504 abs(psurf->SurfObj.sizlBitmap.cy);
505
506 /* If the bits vector is null, the function should return the read size */
507 if (pUnsafeBits == NULL)
508 {
509 SURFACE_UnlockSurface(psurf);
510 return bmSize;
511 }
512
513 /* Don't copy more bytes than the buffer has */
514 Bytes = min(Bytes, bmSize);
515
516 // FIXME: use MmSecureVirtualMemory
517 _SEH2_TRY
518 {
519 ProbeForWrite(pUnsafeBits, Bytes, 1);
520 ret = IntGetBitmapBits(psurf, Bytes, pUnsafeBits);
521 }
522 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
523 {
524 ret = 0;
525 }
526 _SEH2_END
527
528 SURFACE_UnlockSurface(psurf);
529
530 return ret;
531 }
532
533
534 LONG APIENTRY
535 IntSetBitmapBits(
536 PSURFACE psurf,
537 DWORD Bytes,
538 IN PBYTE Bits)
539 {
540 LONG ret;
541
542 /* Don't copy more bytes than the buffer has */
543 Bytes = min(Bytes, psurf->SurfObj.cjBits);
544
545 #if 0
546 /* FIXME: call DDI specific function here if available */
547 if (psurf->DDBitmap)
548 {
549 DPRINT("Calling device specific BitmapBits\n");
550 if (psurf->DDBitmap->funcs->pBitmapBits)
551 {
552 ret = psurf->DDBitmap->funcs->pBitmapBits(hBitmap,
553 (void *)Bits,
554 Bytes,
555 DDB_SET);
556 }
557 else
558 {
559 DPRINT("BitmapBits == NULL??\n");
560 ret = 0;
561 }
562 }
563 else
564 #endif
565 {
566 RtlCopyMemory(psurf->SurfObj.pvBits, Bits, Bytes);
567 ret = Bytes;
568 }
569
570 return ret;
571 }
572
573
574 LONG APIENTRY
575 NtGdiSetBitmapBits(
576 HBITMAP hBitmap,
577 DWORD Bytes,
578 IN PBYTE pUnsafeBits)
579 {
580 LONG ret;
581 PSURFACE psurf;
582
583 if (pUnsafeBits == NULL || Bytes == 0)
584 {
585 return 0;
586 }
587
588 psurf = SURFACE_LockSurface(hBitmap);
589 if (psurf == NULL)
590 {
591 SetLastWin32Error(ERROR_INVALID_HANDLE);
592 return 0;
593 }
594
595 _SEH2_TRY
596 {
597 ProbeForRead(pUnsafeBits, Bytes, 1);
598 ret = IntSetBitmapBits(psurf, Bytes, pUnsafeBits);
599 }
600 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
601 {
602 ret = 0;
603 }
604 _SEH2_END
605
606 SURFACE_UnlockSurface(psurf);
607
608 return ret;
609 }
610
611 BOOL APIENTRY
612 NtGdiSetBitmapDimension(
613 HBITMAP hBitmap,
614 INT Width,
615 INT Height,
616 LPSIZE Size)
617 {
618 PSURFACE psurf;
619 BOOL Ret = TRUE;
620
621 if (hBitmap == NULL)
622 return FALSE;
623
624 psurf = SURFACE_LockSurface(hBitmap);
625 if (psurf == NULL)
626 {
627 SetLastWin32Error(ERROR_INVALID_HANDLE);
628 return FALSE;
629 }
630
631 if (Size)
632 {
633 _SEH2_TRY
634 {
635 ProbeForWrite(Size, sizeof(SIZE), 1);
636 *Size = psurf->dimension;
637 }
638 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
639 {
640 Ret = FALSE;
641 }
642 _SEH2_END
643 }
644
645 /* The dimension is changed even if writing the old value failed */
646 psurf->dimension.cx = Width;
647 psurf->dimension.cy = Height;
648
649 SURFACE_UnlockSurface(psurf);
650
651 return Ret;
652 }
653
654 BOOL APIENTRY
655 GdiSetPixelV(
656 HDC hDC,
657 INT X,
658 INT Y,
659 COLORREF Color)
660 {
661 HBRUSH hbrush = NtGdiCreateSolidBrush(Color, NULL);
662 HGDIOBJ OldBrush;
663
664 if (hbrush == NULL)
665 return(FALSE);
666
667 OldBrush = NtGdiSelectBrush(hDC, hbrush);
668 if (OldBrush == NULL)
669 {
670 NtGdiDeleteObject(hbrush);
671 return(FALSE);
672 }
673
674 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
675 NtGdiSelectBrush(hDC, OldBrush);
676 NtGdiDeleteObject(hbrush);
677
678 return TRUE;
679 }
680
681 COLORREF APIENTRY
682 NtGdiSetPixel(
683 HDC hDC,
684 INT X,
685 INT Y,
686 COLORREF Color)
687 {
688 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
689
690 if (GdiSetPixelV(hDC,X,Y,Color))
691 {
692 Color = NtGdiGetPixel(hDC,X,Y);
693 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
694 return Color;
695 }
696
697 Color = (COLORREF)CLR_INVALID;
698 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
699 return Color;
700 }
701
702
703 /* Internal Functions */
704
705 UINT FASTCALL
706 BITMAP_GetRealBitsPixel(UINT nBitsPixel)
707 {
708 if (nBitsPixel <= 1)
709 return 1;
710 if (nBitsPixel <= 4)
711 return 4;
712 if (nBitsPixel <= 8)
713 return 8;
714 if (nBitsPixel <= 16)
715 return 16;
716 if (nBitsPixel <= 24)
717 return 24;
718 if (nBitsPixel <= 32)
719 return 32;
720
721 return 0;
722 }
723
724 INT FASTCALL
725 BITMAP_GetWidthBytes(INT bmWidth, INT bpp)
726 {
727 #if 0
728 switch (bpp)
729 {
730 case 1:
731 return 2 * ((bmWidth+15) >> 4);
732
733 case 24:
734 bmWidth *= 3; /* fall through */
735 case 8:
736 return bmWidth + (bmWidth & 1);
737
738 case 32:
739 return bmWidth * 4;
740
741 case 16:
742 case 15:
743 return bmWidth * 2;
744
745 case 4:
746 return 2 * ((bmWidth+3) >> 2);
747
748 default:
749 DPRINT ("stub");
750 }
751
752 return -1;
753 #endif
754
755 return ((bmWidth * bpp + 15) & ~15) >> 3;
756 }
757
758 HBITMAP FASTCALL
759 BITMAP_CopyBitmap(HBITMAP hBitmap)
760 {
761 HBITMAP res;
762 BITMAP bm;
763 SURFACE *Bitmap, *resBitmap;
764 SIZEL Size;
765
766 if (hBitmap == NULL)
767 {
768 return 0;
769 }
770
771 Bitmap = GDIOBJ_LockObj(hBitmap, GDI_OBJECT_TYPE_BITMAP);
772 if (Bitmap == NULL)
773 {
774 return 0;
775 }
776
777 BITMAP_GetObject(Bitmap, sizeof(BITMAP), (PVOID)&bm);
778 bm.bmBits = NULL;
779 if (Bitmap->SurfObj.lDelta >= 0)
780 bm.bmHeight = -bm.bmHeight;
781
782 Size.cx = abs(bm.bmWidth);
783 Size.cy = abs(bm.bmHeight);
784 res = IntCreateBitmap(Size,
785 bm.bmWidthBytes,
786 BitmapFormat(bm.bmBitsPixel * bm.bmPlanes, BI_RGB),
787 (bm.bmHeight < 0 ? BMF_TOPDOWN : 0) | BMF_NOZEROINIT,
788 NULL);
789
790 if (res)
791 {
792 PBYTE buf;
793
794 resBitmap = GDIOBJ_LockObj(res, GDI_OBJECT_TYPE_BITMAP);
795 if (resBitmap)
796 {
797 buf = ExAllocatePoolWithTag(PagedPool,
798 bm.bmWidthBytes * abs(bm.bmHeight),
799 TAG_BITMAP);
800 if (buf == NULL)
801 {
802 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
803 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
804 NtGdiDeleteObject(res);
805 return 0;
806 }
807 IntGetBitmapBits(Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
808 IntSetBitmapBits(resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
809 ExFreePoolWithTag(buf,TAG_BITMAP);
810 resBitmap->flFlags = Bitmap->flFlags;
811 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
812 }
813 else
814 {
815 NtGdiDeleteObject(res);
816 res = NULL;
817 }
818 }
819
820 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
821
822 return res;
823 }
824
825 INT APIENTRY
826 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
827 {
828 PBITMAP pBitmap;
829
830 if (!buffer) return sizeof(BITMAP);
831 if ((UINT)Count < sizeof(BITMAP)) return 0;
832
833 /* always fill a basic BITMAP structure */
834 pBitmap = buffer;
835 pBitmap->bmType = 0;
836 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
837 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
838 pBitmap->bmWidthBytes = abs(psurf->SurfObj.lDelta);
839 pBitmap->bmPlanes = 1;
840 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
841
842 /* Check for DIB section */
843 if (psurf->hSecure)
844 {
845 /* Set bmBits in this case */
846 pBitmap->bmBits = psurf->SurfObj.pvBits;
847
848 if (Count >= sizeof(DIBSECTION))
849 {
850 /* Fill rest of DIBSECTION */
851 PDIBSECTION pds = buffer;
852
853 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
854 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
855 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
856 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
857 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
858 switch (psurf->SurfObj.iBitmapFormat)
859 {
860 /* FIXME: What about BI_BITFIELDS? */
861 case BMF_1BPP:
862 case BMF_4BPP:
863 case BMF_8BPP:
864 case BMF_16BPP:
865 case BMF_24BPP:
866 case BMF_32BPP:
867 pds->dsBmih.biCompression = BI_RGB;
868 break;
869 case BMF_4RLE:
870 pds->dsBmih.biCompression = BI_RLE4;
871 break;
872 case BMF_8RLE:
873 pds->dsBmih.biCompression = BI_RLE8;
874 break;
875 case BMF_JPEG:
876 pds->dsBmih.biCompression = BI_JPEG;
877 break;
878 case BMF_PNG:
879 pds->dsBmih.biCompression = BI_PNG;
880 break;
881 }
882 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
883 pds->dsBmih.biXPelsPerMeter = 0;
884 pds->dsBmih.biYPelsPerMeter = 0;
885 pds->dsBmih.biClrUsed = psurf->biClrUsed;
886 pds->dsBmih.biClrImportant = psurf->biClrImportant;
887 pds->dsBitfields[0] = psurf->dsBitfields[0];
888 pds->dsBitfields[1] = psurf->dsBitfields[1];
889 pds->dsBitfields[2] = psurf->dsBitfields[2];
890 pds->dshSection = psurf->hDIBSection;
891 pds->dsOffset = psurf->dwOffset;
892
893 return sizeof(DIBSECTION);
894 }
895 }
896 else
897 {
898 /* not set according to wine test, confirmed in win2k */
899 pBitmap->bmBits = NULL;
900 }
901
902 return sizeof(BITMAP);
903 }
904
905 /*
906 * @implemented
907 */
908 HDC
909 APIENTRY
910 NtGdiGetDCforBitmap(
911 IN HBITMAP hsurf)
912 {
913 HDC hDC = NULL;
914 PSURFACE psurf = SURFACE_LockSurface(hsurf);
915 if (psurf)
916 {
917 hDC = psurf->hDC;
918 SURFACE_UnlockSurface(psurf);
919 }
920 return hDC;
921 }
922
923 /*
924 * @implemented
925 */
926 HBITMAP
927 APIENTRY
928 NtGdiSelectBitmap(
929 IN HDC hDC,
930 IN HBITMAP hBmp)
931 {
932 PDC pDC;
933 PDC_ATTR pdcattr;
934 HBITMAP hOrgBmp;
935 PSURFACE psurfBmp;
936 HRGN hVisRgn;
937 BOOLEAN bFailed;
938 PBRUSH pbrush;
939
940 if (hDC == NULL || hBmp == NULL) return NULL;
941
942 pDC = DC_LockDc(hDC);
943 if (!pDC)
944 {
945 return NULL;
946 }
947
948 pdcattr = pDC->pdcattr;
949
950 /* must be memory dc to select bitmap */
951 if (pDC->dctype != DC_TYPE_MEMORY)
952 {
953 DC_UnlockDc(pDC);
954 return NULL;
955 }
956
957 psurfBmp = SURFACE_LockSurface(hBmp);
958 if (!psurfBmp)
959 {
960 DC_UnlockDc(pDC);
961 return NULL;
962 }
963 hOrgBmp = pDC->rosdc.hBitmap;
964
965 /* Release the old bitmap, lock the new one and convert it to a SURF */
966 pDC->rosdc.hBitmap = hBmp;
967
968 // If Info DC this is zero and pSurface is moved to DC->pSurfInfo.
969 pDC->dclevel.pSurface = psurfBmp;
970 psurfBmp->hDC = hDC;
971
972 // if we're working with a DIB, get the palette
973 // [fixme: only create if the selected palette is null]
974 if (psurfBmp->hSecure)
975 {
976 // pDC->rosdcbitsPerPixel = psurfBmp->dib->dsBmih.biBitCount; ???
977 pDC->rosdc.bitsPerPixel = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
978 }
979 else
980 {
981 pDC->rosdc.bitsPerPixel = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
982 }
983
984 hVisRgn = NtGdiCreateRectRgn(0,
985 0,
986 psurfBmp->SurfObj.sizlBitmap.cx,
987 psurfBmp->SurfObj.sizlBitmap.cy);
988 SURFACE_UnlockSurface(psurfBmp);
989
990 /* Regenerate the XLATEOBJs. */
991 pbrush = BRUSH_LockBrush(pdcattr->hbrush);
992 if (pbrush)
993 {
994 if (pDC->rosdc.XlateBrush)
995 {
996 EngDeleteXlate(pDC->rosdc.XlateBrush);
997 }
998 pDC->rosdc.XlateBrush = IntGdiCreateBrushXlate(pDC, pbrush, &bFailed);
999 BRUSH_UnlockBrush(pbrush);
1000 }
1001
1002 pbrush = PENOBJ_LockPen(pdcattr->hpen);
1003 if (pbrush)
1004 {
1005 if (pDC->rosdc.XlatePen)
1006 {
1007 EngDeleteXlate(pDC->rosdc.XlatePen);
1008 }
1009 pDC->rosdc.XlatePen = IntGdiCreateBrushXlate(pDC, pbrush, &bFailed);
1010 PENOBJ_UnlockPen(pbrush);
1011 }
1012
1013 DC_UnlockDc(pDC);
1014
1015 if (hVisRgn)
1016 {
1017 GdiSelectVisRgn(hDC, hVisRgn);
1018 NtGdiDeleteObject(hVisRgn);
1019 }
1020
1021 return hOrgBmp;
1022 }
1023
1024 /* EOF */