// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//
#include "swdirectgdiengine.h"
#include "swdirectgdidriverimpl.h"
#include "directgdiadapter.h"
#include <bitdrawinterfaceid.h>
#include <bmalphablend.h>
#include <graphics/bitmap.inl>
#include <graphics/gdi/gdiinline.inl>
/**
@see MDirectGdiEngine::BitBlt()
@panic DGDIAdapter 7, aBitmap is invalid (debug only).
*/
void CSwDirectGdiEngine::BitBlt(const TPoint& aDestPos,
const CFbsBitmap& aBitmap,
const TRect& aSrceRect)
{
if (aBitmap.ExtendedBitmapType() != KNullUid)
{
iDriver->SetError(KErrNotSupported); // Not supported for extended bitmaps
return;
}
TRect srceRect(aSrceRect);
const TPoint destPoint(aDestPos + iOrigin + srceRect.iTl - aSrceRect.iTl);
const TPoint offset(srceRect.iTl - destPoint);
TRect targetRect(destPoint,srceRect.Size());
aBitmap.BeginDataAccess();
CBitwiseBitmap* srce = static_cast<const CSwDirectGdiBitmap&>(aBitmap).Address();
GRAPHICS_ASSERT_DEBUG(srce,EDirectGdiPanicInvalidBitmap);
const TInt limit = iDefaultRegionPtr->Count();
TBool opaqueSource = (!IsAlphaChannel(aBitmap.DisplayMode())) && (iDrawMode == DirectGdi::EDrawModePEN);
TRect clipRect;
for (TInt count = 0; count < limit; count++)
{
clipRect = (*iDefaultRegionPtr)[count];
if(!clipRect.Intersects(targetRect))
{
continue;
}
clipRect.Intersection(targetRect);
TRect clippedSrceRect(clipRect);
clippedSrceRect.Move(offset);
if (opaqueSource)
{
iDrawMode = DirectGdi::EDrawModeWriteAlpha; // write rather than blend.
}
DoBitBlt(clipRect.iTl, srce, aBitmap.DataAddress(), aBitmap.DataStride(), clippedSrceRect);
if (opaqueSource)
{
iDrawMode = DirectGdi::EDrawModePEN; // set it back to how it was.
}
iDrawDevice->UpdateRegion(clipRect);
}
aBitmap.EndDataAccess(ETrue);
}
/**
@see MDirectGdiEngine::BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, TBool)
@panic DGDIAdapter 7, if either aMaskBitmap or aBitmap are invalid (debug only).
*/
void CSwDirectGdiEngine::BitBltMasked(const TPoint& aDestPos,
const CFbsBitmap& aBitmap,
const TRect& aSrcRect,
const CFbsBitmap& aMaskBitmap,
TBool aInvertMask)
{
if ((aBitmap.ExtendedBitmapType() != KNullUid) || (aMaskBitmap.ExtendedBitmapType() != KNullUid))
{
iDriver->SetError(KErrNotSupported); // Not supported for extended bitmaps
return;
}
TRect localSrcRect(aSrcRect);
const TPoint destPoint(aDestPos + iOrigin + localSrcRect.iTl - aSrcRect.iTl);
const TRect destRect(destPoint, localSrcRect.Size());
const TPoint offset(localSrcRect.iTl - destPoint);
TRect targetRect(destRect);
aBitmap.BeginDataAccess();
aMaskBitmap.BeginDataAccess();
CBitwiseBitmap* srcebmp = static_cast<const CSwDirectGdiBitmap&>(aBitmap).Address();
CBitwiseBitmap* maskbmp = static_cast<const CSwDirectGdiBitmap&>(aMaskBitmap).Address();
GRAPHICS_ASSERT_DEBUG(srcebmp,EDirectGdiPanicInvalidBitmap);
GRAPHICS_ASSERT_DEBUG(maskbmp,EDirectGdiPanicInvalidBitmap);
const TDisplayMode maskMode = maskbmp->DisplayMode();
const TInt limit = iDefaultRegionPtr->Count();
TBool opaqueSource = (!IsAlphaChannel(aBitmap.DisplayMode())) && (iDrawMode == DirectGdi::EDrawModePEN);
TRect clipRect;
for (TInt count = 0; count < limit; count++)
{
clipRect = (*iDefaultRegionPtr)[count];
if (!clipRect.Intersects(targetRect))
{
continue;
}
clipRect.Intersection(targetRect);
TRect clippedSrceRect(clipRect);
clippedSrceRect.Move(offset);
if (opaqueSource)
{
iDrawMode = DirectGdi::EDrawModeWriteAlpha; // ie write rather than blend
}
DoBitBltMasked(clipRect.iTl, srcebmp, aBitmap.DataAddress(), clippedSrceRect, maskbmp,
aMaskBitmap.DataAddress(), aInvertMask);
if (opaqueSource)
{
iDrawMode = DirectGdi::EDrawModePEN; // set to default
}
iDrawDevice->UpdateRegion(clipRect);
}
aBitmap.EndDataAccess(ETrue);
aMaskBitmap.EndDataAccess(ETrue);
}
/**
@see MDirectGdiEngine::BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, const TPoint&)
@panic DGDIAdapter 7, if either aBitmap or aMaskBitmap are invalid.
@panic DGDIAdapter 1022, if the top-left corner of aSrcRect is out of bounds (debug only).
*/
void CSwDirectGdiEngine::BitBltMasked(const TPoint& aDestPt,
const CFbsBitmap& aBitmap, const TRect& aSrcRect,
const CFbsBitmap& aMaskBitmap, const TPoint& aAlphaPt)
{
if ((aBitmap.ExtendedBitmapType() != KNullUid) || (aMaskBitmap.ExtendedBitmapType() != KNullUid))
{
iDriver->SetError(KErrNotSupported); // Not supported for extended bitmaps
return;
}
TRect srcRect(aSrcRect);
//Calculate the destination rect
TPoint destPt(aDestPt + iOrigin);
TRect destRect(destPt, srcRect.Size());
TPoint offset(srcRect.iTl - destPt);
TRect targetRect(destRect);
aBitmap.BeginDataAccess();
aMaskBitmap.BeginDataAccess();
CBitwiseBitmap* srcBmp = static_cast<const CSwDirectGdiBitmap&>(aBitmap).Address();
CBitwiseBitmap* alphaBmp = static_cast<const CSwDirectGdiBitmap&>(aMaskBitmap).Address();
GRAPHICS_ASSERT_DEBUG(srcBmp, EDirectGdiPanicInvalidBitmap);
GRAPHICS_ASSERT_DEBUG(alphaBmp, EDirectGdiPanicInvalidBitmap);
TUint32* srcDataAddr = aBitmap.DataAddress();
TUint32* alphaDataAddr = aMaskBitmap.DataAddress();
//For each region - find the clipping rect and draw
TInt limit = iDefaultRegionPtr->Count ();
TRect clipRect;
for (TInt count=0; count<limit;count++)
{
clipRect=(*iDefaultRegionPtr)[count];
if ( !clipRect.Intersects(targetRect))
{
continue;
}
//targetRect was constructed from destRect. destRect was constructed from srcRect.
clipRect.Intersection (targetRect);
TRect clippedSrcRect(clipRect);
clippedSrcRect.Move(offset);//clippedSrcRect - maps to a part of srcRect now.
TPoint shift(clippedSrcRect.iTl - srcRect.iTl);
GRAPHICS_ASSERT_DEBUG(shift.iX >= 0, EDirectGdiPanicNegativeShift);
GRAPHICS_ASSERT_DEBUG(shift.iY >= 0, EDirectGdiPanicNegativeShift);
DoBitBltAlpha (clipRect.iTl, srcBmp, srcDataAddr, clippedSrcRect,
alphaBmp, alphaDataAddr, aAlphaPt + shift, EFalse);
iDrawDevice->UpdateRegion (clipRect);
}
aBitmap.EndDataAccess(ETrue);
aMaskBitmap.EndDataAccess(ETrue);
return;
}
/**
Calculates the position into the scanline for the given x coordinate.
@param aX The given x-coordinate.
@param aDisplayMode The applied display mode.
@return The memory offset, or 0 if the mode is not supported.
@panic DGDIAdapter 1009, if aDisplayMode is not supported (debug only).
*/
TUint CSwDirectGdiEngine::MemoryOffsetForPixelPitch(TUint aX, TDisplayMode aDisplayMode) const
{
switch (aDisplayMode)
{
case EColor16MU:
case EColor16MAP:
return aX << 2;
case EColor64K:
return aX << 1;
default:
GRAPHICS_PANIC_DEBUG(EDirectGdiPanicInvalidDisplayMode);
}
return 0;
}
TUint32* CSwDirectGdiEngine::GetScanLineOffsetPtr(CBitwiseBitmap* aSrce, TUint32*& aSlptr,
TInt aLength, TPoint aPixel, TUint32* aBase,
TLineScanningPosition& aLineScanningPosition, TUint aXOffset)
{
aSrce->GetScanLinePtr(aSlptr, aLength, aPixel, aBase, aLineScanningPosition);
return (TUint32*)((TUint8*)aSlptr + aXOffset);
}
/**
Performs the actual bitblt to the device.
This function may also be called by DrawBitmap(), and DrawRect() when using a patterned brush,
so any changes to this function may impact on them also.
@pre aSrce A bitmap with non-zero dimensions. aSrceRect has been clipped against the target.
@param aDest The target position on the device which will contain the top left
corner of the source bitmap.
@param aSrce The bitmap object that contains the pixels to draw.
@param aBase The address of the bitmap pixels.
@param aStride The length in bytes between scanlines in memory.
@param aSrceRect The area of the bitmap to draw from.
@panic DGDIAdapter 1013, if aDest is fully outside of the bounds of the target, or aSrceRect.iTl is not
within the drawing area (debug only).
*/
void CSwDirectGdiEngine::DoBitBlt(const TPoint& aDest,
CBitwiseBitmap* aSrce,
TUint32* aBase,
TInt aStride,
const TRect& aSrceRect)
{
// Does multiple bitmap widths for painting rects only
const TInt width = aSrceRect.Width ();
#ifdef _DEBUG
TRect deviceDestRect;
iDrawDevice->GetDrawRect(deviceDestRect);
GRAPHICS_ASSERT_DEBUG(aDest.iX >= deviceDestRect.iTl.iX, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG(aDest.iY >= deviceDestRect.iTl.iY, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG((aDest.iX + aSrceRect.Width()) <= deviceDestRect.iBr.iX, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG((aDest.iY + aSrceRect.Height()) <= deviceDestRect.iBr.iY, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG(aDest.iX >= 0 && aDest.iY >= 0, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG(aSrceRect.iTl.iX >= 0 && aSrceRect.iTl.iY >= 0, EDirectGdiPanicOutOfBounds);
#endif
TSize srcSize = aSrce->SizeInPixels ();
const TPoint KZeroPoint(0,0);
TAny* interface = NULL;
if (iDrawMode == DirectGdi::EDrawModeWriteAlpha &&
aSrceRect.iBr.iX <= srcSize.iWidth &&
aSrceRect.iBr.iY <= srcSize.iHeight &&
!aSrce->IsCompressed() &&
aSrce->DisplayMode() == iDrawDevice->DisplayMode() &&
iDrawDevice->GetInterface(KFastBlit2InterfaceID, interface) == KErrNone)
{
// Conditions in CFbsBitGc allow for optimised blitting.
// The draw device supports the optimised blitting function.
// Operation may fail regardless due to unacceptable conditions in the draw device.
MFastBlit2* fastBlit = reinterpret_cast<MFastBlit2*>(interface);
if (fastBlit && (fastBlit->WriteBitmapBlock(aDest, aBase, aStride, srcSize, aSrceRect) == KErrNone))
{
return;
}
}
MFastBlend* fastBlend=NULL;
if (FastBlendInterface(aSrce,NULL,fastBlend)==KErrNone)
{
if (fastBlend->FastBlendBitmap(aDest, aBase, aStride, srcSize, aSrceRect, aSrce->DisplayMode(), GcDrawMode(iDrawMode), CFbsDrawDevice::ENoShadow)== KErrNone)
{
return;
}
}
const TInt scanLineBytes = iDrawDevice->ScanLineBytes();
TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer();
TPtr8 scanLineDes((TUint8*)scanLineBuffer, scanLineBytes, scanLineBytes);
const TDisplayMode dispMode = ScanLineBufferDisplayMode(iDrawDevice);
const TBool useScanLinePtr = (dispMode == aSrce->DisplayMode()) &&
(TDisplayModeUtils::NumDisplayModeBitsPerPixel(dispMode) >= 8);
TUint32* slptr = NULL;
TUint offset = 0;
TUint32* lastScanLine = NULL;
if (useScanLinePtr)
{
lastScanLine = aSrce->ScanLineAddress(aBase, aSrceRect.iBr.iY-1);
}
TInt srceWidth = srcSize.iWidth;
TInt partlinestart = aSrceRect.iTl.iX % srceWidth;
if (partlinestart < 0)
{
partlinestart += srceWidth;
}
const TInt partlinelength = Min(srceWidth - partlinestart, width);
TInt destX = aDest.iX;
const TInt destXlimit = destX+width;
const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode);
// first part line
if (partlinestart > 0 && partlinelength > 0)
{
TPoint srcecoord1(partlinestart, aSrceRect.iTl.iY);
TInt desty = aDest.iY;
TLineScanningPosition lineScanPos(aBase);
if (useScanLinePtr)
{
offset = MemoryOffsetForPixelPitch(partlinestart, dispMode);
if (aSrce->IsCompressed ())
{
while (srcecoord1.iY < aSrceRect.iBr.iY)
{
scanLineBuffer = GetScanLineOffsetPtr (aSrce, slptr,
partlinelength, srcecoord1, aBase, lineScanPos, offset);
if (srcecoord1.iY == aSrceRect.iTl.iY)
{
aSrce->SetCompressionBookmark(lineScanPos, aBase, NULL);
}
iDrawDevice->WriteLine(aDest.iX, desty, partlinelength,
scanLineBuffer, drawMode);
srcecoord1.iY++;
desty++;
}
}
else
{
while (srcecoord1.iY < aSrceRect.iBr.iY)
{
scanLineBuffer = GetScanLineOffsetPtr (aSrce, slptr,
partlinelength, srcecoord1, aBase, lineScanPos,
offset);
do
{
iDrawDevice->WriteLine (aDest.iX, desty,
partlinelength, scanLineBuffer, drawMode);
scanLineBuffer = (TUint32*)((TUint8*)scanLineBuffer + aStride);
srcecoord1.iY++;
desty++;
}
while ((srcecoord1.iY < aSrceRect.iBr.iY) && (scanLineBuffer < lastScanLine)) ;
}
}
}
else
{
for ( ; srcecoord1.iY < aSrceRect.iBr.iY; srcecoord1.iY++, desty++)
{
aSrce->GetScanLine (scanLineDes, srcecoord1, partlinelength,
EFalse, KZeroPoint, dispMode, aBase, lineScanPos);
if ( srcecoord1.iY==aSrceRect.iTl.iY)
{
aSrce->SetCompressionBookmark (lineScanPos, aBase, NULL);
}
iDrawDevice->WriteLine (aDest.iX, desty, partlinelength,
scanLineBuffer, drawMode);
}
}
destX += partlinelength;
}
// multiple complete lines - columns
TInt numcolumns = (destXlimit - destX) / srceWidth;
if (numcolumns > 0)
{
TPoint srcecoord2(0, aSrceRect.iTl.iY);
TInt desty = aDest.iY;
TLineScanningPosition lineScanPos(aBase);
if (useScanLinePtr)
{
if (aSrce->IsCompressed())
{
while (srcecoord2.iY < aSrceRect.iBr.iY)
{
TPoint coord(srcecoord2);
aSrce->GetScanLinePtr (slptr, srceWidth, coord, aBase, lineScanPos);
if (srcecoord2.iY == aSrceRect.iTl.iY)
{
aSrce->SetCompressionBookmark(lineScanPos, aBase, NULL);
}
TInt tempdestX = destX;
for (TInt count = 0; count < numcolumns; count++, tempdestX += srceWidth)
{
iDrawDevice->WriteLine(tempdestX, desty, srceWidth, slptr, drawMode);
}
srcecoord2.iY++;
desty++;
}
}
else
{
while (srcecoord2.iY < aSrceRect.iBr.iY)
{
TPoint coord(srcecoord2);
aSrce->GetScanLinePtr (slptr, srceWidth, coord, aBase, lineScanPos);
do
{
TInt tempdestX = destX;
for (TInt count = 0; count < numcolumns; count++, tempdestX += srceWidth)
{
iDrawDevice->WriteLine (tempdestX, desty, srceWidth, slptr, drawMode);
}
slptr = (TUint32*)((TUint8*)slptr + aStride);
srcecoord2.iY++;
desty++;
}
while ((srcecoord2.iY < aSrceRect.iBr.iY) && (slptr < lastScanLine));
}
}
}
else
{
for (; srcecoord2.iY < aSrceRect.iBr.iY; srcecoord2.iY++, desty++)
{
TInt tempdestX = destX;
TPoint coord(srcecoord2);
aSrce->GetScanLinePtr (slptr, srceWidth, coord, aBase, lineScanPos);
if (srcecoord2.iY == aSrceRect.iTl.iY)
{
aSrce->SetCompressionBookmark (lineScanPos, aBase, NULL);
}
for (TInt count = 0; count < numcolumns; count++, tempdestX += srceWidth)
{
aSrce->GetScanLine(slptr, scanLineDes, coord, srceWidth,
EFalse, KZeroPoint, dispMode);
iDrawDevice->WriteLine(tempdestX, desty, srceWidth, scanLineBuffer, drawMode);
}
}
}
destX += numcolumns * srceWidth;
}
// final part line
if (destX < destXlimit)
{
const TInt restofline = destXlimit - destX;
TPoint srcecoord3(0, aSrceRect.iTl.iY);
TInt desty = aDest.iY;
TLineScanningPosition lineScanPos(aBase);
if (useScanLinePtr)
{
offset = 0;
if (aSrce->IsCompressed())
{
while (srcecoord3.iY < aSrceRect.iBr.iY)
{
scanLineBuffer = GetScanLineOffsetPtr (aSrce, slptr,
srceWidth, srcecoord3, aBase, lineScanPos, offset);
if (srcecoord3.iY == aSrceRect.iTl.iY)
{
aSrce->SetCompressionBookmark (lineScanPos, aBase, NULL);
}
iDrawDevice->WriteLine(destX, desty, restofline, scanLineBuffer, drawMode);
srcecoord3.iY++;
desty++;
}
}
else
{
while (srcecoord3.iY < aSrceRect.iBr.iY)
{
scanLineBuffer = GetScanLineOffsetPtr (aSrce, slptr,
srceWidth, srcecoord3, aBase, lineScanPos, offset);
do
{
iDrawDevice->WriteLine(destX, desty, restofline, scanLineBuffer, drawMode);
scanLineBuffer = (TUint32*)((TUint8*)scanLineBuffer + aStride);
srcecoord3.iY++;
desty++;
}
while ((srcecoord3.iY < aSrceRect.iBr.iY) && (scanLineBuffer < lastScanLine));
}
}
}
else
{
for (; srcecoord3.iY < aSrceRect.iBr.iY; srcecoord3.iY++, desty++)
{
aSrce->GetScanLine (scanLineDes, srcecoord3, srceWidth, EFalse,
KZeroPoint, dispMode, aBase, lineScanPos);
if (srcecoord3.iY == aSrceRect.iTl.iY)
{
aSrce->SetCompressionBookmark (lineScanPos, aBase, NULL);
}
iDrawDevice->WriteLine(destX, desty, restofline, scanLineBuffer, drawMode);
}
}
}
}
/**
Performs the masked bitblt to the device.
@param aDest The target position on the device which will contain the top left
corner of the source bitmap.
@param aSourceBitmap The bitmap object that contains the pixels to draw.
@param aSourceBase The address of the source bitmap pixels.
@param aSourceRect The area of the bitmap to draw from.
@param aMaskBitmap The bitmap object that contains the mask.
@param aMaskBase The address of the mask pixels.
@param aInvertMask Inverts the mask if ETrue.
@panic DGDIAdapter 1013, if aDest is outside of the device bounds (debug only).
*/
void CSwDirectGdiEngine::DoBitBltMasked(const TPoint& aDest,
CBitwiseBitmap* aSourceBitmap,
TUint32* aSourceBase,
const TRect& aSourceRect,
CBitwiseBitmap* aMaskBitmap,
TUint32* aMaskBase,
TBool aInvertMask)
{
#ifdef _DEBUG
TRect deviceDestRect;
iDrawDevice->GetDrawRect (deviceDestRect);
#endif
GRAPHICS_ASSERT_DEBUG (aDest.iX >= deviceDestRect.iTl.iX, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG (aDest.iY >= deviceDestRect.iTl.iY, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG ((aDest.iX + aSourceRect.Width()) <= deviceDestRect.iBr.iX, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG ((aDest.iY + aSourceRect.Height()) <= deviceDestRect.iBr.iY, EDirectGdiPanicOutOfBounds);
const TPoint KZeroPoint(0,0);
MFastBlend* fastBlend=NULL;
if (FastBlendInterface(aSourceBitmap,aMaskBitmap,fastBlend)==KErrNone)
{
if (fastBlend->FastBlendBitmapMasked(aDest, aSourceBase, aSourceBitmap->DataStride(), aSourceBitmap->SizeInPixels(), aSourceRect, aSourceBitmap->DisplayMode(),
aMaskBase, aMaskBitmap->DataStride(), aMaskBitmap->DisplayMode(), aMaskBitmap->SizeInPixels(), aSourceRect.iTl, aInvertMask,
GcDrawMode(iDrawMode), CFbsDrawDevice::ENoShadow)==KErrNone)
{
return;
}
}
if (aMaskBitmap->DisplayMode() == EGray256)
{
DoBitBltAlpha (aDest, aSourceBitmap, aSourceBase, aSourceRect,
aMaskBitmap, aMaskBase, aSourceRect.iTl, EFalse);
}
// if screen driver is 16MAP we avoid logical operator pen modes by using DoBitBltAlpha() for blitting
else if(iDrawDevice->ScanLineDisplayMode() == EColor16MAP)
{
DoBitBltAlpha (aDest, aSourceBitmap, aSourceBase, aSourceRect,
aMaskBitmap, aMaskBase, aSourceRect.iTl, aInvertMask);
}
else if (aSourceBitmap == aMaskBitmap)
{
const TInt width = aSourceRect.Width();
const TDisplayMode dispMode = ScanLineBufferDisplayMode(iDrawDevice);
const CGraphicsContext::TDrawMode drawMode = aInvertMask ? CGraphicsContext::EDrawModeAND : CGraphicsContext::EDrawModeOR;
TPoint srcePoint(aSourceRect.iTl);
TInt destY = aDest.iY;
TLineScanningPosition lineScanPos(aSourceBase);
const TBool useScanLinePtr = (dispMode == aSourceBitmap->DisplayMode() &&
(TDisplayModeUtils::NumDisplayModeBitsPerPixel(dispMode)>=8));
if (useScanLinePtr)
{
TUint32* scanLineBuffer = NULL;
TUint32* slptr = NULL;
TUint offset = MemoryOffsetForPixelPitch (srcePoint.iX, dispMode);
if (aSourceBitmap->IsCompressed())
{
for ( ; srcePoint.iY < aSourceRect.iBr.iY; destY++,
srcePoint.iY++)
{
scanLineBuffer = GetScanLineOffsetPtr (
aSourceBitmap, slptr, width, srcePoint,
aSourceBase, lineScanPos, offset);
iDrawDevice->WriteLine (aDest.iX, destY, width,
scanLineBuffer, drawMode);
}
}
else
{
TUint stride = aSourceBitmap->DataStride ();
TUint32* lastScanLine = aSourceBitmap->ScanLineAddress(aSourceBase, aSourceRect.iBr.iY-1);
while (srcePoint.iY < aSourceRect.iBr.iY)
{
scanLineBuffer = GetScanLineOffsetPtr(aSourceBitmap, slptr, width, srcePoint,
aSourceBase, lineScanPos, offset);
do
{
iDrawDevice->WriteLine (aDest.iX, destY, width, scanLineBuffer, drawMode);
scanLineBuffer = (TUint32*)((TUint8*)scanLineBuffer + stride);
destY++;
srcePoint.iY++;
}
while ((srcePoint.iY < aSourceRect.iBr.iY) && (scanLineBuffer < lastScanLine));
}
}
}
else
{
const TInt scanLineBytes = iDrawDevice->ScanLineBytes();
TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer();
TPtr8 scanLineDes((TUint8*)scanLineBuffer, scanLineBytes,
scanLineBytes);
for (; srcePoint.iY < aSourceRect.iBr.iY; destY++,
srcePoint.iY++)
{
aSourceBitmap->GetScanLine (scanLineDes, srcePoint,
width, EFalse, KZeroPoint, dispMode,
aSourceBase, lineScanPos);
iDrawDevice->WriteLine (aDest.iX, destY, width,
scanLineBuffer, drawMode);
}
}
}
else
{
DoBitBltMaskedFlicker(aDest, aSourceBitmap, aSourceBase,
aSourceRect, aMaskBitmap, aMaskBase, aInvertMask);
}
}
/**
@see DoBitBltMasked()
*/
void CSwDirectGdiEngine::DoBitBltMaskedFlicker(const TPoint& aDest,
CBitwiseBitmap* aSourceBitmap,
TUint32* aSourceBase,
const TRect& aSourceRect,
CBitwiseBitmap* aMaskBitmap,
TUint32* aMaskBase,
TBool aInvertMask)
{
const TInt width = aSourceRect.Width();
TInt destY = aDest.iY;
TPoint srcePoint(aSourceRect.iTl);
TLineScanningPosition lineScanPos(aSourceBase);
TLineScanningPosition lineScanPosMask(aMaskBase);
const TDisplayMode srcFormat = aSourceBitmap->DisplayMode();
const TDisplayMode maskFormat = aMaskBitmap->DisplayMode();
if (aMaskBitmap->IsCompressed())
{
HBufC8* hBuf = CFbsBitmap::GetDecompressionBuffer(aMaskBitmap->DataStride() + 4);
if (!hBuf)
{
iDriver->SetError(KErrNoMemory);
return; // Out of memory so do not draw anything
}
lineScanPosMask.iScanLineBuffer = hBuf;
}
TAny* interface = NULL;
if ( (srcFormat == EColor16MU || srcFormat == EColor64K ) &&
maskFormat == EGray2 &&
aSourceBitmap->SizeInPixels().iWidth <= aMaskBitmap->SizeInPixels().iWidth &&
aSourceBitmap->SizeInPixels().iHeight <= aMaskBitmap->SizeInPixels().iHeight &&
iDrawDevice->GetInterface(KFastBlitInterfaceID, interface) == KErrNone )
{
// Parameters allow optimised code path
TInt length = width;
TUint32* srcPtr=NULL;
TUint32* maskPtr=NULL;
MFastBlit* fastBlit = reinterpret_cast<MFastBlit*>(interface);
while (srcePoint.iY < aSourceRect.iBr.iY)
{
aSourceBitmap->GetScanLinePtr(srcPtr, length, srcePoint, aSourceBase, lineScanPos);
aMaskBitmap->GetScanLinePtr(maskPtr, length, srcePoint, aMaskBase, lineScanPosMask);
fastBlit->WriteMaskLineEx(aDest.iX,destY,length,srcePoint.iX,srcPtr,srcFormat,srcePoint.iX,maskPtr,aInvertMask);
destY++;
++srcePoint.iY;
}
return;
}
const TDisplayMode dispMode = ScanLineBufferDisplayMode(iDrawDevice);
const CGraphicsContext::TDrawMode drawMode = aInvertMask ? CGraphicsContext::EDrawModeAND : CGraphicsContext::EDrawModeANDNOT;
TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer();
const TInt scanLineBytes = iDrawDevice->ScanLineBytes();
TPtr8 scanLineDes((TUint8*)scanLineBuffer,scanLineBytes,scanLineBytes);
TLineScanningPosition lineScanPos2(aSourceBase);
const TPoint KZeroPoint(0,0);
//scanline modifications required if using different modes, bits per pixel less than 8
if ( (dispMode == aSourceBitmap->DisplayMode()) &&
(TDisplayModeUtils::NumDisplayModeBitsPerPixel(dispMode)>=8))
{
TUint offset = MemoryOffsetForPixelPitch(srcePoint.iX, dispMode);
TUint32* slptr=NULL;
//mask scanline modifications required for EInvertPen, different screen modes
if ((drawMode != CGraphicsContext::EDrawModeANDNOT) && (dispMode == aMaskBitmap->DisplayMode()))
{
TUint32* scanLineBufferMask = NULL;
//stride jumping not possible with compressed bitmaps
if (aSourceBitmap->IsCompressed() || aMaskBitmap->IsCompressed())
{
for (; srcePoint.iY < aSourceRect.iBr.iY; destY++,srcePoint.iY++)
{
scanLineBuffer = GetScanLineOffsetPtr(aSourceBitmap, slptr, width, srcePoint, aSourceBase, lineScanPos, offset);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer, CGraphicsContext::EDrawModeXOR);
scanLineBufferMask = GetScanLineOffsetPtr(aMaskBitmap, slptr, width, srcePoint, aMaskBase, lineScanPosMask, offset);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferMask,drawMode);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer, CGraphicsContext::EDrawModeXOR);
}
}
else
{
TUint strideSrc = aSourceBitmap->DataStride();
TUint strideMask = aMaskBitmap->DataStride();
TUint32* lastScanLineSrc = aSourceBitmap->ScanLineAddress(aSourceBase,aSourceRect.iBr.iY-1);
TUint32* lastScanLineMask = aMaskBitmap->ScanLineAddress(aMaskBase,aSourceRect.iBr.iY-1);
while (srcePoint.iY < aSourceRect.iBr.iY)
{
scanLineBuffer = GetScanLineOffsetPtr(aSourceBitmap, slptr, width, srcePoint, aSourceBase, lineScanPos, offset);
scanLineBufferMask = GetScanLineOffsetPtr(aMaskBitmap, slptr, width, srcePoint, aMaskBase, lineScanPosMask, offset);
do
{
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,CGraphicsContext::EDrawModeXOR);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferMask,drawMode);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,CGraphicsContext::EDrawModeXOR);
destY++;
srcePoint.iY++;
}
while ((srcePoint.iY < aSourceRect.iBr.iY) &&
(scanLineBuffer < lastScanLineSrc) &&
(scanLineBufferMask < lastScanLineMask) &&
((scanLineBuffer = (TUint32*)((TUint8*)scanLineBuffer + strideSrc))>(TUint32*)0) &&
((scanLineBufferMask = (TUint32*)((TUint8*)scanLineBufferMask + strideMask))>(TUint32*)0) );
}
}
}
else
{
TUint32* scanLineBufferPtr = NULL;
//stride jumping not possible with compressed bitmaps
if (aSourceBitmap->IsCompressed())
{
for (; srcePoint.iY < aSourceRect.iBr.iY; destY++,srcePoint.iY++)
{
scanLineBufferPtr = GetScanLineOffsetPtr(aSourceBitmap, slptr, width, srcePoint, aSourceBase, lineScanPos, offset);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferPtr,CGraphicsContext::EDrawModeXOR);
aMaskBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse , KZeroPoint, dispMode, aMaskBase, lineScanPosMask);
TileScanLine(scanLineDes, width, srcePoint, aMaskBitmap, lineScanPosMask, aMaskBase, dispMode);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,drawMode);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferPtr,CGraphicsContext::EDrawModeXOR);
}
}
else
{
TUint stride = aSourceBitmap->DataStride();
TUint32* lastScanLine = aSourceBitmap->ScanLineAddress(aSourceBase,aSourceRect.iBr.iY-1);
while (srcePoint.iY < aSourceRect.iBr.iY)
{
scanLineBufferPtr = GetScanLineOffsetPtr(aSourceBitmap, slptr, width, srcePoint, aSourceBase, lineScanPos, offset);
do
{
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferPtr,CGraphicsContext::EDrawModeXOR);
aMaskBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse, KZeroPoint, dispMode,aMaskBase, lineScanPosMask);
TileScanLine(scanLineDes, width, srcePoint, aMaskBitmap, lineScanPosMask, aMaskBase, dispMode);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,drawMode);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferPtr,CGraphicsContext::EDrawModeXOR);
destY++;
srcePoint.iY++;
}
while ((srcePoint.iY < aSourceRect.iBr.iY) && (scanLineBufferPtr < lastScanLine) &&
((scanLineBufferPtr = (TUint32*)((TUint8*)scanLineBufferPtr + stride))>(TUint32*)0));
}
}
}
}
else
{
for (; srcePoint.iY < aSourceRect.iBr.iY; destY++,srcePoint.iY++)
{
aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse, KZeroPoint,
dispMode,aSourceBase,lineScanPos);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,CGraphicsContext::EDrawModeXOR);
aMaskBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse , KZeroPoint, dispMode,
aMaskBase, lineScanPosMask);
TileScanLine(scanLineDes, width, srcePoint, aMaskBitmap, lineScanPosMask, aMaskBase, dispMode);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,drawMode);
aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse , KZeroPoint ,dispMode,
aSourceBase,lineScanPos2);
iDrawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,CGraphicsContext::EDrawModeXOR);
}
}
}
/**
@see DoBitBltMasked()
*/
void CSwDirectGdiEngine::DoBitBltAlpha(const TPoint& aDest ,CBitwiseBitmap* aSourceBitmap,
TUint32* aSourceBase, const TRect& aSourceRect,
CBitwiseBitmap* aMaskBitmap, TUint32* aMaskBase,
const TPoint& aAlphaPoint, TBool aInvertMask)
{
MFastBlend* fastBlend=NULL;
if (FastBlendInterface(aSourceBitmap,aMaskBitmap,fastBlend)==KErrNone)
{
if (fastBlend->FastBlendBitmapMasked(aDest, aSourceBase, aSourceBitmap->DataStride(), aSourceBitmap->SizeInPixels(), aSourceRect, aSourceBitmap->DisplayMode(),
aMaskBase, aMaskBitmap->DataStride(), aMaskBitmap->DisplayMode(), aMaskBitmap->SizeInPixels(), aAlphaPoint, aInvertMask,
GcDrawMode(iDrawMode), CFbsDrawDevice::ENoShadow)==KErrNone)
{
return;
}
}
const TPoint KZeroPoint(0,0);
const TInt KScanLineLength = 256;
const TInt KRgbSize = 4;
TUint8 srceRgbBuffer[KScanLineLength * KRgbSize];
TUint8 maskBuffer[KScanLineLength];
TUint8* srceRgbBufferPtr(srceRgbBuffer);
TPtr8 srceRgbDes(srceRgbBuffer, KScanLineLength * KRgbSize, KScanLineLength * KRgbSize);
TPtr8 maskDes(maskBuffer, KScanLineLength, KScanLineLength);
TInt srceY = aSourceRect.iTl.iY;
TInt destY = aDest.iY;
TInt alphaY = aAlphaPoint.iY;
TLineScanningPosition lineScanPosSrc(aSourceBase);
TLineScanningPosition lineScanPosMask(aMaskBase);
TDisplayMode sourceMode = aSourceBitmap->DisplayMode();
if (aMaskBitmap->IsCompressed())
{
HBufC8* hBuf= CFbsBitmap::GetDecompressionBuffer(aMaskBitmap->DataStride());
if (hBuf == NULL)
{
iDriver->SetError(KErrNoMemory); // Out of memory so do not draw anything
return;
}
lineScanPosMask.iScanLineBuffer = hBuf;
}
TAny* interface = NULL;
if ( (sourceMode == EColor16MU || sourceMode == EColor64K) &&
aMaskBitmap->DisplayMode() == EGray256 && // ensure a monochrome mask isn't passed in as an alpha channel
aSourceBitmap->SizeInPixels().iWidth <= aMaskBitmap->SizeInPixels().iWidth &&
aSourceBitmap->SizeInPixels().iHeight <= aMaskBitmap->SizeInPixels().iHeight &&
iDrawDevice->GetInterface(KFastBlitInterfaceID, interface) == KErrNone )
{
TInt length = aSourceRect.Width();
const TInt srceX = aSourceRect.iTl.iX;
const TInt alphaX = aAlphaPoint.iX;
const TInt destX = aDest.iX;
MFastBlit* fastBlit = reinterpret_cast<MFastBlit*>(interface);
while (srceY < aSourceRect.iBr.iY)
{
TUint32* srcPtr;
TUint32* maskPtr;
TPoint srcPoint(srceX, srceY);
TPoint maskPoint(alphaX, alphaY);
aSourceBitmap->GetScanLinePtr(srcPtr, length, srcPoint, aSourceBase, lineScanPosSrc);
aMaskBitmap->GetScanLinePtr(maskPtr, length, maskPoint, aMaskBase, lineScanPosMask);
fastBlit->WriteAlphaLineEx(destX, destY, length, srceX, srcPtr,
sourceMode, alphaX, maskPtr, MAlphaBlend::EShdwBefore);
srceY++;
destY++;
alphaY++;
}
return;
}
const TBool useScanLinePtr = ( (EColor16MA == aSourceBitmap->DisplayMode()));
TUint32* slptr = NULL;
TUint offset = 0;
while (srceY < aSourceRect.iBr.iY)
{
TInt srceX = aSourceRect.iTl.iX;
TInt destX = aDest.iX;
TInt alphaX = aAlphaPoint.iX;
while (srceX < aSourceRect.iBr.iX)
{
TPoint srcePoint(srceX,srceY);
TPoint alphaPoint(alphaX,alphaY);
const TInt width = Min(KScanLineLength, aSourceRect.iBr.iX - srceX);
if (useScanLinePtr)
{
offset = MemoryOffsetForPixelPitch(srceX, EColor16MU);
srceRgbBufferPtr = (TUint8*)GetScanLineOffsetPtr(aSourceBitmap, slptr, width,
srcePoint, aSourceBase, lineScanPosSrc, offset);
}
else
{
aSourceBitmap->GetScanLine(srceRgbDes,srcePoint,width,EFalse,KZeroPoint,
ERgb,aSourceBase,lineScanPosSrc);
}
aMaskBitmap->GetScanLine(maskDes, alphaPoint, width, EFalse, KZeroPoint,
EGray256, aMaskBase, lineScanPosMask);
TileScanLine(maskDes, width, alphaPoint, aMaskBitmap, lineScanPosMask, aMaskBase, EGray256);
// aInvertMask is not used for alpha channels (EGray256 mask)
if (aInvertMask && aMaskBitmap->DisplayMode() != EGray256)
{
for (TInt i = 0; i < width; ++i)
{
maskBuffer[i] = ~maskBuffer[i];
}
}
iDrawDevice->WriteRgbAlphaLine(destX, destY, width, srceRgbBufferPtr, maskBuffer, GcDrawMode(iDrawMode));
srceX += KScanLineLength;
destX += KScanLineLength;
alphaX += KScanLineLength;
}
srceY++;
destY++;
alphaY++;
}
}
/**
Tiles the scan line if its length in pixels is less than aLengthInPixels.
@param aScanLine A pointer to the scan line buffer.
@param aLengthInPixels The scan line size in pixels.
@param aSrcPt Position of the first pixel in aMaskBitmap that should be used as a source
for the pixels in scan line buffer.
@param aMaskBitmap Any additional pixels for the scan line buffer will be taken from here.
@param aScanLinePos This argument is used for some internal optimisations. It should not be
modified by the caller.
@param aMaskBase The base address of aMaskBitmap data.
@param aDisplayMode Any additional pixels should be taken from aMaskBitmap using aDisplayMode
as an argument for GetScanLine() call.
@panic DGDIAdapter 1021, if the memory required for the scanline is greater than the size of aScanLine (debug only).
*/
void CSwDirectGdiEngine::TileScanLine(TPtr8& aScanLine,
TInt aLengthInPixels,
const TPoint& aSrcPt,
const CBitwiseBitmap* aMaskBitmap,
TLineScanningPosition& aScanLinePos,
TUint32* aMaskBase,
TDisplayMode aDisplayMode
)
{
TInt lengthInBytes = CFbsBitmap::ScanLineLength(aLengthInPixels, aDisplayMode);
GRAPHICS_ASSERT_DEBUG(lengthInBytes <= aScanLine.MaxLength(), EDirectGdiPanicInvalidArg);
TInt scanLineLength = aScanLine.Length();
if(scanLineLength < lengthInBytes && aSrcPt.iX > 0)
{
//If, for example, src bmp is 100 pixels width, mask bmp is 20 pixels width and src
//rect is (10, 0, 100, 1) -> We will read only pixels 10..19 from the first scan line
//of the mask bmp. We have to have 90 mask bmp pixels.
//So we have to make a second mask bmp read startig from pixel 0 - 10 pixels length.
TInt maxLen = Min(aScanLine.MaxLength() - scanLineLength, aSrcPt.iX);
TPtr8 maskDes2(const_cast <TUint8*> (aScanLine.Ptr()) + scanLineLength, maxLen, maxLen);
TPoint srcPt(0, aSrcPt.iY);
TPoint zeroPt(0, 0);
aMaskBitmap->GetScanLine(maskDes2, srcPt, maxLen, EFalse, zeroPt, aDisplayMode, aMaskBase, aScanLinePos);
aScanLine.SetLength(scanLineLength + maskDes2.Length());
scanLineLength = aScanLine.Length();
}
if(scanLineLength >= lengthInBytes || scanLineLength == 0)
{
return;
}
//If we still don't have enough mask bmp pixels - we have to tile the scan line
TInt repeatCnt = lengthInBytes / scanLineLength - 1;
TInt bytesLeft = lengthInBytes % scanLineLength;
const TUint8* src = aScanLine.Ptr();
TUint8* dest = const_cast <TUint8*> (src) + scanLineLength;
for(;repeatCnt>0;dest+=scanLineLength,repeatCnt--)
{
Mem::Copy(dest, src, scanLineLength);
}
if(bytesLeft)
{
Mem::Copy(dest, src, bytesLeft);
}
aScanLine.SetLength(lengthInBytes);
}
/**
Draws a masked rectangular section of the source bitmap and does a compress/stretch to
fit a given destination rectangle. It uses DoBitBltMasked() if no stretching is involved.
@see DrawBitmapMasked()
@param aDestRect The target position on the device containing the top left corner of the source bitmap.
@param aSourceBitmap The bitmap object that contains the pixels to draw.
@param aSourceBase The address of the source bitmap pixels.
@param aSourceRect The area of the bitmap to draw from.
@param aMaskBitmap The bitmap object that contains the mask.
@param aMaskBase The address of the mask pixels.
@param aInvertMask Inverts the mask if ETrue.
@param aClipRect A clipping rectangle.
@panic DGDIAdapter 1013, if the clipping rectangle is fully outside of the device bounds (debug only).
*/
void CSwDirectGdiEngine::DoDrawBitmapMasked(const TRect& aDestRect,
CBitwiseBitmap* aSourceBitmap,
TUint32* aSourceBase,
const TRect& aSourceRect,
CBitwiseBitmap* aMaskBitmap,
TUint32* aMaskBase,
TBool aInvertMask,
const TRect& aClipRect)
{
CFbsDrawDevice* drawDevice = iDrawDevice;
#ifdef _DEBUG
TRect deviceDestRect;
drawDevice->GetDrawRect(deviceDestRect);
GRAPHICS_ASSERT_DEBUG(aClipRect.iTl.iX >= deviceDestRect.iTl.iX, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG(aClipRect.iTl.iY >= deviceDestRect.iTl.iY, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG(aClipRect.iBr.iX <= deviceDestRect.iBr.iX, EDirectGdiPanicOutOfBounds);
GRAPHICS_ASSERT_DEBUG(aClipRect.iBr.iY <= deviceDestRect.iBr.iY, EDirectGdiPanicOutOfBounds);
#endif
// The clipped version of the destination rectangle
TRect clippedDestRect(aDestRect);
clippedDestRect.Intersection(aClipRect);
// If the source rectangle and the destination rectangle are same,
// no stretch/compress operation required, just do BitBltMasked
if (aDestRect.Size() == aSourceRect.Size())
{
if (!clippedDestRect.IsEmpty())
{
const TPoint destPoint(clippedDestRect.iTl);
clippedDestRect.Move(aSourceRect.iTl - aDestRect.iTl);
DoBitBltMasked(destPoint,
aSourceBitmap,
aSourceBase,
clippedDestRect,
aMaskBitmap,
aMaskBase,
aInvertMask);
}
return;
}
MFastBlend* fastBlend=NULL;
if (FastBlendInterface(aSourceBitmap,aMaskBitmap,fastBlend)==KErrNone)
{
if (fastBlend->FastBlendBitmapMaskedScaled(aClipRect, aDestRect, aSourceRect, aSourceBase, aSourceBitmap->DataStride(),
aSourceBitmap->DisplayMode(),aSourceBitmap->SizeInPixels(),
aMaskBase, aMaskBitmap->DataStride(), aMaskBitmap->DisplayMode(), aMaskBitmap->SizeInPixels(), aInvertMask,
GcDrawMode(iDrawMode), CFbsDrawDevice::ENoShadow)==KErrNone)
{
return;
}
}
TUint32* scanLineBuffer = drawDevice->ScanLineBuffer();
const TInt scanLineBytes = drawDevice->ScanLineBytes();
TPtr8 scanLineDes(reinterpret_cast<TUint8*>(scanLineBuffer),scanLineBytes,scanLineBytes);
const TInt KScanLineLength = 256;
const TInt KRgbSize = 4;
TUint8 maskBuffer[KScanLineLength];
TUint8 sourceBuffer[KScanLineLength*KRgbSize];
TPtr8 sourceDes(sourceBuffer,KScanLineLength*KRgbSize,KScanLineLength*KRgbSize);
const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice);
CGraphicsContext::TDrawMode drawMode = aInvertMask ? CGraphicsContext::EDrawModeAND : CGraphicsContext::EDrawModeANDNOT;
// If the source bitmap and the mask bitmap are same, draw the source bitmap either
// with EDrawModeAND or EDrawModeOR based on aInvertMask parameter.
if (aSourceBitmap == aMaskBitmap)
{
drawMode = aInvertMask ? CGraphicsContext::EDrawModeAND : CGraphicsContext::EDrawModeOR;
}
TLinearDDA xLine;
TInt bitmapXStart = 0;
xLine.Construct(TPoint(aSourceRect.iTl.iX,aDestRect.iTl.iX),
TPoint(aSourceRect.iBr.iX,aDestRect.iBr.iX),TLinearDDA::ELeft);
xLine.JumpToYCoord2(bitmapXStart,clippedDestRect.iTl.iX);
TLinearDDA yLine;
TPoint yCoord(aSourceRect.iTl.iY,aDestRect.iTl.iY);
yLine.Construct(yCoord,TPoint(aSourceRect.iBr.iY,aDestRect.iBr.iY),TLinearDDA::ELeft);
TInt dummy;
yLine.JumpToYCoord2(dummy,clippedDestRect.iTl.iY);
yCoord.SetXY(dummy,clippedDestRect.iTl.iY);
const TInt srceWidth = aSourceRect.Width();
const TInt destWidth = aDestRect.Width();
const TInt clipWidth = clippedDestRect.Width();
const TInt clipStrch = clippedDestRect.iTl.iX - aDestRect.iTl.iX;
const TInt sourceBmpWidth = aSourceBitmap->SizeInPixels().iWidth;
const TInt maskWidth = aMaskBitmap->SizeInPixels().iWidth;
const TInt maskHeight = aMaskBitmap->SizeInPixels().iHeight;
TLineScanningPosition lineScanPos(aSourceBase);
TLineScanningPosition lineScanPos2(aSourceBase);
TLineScanningPosition lineScanPosMask(aMaskBase);
HBufC8* alphaBuffer = NULL;
TPtr8 alphaBufferDes(NULL, 0);
const TDisplayMode maskDisplayMode = aMaskBitmap->DisplayMode();
// Mask inversion is not supported if the original source mask format is EGray256.
// Note that this is only used for pre-multiplied alpha targets.
TUint8 maskInverter = (aInvertMask && maskDisplayMode != EGray256) ? 0xFF : 0x00;
if (aSourceBitmap != aMaskBitmap)
{
// Get buffer to be used to convert non-EGray256 masks to EGray256 when display mode is EColor16MAP
// or to tile the mask when the mask width is smaller than the source bitmap width.
if (maskDisplayMode != EGray256 && (dispMode == EColor16MAP || maskWidth < sourceBmpWidth))
{
alphaBuffer = CFbsBitmap::GetExtraBuffer(CFbsBitmap::ScanLineLength(maskWidth, EGray256));
if (!alphaBuffer)
{
return; // Out of memory so do not draw anything
}
alphaBufferDes.Set(alphaBuffer->Des());
}
// Get buffer to be used for decompressing compressed masks when mask is EGray256
if (maskDisplayMode == EGray256 && aMaskBitmap->IsCompressed())
{
HBufC8* hBuf= CFbsBitmap::GetDecompressionBuffer(aMaskBitmap->DataStride());
if (!hBuf)
{
return; // Out of memory so do not draw anything
}
lineScanPosMask.iScanLineBuffer = hBuf;
}
}
const TPoint KZeroPoint(0,0);
while (yCoord.iY < clippedDestRect.iBr.iY)
{
// Draw only the source bitmap, if the source bitmap and the mask bitmap are same.
// else draw both the bitmaps
if (aSourceBitmap == aMaskBitmap)
{
aSourceBitmap->StretchScanLine(scanLineDes,TPoint(bitmapXStart,yCoord.iX),
clipStrch,clipWidth,destWidth,aSourceRect.iTl.iX,
srceWidth, KZeroPoint,dispMode,aSourceBase,lineScanPos);
if (yCoord.iY==clippedDestRect.iTl.iY)
aSourceBitmap->SetCompressionBookmark(lineScanPos,aSourceBase,NULL);
drawDevice->WriteLine(clippedDestRect.iTl.iX,yCoord.iY,clipWidth,scanLineBuffer,drawMode);
}
else if ((maskDisplayMode == EGray256) || (dispMode == EColor16MAP))
{
// Stretch the source bitmap and the mask bitmap for KScanLineLength as stretch length
// then do alpha blending for this length. If the length is more then KScanLineLength
// repeat it till you stretch complete destination length.
const TPoint startPt(bitmapXStart,yCoord.iX);
TInt clipWidthPart = clippedDestRect.Width();
TBool loopLast = ETrue;
if(clipWidthPart > KScanLineLength)
{
clipWidthPart = KScanLineLength;
loopLast = EFalse;
}
TInt clipIncStrch = clippedDestRect.iTl.iX - aDestRect.iTl.iX;
TInt startClip=clippedDestRect.iTl.iX;
TPoint sourceDestXCoords(bitmapXStart,clippedDestRect.iTl.iX);
xLine.Construct(TPoint(aSourceRect.iTl.iX,aDestRect.iTl.iX),
TPoint(aSourceRect.iBr.iX,aDestRect.iBr.iX),TLinearDDA::ELeft);
xLine.JumpToYCoord2(sourceDestXCoords.iX,sourceDestXCoords.iY);
TPoint srcPixel(bitmapXStart % maskWidth,yCoord.iX % maskHeight);
TInt spaceLeft = 0;
TRgb maskRgbValue;
TUint32* maskScanLinePtr32 = NULL;
TPoint currentYValue(0,srcPixel.iY);
aMaskBitmap->GetScanLinePtr(maskScanLinePtr32, currentYValue, maskWidth, aMaskBase, lineScanPosMask);
// To implement non EGray256 mask support with EColor16MAP display mode, we convert
// the mask to EGray256.
if (maskDisplayMode != EGray256) // Convert scan-line to EGray256 and set maskScanLinePtr32 to the conversion.
{
aMaskBitmap->GetScanLine(maskScanLinePtr32, alphaBufferDes, currentYValue, maskWidth, EFalse, TPoint(0, 0), EGray256);
maskScanLinePtr32 = (TUint32*)alphaBuffer->Ptr();
}
TUint8* maskScanLinePtr = reinterpret_cast<TUint8*>(maskScanLinePtr32);
// Outer loop over all KScanLineLengths
FOREVER
{
aSourceBitmap->StretchScanLine(sourceDes,startPt,clipIncStrch,clipWidthPart,destWidth,
aSourceRect.iTl.iX,srceWidth, KZeroPoint ,EColor16MU,aSourceBase,lineScanPos);
// Inner loop to tile the mask if necessary
spaceLeft = clipWidthPart;
do {
srcPixel.iX = sourceDestXCoords.iX % maskWidth;
// Invert the mask using the inversion mask.
maskBuffer[(sourceDestXCoords.iY-clippedDestRect.iTl.iX)%KScanLineLength]=
maskInverter^maskScanLinePtr[srcPixel.iX];
xLine.NextStep(sourceDestXCoords);
} while (--spaceLeft>0);
if (yCoord.iY == clippedDestRect.iTl.iY && startClip == clippedDestRect.iTl.iX)
{
aSourceBitmap->SetCompressionBookmark(lineScanPos,aSourceBase,NULL);
aMaskBitmap->SetCompressionBookmark(lineScanPosMask,aMaskBase,NULL);
}
drawDevice->WriteRgbAlphaLine(startClip,yCoord.iY,clipWidthPart,sourceBuffer,maskBuffer, GcDrawMode(iDrawMode));
if (loopLast)
{
break;
}
startClip+=KScanLineLength;
if (clippedDestRect.iBr.iX - startClip <= KScanLineLength)
{
loopLast = ETrue;
clipWidthPart = clippedDestRect.iBr.iX - startClip;
}
clipIncStrch += KScanLineLength;
}
}
else
{
aSourceBitmap->StretchScanLine(scanLineDes,TPoint(bitmapXStart,yCoord.iX),
clipStrch,clipWidth,destWidth,aSourceRect.iTl.iX,
srceWidth, KZeroPoint ,dispMode,aSourceBase,lineScanPos2);
drawDevice->WriteLine(clippedDestRect.iTl.iX,yCoord.iY,clipWidth,scanLineBuffer,CGraphicsContext::EDrawModeXOR);
TInt maskXStart = bitmapXStart % maskWidth;
if(maskWidth < sourceBmpWidth)
{
TPoint sourceDestXCoords(bitmapXStart,clippedDestRect.iTl.iX);
xLine.Construct(TPoint(aSourceRect.iTl.iX,aDestRect.iTl.iX),
TPoint(aSourceRect.iBr.iX,aDestRect.iBr.iX),TLinearDDA::ELeft);
xLine.JumpToYCoord2(sourceDestXCoords.iX,sourceDestXCoords.iY);
TPoint srcPixel(maskXStart,yCoord.iX % maskHeight);
TInt spaceLeft = clipWidth;
TPoint prevSourceDestXCoords(-1,-1);
TRgb maskRgbValue;
aMaskBitmap->GetScanLine(alphaBufferDes, TPoint(0,srcPixel.iY), maskWidth, EFalse, TPoint(0, 0), EGray256, aMaskBase, lineScanPosMask);
// Loop to tile the mask
do {
if (sourceDestXCoords.iY != prevSourceDestXCoords.iY)
{
if (sourceDestXCoords.iX != prevSourceDestXCoords.iX)
{
srcPixel.iX = sourceDestXCoords.iX % maskWidth;
if (srcPixel.iX < 0)
srcPixel.iX += maskWidth;
maskRgbValue = TRgb::Gray256((*alphaBuffer)[srcPixel.iX]);
}
drawDevice->WriteRgb(sourceDestXCoords.iY,yCoord.iY,maskRgbValue,drawMode);
spaceLeft--;
}
prevSourceDestXCoords = sourceDestXCoords;
xLine.SingleStep(sourceDestXCoords);
} while (spaceLeft > 0);
}
else
{
// No need to tile the mask
aMaskBitmap->StretchScanLine(scanLineDes,TPoint(maskXStart,yCoord.iX % maskHeight),
clipStrch,clipWidth,destWidth,aSourceRect.iTl.iX,
srceWidth, KZeroPoint ,dispMode,aMaskBase,lineScanPosMask);
drawDevice->WriteLine(clippedDestRect.iTl.iX,yCoord.iY,clipWidth,scanLineBuffer,drawMode);
// Redo stretching of the aSourceBitmap scanline
aSourceBitmap->StretchScanLine(scanLineDes,TPoint(bitmapXStart,yCoord.iX),
clipStrch,clipWidth,destWidth,aSourceRect.iTl.iX,
srceWidth, KZeroPoint ,dispMode,aSourceBase,lineScanPos2);
}
if (yCoord.iY==clippedDestRect.iTl.iY)
{
aSourceBitmap->SetCompressionBookmark(lineScanPos2,aSourceBase,NULL);
aMaskBitmap->SetCompressionBookmark(lineScanPosMask,aMaskBase,NULL);
}
drawDevice->WriteLine(clippedDestRect.iTl.iX,yCoord.iY,clipWidth,scanLineBuffer,CGraphicsContext::EDrawModeXOR);
}
yLine.NextStep(yCoord);
}
}
TInt CSwDirectGdiEngine::FastBlendInterface(const CBitwiseBitmap* aSource, const CBitwiseBitmap* aMask, MFastBlend*& aFastBlend) const
{
#if defined(__ALLOW_FAST_BLEND_DISABLE__)
if (iFastBlendDisabled)
return(KErrNotSupported);
#endif
if ((aSource && aSource->IsCompressed()) || (aMask && aMask->IsCompressed()))
return(KErrNotSupported);
TAny* interface=NULL;
TInt ret= iDrawDevice->GetInterface(KFastBlendInterfaceID, interface);
aFastBlend=(MFastBlend*)interface;
return(ret);
}
/*
Returns the pixel-format to be used when extracting a scan-line through CBitwiseBitmap::GetScanLine(), CBitwiseBitmap::GetVerticalScanLine(), and CBitwiseBitmap::StretchScanLine() for consumption by CFbsDrawDevice::WriteLine() and associated methods.
@see CBitwiseBitmap::GetScanLine()
@see CBitwiseBitmap::GetVerticalScanLine()
@see CBitwiseBitmap::StretchScanLine()
@see CFbsDrawDevice::WriteLine()
@internalComponent
*/
TDisplayMode CSwDirectGdiEngine::ScanLineBufferDisplayMode(CFbsDrawDevice* aDrawDevice)
{
return iDrawMode == DirectGdi::EDrawModeWriteAlpha ? aDrawDevice->DisplayMode() : aDrawDevice->ScanLineDisplayMode();
}