diff -r 000000000000 -r bde4ae8d615e os/graphics/graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdibitblt.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/graphics/graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdibitblt.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1358 @@ +// 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(); + }