/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: GDI TransparentBlt Function * FILE: win32ss/gdi/eng/transblt.c * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net) */ #include #define NDEBUG #include BOOL APIENTRY EngTransparentBlt( SURFOBJ *psoDest, SURFOBJ *psoSource, CLIPOBJ *Clip, XLATEOBJ *ColorTranslation, PRECTL DestRect, PRECTL SourceRect, ULONG iTransColor, ULONG Reserved) { BOOL Ret = TRUE; BYTE ClippingType; INTENG_ENTER_LEAVE EnterLeaveSource, EnterLeaveDest; SURFOBJ *InputObj, *OutputObj; RECTL OutputRect, InputRect; POINTL Translate; LONG DstHeight; LONG DstWidth; LONG SrcHeight; LONG SrcWidth; InputRect = *SourceRect; if (!IntEngEnter(&EnterLeaveSource, psoSource, &InputRect, TRUE, &Translate, &InputObj)) { return FALSE; } InputRect.left += Translate.x; InputRect.right += Translate.x; InputRect.top += Translate.y; InputRect.bottom += Translate.y; OutputRect = *DestRect; if (OutputRect.right < OutputRect.left) { OutputRect.left = DestRect->right; OutputRect.right = DestRect->left; } if (OutputRect.bottom < OutputRect.top) { OutputRect.top = DestRect->bottom; OutputRect.bottom = DestRect->top; } if (Clip) { if (OutputRect.left < Clip->rclBounds.left) { InputRect.left += Clip->rclBounds.left - OutputRect.left; OutputRect.left = Clip->rclBounds.left; } if (Clip->rclBounds.right < OutputRect.right) { InputRect.right -= OutputRect.right - Clip->rclBounds.right; OutputRect.right = Clip->rclBounds.right; } if (OutputRect.top < Clip->rclBounds.top) { InputRect.top += Clip->rclBounds.top - OutputRect.top; OutputRect.top = Clip->rclBounds.top; } if (Clip->rclBounds.bottom < OutputRect.bottom) { InputRect.bottom -= OutputRect.bottom - Clip->rclBounds.bottom; OutputRect.bottom = Clip->rclBounds.bottom; } } /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's nothing to do */ if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top) { IntEngLeave(&EnterLeaveSource); return TRUE; } if (!IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &OutputObj)) { IntEngLeave(&EnterLeaveSource); return FALSE; } OutputRect.left = DestRect->left + Translate.x; OutputRect.right = DestRect->right + Translate.x; OutputRect.top = DestRect->top + Translate.y; OutputRect.bottom = DestRect->bottom + Translate.y; ClippingType = (Clip ? Clip->iDComplexity : DC_TRIVIAL); DstHeight = OutputRect.bottom - OutputRect.top; DstWidth = OutputRect.right - OutputRect.left; SrcHeight = InputRect.bottom - InputRect.top; SrcWidth = InputRect.right - InputRect.left; switch (ClippingType) { case DC_TRIVIAL: { Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt( OutputObj, InputObj, &OutputRect, &InputRect, ColorTranslation, iTransColor); break; } case DC_RECT: { RECTL ClipRect, CombinedRect; RECTL InputToCombinedRect; ClipRect.left = Clip->rclBounds.left + Translate.x; ClipRect.right = Clip->rclBounds.right + Translate.x; ClipRect.top = Clip->rclBounds.top + Translate.y; ClipRect.bottom = Clip->rclBounds.bottom + Translate.y; if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) { InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight; InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight; InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth; InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth; Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt( OutputObj, InputObj, &CombinedRect, &InputToCombinedRect, ColorTranslation, iTransColor); } break; } case DC_COMPLEX: { ULONG Direction, i; RECT_ENUM RectEnum; BOOL EnumMore; if (OutputObj == InputObj) { if (OutputRect.top < InputRect.top) { Direction = OutputRect.left < (InputRect.left ? CD_RIGHTDOWN : CD_LEFTDOWN); } else { Direction = OutputRect.left < (InputRect.left ? CD_RIGHTUP : CD_LEFTUP); } } else { Direction = CD_ANY; } CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, Direction, 0); do { EnumMore = CLIPOBJ_bEnum(Clip, sizeof(RectEnum), (PVOID)&RectEnum); for (i = 0; i < RectEnum.c; i++) { RECTL ClipRect, CombinedRect; RECTL InputToCombinedRect; ClipRect.left = RectEnum.arcl[i].left + Translate.x; ClipRect.right = RectEnum.arcl[i].right + Translate.x; ClipRect.top = RectEnum.arcl[i].top + Translate.y; ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y; if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect)) { InputToCombinedRect.top = InputRect.top + (CombinedRect.top - OutputRect.top) * SrcHeight / DstHeight; InputToCombinedRect.bottom = InputRect.top + (CombinedRect.bottom - OutputRect.top) * SrcHeight / DstHeight; InputToCombinedRect.left = InputRect.left + (CombinedRect.left - OutputRect.left) * SrcWidth / DstWidth; InputToCombinedRect.right = InputRect.left + (CombinedRect.right - OutputRect.left) * SrcWidth / DstWidth; Ret = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_TransparentBlt( OutputObj, InputObj, &CombinedRect, &InputToCombinedRect, ColorTranslation, iTransColor); if (!Ret) { break; } } } } while (EnumMore && Ret); break; } default: { Ret = FALSE; break; } } IntEngLeave(&EnterLeaveDest); IntEngLeave(&EnterLeaveSource); return Ret; } BOOL FASTCALL IntEngTransparentBlt( SURFOBJ *psoDest, SURFOBJ *psoSource, CLIPOBJ *Clip, XLATEOBJ *ColorTranslation, PRECTL DestRect, PRECTL SourceRect, ULONG iTransColor, ULONG Reserved) { BOOL Ret; RECTL OutputRect, InputClippedRect; SURFACE *psurfDest; SURFACE *psurfSource; RECTL InputRect; LONG InputClWidth, InputClHeight, InputWidth, InputHeight; ASSERT(psoDest); ASSERT(psoSource); ASSERT(DestRect); psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj); psurfSource = CONTAINING_RECORD(psoSource, SURFACE, SurfObj); ASSERT(psurfDest); ASSERT(psurfSource); /* If no clip object is given, use trivial one */ if (!Clip) Clip = (CLIPOBJ *)&gxcoTrivial; InputClippedRect = *DestRect; if (InputClippedRect.right < InputClippedRect.left) { InputClippedRect.left = DestRect->right; InputClippedRect.right = DestRect->left; } if (InputClippedRect.bottom < InputClippedRect.top) { InputClippedRect.top = DestRect->bottom; InputClippedRect.bottom = DestRect->top; } InputRect = *SourceRect; /* Clip against the bounds of the clipping region so we won't try to write * outside the surface */ if (Clip->iDComplexity != DC_TRIVIAL) { if (!RECTL_bIntersectRect(&OutputRect, &InputClippedRect, &Clip->rclBounds)) { return TRUE; } /* Update source rect */ InputClWidth = InputClippedRect.right - InputClippedRect.left; InputClHeight = InputClippedRect.bottom - InputClippedRect.top; InputWidth = InputRect.right - InputRect.left; InputHeight = InputRect.bottom - InputRect.top; InputRect.left += (InputWidth * (OutputRect.left - InputClippedRect.left)) / InputClWidth; InputRect.right -= (InputWidth * (InputClippedRect.right - OutputRect.right)) / InputClWidth; InputRect.top += (InputHeight * (OutputRect.top - InputClippedRect.top)) / InputClHeight; InputRect.bottom -= (InputHeight * (InputClippedRect.bottom - OutputRect.bottom)) / InputClHeight; } else { OutputRect = InputClippedRect; } if (psurfDest->flags & HOOK_TRANSPARENTBLT) { Ret = GDIDEVFUNCS(psoDest).TransparentBlt(psoDest, psoSource, Clip, ColorTranslation, &OutputRect, &InputRect, iTransColor, Reserved); } else Ret = FALSE; if (!Ret) { Ret = EngTransparentBlt(psoDest, psoSource, Clip, ColorTranslation, &OutputRect, &InputRect, iTransColor, Reserved); } return Ret; } /* EOF */