reactos/win32ss/gdi/eng/transblt.c

304 lines
10 KiB
C

/*
* 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 <win32k.h>
#define NDEBUG
#include <debug.h>
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 */