2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Bit blit functions
5 * FILE: subsys/win32k/objects/bitblt.c
14 #define ROP_USES_SOURCE(Rop) (((((Rop) & 0xCC0000) >> 2) != ((Rop) & 0x330000)) || ((((Rop) & 0xCC000000) >> 2) != ((Rop) & 0x33000000)))
15 #define ROP_USES_MASK(Rop) (((Rop) & 0xFF000000) != (((Rop) & 0xff0000) << 8))
17 #define FIXUP_ROP(Rop) if(((Rop) & 0xFF000000) == 0) Rop = MAKEROP4((Rop), (Rop))
18 #define ROP_TO_ROP4(Rop) ((Rop) >> 16)
32 BLENDFUNCTION BlendFunc
,
39 SURFACE
*BitmapDest
, *BitmapSrc
;
40 RECTL DestRect
, SourceRect
;
44 BlendObj
.BlendFunction
= BlendFunc
;
46 if (WidthDest
< 0 || HeightDest
< 0 || WidthSrc
< 0 || HeightSrc
< 0)
48 EngSetLastError(ERROR_INVALID_PARAMETER
);
52 DPRINT("Locking DCs\n");
55 if (!GDIOBJ_bLockMultipleObjects(2, ahDC
, apObj
, GDIObjType_DC_TYPE
))
57 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hDCDest
, hDCSrc
);
58 EngSetLastError(ERROR_INVALID_HANDLE
);
64 if (DCDest
->dctype
== DC_TYPE_INFO
|| DCDest
->dctype
== DCTYPE_INFO
)
66 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
67 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
68 /* Yes, Windows really returns TRUE in this case */
72 DestRect
.left
= XOriginDest
;
73 DestRect
.top
= YOriginDest
;
74 DestRect
.right
= XOriginDest
+ WidthDest
;
75 DestRect
.bottom
= YOriginDest
+ HeightDest
;
76 IntLPtoDP(DCDest
, (LPPOINT
)&DestRect
, 2);
78 DestRect
.left
+= DCDest
->ptlDCOrig
.x
;
79 DestRect
.top
+= DCDest
->ptlDCOrig
.y
;
80 DestRect
.right
+= DCDest
->ptlDCOrig
.x
;
81 DestRect
.bottom
+= DCDest
->ptlDCOrig
.y
;
83 SourceRect
.left
= XOriginSrc
;
84 SourceRect
.top
= YOriginSrc
;
85 SourceRect
.right
= XOriginSrc
+ WidthSrc
;
86 SourceRect
.bottom
= YOriginSrc
+ HeightSrc
;
87 IntLPtoDP(DCSrc
, (LPPOINT
)&SourceRect
, 2);
89 SourceRect
.left
+= DCSrc
->ptlDCOrig
.x
;
90 SourceRect
.top
+= DCSrc
->ptlDCOrig
.y
;
91 SourceRect
.right
+= DCSrc
->ptlDCOrig
.x
;
92 SourceRect
.bottom
+= DCSrc
->ptlDCOrig
.y
;
94 if (!DestRect
.right
||
99 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
100 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
104 /* Prepare DCs for blit */
105 DPRINT("Preparing DCs for blit\n");
106 DC_vPrepareDCsForBlit(DCDest
, DestRect
, DCSrc
, SourceRect
);
108 /* Determine surfaces to be used in the bitblt */
109 BitmapDest
= DCDest
->dclevel
.pSurface
;
116 BitmapSrc
= DCSrc
->dclevel
.pSurface
;
123 /* Create the XLATEOBJ. */
124 EXLATEOBJ_vInitXlateFromDCs(&exlo
, DCSrc
, DCDest
);
126 /* Perform the alpha blend operation */
127 DPRINT("Performing the alpha blend\n");
128 bResult
= IntEngAlphaBlend(&BitmapDest
->SurfObj
,
130 DCDest
->rosdc
.CombinedClip
,
136 EXLATEOBJ_vCleanup(&exlo
);
138 DPRINT("Finishing blit\n");
139 DC_vFinishBlit(DCDest
, DCSrc
);
140 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
141 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
157 IN DWORD crBackColor
,
160 /* Forward to NtGdiMaskBlt */
161 // TODO: What's fl for?
162 return NtGdiMaskBlt(hDCDest
,
195 SURFACE
*BitmapDest
, *BitmapSrc
= NULL
;
196 ULONG TransparentColor
= 0;
200 DPRINT("Locking DCs\n");
203 if (!GDIOBJ_bLockMultipleObjects(2, ahDC
, apObj
, GDIObjType_DC_TYPE
))
205 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hdcDst
, hdcSrc
);
206 EngSetLastError(ERROR_INVALID_HANDLE
);
212 if (DCDest
->dctype
== DC_TYPE_INFO
|| DCDest
->dctype
== DCTYPE_INFO
)
214 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
215 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
216 /* Yes, Windows really returns TRUE in this case */
222 rcDest
.right
= rcDest
.left
+ cxDst
;
223 rcDest
.bottom
= rcDest
.top
+ cyDst
;
224 IntLPtoDP(DCDest
, (LPPOINT
)&rcDest
, 2);
226 rcDest
.left
+= DCDest
->ptlDCOrig
.x
;
227 rcDest
.top
+= DCDest
->ptlDCOrig
.y
;
228 rcDest
.right
+= DCDest
->ptlDCOrig
.x
;
229 rcDest
.bottom
+= DCDest
->ptlDCOrig
.y
;
233 rcSrc
.right
= rcSrc
.left
+ cxSrc
;
234 rcSrc
.bottom
= rcSrc
.top
+ cySrc
;
235 IntLPtoDP(DCSrc
, (LPPOINT
)&rcSrc
, 2);
237 rcSrc
.left
+= DCSrc
->ptlDCOrig
.x
;
238 rcSrc
.top
+= DCSrc
->ptlDCOrig
.y
;
239 rcSrc
.right
+= DCSrc
->ptlDCOrig
.x
;
240 rcSrc
.bottom
+= DCSrc
->ptlDCOrig
.y
;
242 /* Prepare for blit */
243 DC_vPrepareDCsForBlit(DCDest
, rcDest
, DCSrc
, rcSrc
);
245 BitmapDest
= DCDest
->dclevel
.pSurface
;
251 BitmapSrc
= DCSrc
->dclevel
.pSurface
;
257 /* Translate Transparent (RGB) Color to the source palette */
258 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, BitmapSrc
->ppal
, 0, 0, 0);
259 TransparentColor
= XLATEOBJ_iXlate(&exlo
.xlo
, (ULONG
)TransColor
);
260 EXLATEOBJ_vCleanup(&exlo
);
262 EXLATEOBJ_vInitXlateFromDCs(&exlo
, DCSrc
, DCDest
);
264 Ret
= IntEngTransparentBlt(&BitmapDest
->SurfObj
, &BitmapSrc
->SurfObj
,
265 DCDest
->rosdc
.CombinedClip
, &exlo
.xlo
, &rcDest
, &rcSrc
,
266 TransparentColor
, 0);
268 EXLATEOBJ_vCleanup(&exlo
);
271 DC_vFinishBlit(DCDest
, DCSrc
);
272 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
273 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
292 IN DWORD crBackColor
)
298 PDC_ATTR pdcattr
= NULL
;
299 SURFACE
*BitmapDest
, *BitmapSrc
= NULL
, *psurfMask
= NULL
;
300 RECTL DestRect
, SourceRect
;
301 POINTL SourcePoint
, MaskPoint
;
304 XLATEOBJ
*XlateObj
= NULL
;
305 BOOL UsesSource
= ROP_USES_SOURCE(dwRop
);
310 UsesMask
= ROP_USES_MASK(dwRop
);
312 //DPRINT1("dwRop : 0x%08x\n", dwRop);
313 if (!hdcDest
|| (UsesSource
&& !hdcSrc
))
315 EngSetLastError(ERROR_INVALID_PARAMETER
);
319 /* Take care of mask bitmap */
322 psurfMask
= SURFACE_ShareLockSurface(hbmMask
);
325 EngSetLastError(ERROR_INVALID_HANDLE
);
334 EngSetLastError(ERROR_INVALID_PARAMETER
);
337 if(gajBitsPerFormat
[psurfMask
->SurfObj
.iBitmapFormat
] != 1)
339 EngSetLastError(ERROR_INVALID_PARAMETER
);
340 SURFACE_ShareUnlockSurface(psurfMask
);
346 DPRINT1("Getting Mask bitmap without needing it?\n");
347 SURFACE_ShareUnlockSurface(psurfMask
);
353 /* Take care of source and destination bitmap */
354 DPRINT("Locking DCs\n");
356 ahDC
[1] = UsesSource
? hdcSrc
: NULL
;
357 if (!GDIOBJ_bLockMultipleObjects(2, ahDC
, apObj
, GDIObjType_DC_TYPE
))
359 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hdcDest
, hdcSrc
);
360 EngSetLastError(ERROR_INVALID_HANDLE
);
369 if(DCSrc
) DC_UnlockDc(DCSrc
);
370 DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hdcDest
);
374 if (DCDest
->dctype
== DC_TYPE_INFO
)
376 if(DCSrc
) DC_UnlockDc(DCSrc
);
378 /* Yes, Windows really returns TRUE in this case */
385 if (DCSrc
->dctype
== DC_TYPE_INFO
)
389 /* Yes, Windows really returns TRUE in this case */
394 pdcattr
= DCDest
->pdcattr
;
396 DestRect
.left
= nXDest
;
397 DestRect
.top
= nYDest
;
398 DestRect
.right
= nXDest
+ nWidth
;
399 DestRect
.bottom
= nYDest
+ nHeight
;
400 IntLPtoDP(DCDest
, (LPPOINT
)&DestRect
, 2);
402 DestRect
.left
+= DCDest
->ptlDCOrig
.x
;
403 DestRect
.top
+= DCDest
->ptlDCOrig
.y
;
404 DestRect
.right
+= DCDest
->ptlDCOrig
.x
;
405 DestRect
.bottom
+= DCDest
->ptlDCOrig
.y
;
407 SourcePoint
.x
= nXSrc
;
408 SourcePoint
.y
= nYSrc
;
412 IntLPtoDP(DCSrc
, (LPPOINT
)&SourcePoint
, 1);
414 SourcePoint
.x
+= DCSrc
->ptlDCOrig
.x
;
415 SourcePoint
.y
+= DCSrc
->ptlDCOrig
.y
;
416 /* Calculate Source Rect */
417 SourceRect
.left
= SourcePoint
.x
;
418 SourceRect
.top
= SourcePoint
.y
;
419 SourceRect
.right
= SourcePoint
.x
+ DestRect
.right
- DestRect
.left
;
420 SourceRect
.bottom
= SourcePoint
.y
+ DestRect
.bottom
- DestRect
.top
;
424 DC_vPrepareDCsForBlit(DCDest
, DestRect
, DCSrc
, SourceRect
);
426 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
427 DC_vUpdateFillBrush(DCDest
);
429 /* Determine surfaces to be used in the bitblt */
430 BitmapDest
= DCDest
->dclevel
.pSurface
;
437 BitmapSrc
= DCSrc
->dclevel
.pSurface
;
443 /* Create the XLATEOBJ. */
446 EXLATEOBJ_vInitXlateFromDCs(&exlo
, DCSrc
, DCDest
);
447 XlateObj
= &exlo
.xlo
;
451 /* Perform the bitblt operation */
452 Status
= IntEngBitBlt(&BitmapDest
->SurfObj
,
453 BitmapSrc
? &BitmapSrc
->SurfObj
: NULL
,
454 psurfMask
? &psurfMask
->SurfObj
: NULL
,
455 DCDest
->rosdc
.CombinedClip
,
460 &DCDest
->eboFill
.BrushObject
,
461 &DCDest
->dclevel
.pbrFill
->ptOrigin
,
465 EXLATEOBJ_vCleanup(&exlo
);
467 DC_vFinishBlit(DCDest
, DCSrc
);
473 if(psurfMask
) SURFACE_ShareUnlockSurface(psurfMask
);
491 IN DWORD crBackColor
)
510 IN DWORD dwBackColor
,
521 SURFACE
*BitmapDest
, *BitmapSrc
= NULL
;
522 SURFACE
*BitmapMask
= NULL
;
528 XLATEOBJ
*XlateObj
= NULL
;
534 UsesSource
= ROP_USES_SOURCE(ROP
);
535 UsesMask
= ROP_USES_MASK(ROP
);
537 if (0 == WidthDest
|| 0 == HeightDest
|| 0 == WidthSrc
|| 0 == HeightSrc
)
539 EngSetLastError(ERROR_INVALID_PARAMETER
);
543 if (!hDCDest
|| (UsesSource
&& !hDCSrc
) || (UsesMask
&& !hDCMask
))
545 EngSetLastError(ERROR_INVALID_PARAMETER
);
550 ahDC
[1] = UsesSource
? hDCSrc
: NULL
;
551 ahDC
[2] = UsesMask
? hDCMask
: NULL
;
552 if (!GDIOBJ_bLockMultipleObjects(3, ahDC
, apObj
, GDIObjType_DC_TYPE
))
554 DPRINT1("Invalid dc handle (dest=0x%08x, src=0x%08x) passed to NtGdiAlphaBlend\n", hDCDest
, hDCSrc
);
555 EngSetLastError(ERROR_INVALID_HANDLE
);
562 if (DCDest
->dctype
== DC_TYPE_INFO
)
564 if(DCSrc
) GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
565 if(DCMask
) GDIOBJ_vUnlockObject(&DCMask
->BaseObject
);
566 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
567 /* Yes, Windows really returns TRUE in this case */
573 if (DCSrc
->dctype
== DC_TYPE_INFO
)
575 GDIOBJ_vUnlockObject(&DCDest
->BaseObject
);
576 GDIOBJ_vUnlockObject(&DCSrc
->BaseObject
);
577 if(DCMask
) GDIOBJ_vUnlockObject(&DCMask
->BaseObject
);
578 /* Yes, Windows really returns TRUE in this case */
583 pdcattr
= DCDest
->pdcattr
;
585 DestRect
.left
= XOriginDest
;
586 DestRect
.top
= YOriginDest
;
587 DestRect
.right
= XOriginDest
+WidthDest
;
588 DestRect
.bottom
= YOriginDest
+HeightDest
;
589 IntLPtoDP(DCDest
, (LPPOINT
)&DestRect
, 2);
591 DestRect
.left
+= DCDest
->ptlDCOrig
.x
;
592 DestRect
.top
+= DCDest
->ptlDCOrig
.y
;
593 DestRect
.right
+= DCDest
->ptlDCOrig
.x
;
594 DestRect
.bottom
+= DCDest
->ptlDCOrig
.y
;
596 SourceRect
.left
= XOriginSrc
;
597 SourceRect
.top
= YOriginSrc
;
598 SourceRect
.right
= XOriginSrc
+WidthSrc
;
599 SourceRect
.bottom
= YOriginSrc
+HeightSrc
;
603 IntLPtoDP(DCSrc
, (LPPOINT
)&SourceRect
, 2);
605 SourceRect
.left
+= DCSrc
->ptlDCOrig
.x
;
606 SourceRect
.top
+= DCSrc
->ptlDCOrig
.y
;
607 SourceRect
.right
+= DCSrc
->ptlDCOrig
.x
;
608 SourceRect
.bottom
+= DCSrc
->ptlDCOrig
.y
;
614 /* Only prepare Source and Dest, hdcMask represents a DIB */
615 DC_vPrepareDCsForBlit(DCDest
, DestRect
, DCSrc
, SourceRect
);
617 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
618 DC_vUpdateFillBrush(DCDest
);
620 /* Determine surfaces to be used in the bitblt */
621 BitmapDest
= DCDest
->dclevel
.pSurface
;
622 if (BitmapDest
== NULL
)
626 BitmapSrc
= DCSrc
->dclevel
.pSurface
;
627 if (BitmapSrc
== NULL
)
630 /* Create the XLATEOBJ. */
631 EXLATEOBJ_vInitXlateFromDCs(&exlo
, DCSrc
, DCDest
);
632 XlateObj
= &exlo
.xlo
;
635 /* Offset the brush */
636 BrushOrigin
.x
+= DCDest
->ptlDCOrig
.x
;
637 BrushOrigin
.y
+= DCDest
->ptlDCOrig
.y
;
639 /* Make mask surface for source surface */
640 if (BitmapSrc
&& DCMask
)
642 BitmapMask
= DCMask
->dclevel
.pSurface
;
644 (BitmapMask
->SurfObj
.sizlBitmap
.cx
< WidthSrc
||
645 BitmapMask
->SurfObj
.sizlBitmap
.cy
< HeightSrc
))
647 DPRINT1("%dx%d mask is smaller than %dx%d bitmap\n",
648 BitmapMask
->SurfObj
.sizlBitmap
.cx
, BitmapMask
->SurfObj
.sizlBitmap
.cy
,
649 WidthSrc
, HeightSrc
);
650 EXLATEOBJ_vCleanup(&exlo
);
653 /* Create mask offset point */
654 MaskPoint
.x
= XOriginMask
;
655 MaskPoint
.y
= YOriginMask
;
656 IntLPtoDP(DCMask
, &MaskPoint
, 1);
657 MaskPoint
.x
+= DCMask
->ptlDCOrig
.x
;
658 MaskPoint
.y
+= DCMask
->ptlDCOrig
.y
;
661 /* Perform the bitblt operation */
662 Status
= IntEngStretchBlt(&BitmapDest
->SurfObj
,
664 BitmapMask
? &BitmapMask
->SurfObj
: NULL
,
665 DCDest
->rosdc
.CombinedClip
,
669 BitmapMask
? &MaskPoint
: NULL
,
670 &DCDest
->eboFill
.BrushObject
,
675 EXLATEOBJ_vCleanup(&exlo
);
679 DC_vFinishBlit(DCDest
, DCSrc
);
707 IN DWORD dwBackColor
)
709 return GreStretchBltMask(
748 if (pbrush
->flAttrs
& GDIBRUSH_IS_NULL
)
755 DestRect
.left
= XLeft
;
756 DestRect
.right
= XLeft
+ Width
;
760 DestRect
.left
= XLeft
+ Width
+ 1;
761 DestRect
.right
= XLeft
+ 1;
766 DestRect
.top
= YLeft
;
767 DestRect
.bottom
= YLeft
+ Height
;
771 DestRect
.top
= YLeft
+ Height
+ 1;
772 DestRect
.bottom
= YLeft
+ 1;
775 IntLPtoDP(pdc
, (LPPOINT
)&DestRect
, 2);
777 DestRect
.left
+= pdc
->ptlDCOrig
.x
;
778 DestRect
.top
+= pdc
->ptlDCOrig
.y
;
779 DestRect
.right
+= pdc
->ptlDCOrig
.x
;
780 DestRect
.bottom
+= pdc
->ptlDCOrig
.y
;
782 BrushOrigin
.x
= pbrush
->ptOrigin
.x
+ pdc
->ptlDCOrig
.x
+ XLeft
;
783 BrushOrigin
.y
= pbrush
->ptOrigin
.y
+ pdc
->ptlDCOrig
.y
+ YLeft
;
785 BrushOrigin
.x
= pbrush
->ptOrigin
.x
+ pdc
->ptlDCOrig
.x
;
786 BrushOrigin
.y
= pbrush
->ptOrigin
.y
+ pdc
->ptlDCOrig
.y
;
789 DC_vPrepareDCsForBlit(pdc
, DestRect
, NULL
, DestRect
);
791 psurf
= pdc
->dclevel
.pSurface
;
793 if (pdc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
794 DC_vUpdateFillBrush(pdc
);
796 EBRUSHOBJ_vInit(&eboFill
, pbrush
, pdc
);
802 pdc
->rosdc
.CombinedClip
,
807 &eboFill
.BrushObject
,
811 DC_vFinishBlit(pdc
, NULL
);
813 EBRUSHOBJ_vCleanup(&eboFill
);
830 pdc
= DC_LockDc(hDC
);
833 EngSetLastError(ERROR_INVALID_HANDLE
);
837 if (pdc
->dctype
== DC_TYPE_INFO
)
840 /* Yes, Windows really returns TRUE in this case */
844 for (i
= 0; i
< cRects
; i
++)
846 pbrush
= BRUSH_ShareLockBrush(pRects
->hBrush
);
857 BRUSH_ShareUnlockBrush(pbrush
);
881 BOOL UsesSource
= ROP_USES_SOURCE(ROP
);
884 /* In this case we call on GdiMaskBlt */
885 return NtGdiMaskBlt(hDC
, XLeft
, YLeft
, Width
, Height
, 0,0,0,0,0,0,ROP
,0);
891 EngSetLastError(ERROR_INVALID_HANDLE
);
894 if (dc
->dctype
== DC_TYPE_INFO
)
897 DPRINT1("NtGdiPatBlt on info DC!\n");
898 /* Yes, Windows really returns TRUE in this case */
902 pdcattr
= dc
->pdcattr
;
904 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
905 DC_vUpdateFillBrush(dc
);
907 pbrush
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
910 EngSetLastError(ERROR_INVALID_HANDLE
);
915 ret
= IntPatBlt(dc
, XLeft
, YLeft
, Width
, Height
, ROP
, pbrush
);
917 BRUSH_ShareUnlockBrush(pbrush
);
927 IN PPOLYPATBLT pRects
,
932 NTSTATUS Status
= STATUS_SUCCESS
;
937 rb
= ExAllocatePoolWithTag(PagedPool
, sizeof(PATRECT
) * cRects
, GDITAG_PLGBLT_DATA
);
940 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
946 cRects
* sizeof(PATRECT
),
950 cRects
* sizeof(PATRECT
));
952 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
954 Status
= _SEH2_GetExceptionCode();
958 if (!NT_SUCCESS(Status
))
960 ExFreePoolWithTag(rb
, GDITAG_PLGBLT_DATA
);
961 SetLastNtError(Status
);
966 Ret
= IntGdiPolyPatBlt(hDC
, dwRop
, rb
, cRects
, Mode
);
969 ExFreePoolWithTag(rb
, GDITAG_PLGBLT_DATA
);