mirror of
https://github.com/reactos/reactos.git
synced 2024-11-27 05:23:33 +08:00
304 lines
10 KiB
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 */
|