graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdibitblt.cpp
author Faisal Memon <faisal.memon@nokia.com>
Thu, 06 May 2010 11:31:11 +0100
branchNewGraphicsArchitecture
changeset 47 48b924ae7197
parent 0 5d03bc08d59c
permissions -rw-r--r--
Applied patch 1, to provide a syborg specific minigui oby file. Need to compare this with the "stripped" version currently in the tree. This supplied version applies for Nokia builds, but need to repeat the test for SF builds to see if pruning is needed, or if the file needs to be device-specific.

// 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();
	}