rename DCs pDc_Attr to pdcattr, like in gdikdx.
[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, ((PGDIDEVICE)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 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 /* If the bits vector is null, the function should return the read size */
503 if (pUnsafeBits == NULL)
504 {
505 ret = psurf->SurfObj.cjBits;
506 SURFACE_UnlockSurface(psurf);
507 return ret;
508 }
509
510 /* Don't copy more bytes than the buffer has */
511 Bytes = min(Bytes, psurf->SurfObj.cjBits);
512
513 // FIXME: use MmSecureVirtualMemory
514 _SEH2_TRY
515 {
516 ProbeForWrite(pUnsafeBits, Bytes, 1);
517 ret = IntGetBitmapBits(psurf, Bytes, pUnsafeBits);
518 }
519 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
520 {
521 ret = 0;
522 }
523 _SEH2_END
524
525 SURFACE_UnlockSurface(psurf);
526
527 return ret;
528 }
529
530
531 LONG APIENTRY
532 IntSetBitmapBits(
533 PSURFACE psurf,
534 DWORD Bytes,
535 IN PBYTE Bits)
536 {
537 LONG ret;
538
539 /* Don't copy more bytes than the buffer has */
540 Bytes = min(Bytes, psurf->SurfObj.cjBits);
541
542 #if 0
543 /* FIXME: call DDI specific function here if available */
544 if (psurf->DDBitmap)
545 {
546 DPRINT("Calling device specific BitmapBits\n");
547 if (psurf->DDBitmap->funcs->pBitmapBits)
548 {
549 ret = psurf->DDBitmap->funcs->pBitmapBits(hBitmap,
550 (void *)Bits,
551 Bytes,
552 DDB_SET);
553 }
554 else
555 {
556 DPRINT("BitmapBits == NULL??\n");
557 ret = 0;
558 }
559 }
560 else
561 #endif
562 {
563 RtlCopyMemory(psurf->SurfObj.pvBits, Bits, Bytes);
564 ret = Bytes;
565 }
566
567 return ret;
568 }
569
570
571 LONG APIENTRY
572 NtGdiSetBitmapBits(
573 HBITMAP hBitmap,
574 DWORD Bytes,
575 IN PBYTE pUnsafeBits)
576 {
577 LONG ret;
578 PSURFACE psurf;
579
580 if (pUnsafeBits == NULL || Bytes == 0)
581 {
582 return 0;
583 }
584
585 psurf = SURFACE_LockSurface(hBitmap);
586 if (psurf == NULL)
587 {
588 SetLastWin32Error(ERROR_INVALID_HANDLE);
589 return 0;
590 }
591
592 _SEH2_TRY
593 {
594 ProbeForRead(pUnsafeBits, Bytes, 1);
595 ret = IntSetBitmapBits(psurf, Bytes, pUnsafeBits);
596 }
597 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
598 {
599 ret = 0;
600 }
601 _SEH2_END
602
603 SURFACE_UnlockSurface(psurf);
604
605 return ret;
606 }
607
608 BOOL APIENTRY
609 NtGdiSetBitmapDimension(
610 HBITMAP hBitmap,
611 INT Width,
612 INT Height,
613 LPSIZE Size)
614 {
615 PSURFACE psurf;
616 BOOL Ret = TRUE;
617
618 if (hBitmap == NULL)
619 return FALSE;
620
621 psurf = SURFACE_LockSurface(hBitmap);
622 if (psurf == NULL)
623 {
624 SetLastWin32Error(ERROR_INVALID_HANDLE);
625 return FALSE;
626 }
627
628 if (Size)
629 {
630 _SEH2_TRY
631 {
632 ProbeForWrite(Size, sizeof(SIZE), 1);
633 *Size = psurf->dimension;
634 }
635 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
636 {
637 Ret = FALSE;
638 }
639 _SEH2_END
640 }
641
642 /* The dimension is changed even if writing the old value failed */
643 psurf->dimension.cx = Width;
644 psurf->dimension.cy = Height;
645
646 SURFACE_UnlockSurface(psurf);
647
648 return Ret;
649 }
650
651 BOOL APIENTRY
652 GdiSetPixelV(
653 HDC hDC,
654 INT X,
655 INT Y,
656 COLORREF Color)
657 {
658 HBRUSH NewBrush = NtGdiCreateSolidBrush(Color, NULL);
659 HGDIOBJ OldBrush;
660
661 if (NewBrush == NULL)
662 return(FALSE);
663
664 OldBrush = NtGdiSelectBrush(hDC, NewBrush);
665 if (OldBrush == NULL)
666 {
667 NtGdiDeleteObject(NewBrush);
668 return(FALSE);
669 }
670
671 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
672 NtGdiSelectBrush(hDC, OldBrush);
673 NtGdiDeleteObject(NewBrush);
674
675 return TRUE;
676 }
677
678 COLORREF APIENTRY
679 NtGdiSetPixel(
680 HDC hDC,
681 INT X,
682 INT Y,
683 COLORREF Color)
684 {
685 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
686
687 if (GdiSetPixelV(hDC,X,Y,Color))
688 {
689 Color = NtGdiGetPixel(hDC,X,Y);
690 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
691 return Color;
692 }
693
694 Color = (COLORREF)CLR_INVALID;
695 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X, Y, Color);
696 return Color;
697 }
698
699
700 /* Internal Functions */
701
702 UINT FASTCALL
703 BITMAP_GetRealBitsPixel(UINT nBitsPixel)
704 {
705 if (nBitsPixel <= 1)
706 return 1;
707 if (nBitsPixel <= 4)
708 return 4;
709 if (nBitsPixel <= 8)
710 return 8;
711 if (nBitsPixel <= 16)
712 return 16;
713 if (nBitsPixel <= 24)
714 return 24;
715 if (nBitsPixel <= 32)
716 return 32;
717
718 return 0;
719 }
720
721 INT FASTCALL
722 BITMAP_GetWidthBytes(INT bmWidth, INT bpp)
723 {
724 #if 0
725 switch (bpp)
726 {
727 case 1:
728 return 2 * ((bmWidth+15) >> 4);
729
730 case 24:
731 bmWidth *= 3; /* fall through */
732 case 8:
733 return bmWidth + (bmWidth & 1);
734
735 case 32:
736 return bmWidth * 4;
737
738 case 16:
739 case 15:
740 return bmWidth * 2;
741
742 case 4:
743 return 2 * ((bmWidth+3) >> 2);
744
745 default:
746 DPRINT ("stub");
747 }
748
749 return -1;
750 #endif
751
752 return ((bmWidth * bpp + 15) & ~15) >> 3;
753 }
754
755 HBITMAP FASTCALL
756 BITMAP_CopyBitmap(HBITMAP hBitmap)
757 {
758 HBITMAP res;
759 BITMAP bm;
760 SURFACE *Bitmap, *resBitmap;
761 SIZEL Size;
762
763 if (hBitmap == NULL)
764 {
765 return 0;
766 }
767
768 Bitmap = GDIOBJ_LockObj(hBitmap, GDI_OBJECT_TYPE_BITMAP);
769 if (Bitmap == NULL)
770 {
771 return 0;
772 }
773
774 BITMAP_GetObject(Bitmap, sizeof(BITMAP), (PVOID)&bm);
775 bm.bmBits = NULL;
776 if (Bitmap->SurfObj.lDelta >= 0)
777 bm.bmHeight = -bm.bmHeight;
778
779 Size.cx = abs(bm.bmWidth);
780 Size.cy = abs(bm.bmHeight);
781 res = IntCreateBitmap(Size,
782 bm.bmWidthBytes,
783 BitmapFormat(bm.bmBitsPixel * bm.bmPlanes, BI_RGB),
784 (bm.bmHeight < 0 ? BMF_TOPDOWN : 0) | BMF_NOZEROINIT,
785 NULL);
786
787 if (res)
788 {
789 PBYTE buf;
790
791 resBitmap = GDIOBJ_LockObj(res, GDI_OBJECT_TYPE_BITMAP);
792 if (resBitmap)
793 {
794 buf = ExAllocatePoolWithTag(PagedPool,
795 bm.bmWidthBytes * abs(bm.bmHeight),
796 TAG_BITMAP);
797 if (buf == NULL)
798 {
799 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
800 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
801 NtGdiDeleteObject(res);
802 return 0;
803 }
804 IntGetBitmapBits(Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
805 IntSetBitmapBits(resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
806 ExFreePoolWithTag(buf,TAG_BITMAP);
807 resBitmap->flFlags = Bitmap->flFlags;
808 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
809 }
810 else
811 {
812 NtGdiDeleteObject(res);
813 res = NULL;
814 }
815 }
816
817 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
818
819 return res;
820 }
821
822 INT APIENTRY
823 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
824 {
825 PBITMAP pBitmap;
826
827 if (!buffer) return sizeof(BITMAP);
828 if ((UINT)Count < sizeof(BITMAP)) return 0;
829
830 /* always fill a basic BITMAP structure */
831 pBitmap = buffer;
832 pBitmap->bmType = 0;
833 pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
834 pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
835 pBitmap->bmWidthBytes = abs(psurf->SurfObj.lDelta);
836 pBitmap->bmPlanes = 1;
837 pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
838
839 /* Check for DIB section */
840 if (psurf->hSecure)
841 {
842 /* Set bmBits in this case */
843 pBitmap->bmBits = psurf->SurfObj.pvBits;
844
845 if (Count >= sizeof(DIBSECTION))
846 {
847 /* Fill rest of DIBSECTION */
848 PDIBSECTION pds = buffer;
849
850 pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
851 pds->dsBmih.biWidth = pds->dsBm.bmWidth;
852 pds->dsBmih.biHeight = pds->dsBm.bmHeight;
853 pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
854 pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
855 pds->dsBmih.biCompression = 0; // FIXME!
856 pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
857 pds->dsBmih.biXPelsPerMeter = 0;
858 pds->dsBmih.biYPelsPerMeter = 0;
859 pds->dsBmih.biClrUsed = psurf->biClrUsed;
860 pds->dsBmih.biClrImportant = psurf->biClrImportant;
861 pds->dsBitfields[0] = psurf->dsBitfields[0];
862 pds->dsBitfields[1] = psurf->dsBitfields[1];
863 pds->dsBitfields[2] = psurf->dsBitfields[2];
864 pds->dshSection = psurf->hDIBSection;
865 pds->dsOffset = psurf->dwOffset;
866
867 return sizeof(DIBSECTION);
868 }
869 }
870 else
871 {
872 /* not set according to wine test, confirmed in win2k */
873 pBitmap->bmBits = NULL;
874 }
875
876 return sizeof(BITMAP);
877 }
878
879 /*
880 * @implemented
881 */
882 HDC
883 APIENTRY
884 NtGdiGetDCforBitmap(
885 IN HBITMAP hsurf)
886 {
887 HDC hDC = NULL;
888 PSURFACE psurf = SURFACE_LockSurface(hsurf);
889 if (psurf)
890 {
891 hDC = psurf->hDC;
892 SURFACE_UnlockSurface(psurf);
893 }
894 return hDC;
895 }
896
897 /*
898 * @implemented
899 */
900 HBITMAP
901 APIENTRY
902 NtGdiSelectBitmap(
903 IN HDC hDC,
904 IN HBITMAP hBmp)
905 {
906 PDC pDC;
907 PDC_ATTR pdcattr;
908 HBITMAP hOrgBmp;
909 PSURFACE psurfBmp;
910 HRGN hVisRgn;
911 BOOLEAN bFailed;
912 PGDIBRUSHOBJ pBrush;
913
914 if (hDC == NULL || hBmp == NULL) return NULL;
915
916 pDC = DC_LockDc(hDC);
917 if (!pDC)
918 {
919 return NULL;
920 }
921
922 pdcattr = pDC->pdcattr;
923
924 /* must be memory dc to select bitmap */
925 if (pDC->dctype != DC_TYPE_MEMORY)
926 {
927 DC_UnlockDc(pDC);
928 return NULL;
929 }
930
931 psurfBmp = SURFACE_LockSurface(hBmp);
932 if (!psurfBmp)
933 {
934 DC_UnlockDc(pDC);
935 return NULL;
936 }
937 hOrgBmp = pDC->rosdc.hBitmap;
938
939 /* Release the old bitmap, lock the new one and convert it to a SURF */
940 pDC->rosdc.hBitmap = hBmp;
941
942 // If Info DC this is zero and pSurface is moved to DC->pSurfInfo.
943 pDC->DcLevel.pSurface = psurfBmp;
944 psurfBmp->hDC = hDC;
945
946 // if we're working with a DIB, get the palette
947 // [fixme: only create if the selected palette is null]
948 if (psurfBmp->hSecure)
949 {
950 // pDC->rosdcbitsPerPixel = psurfBmp->dib->dsBmih.biBitCount; ???
951 pDC->rosdc.bitsPerPixel = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
952 }
953 else
954 {
955 pDC->rosdc.bitsPerPixel = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
956 }
957
958 hVisRgn = NtGdiCreateRectRgn(0,
959 0,
960 psurfBmp->SurfObj.sizlBitmap.cx,
961 psurfBmp->SurfObj.sizlBitmap.cy);
962 SURFACE_UnlockSurface(psurfBmp);
963
964 /* Regenerate the XLATEOBJs. */
965 pBrush = BRUSHOBJ_LockBrush(pdcattr->hbrush);
966 if (pBrush)
967 {
968 if (pDC->rosdc.XlateBrush)
969 {
970 EngDeleteXlate(pDC->rosdc.XlateBrush);
971 }
972 pDC->rosdc.XlateBrush = IntGdiCreateBrushXlate(pDC, pBrush, &bFailed);
973 BRUSHOBJ_UnlockBrush(pBrush);
974 }
975
976 pBrush = PENOBJ_LockPen(pdcattr->hpen);
977 if (pBrush)
978 {
979 if (pDC->rosdc.XlatePen)
980 {
981 EngDeleteXlate(pDC->rosdc.XlatePen);
982 }
983 pDC->rosdc.XlatePen = IntGdiCreateBrushXlate(pDC, pBrush, &bFailed);
984 PENOBJ_UnlockPen(pBrush);
985 }
986
987 DC_UnlockDc(pDC);
988
989 if (hVisRgn)
990 {
991 GdiSelectVisRgn(hDC, hVisRgn);
992 NtGdiDeleteObject(hVisRgn);
993 }
994
995 return hOrgBmp;
996 }
997
998 /* EOF */