2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
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.
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.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 /* $Id: bitmaps.c 28300 2007-08-12 15:20:09Z tkreuzer $ */
26 #define ROP_USES_SOURCE(Rop) (((((Rop) & 0xCC0000) >> 2) != ((Rop) & 0x330000)) || ((((Rop) & 0xCC000000) >> 2) != ((Rop) & 0x33000000)))
27 #define ROP_USES_MASK(Rop) (((Rop) & 0xFF000000) != (((Rop) & 0xff0000) << 8))
29 #define FIXUP_ROP(Rop) if(((Rop) & 0xFF000000) == 0) Rop = MAKEROP4((Rop), (Rop))
30 #define ROP_TO_ROP4(Rop) ((Rop) >> 16)
44 BLENDFUNCTION BlendFunc
,
51 SURFACE
*BitmapDest
, *BitmapSrc
;
52 RECTL DestRect
, SourceRect
;
56 BlendObj
.BlendFunction
= BlendFunc
;
58 if (WidthDest
< 0 || HeightDest
< 0 || WidthSrc
< 0 || HeightSrc
< 0)
60 EngSetLastError(ERROR_INVALID_PARAMETER
);
64 DPRINT("Locking DCs\n");
67 if (!GDIOBJ_bLockMultipleObjects(2, ahDC
, apObj
, GDIObjType_DC_TYPE
))
69 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hDCDest
, hDCSrc
);
70 EngSetLastError(ERROR_INVALID_HANDLE
);
76 if (DCDest
->dctype
== DC_TYPE_INFO
|| DCDest
->dctype
== DCTYPE_INFO
)
78 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
79 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
80 /* Yes, Windows really returns TRUE in this case */
84 DestRect
.left
= XOriginDest
;
85 DestRect
.top
= YOriginDest
;
86 DestRect
.right
= XOriginDest
+ WidthDest
;
87 DestRect
.bottom
= YOriginDest
+ HeightDest
;
88 IntLPtoDP(DCDest
, (LPPOINT
)&DestRect
, 2);
90 DestRect
.left
+= DCDest
->ptlDCOrig
.x
;
91 DestRect
.top
+= DCDest
->ptlDCOrig
.y
;
92 DestRect
.right
+= DCDest
->ptlDCOrig
.x
;
93 DestRect
.bottom
+= DCDest
->ptlDCOrig
.y
;
95 SourceRect
.left
= XOriginSrc
;
96 SourceRect
.top
= YOriginSrc
;
97 SourceRect
.right
= XOriginSrc
+ WidthSrc
;
98 SourceRect
.bottom
= YOriginSrc
+ HeightSrc
;
99 IntLPtoDP(DCSrc
, (LPPOINT
)&SourceRect
, 2);
101 SourceRect
.left
+= DCSrc
->ptlDCOrig
.x
;
102 SourceRect
.top
+= DCSrc
->ptlDCOrig
.y
;
103 SourceRect
.right
+= DCSrc
->ptlDCOrig
.x
;
104 SourceRect
.bottom
+= DCSrc
->ptlDCOrig
.y
;
106 if (!DestRect
.right
||
111 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
112 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
116 /* Prepare DCs for blit */
117 DPRINT("Preparing DCs for blit\n");
118 DC_vPrepareDCsForBlit(DCDest
, DestRect
, DCSrc
, SourceRect
);
120 /* Determine surfaces to be used in the bitblt */
121 BitmapDest
= DCDest
->dclevel
.pSurface
;
128 BitmapSrc
= DCSrc
->dclevel
.pSurface
;
135 /* Create the XLATEOBJ. */
136 EXLATEOBJ_vInitXlateFromDCs(&exlo
, DCSrc
, DCDest
);
138 /* Perform the alpha blend operation */
139 DPRINT("Performing the alpha Blend\n");
140 bResult
= IntEngAlphaBlend(&BitmapDest
->SurfObj
,
142 DCDest
->rosdc
.CombinedClip
,
148 EXLATEOBJ_vCleanup(&exlo
);
150 DPRINT("Finishing blit\n");
151 DC_vFinishBlit(DCDest
, DCSrc
);
152 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
153 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
169 IN DWORD crBackColor
,
172 /* Forward to NtGdiMaskBlt */
173 // TODO : what's fl for?
174 return NtGdiMaskBlt(hDCDest
,
207 SURFACE
*BitmapDest
, *BitmapSrc
= NULL
;
208 ULONG TransparentColor
= 0;
212 DPRINT("Locking DCs\n");
215 if (!GDIOBJ_bLockMultipleObjects(2, ahDC
, apObj
, GDIObjType_DC_TYPE
))
217 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hdcDst
, hdcSrc
);
218 EngSetLastError(ERROR_INVALID_HANDLE
);
224 if (DCDest
->dctype
== DC_TYPE_INFO
|| DCDest
->dctype
== DCTYPE_INFO
)
226 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
227 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
228 /* Yes, Windows really returns TRUE in this case */
234 rcDest
.right
= rcDest
.left
+ cxDst
;
235 rcDest
.bottom
= rcDest
.top
+ cyDst
;
236 IntLPtoDP(DCDest
, (LPPOINT
)&rcDest
, 2);
238 rcDest
.left
+= DCDest
->ptlDCOrig
.x
;
239 rcDest
.top
+= DCDest
->ptlDCOrig
.y
;
240 rcDest
.right
+= DCDest
->ptlDCOrig
.x
;
241 rcDest
.bottom
+= DCDest
->ptlDCOrig
.y
;
245 rcSrc
.right
= rcSrc
.left
+ cxSrc
;
246 rcSrc
.bottom
= rcSrc
.top
+ cySrc
;
247 IntLPtoDP(DCSrc
, (LPPOINT
)&rcSrc
, 2);
249 rcSrc
.left
+= DCSrc
->ptlDCOrig
.x
;
250 rcSrc
.top
+= DCSrc
->ptlDCOrig
.y
;
251 rcSrc
.right
+= DCSrc
->ptlDCOrig
.x
;
252 rcSrc
.bottom
+= DCSrc
->ptlDCOrig
.y
;
254 /* Prepare for blit */
255 DC_vPrepareDCsForBlit(DCDest
, rcDest
, DCSrc
, rcSrc
);
257 BitmapDest
= DCDest
->dclevel
.pSurface
;
263 BitmapSrc
= DCSrc
->dclevel
.pSurface
;
269 /* Translate Transparent (RGB) Color to the source palette */
270 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, BitmapSrc
->ppal
, 0, 0, 0);
271 TransparentColor
= XLATEOBJ_iXlate(&exlo
.xlo
, (ULONG
)TransColor
);
272 EXLATEOBJ_vCleanup(&exlo
);
274 EXLATEOBJ_vInitXlateFromDCs(&exlo
, DCSrc
, DCDest
);
276 Ret
= IntEngTransparentBlt(&BitmapDest
->SurfObj
, &BitmapSrc
->SurfObj
,
277 DCDest
->rosdc
.CombinedClip
, &exlo
.xlo
, &rcDest
, &rcSrc
,
278 TransparentColor
, 0);
280 EXLATEOBJ_vCleanup(&exlo
);
283 DC_vFinishBlit(DCDest
, DCSrc
);
284 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
285 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
304 IN DWORD crBackColor
)
310 PDC_ATTR pdcattr
= NULL
;
311 SURFACE
*BitmapDest
, *BitmapSrc
= NULL
, *psurfMask
= NULL
;
312 RECTL DestRect
, SourceRect
;
313 POINTL SourcePoint
, MaskPoint
;
316 XLATEOBJ
*XlateObj
= NULL
;
317 BOOL UsesSource
= ROP_USES_SOURCE(dwRop
);
322 UsesMask
= ROP_USES_MASK(dwRop
);
324 //DPRINT1("dwRop : 0x%08x\n", dwRop);
325 if (!hdcDest
|| (UsesSource
&& !hdcSrc
))
327 EngSetLastError(ERROR_INVALID_PARAMETER
);
331 /* Take care of mask bitmap */
334 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
337 EngSetLastError(ERROR_INVALID_HANDLE
);
346 EngSetLastError(ERROR_INVALID_PARAMETER
);
349 if(gajBitsPerFormat
[psurfMask
->SurfObj
.iBitmapFormat
] != 1)
351 EngSetLastError(ERROR_INVALID_PARAMETER
);
352 SURFACE_ShareUnlockSurface(psurfMask
);
358 DPRINT1("Getting Mask bitmap without needing it?\n");
359 SURFACE_ShareUnlockSurface(psurfMask
);
365 /* Take care of source and destination bitmap */
366 DPRINT("Locking DCs\n");
368 ahDC
[1] = UsesSource
? hdcSrc
: NULL
;
369 if (!GDIOBJ_bLockMultipleObjects(2, ahDC
, apObj
, GDIObjType_DC_TYPE
))
371 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hdcDest
, hdcSrc
);
372 EngSetLastError(ERROR_INVALID_HANDLE
);
381 if(DCSrc
) DC_UnlockDc(DCSrc
);
382 DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hdcDest
);
386 if (DCDest
->dctype
== DC_TYPE_INFO
)
388 if(DCSrc
) DC_UnlockDc(DCSrc
);
390 /* Yes, Windows really returns TRUE in this case */
397 if (DCSrc
->dctype
== DC_TYPE_INFO
)
401 /* Yes, Windows really returns TRUE in this case */
406 pdcattr
= DCDest
->pdcattr
;
408 DestRect
.left
= nXDest
;
409 DestRect
.top
= nYDest
;
410 DestRect
.right
= nXDest
+ nWidth
;
411 DestRect
.bottom
= nYDest
+ nHeight
;
412 IntLPtoDP(DCDest
, (LPPOINT
)&DestRect
, 2);
414 DestRect
.left
+= DCDest
->ptlDCOrig
.x
;
415 DestRect
.top
+= DCDest
->ptlDCOrig
.y
;
416 DestRect
.right
+= DCDest
->ptlDCOrig
.x
;
417 DestRect
.bottom
+= DCDest
->ptlDCOrig
.y
;
419 SourcePoint
.x
= nXSrc
;
420 SourcePoint
.y
= nYSrc
;
424 IntLPtoDP(DCSrc
, (LPPOINT
)&SourcePoint
, 1);
426 SourcePoint
.x
+= DCSrc
->ptlDCOrig
.x
;
427 SourcePoint
.y
+= DCSrc
->ptlDCOrig
.y
;
428 /* Calculate Source Rect */
429 SourceRect
.left
= SourcePoint
.x
;
430 SourceRect
.top
= SourcePoint
.y
;
431 SourceRect
.right
= SourcePoint
.x
+ DestRect
.right
- DestRect
.left
;
432 SourceRect
.bottom
= SourcePoint
.y
+ DestRect
.bottom
- DestRect
.top
;
436 DC_vPrepareDCsForBlit(DCDest
, DestRect
, DCSrc
, SourceRect
);
438 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
439 DC_vUpdateFillBrush(DCDest
);
441 /* Determine surfaces to be used in the bitblt */
442 BitmapDest
= DCDest
->dclevel
.pSurface
;
449 BitmapSrc
= DCSrc
->dclevel
.pSurface
;
455 /* Create the XLATEOBJ. */
458 EXLATEOBJ_vInitXlateFromDCs(&exlo
, DCSrc
, DCDest
);
459 XlateObj
= &exlo
.xlo
;
463 /* Perform the bitblt operation */
464 Status
= IntEngBitBlt(&BitmapDest
->SurfObj
,
465 BitmapSrc
? &BitmapSrc
->SurfObj
: NULL
,
466 psurfMask
? &psurfMask
->SurfObj
: NULL
,
467 DCDest
->rosdc
.CombinedClip
,
472 &DCDest
->eboFill
.BrushObject
,
473 &DCDest
->dclevel
.pbrFill
->ptOrigin
,
477 EXLATEOBJ_vCleanup(&exlo
);
479 DC_vFinishBlit(DCDest
, DCSrc
);
485 if(psurfMask
) SURFACE_ShareUnlockSurface(psurfMask
);
503 IN DWORD crBackColor
)
522 IN DWORD dwBackColor
,
533 SURFACE
*BitmapDest
, *BitmapSrc
= NULL
;
534 SURFACE
*BitmapMask
= NULL
;
540 XLATEOBJ
*XlateObj
= NULL
;
546 UsesSource
= ROP_USES_SOURCE(ROP
);
547 UsesMask
= ROP_USES_MASK(ROP
);
549 if (0 == WidthDest
|| 0 == HeightDest
|| 0 == WidthSrc
|| 0 == HeightSrc
)
551 EngSetLastError(ERROR_INVALID_PARAMETER
);
555 if (!hDCDest
|| (UsesSource
&& !hDCSrc
) || (UsesMask
&& !hDCMask
))
557 EngSetLastError(ERROR_INVALID_PARAMETER
);
562 ahDC
[1] = UsesSource
? hDCSrc
: NULL
;
563 ahDC
[2] = UsesMask
? hDCMask
: NULL
;
564 if (!GDIOBJ_bLockMultipleObjects(3, ahDC
, apObj
, GDIObjType_DC_TYPE
))
566 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hDCDest
, hDCSrc
);
567 EngSetLastError(ERROR_INVALID_HANDLE
);
574 if (DCDest
->dctype
== DC_TYPE_INFO
)
576 if(DCSrc
) GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
577 if(DCMask
) GDIOBJ_vUnlockObject(&DCMask
->BaseObject
);
578 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
579 /* Yes, Windows really returns TRUE in this case */
585 if (DCSrc
->dctype
== DC_TYPE_INFO
)
587 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
588 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
589 if(DCMask
) GDIOBJ_vUnlockObject(&DCMask
->BaseObject
);
590 /* Yes, Windows really returns TRUE in this case */
595 pdcattr
= DCDest
->pdcattr
;
597 DestRect
.left
= XOriginDest
;
598 DestRect
.top
= YOriginDest
;
599 DestRect
.right
= XOriginDest
+WidthDest
;
600 DestRect
.bottom
= YOriginDest
+HeightDest
;
601 IntLPtoDP(DCDest
, (LPPOINT
)&DestRect
, 2);
603 DestRect
.left
+= DCDest
->ptlDCOrig
.x
;
604 DestRect
.top
+= DCDest
->ptlDCOrig
.y
;
605 DestRect
.right
+= DCDest
->ptlDCOrig
.x
;
606 DestRect
.bottom
+= DCDest
->ptlDCOrig
.y
;
608 SourceRect
.left
= XOriginSrc
;
609 SourceRect
.top
= YOriginSrc
;
610 SourceRect
.right
= XOriginSrc
+WidthSrc
;
611 SourceRect
.bottom
= YOriginSrc
+HeightSrc
;
615 IntLPtoDP(DCSrc
, (LPPOINT
)&SourceRect
, 2);
617 SourceRect
.left
+= DCSrc
->ptlDCOrig
.x
;
618 SourceRect
.top
+= DCSrc
->ptlDCOrig
.y
;
619 SourceRect
.right
+= DCSrc
->ptlDCOrig
.x
;
620 SourceRect
.bottom
+= DCSrc
->ptlDCOrig
.y
;
626 /* Only prepare Source and Dest, hdcMask represents a DIB */
627 DC_vPrepareDCsForBlit(DCDest
, DestRect
, DCSrc
, SourceRect
);
629 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
630 DC_vUpdateFillBrush(DCDest
);
632 /* Determine surfaces to be used in the bitblt */
633 BitmapDest
= DCDest
->dclevel
.pSurface
;
634 if (BitmapDest
== NULL
)
638 BitmapSrc
= DCSrc
->dclevel
.pSurface
;
639 if (BitmapSrc
== NULL
)
642 /* Create the XLATEOBJ. */
643 EXLATEOBJ_vInitXlateFromDCs(&exlo
, DCSrc
, DCDest
);
644 XlateObj
= &exlo
.xlo
;
647 /* Offset the brush */
648 BrushOrigin
.x
+= DCDest
->ptlDCOrig
.x
;
649 BrushOrigin
.y
+= DCDest
->ptlDCOrig
.y
;
651 /* Make mask surface for source surface */
652 if (BitmapSrc
&& DCMask
)
654 BitmapMask
= DCMask
->dclevel
.pSurface
;
656 (BitmapMask
->SurfObj
.sizlBitmap
.cx
< WidthSrc
||
657 BitmapMask
->SurfObj
.sizlBitmap
.cy
< HeightSrc
))
659 DPRINT1("%dx%d mask is smaller than %dx%d bitmap\n",
660 BitmapMask
->SurfObj
.sizlBitmap
.cx
, BitmapMask
->SurfObj
.sizlBitmap
.cy
,
661 WidthSrc
, HeightSrc
);
662 EXLATEOBJ_vCleanup(&exlo
);
665 /* Create mask offset point */
666 MaskPoint
.x
= XOriginMask
;
667 MaskPoint
.y
= YOriginMask
;
668 IntLPtoDP(DCMask
, &MaskPoint
, 1);
669 MaskPoint
.x
+= DCMask
->ptlDCOrig
.x
;
670 MaskPoint
.y
+= DCMask
->ptlDCOrig
.y
;
673 /* Perform the bitblt operation */
674 Status
= IntEngStretchBlt(&BitmapDest
->SurfObj
,
676 BitmapMask
? &BitmapMask
->SurfObj
: NULL
,
677 DCDest
->rosdc
.CombinedClip
,
681 BitmapMask
? &MaskPoint
: NULL
,
682 &DCDest
->eboFill
.BrushObject
,
687 EXLATEOBJ_vCleanup(&exlo
);
691 DC_vFinishBlit(DCDest
, DCSrc
);
719 IN DWORD dwBackColor
)
721 return GreStretchBltMask(
760 if (pbrush
->flAttrs
& GDIBRUSH_IS_NULL
)
767 DestRect
.left
= XLeft
;
768 DestRect
.right
= XLeft
+ Width
;
772 DestRect
.left
= XLeft
+ Width
+ 1;
773 DestRect
.right
= XLeft
+ 1;
778 DestRect
.top
= YLeft
;
779 DestRect
.bottom
= YLeft
+ Height
;
783 DestRect
.top
= YLeft
+ Height
+ 1;
784 DestRect
.bottom
= YLeft
+ 1;
787 IntLPtoDP(pdc
, (LPPOINT
)&DestRect
, 2);
789 DestRect
.left
+= pdc
->ptlDCOrig
.x
;
790 DestRect
.top
+= pdc
->ptlDCOrig
.y
;
791 DestRect
.right
+= pdc
->ptlDCOrig
.x
;
792 DestRect
.bottom
+= pdc
->ptlDCOrig
.y
;
794 BrushOrigin
.x
= pbrush
->ptOrigin
.x
+ pdc
->ptlDCOrig
.x
;
795 BrushOrigin
.y
= pbrush
->ptOrigin
.y
+ pdc
->ptlDCOrig
.y
;
797 DC_vPrepareDCsForBlit(pdc
, DestRect
, NULL
, DestRect
);
799 psurf
= pdc
->dclevel
.pSurface
;
801 if (pdc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
802 DC_vUpdateFillBrush(pdc
);
804 EBRUSHOBJ_vInit(&eboFill
, pbrush
, pdc
);
810 pdc
->rosdc
.CombinedClip
,
815 &eboFill
.BrushObject
,
819 DC_vFinishBlit(pdc
, NULL
);
821 EBRUSHOBJ_vCleanup(&eboFill
);
838 pdc
= DC_LockDc(hDC
);
841 EngSetLastError(ERROR_INVALID_HANDLE
);
845 if (pdc
->dctype
== DC_TYPE_INFO
)
848 /* Yes, Windows really returns TRUE in this case */
852 for (i
= 0; i
< cRects
; i
++)
854 pbrush
= BRUSH_ShareLockBrush(pRects
->hBrush
);
865 BRUSH_ShareUnlockBrush(pbrush
);
890 BOOL UsesSource
= ROP_USES_SOURCE(ROP
);
893 /* in this case we call on GdiMaskBlt */
894 return NtGdiMaskBlt(hDC
, XLeft
, YLeft
, Width
, Height
, 0,0,0,0,0,0,ROP
,0);
900 EngSetLastError(ERROR_INVALID_HANDLE
);
903 if (dc
->dctype
== DC_TYPE_INFO
)
906 DPRINT1("NtGdiPatBlt on info DC!\n");
907 /* Yes, Windows really returns TRUE in this case */
911 pdcattr
= dc
->pdcattr
;
913 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
914 DC_vUpdateFillBrush(dc
);
916 pbrush
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
919 EngSetLastError(ERROR_INVALID_HANDLE
);
924 ret
= IntPatBlt(dc
, XLeft
, YLeft
, Width
, Height
, ROP
, pbrush
);
926 BRUSH_ShareUnlockBrush(pbrush
);
936 IN PPOLYPATBLT pRects
,
941 NTSTATUS Status
= STATUS_SUCCESS
;
946 rb
= ExAllocatePoolWithTag(PagedPool
, sizeof(PATRECT
) * cRects
, GDITAG_PLGBLT_DATA
);
949 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
955 cRects
* sizeof(PATRECT
),
959 cRects
* sizeof(PATRECT
));
961 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
963 Status
= _SEH2_GetExceptionCode();
967 if (!NT_SUCCESS(Status
))
969 ExFreePoolWithTag(rb
, GDITAG_PLGBLT_DATA
);
970 SetLastNtError(Status
);
975 Ret
= IntGdiPolyPatBlt(hDC
, dwRop
, rb
, cRects
, Mode
);
978 ExFreePoolWithTag(rb
, GDITAG_PLGBLT_DATA
);