[FORMATTING]
[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 #define IN_RECT(r,x,y) \
27 ( \
28 (x) >= (r).left && \
29 (y) >= (r).top && \
30 (x) < (r).right && \
31 (y) < (r).bottom \
32 )
33
34 HBITMAP APIENTRY
35 IntGdiCreateBitmap(
36 INT Width,
37 INT Height,
38 UINT Planes,
39 UINT BitsPixel,
40 IN OPTIONAL LPBYTE pBits)
41 {
42 HBITMAP hBitmap;
43 SIZEL Size;
44 LONG WidthBytes;
45 PSURFACE psurfBmp;
46
47 /* NOTE: Windows also doesn't store nr. of planes separately! */
48 BitsPixel = BITMAP_GetRealBitsPixel(BitsPixel * Planes);
49
50 /* Check parameters */
51 if (BitsPixel == 0 || Width <= 0 || Width >= 0x8000000 || Height == 0)
52 {
53 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
54 Width, Height, BitsPixel);
55 SetLastWin32Error(ERROR_INVALID_PARAMETER);
56 return 0;
57 }
58
59 WidthBytes = BITMAP_GetWidthBytes(Width, BitsPixel);
60
61 Size.cx = Width;
62 Size.cy = abs(Height);
63
64 /* Make sure that cjBits will not overflow */
65 if ((ULONGLONG)WidthBytes * Size.cy >= 0x100000000ULL)
66 {
67 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
68 Width, Height, BitsPixel);
69 SetLastWin32Error(ERROR_INVALID_PARAMETER);
70 return 0;
71 }
72
73 /* Create the bitmap object. */
74 hBitmap = IntCreateBitmap(Size, WidthBytes,
75 BitmapFormat(BitsPixel, BI_RGB),
76 (Height < 0 ? BMF_TOPDOWN : 0) |
77 (NULL == pBits ? 0 : BMF_NOZEROINIT), NULL);
78 if (!hBitmap)
79 {
80 DPRINT("IntGdiCreateBitmap: returned 0\n");
81 return 0;
82 }
83
84 psurfBmp = SURFACE_LockSurface(hBitmap);
85 if (psurfBmp == NULL)
86 {
87 NtGdiDeleteObject(hBitmap);
88 return NULL;
89 }
90
91 psurfBmp->flFlags = BITMAPOBJ_IS_APIBITMAP;
92 psurfBmp->hDC = NULL; // Fixme
93
94 if (NULL != pBits)
95 {
96 IntSetBitmapBits(psurfBmp, psurfBmp->SurfObj.cjBits, pBits);
97 }
98
99 SURFACE_UnlockSurface(psurfBmp);
100
101 DPRINT("IntGdiCreateBitmap : %dx%d, %d BPP colors, topdown %d, returning %08x\n",
102 Size.cx, Size.cy, BitsPixel, (Height < 0 ? 1 : 0), hBitmap);
103
104 return hBitmap;
105 }
106
107
108 HBITMAP APIENTRY
109 NtGdiCreateBitmap(
110 INT Width,
111 INT Height,
112 UINT Planes,
113 UINT BitsPixel,
114 IN OPTIONAL LPBYTE pUnsafeBits)
115 {
116 if (pUnsafeBits)
117 {
118 BOOL Hit = FALSE;
119 UINT cjBits = BITMAP_GetWidthBytes(Width, BitsPixel) * abs(Height);
120
121 // FIXME: Use MmSecureVirtualMemory
122 _SEH2_TRY
123 {
124 ProbeForRead(pUnsafeBits, cjBits, 1);
125 }
126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
127 {
128 Hit = TRUE;
129 }
130 _SEH2_END
131
132 if (Hit) return 0;
133 }
134
135 return IntGdiCreateBitmap(Width, Height, Planes, BitsPixel, pUnsafeBits);
136 }
137
138 HBITMAP FASTCALL
139 IntCreateCompatibleBitmap(
140 PDC Dc,
141 INT Width,
142 INT Height)
143 {
144 HBITMAP Bmp = NULL;
145
146 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
147 if (0 == Width || 0 == Height)
148 {
149 Bmp = NtGdiGetStockObject(DEFAULT_BITMAP);
150 }
151 else
152 {
153 if (Dc->DC_Type != DC_TYPE_MEMORY)
154 {
155 Bmp = IntGdiCreateBitmap(abs(Width),
156 abs(Height),
157 IntGdiGetDeviceCaps(Dc,PLANES),
158 IntGdiGetDeviceCaps(Dc,BITSPIXEL),
159 NULL);
160 }
161 else
162 {
163 DIBSECTION dibs;
164 INT Count;
165 PSURFACE psurf = SURFACE_LockSurface(Dc->w.hBitmap);
166 Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
167
168 if (Count)
169 {
170 if (Count == sizeof(BITMAP))
171 {
172 /* We have a bitmap bug!!! W/O the HACK, we have white icons.
173
174 MSDN Note: When a memory device context is created, it initially
175 has a 1-by-1 monochrome bitmap selected into it. If this memory
176 device context is used in CreateCompatibleBitmap, the bitmap that
177 is created is a monochrome bitmap. To create a color bitmap, use
178 the hDC that was used to create the memory device context, as
179 shown in the following code:
180
181 HDC memDC = CreateCompatibleDC(hDC);
182 HBITMAP memBM = CreateCompatibleBitmap(hDC, nWidth, nHeight);
183 SelectObject(memDC, memBM);
184 */
185 Bmp = IntGdiCreateBitmap(abs(Width),
186 abs(Height),
187 dibs.dsBm.bmPlanes,
188 IntGdiGetDeviceCaps(Dc,BITSPIXEL),//<-- HACK! dibs.dsBm.bmBitsPixel, // <-- Correct!
189 NULL);
190 }
191 else
192 {
193 /* A DIB section is selected in the DC */
194 BITMAPINFO *bi;
195 PVOID Bits;
196
197 /* Allocate memory for a BITMAPINFOHEADER structure and a
198 color table. The maximum number of colors in a color table
199 is 256 which corresponds to a bitmap with depth 8.
200 Bitmaps with higher depths don't have color tables. */
201 bi = ExAllocatePoolWithTag(PagedPool,
202 sizeof(BITMAPINFOHEADER) +
203 256 * sizeof(RGBQUAD),
204 TAG_TEMP);
205
206 if (bi)
207 {
208 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
209 bi->bmiHeader.biWidth = Width;
210 bi->bmiHeader.biHeight = Height;
211 bi->bmiHeader.biPlanes = dibs.dsBmih.biPlanes;
212 bi->bmiHeader.biBitCount = dibs.dsBmih.biBitCount;
213 bi->bmiHeader.biCompression = dibs.dsBmih.biCompression;
214 bi->bmiHeader.biSizeImage = 0;
215 bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
216 bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
217 bi->bmiHeader.biClrUsed = dibs.dsBmih.biClrUsed;
218 bi->bmiHeader.biClrImportant = dibs.dsBmih.biClrImportant;
219
220 if (bi->bmiHeader.biCompression == BI_BITFIELDS)
221 {
222 /* Copy the color masks */
223 RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3 * sizeof(DWORD));
224 }
225 else if (bi->bmiHeader.biBitCount <= 8)
226 {
227 /* Copy the color table */
228 UINT Index;
229 PPALGDI PalGDI = PALETTE_LockPalette(psurf->hDIBPalette);
230
231 if (!PalGDI)
232 {
233 ExFreePoolWithTag(bi, TAG_TEMP);
234 SURFACE_UnlockSurface(psurf);
235 SetLastWin32Error(ERROR_INVALID_HANDLE);
236 return 0;
237 }
238
239 for (Index = 0;
240 Index < 256 && Index < PalGDI->NumColors;
241 Index++)
242 {
243 bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
244 bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
245 bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
246 bi->bmiColors[Index].rgbReserved = 0;
247 }
248 PALETTE_UnlockPalette(PalGDI);
249 }
250 SURFACE_UnlockSurface(psurf);
251
252 Bmp = DIB_CreateDIBSection(Dc,
253 bi,
254 DIB_RGB_COLORS,
255 &Bits,
256 NULL,
257 0,
258 0);
259
260 ExFreePoolWithTag(bi, TAG_TEMP);
261 return Bmp;
262 }
263 }
264 }
265 SURFACE_UnlockSurface(psurf);
266 }
267 }
268 return Bmp;
269 }
270
271 HBITMAP APIENTRY
272 NtGdiCreateCompatibleBitmap(
273 HDC hDC,
274 INT Width,
275 INT Height)
276 {
277 HBITMAP Bmp;
278 PDC Dc;
279
280 if (Width <= 0 || Height <= 0 || (Width * Height) > 0x3FFFFFFF)
281 {
282 SetLastWin32Error(ERROR_INVALID_PARAMETER);
283 return NULL;
284 }
285
286 if (!hDC)
287 return IntGdiCreateBitmap(Width, Height, 1, 1, 0);
288
289 Dc = DC_LockDc(hDC);
290
291 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n",
292 hDC, Width, Height, ((PGDIDEVICE)Dc->pPDev)->GDIInfo.cBitsPixel);
293
294 if (NULL == Dc)
295 {
296 SetLastWin32Error(ERROR_INVALID_HANDLE);
297 return NULL;
298 }
299
300 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
301
302 DPRINT("\t\t%04x\n", Bmp);
303 DC_UnlockDc(Dc);
304 return Bmp;
305 }
306
307 BOOL APIENTRY
308 NtGdiGetBitmapDimension(
309 HBITMAP hBitmap,
310 LPSIZE Dimension)
311 {
312 PSURFACE psurfBmp;
313 BOOL Ret = TRUE;
314
315 if (hBitmap == NULL)
316 return FALSE;
317
318 psurfBmp = SURFACE_LockSurface(hBitmap);
319 if (psurfBmp == NULL)
320 {
321 SetLastWin32Error(ERROR_INVALID_HANDLE);
322 return FALSE;
323 }
324
325 _SEH2_TRY
326 {
327 ProbeForWrite(Dimension, sizeof(SIZE), 1);
328 *Dimension = psurfBmp->dimension;
329 }
330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
331 {
332 Ret = FALSE;
333 }
334 _SEH2_END
335
336 SURFACE_UnlockSurface(psurfBmp);
337
338 return Ret;
339 }
340
341 COLORREF APIENTRY
342 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
343 {
344 PDC dc = NULL;
345 COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
346 BOOL bInRect = FALSE;
347 SURFACE *psurf;
348 SURFOBJ *pso;
349 HPALETTE Pal = 0;
350 XLATEOBJ *XlateObj;
351 HBITMAP hBmpTmp;
352
353 dc = DC_LockDc(hDC);
354
355 if (!dc)
356 {
357 SetLastWin32Error(ERROR_INVALID_HANDLE);
358 return Result;
359 }
360
361 if (dc->DC_Type == DC_TYPE_INFO)
362 {
363 DC_UnlockDc(dc);
364 return Result;
365 }
366
367 XPos += dc->ptlDCOrig.x;
368 YPos += dc->ptlDCOrig.y;
369 if (IN_RECT(dc->CombinedClip->rclBounds,XPos,YPos))
370 {
371 bInRect = TRUE;
372 psurf = SURFACE_LockSurface(dc->w.hBitmap);
373 pso = &psurf->SurfObj;
374 if (psurf)
375 {
376 Pal = psurf->hDIBPalette;
377 if (!Pal) Pal = pPrimarySurface->DevInfo.hpalDefault;
378
379 /* FIXME: Verify if it shouldn't be PAL_BGR! */
380 XlateObj = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, 0, NULL, Pal);
381 if (XlateObj)
382 {
383 // check if this DC has a DIB behind it...
384 if (pso->pvScan0) // STYPE_BITMAP == pso->iType
385 {
386 ASSERT(pso->lDelta);
387 Result = XLATEOBJ_iXlate(XlateObj,
388 DibFunctionsForBitmapFormat[pso->iBitmapFormat].DIB_GetPixel(pso, XPos, YPos));
389 }
390 EngDeleteXlate(XlateObj);
391 }
392 SURFACE_UnlockSurface(psurf);
393 }
394 }
395 DC_UnlockDc(dc);
396
397 // if Result is still CLR_INVALID, then the "quick" method above didn't work
398 if (bInRect && Result == CLR_INVALID)
399 {
400 // FIXME: create a 1x1 32BPP DIB, and blit to it
401 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
402 if (hDCTmp)
403 {
404 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
405 BITMAPINFO bi;
406 RtlMoveMemory(&(bi.bmiHeader), &bih, sizeof(bih));
407 hBmpTmp = NtGdiCreateDIBitmapInternal(hDC,
408 bi.bmiHeader.biWidth,
409 bi.bmiHeader.biHeight,
410 0,
411 NULL,
412 &bi,
413 DIB_RGB_COLORS,
414 bi.bmiHeader.biBitCount,
415 bi.bmiHeader.biSizeImage,
416 0,
417 0);
418
419 //HBITMAP hBmpTmp = IntGdiCreateBitmap(1, 1, 1, 32, NULL);
420 if (hBmpTmp)
421 {
422 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap(hDCTmp, hBmpTmp);
423 if (hBmpOld)
424 {
425 PSURFACE psurf;
426
427 NtGdiBitBlt(hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0);
428 NtGdiSelectBitmap(hDCTmp, hBmpOld);
429
430 // our bitmap is no longer selected, so we can access it's stuff...
431 psurf = SURFACE_LockSurface(hBmpTmp);
432 if (psurf)
433 {
434 // Dont you need to convert something here?
435 Result = *(COLORREF*)psurf->SurfObj.pvScan0;
436 SURFACE_UnlockSurface(psurf);
437 }
438 }
439 NtGdiDeleteObject(hBmpTmp);
440 }
441 NtGdiDeleteObjectApp(hDCTmp);
442 }
443 }
444
445 return Result;
446 }
447
448
449 LONG APIENTRY
450 IntGetBitmapBits(
451 PSURFACE psurf,
452 DWORD Bytes,
453 OUT PBYTE Bits)
454 {
455 LONG ret;
456
457 ASSERT(Bits);
458
459 /* Don't copy more bytes than the buffer has */
460 Bytes = min(Bytes, psurf->SurfObj.cjBits);
461
462 #if 0
463 /* FIXME: Call DDI CopyBits here if available */
464 if (psurf->DDBitmap)
465 {
466 DPRINT("Calling device specific BitmapBits\n");
467 if (psurf->DDBitmap->funcs->pBitmapBits)
468 {
469 ret = psurf->DDBitmap->funcs->pBitmapBits(hbitmap,
470 bits,
471 count,
472 DDB_GET);
473 }
474 else
475 {
476 ERR_(bitmap)("BitmapBits == NULL??\n");
477 ret = 0;
478 }
479 }
480 else
481 #endif
482 {
483 RtlCopyMemory(Bits, psurf->SurfObj.pvBits, Bytes);
484 ret = Bytes;
485 }
486 return ret;
487 }
488
489 LONG APIENTRY
490 NtGdiGetBitmapBits(
491 HBITMAP hBitmap,
492 ULONG Bytes,
493 OUT OPTIONAL PBYTE pUnsafeBits)
494 {
495 PSURFACE psurf;
496 LONG ret;
497
498 if (pUnsafeBits != NULL && Bytes == 0)
499 {
500 return 0;
501 }
502
503 psurf = SURFACE_LockSurface(hBitmap);
504 if (!psurf)
505 {
506 SetLastWin32Error(ERROR_INVALID_HANDLE);
507 return 0;
508 }
509
510 /* If the bits vector is null, the function should return the read size */
511 if (pUnsafeBits == NULL)
512 {
513 ret = psurf->SurfObj.cjBits;
514 SURFACE_UnlockSurface(psurf);
515 return ret;
516 }
517
518 /* Don't copy more bytes than the buffer has */
519 Bytes = min(Bytes, psurf->SurfObj.cjBits);
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 NewBrush = NtGdiCreateSolidBrush(Color, NULL);
667 HGDIOBJ OldBrush;
668
669 if (NewBrush == NULL)
670 return(FALSE);
671
672 OldBrush = NtGdiSelectBrush(hDC, NewBrush);
673 if (OldBrush == NULL)
674 {
675 NtGdiDeleteObject(NewBrush);
676 return(FALSE);
677 }
678
679 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
680 NtGdiSelectBrush(hDC, OldBrush);
681 NtGdiDeleteObject(NewBrush);
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 NtGdiDeleteObject(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 NtGdiDeleteObject(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 pds->dsBmih.biCompression = 0; // FIXME!
864 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
865 pds->dsBmih.biXPelsPerMeter = 0;
866 pds->dsBmih.biYPelsPerMeter = 0;
867 pds->dsBmih.biClrUsed = psurf->biClrUsed;
868 pds->dsBmih.biClrImportant = psurf->biClrImportant;
869 pds->dsBitfields[0] = psurf->dsBitfields[0];
870 pds->dsBitfields[1] = psurf->dsBitfields[1];
871 pds->dsBitfields[2] = psurf->dsBitfields[2];
872 pds->dshSection = psurf->hDIBSection;
873 pds->dsOffset = psurf->dwOffset;
874
875 return sizeof(DIBSECTION);
876 }
877 }
878 else
879 {
880 /* not set according to wine test, confirmed in win2k */
881 pBitmap->bmBits = NULL;
882 }
883
884 return sizeof(BITMAP);
885 }
886
887 /*
888 * @implemented
889 */
890 HDC
891 APIENTRY
892 NtGdiGetDCforBitmap(
893 IN HBITMAP hsurf)
894 {
895 HDC hDC = NULL;
896 PSURFACE psurf = SURFACE_LockSurface(hsurf);
897 if (psurf)
898 {
899 hDC = psurf->hDC;
900 SURFACE_UnlockSurface(psurf);
901 }
902 return hDC;
903 }
904
905 /*
906 * @implemented
907 */
908 HBITMAP
909 APIENTRY
910 NtGdiSelectBitmap(
911 IN HDC hDC,
912 IN HBITMAP hBmp)
913 {
914 PDC pDC;
915 PDC_ATTR pDc_Attr;
916 HBITMAP hOrgBmp;
917 PSURFACE psurfBmp;
918 HRGN hVisRgn;
919 BOOLEAN bFailed;
920 PGDIBRUSHOBJ pBrush;
921
922 if (hDC == NULL || hBmp == NULL) return NULL;
923
924 pDC = DC_LockDc(hDC);
925 if (!pDC)
926 {
927 return NULL;
928 }
929
930 pDc_Attr = pDC->pDc_Attr;
931 if (!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
932
933 /* must be memory dc to select bitmap */
934 if (pDC->DC_Type != DC_TYPE_MEMORY)
935 {
936 DC_UnlockDc(pDC);
937 return NULL;
938 }
939
940 psurfBmp = SURFACE_LockSurface(hBmp);
941 if (!psurfBmp)
942 {
943 DC_UnlockDc(pDC);
944 return NULL;
945 }
946 hOrgBmp = pDC->w.hBitmap;
947
948 /* Release the old bitmap, lock the new one and convert it to a SURF */
949 pDC->w.hBitmap = hBmp;
950
951 // If Info DC this is zero and pSurface is moved to DC->pSurfInfo.
952 pDC->DcLevel.pSurface = psurfBmp;
953 psurfBmp->hDC = hDC;
954
955 // if we're working with a DIB, get the palette
956 // [fixme: only create if the selected palette is null]
957 if (psurfBmp->hSecure)
958 {
959 // pDC->w.bitsPerPixel = psurfBmp->dib->dsBmih.biBitCount; ???
960 pDC->w.bitsPerPixel = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
961 }
962 else
963 {
964 pDC->w.bitsPerPixel = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
965 }
966
967 hVisRgn = NtGdiCreateRectRgn(0,
968 0,
969 psurfBmp->SurfObj.sizlBitmap.cx,
970 psurfBmp->SurfObj.sizlBitmap.cy);
971 SURFACE_UnlockSurface(psurfBmp);
972
973 /* Regenerate the XLATEOBJs. */
974 pBrush = BRUSHOBJ_LockBrush(pDc_Attr->hbrush);
975 if (pBrush)
976 {
977 if (pDC->XlateBrush)
978 {
979 EngDeleteXlate(pDC->XlateBrush);
980 }
981 pDC->XlateBrush = IntGdiCreateBrushXlate(pDC, pBrush, &bFailed);
982 BRUSHOBJ_UnlockBrush(pBrush);
983 }
984
985 pBrush = PENOBJ_LockPen(pDc_Attr->hpen);
986 if (pBrush)
987 {
988 if (pDC->XlatePen)
989 {
990 EngDeleteXlate(pDC->XlatePen);
991 }
992 pDC->XlatePen = IntGdiCreateBrushXlate(pDC, pBrush, &bFailed);
993 PENOBJ_UnlockPen(pBrush);
994 }
995
996 DC_UnlockDc(pDC);
997
998 if (hVisRgn)
999 {
1000 GdiSelectVisRgn(hDC, hVisRgn);
1001 NtGdiDeleteObject(hVisRgn);
1002 }
1003
1004 return hOrgBmp;
1005 }
1006
1007 /* EOF */