diff -r 000000000000 -r 5d03bc08d59c graphicsdeviceinterface/bitgdi/sbit/BITBLT.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphicsdeviceinterface/bitgdi/sbit/BITBLT.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,2645 @@ +// Copyright (c) 1997-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 "BITPANIC.H" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GLREF_C void XorBuffers(TUint32* aDestBuffer,const TUint32* aSrceBuffer,TInt aNumBytes); +GLREF_C void AndBuffers(TUint32* aDestBuffer,const TUint32* aSrceBuffer,TInt aNumBytes); +GLREF_C void InvertBuffer(TUint32* aDestBuffer,TInt aNumBytes); +GLREF_C void InvertBuffer(TUint8* aDestBuffer,TInt aNumBytes); +LOCAL_C void TileScanLine(TPtr8& aScanLine, + TInt aLengthInPixels, + const TPoint& aSrcPt, + const CBitwiseBitmap* aMaskBitmap, + TLineScanningPosition& aScanLinePos, + TUint32* aMaskBase, + TDisplayMode aDisplayMode + ); + +/** Draws from another CFbsBitGc. + +@param aPoint The position to draw the top left corner of the piece of bitmap +@param aGc The source bitmap graphics context */ +EXPORT_C void CFbsBitGc::BitBlt(const TPoint& aDest,const CFbsBitGc& aGc) + { + TRect deviceRect; + aGc.iDevice->iDrawDevice->GetDrawRect(deviceRect); + BitBlt(aDest,aGc,deviceRect); + } + +/** Draws a particular rectangle from another CFbsBitGc. + +@param aPoint The position to draw the top left corner of the piece of bitmap. +@param aGc The source bitmap graphics context. +@param aSrceRect A rectangle defining the piece of the source to be drawn. */ +EXPORT_C void CFbsBitGc::BitBlt(const TPoint& aDest, + const CFbsBitGc& aGc, + const TRect& aSrceRect) + { + if (CheckDevice(aSrceRect)) + return; + aGc.CheckDevice(); + CFbsDevice* srceDevice = aGc.iDevice; + if (!srceDevice) + return; + + TRect srceRect(aSrceRect); + TRect deviceRect; + srceDevice->GetDrawRect(deviceRect); + if (!srceRect.Intersects(deviceRect)) + return; + srceRect.Intersection(deviceRect); + + const TPoint destPoint(aDest + iOrigin + srceRect.iTl - aSrceRect.iTl); + const TRect destRect(destPoint,srceRect.Size()); + const TPoint offset(srceRect.iTl - destPoint); + + TRect clippedDestRect(destRect); + AddRect(clippedDestRect); + if (UserClipRect(clippedDestRect)) + return; + + SetupDevice(); + aGc.iDevice->DrawingBegin(); + iDevice->DrawingBegin(); + + const TInt limit = iDefaultRegionPtr->Count(); + TBool opaqueSource = (!IsAlphaChannel(srceDevice->DisplayMode())) && (iDrawMode == EDrawModePEN); + for(TInt count=0;countiDrawDevice->UpdateRegion(iClipRect); + } + + aGc.iDevice->DrawingEnd(); + iDevice->DrawingEnd(); + } + + +/** Draws the whole of a CFbsBitmap. + +@param aDest The position to draw the top left corner of the bitmap. +@param aBitmap The source bitmap. */ +EXPORT_C void CFbsBitGc::BitBlt(const TPoint& aDest,const CFbsBitmap* aBitmap) + { + if (aBitmap == NULL || !aBitmap->Handle()) + return; + + aBitmap->BeginDataAccess(); + BitBlt(aDest,aBitmap,TRect(aBitmap->SizeInPixels())); + aBitmap->EndDataAccess(ETrue); + } + + +/** Draws a particular rectangle from a CFbsBitmap. + +@param aDest The position to draw the top left corner of the bitmap. +@param aBitmap The source bitmap. +@param aSrceRect A rectangle defining the piece of the source to be drawn. */ +EXPORT_C void CFbsBitGc::BitBlt(const TPoint& aDest, + const CFbsBitmap* aBitmap, + const TRect& aSrceRect) + { + if (aBitmap == NULL || !aBitmap->Handle()|| CheckDevice(aSrceRect)) + return; + + aBitmap->BeginDataAccess(); + + TRect srceRect(aSrceRect); + const TRect area(aBitmap->SizeInPixels()); + if (!srceRect.Intersects(area)) + { + aBitmap->EndDataAccess(ETrue); + return; + } + srceRect.Intersection(area); + + const TPoint destPoint(aDest + iOrigin + srceRect.iTl - aSrceRect.iTl); + const TPoint offset(srceRect.iTl - destPoint); + + TRect targetRect(destPoint,srceRect.Size()); + AddRect(targetRect); + if (UserClipRect(targetRect)) + { + aBitmap->EndDataAccess(ETrue); + return; + } + + SetupDevice(); + iDevice->DrawingBegin(); + + CBitwiseBitmap* srce = ((CFbsBitGcBitmap*)aBitmap)->Address(); + BG_ASSERT_DEBUG(srce,EBitgdiPanicInvalidBitmap); + + CFbsRasterizer* rasterizer = PrepareRasterizerForExtendedBitmap(*aBitmap, targetRect, offset); + + TInt count; + const TInt limit = iDefaultRegionPtr->Count(); + CGraphicsAccelerator* ga = GraphicsAccelerator(); + TBool opaqueSource = (!IsAlphaChannel(aBitmap->DisplayMode())) && (iDrawMode == EDrawModePEN); + + if(ga && (iShadowMode == CFbsDrawDevice::ENoShadow)) + { + TInt gaOperationResult = KErrUnknown; + TAcceleratedBitmapSpec bitmapSpec(const_cast(aBitmap)); + iDevice->DrawingEnd(); + + for(count=0;countOperation(TGopBitBlt(iClipRect.iTl,bitmapSpec,clippedSrceRect)); + if(gaOperationResult != KErrNone) + break; + iDevice->iDrawDevice->UpdateRegion(iClipRect); + } + if(gaOperationResult == KErrNone) + goto finish; + iDevice->DrawingBegin(); + } + + for(count=0;countDataAddress(),aBitmap->DataStride(),clippedSrceRect); + if (opaqueSource) + iDrawMode = EDrawModePEN;// set it back how it was + iDevice->iDrawDevice->UpdateRegion(iClipRect); + } + + iDevice->DrawingEnd(); +finish: + if (rasterizer) + { + rasterizer->EndBitmap(aBitmap->SerialNumber()); + } + aBitmap->EndDataAccess(ETrue); + } + + +/** Performs a masked bitmap block transfer. + +The function provides a concrete implementation of the pure virtual +function CBitmapContext::BitBltMasked(). The function +behaviour is the same as documented in that class. + +There are several points to note about this implementation of +BitBltMasked(): + +1.For best performance the aMaskBitmap and source aBitmap should +have the same display mode as the destination device/bitmap. + +2.For performance reasons this implementation does not validate +the contents of the aMaskBitmap. The caller must ensure the mask +pixels are either black or white otherwise undefined blitting causing +unpredictable discoloration will result. This is especially true +for index (where pixel is palette entry) display modes (e.g. EColor16). +It is up to the caller to decide if they wish to utilise +CFbsBitmap::IsMonochrome(). + +3.Alpha blending is used when the display mode of the mask bitmap aMaskBitmap +is EGray256. + +@see CBitmapContext::BitBltMasked() */ +EXPORT_C void CFbsBitGc::BitBltMasked(const TPoint& aDest, + const CFbsBitmap* aBitmap, + const TRect& aSourceRect, + const CFbsBitmap* aMaskBitmap, + TBool aInvertMask) + { + if (aBitmap == NULL || !aBitmap->Handle() || + aMaskBitmap == NULL || !aMaskBitmap->Handle() || + CheckDevice(aSourceRect)) + return; + + aBitmap->BeginDataAccess(); + aMaskBitmap->BeginDataAccess(); + + TRect srceRect(aSourceRect); + const TRect area(aBitmap->SizeInPixels()); + if (!srceRect.Intersects(area)) + { + aBitmap->EndDataAccess(ETrue); + aMaskBitmap->EndDataAccess(ETrue); + return; + } + srceRect.Intersection(area); + + const TPoint destPoint(aDest + iOrigin + srceRect.iTl - aSourceRect.iTl); + const TRect destRect(destPoint,srceRect.Size()); + const TPoint offset(srceRect.iTl - destPoint); + const TPoint ditherorigin(iDitherOrigin + aDest); + + TRect clippedDestRect(destRect); + AddRect(clippedDestRect); + if (UserClipRect(clippedDestRect)) + { + aBitmap->EndDataAccess(ETrue); + aMaskBitmap->EndDataAccess(ETrue); + return; + } + + SetupDevice(); + iDevice->DrawingBegin(); + + + CBitwiseBitmap* srcebmp = ((CFbsBitGcBitmap*)aBitmap)->Address(); + CBitwiseBitmap* maskbmp = ((CFbsBitGcBitmap*)aMaskBitmap)->Address(); + BG_ASSERT_DEBUG(srcebmp,EBitgdiPanicInvalidBitmap); + BG_ASSERT_DEBUG(maskbmp,EBitgdiPanicInvalidBitmap); + + const TDisplayMode maskMode = maskbmp->DisplayMode(); + + // Do the background fill the lazy way with flicker if any of the following are true: + // 1. There is no anti-flicker buffer + // 2. The source and mask bitmaps are the same + // 3. The brush style is patterned and the mask is an alpha mask + // 4. The brush style is not null or solid or patterned + + if (!iDevice->iBitBltMaskedBuffer || + srcebmp == maskbmp || + (maskMode == EGray256 && iBrushStyle == EPatternedBrush) || + iBrushStyle > EPatternedBrush) + { + iBrushBitmap.BeginDataAccess(); + CFbsRasterizer* brushRasterizer = PrepareRasterizerForExtendedBitmap(iBrushBitmap); + RectFill(destRect); + if (brushRasterizer) + { + brushRasterizer->EndBitmap(iBrushBitmap.SerialNumber()); + } + iBrushBitmap.EndDataAccess(ETrue); + } + + const TInt8 shadowMode = iShadowMode; + iShadowMode = CFbsDrawDevice::ENoShadow; + SetupDevice(); + + CFbsRasterizer* rasterizer = PrepareRasterizerForExtendedBitmap(*aBitmap, clippedDestRect, offset); + CFbsRasterizer* maskRasterizer = NULL; + if (srcebmp != maskbmp) + { + if (aMaskBitmap->SizeInPixels().iWidth >= aBitmap->SizeInPixels().iWidth + && aMaskBitmap->SizeInPixels().iHeight >= aBitmap->SizeInPixels().iHeight) + { + // Mask is not tiled. Pass same region of interest as source bitmap to rasterizer. + maskRasterizer = PrepareRasterizerForExtendedBitmap(*aMaskBitmap, clippedDestRect, offset); + } + else + { + // Mask is tiled. Do not pass any region of interest to rasterizer. + maskRasterizer = PrepareRasterizerForExtendedBitmap(*aMaskBitmap); + } + } + + TInt count; + const TInt limit = iDefaultRegionPtr->Count(); + CGraphicsAccelerator* ga = GraphicsAccelerator(); + TBool opaqueSource = (!IsAlphaChannel(aBitmap->DisplayMode())) && (iDrawMode == EDrawModePEN); + + if(ga) + { + if((iBrushStyle == ENullBrush) && aInvertMask && + (shadowMode == CFbsDrawDevice::ENoShadow)) + { + TInt gaOperationResult = KErrUnknown; + TAcceleratedBitmapSpec bitmapSpec(const_cast(aBitmap)); + TAcceleratedBitmapSpec bitmapMaskSpec(const_cast(aMaskBitmap)); + iDevice->DrawingEnd(); + + for(count=0;countDisplayMode() == EGray256) + gaOperationResult = ga->Operation(TGopBitBltAlphaBitmap(iClipRect.iTl, + bitmapSpec, + clippedSrceRect, + bitmapMaskSpec)); + else + gaOperationResult = ga->Operation(TGopBitBltMasked(iClipRect.iTl, + bitmapSpec, + clippedSrceRect, + bitmapMaskSpec)); + + if(gaOperationResult != KErrNone) + break; + iDevice->iDrawDevice->UpdateRegion(iClipRect); + } + if(gaOperationResult == KErrNone) + goto finish; + iDevice->DrawingBegin(); + } + } + + for(count=0;countDataAddress(), + clippedSrceRect, + maskbmp, + aMaskBitmap->DataAddress(), + aInvertMask, + ditherorigin, + shadowMode); + if (opaqueSource) + iDrawMode = EDrawModePEN;// set it back how it was + iDevice->iDrawDevice->UpdateRegion(iClipRect); + } + + iDevice->DrawingEnd(); +finish: + if (rasterizer) + { + rasterizer->EndBitmap(aBitmap->SerialNumber()); + } + if (maskRasterizer) + { + maskRasterizer->EndBitmap(aMaskBitmap->SerialNumber()); + } + aBitmap->EndDataAccess(ETrue); + aMaskBitmap->EndDataAccess(ETrue); + iShadowMode = shadowMode; + } +/** +Does BitBlt operation of source and bitmap per scanline. + +*/ +void CFbsBitGc::DoBitBlt(const TPoint& aDest,CFbsDevice* aSrce,const TRect& aSrceRect) + { + const TInt width = aSrceRect.Width(); + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; +#ifdef _DEBUG + TRect deviceSrcRect; + aSrce->iDrawDevice->GetDrawRect(deviceSrcRect); + TRect deviceDestRect; + drawDevice->GetDrawRect(deviceDestRect); +#endif + BG_ASSERT_DEBUG(aSrceRect.iTl.iX >= deviceSrcRect.iTl.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(aSrceRect.iTl.iY >= deviceSrcRect.iTl.iY, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(aSrceRect.iBr.iX <= deviceSrcRect.iBr.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(aSrceRect.iBr.iY <= deviceSrcRect.iBr.iY, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(aDest.iX >= deviceDestRect.iTl.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(aDest.iY >= deviceDestRect.iTl.iY, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG((aDest.iX + aSrceRect.Width()) <= deviceDestRect.iBr.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG((aDest.iY + aSrceRect.Height()) <= deviceDestRect.iBr.iY, EBitgdiPanicOutOfBounds); + + CFbsDrawDevice* srcDrawDevice = aSrce->iDrawDevice; + TAny* interface=NULL; + if (iDrawMode==EDrawModeWriteAlpha && + iShadowMode == CFbsDrawDevice::ENoShadow && + (aSrceRect.iTl.iX >= 0) && (aSrceRect.iTl.iY >= 0) && + (aDest.iX >= 0) && (aDest.iY >= 0) && + srcDrawDevice->DisplayMode() == drawDevice->DisplayMode() && + drawDevice->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. + BG_ASSERT_DEBUG(interface!=NULL, EBitgdiPanicNullPointer); + MFastBlit2* fastBlit = reinterpret_cast(interface); + if (fastBlit->WriteBitmapBlock(aDest, srcDrawDevice, aSrceRect) == KErrNone) + { + return; + } + } + MFastBlend* fastBlend=NULL; + if (FastBlendInterface(NULL,NULL,fastBlend)==KErrNone) + { + if (fastBlend->FastBlendBitmap(aDest, srcDrawDevice, aSrceRect, iDrawMode, iShadowMode)==KErrNone) + { + return; + } + } + //scanLineBuffer is destination scanline buffer. + TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); + const TInt scanLineBytes = drawDevice->ScanLineBytes(); + TPtr8 scanLineDes((TUint8*)scanLineBuffer,scanLineBytes,scanLineBytes); + //dispMode is destination display mode. + const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice); + TInt destY = aDest.iY; + //Gets the scanline from the source, into the buffer scanLineDes. + //The DoGetScanLine operation is also responsible for converting + // the buffer pixel format to destination display format. + + for (TInt row = aSrceRect.iTl.iY; row < aSrceRect.iBr.iY; row++,destY++) + { + aSrce->DoGetScanLine(scanLineDes,TPoint(aSrceRect.iTl.iX,row),width,dispMode); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,iDrawMode); + } + } + +/** +Calculates the position into the scanline for the given x coordinate +*/ +TUint CFbsBitGc::MemoryOffsetForPixelPitch(TUint aX, TDisplayMode aDisplayMode) + { + switch (aDisplayMode) + { + case EColor16MU: + case EColor16MA: + case EColor16MAP: + return aX << 2; + + case EColor16M: + return aX * 3; + + case EColor4K: + case EColor64K: + return aX << 1; + + case EGray256: + case EColor256: + return aX; + + default: + BG_PANIC_DEBUG(EBitgdiPanicInvalidDisplayMode); + break; + } + return 0; + } + +/** +Gets the scanline pointer with the offset +*/ +TUint32* CFbsBitGc::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); + } + +void CFbsBitGc::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(); + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; +#ifdef _DEBUG + TRect deviceDestRect; + drawDevice->GetDrawRect(deviceDestRect); +#endif + BG_ASSERT_DEBUG(aDest.iX >= deviceDestRect.iTl.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(aDest.iY >= deviceDestRect.iTl.iY, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG((aDest.iX + aSrceRect.Width()) <= deviceDestRect.iBr.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG((aDest.iY + aSrceRect.Height()) <= deviceDestRect.iBr.iY, EBitgdiPanicOutOfBounds); + + TSize srcSize = aSrce->SizeInPixels(); + if (srcSize.iWidth == 0 || srcSize.iHeight == 0) + return; //no point doing anything if asked to draw zero size bitmap + + TAny* interface=NULL; + if (iDrawMode==EDrawModeWriteAlpha && + iShadowMode == CFbsDrawDevice::ENoShadow && + aSrceRect.iTl.iX >= 0 && + aSrceRect.iTl.iY >= 0 && + aSrceRect.iBr.iX <= srcSize.iWidth && + aSrceRect.iBr.iY <= srcSize.iHeight && + (aDest.iX >= 0) && (aDest.iY >= 0) && + !aSrce->IsCompressed() && + aSrce->DisplayMode() == drawDevice->DisplayMode() && + drawDevice->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. + BG_ASSERT_DEBUG(interface!=NULL, EBitgdiPanicNullPointer); + MFastBlit2* fastBlit = reinterpret_cast(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(), iDrawMode, iShadowMode)== KErrNone) + { + return; + } + } + + const TInt scanLineBytes = drawDevice->ScanLineBytes(); + TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); + TPtr8 scanLineDes((TUint8*)scanLineBuffer,scanLineBytes,scanLineBytes); + + const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice); + + const TBool useScanLinePtr = (!iShadowMode) && (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 = 0; + 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; + + // first part line + if (partlinestart > 0 && partlinelength > 0) + { + TPoint srcecoord1(partlinestart,aSrceRect.iTl.iY); + TInt desty = aDest.iY; + TPoint ditherorigin(iDitherOrigin); + ditherorigin.iX += aDest.iX; + ditherorigin.iY += desty; + + 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); + } + drawDevice->WriteLine(aDest.iX,desty,partlinelength, scanLineBuffer,iDrawMode); + srcecoord1.iY++,desty++,ditherorigin.iY++; + } + } + else + { + while (srcecoord1.iY < aSrceRect.iBr.iY) + { + scanLineBuffer = GetScanLineOffsetPtr(aSrce, slptr, partlinelength, srcecoord1, aBase, lineScanPos, offset); + do + { + drawDevice->WriteLine(aDest.iX,desty,partlinelength, scanLineBuffer,iDrawMode); + scanLineBuffer = (TUint32*)((TUint8*)scanLineBuffer + aStride); + srcecoord1.iY++,desty++,ditherorigin.iY++; + } + while ((srcecoord1.iY < aSrceRect.iBr.iY) && (scanLineBuffer < lastScanLine)); + } + } + } + else + { + for (; srcecoord1.iY < aSrceRect.iBr.iY; srcecoord1.iY++,desty++,ditherorigin.iY++) + { + aSrce->GetScanLine(scanLineDes,srcecoord1,partlinelength,ETrue, + ditherorigin,dispMode,aBase, lineScanPos); + if (srcecoord1.iY==aSrceRect.iTl.iY) + { + aSrce->SetCompressionBookmark(lineScanPos,aBase,NULL); + } + drawDevice->WriteLine(aDest.iX,desty,partlinelength, scanLineBuffer,iDrawMode); + } + } + + destX+=partlinelength; + } + + // multiple complete lines - columns + TInt numcolumns = 0; + numcolumns = (destXlimit - destX) / srceWidth; + if (numcolumns > 0) + { + TPoint srcecoord2(0,aSrceRect.iTl.iY); + TInt desty = aDest.iY; + TPoint ditherorigin(iDitherOrigin); + ditherorigin.iX += destX; + ditherorigin.iY += desty; + + 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) + { + drawDevice->WriteLine(tempdestX,desty,srceWidth, slptr,iDrawMode); + ditherorigin.iX += srceWidth; + } + srcecoord2.iY++,desty++,ditherorigin.iY++; + } + } + 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) + { + drawDevice->WriteLine(tempdestX,desty,srceWidth, slptr,iDrawMode); + ditherorigin.iX += srceWidth; + } + slptr = (TUint32*)((TUint8*)slptr + aStride); + srcecoord2.iY++,desty++,ditherorigin.iY++; + } + while ((srcecoord2.iY < aSrceRect.iBr.iY) && (slptr < lastScanLine)); + } + } + } + else + { + for (; srcecoord2.iY < aSrceRect.iBr.iY; srcecoord2.iY++,desty++,ditherorigin.iY++) + { + 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,ETrue, + ditherorigin,dispMode); + drawDevice->WriteLine(tempdestX,desty,srceWidth, scanLineBuffer,iDrawMode); + ditherorigin.iX += srceWidth; + } + } + } + + destX += numcolumns * srceWidth; + } + + // final part line + if (destX < destXlimit) + { + const TInt restofline = destXlimit - destX; + TPoint srcecoord3(0,aSrceRect.iTl.iY); + TInt desty = aDest.iY; + TPoint ditherorigin(iDitherOrigin); + ditherorigin.iX += destX; + ditherorigin.iY += desty; + + 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); + } + drawDevice->WriteLine(destX,desty,restofline,scanLineBuffer,iDrawMode); + srcecoord3.iY++,desty++,ditherorigin.iY++; + } + } + else + { + while (srcecoord3.iY < aSrceRect.iBr.iY) + { + scanLineBuffer = GetScanLineOffsetPtr(aSrce, slptr, srceWidth, srcecoord3, aBase, lineScanPos, offset); + do + { + drawDevice->WriteLine(destX,desty,restofline,scanLineBuffer,iDrawMode); + scanLineBuffer = (TUint32*)((TUint8*)scanLineBuffer + aStride); + srcecoord3.iY++,desty++,ditherorigin.iY++; + } + while ((srcecoord3.iY < aSrceRect.iBr.iY) && (scanLineBuffer < lastScanLine)); + } + } + } + else + { + for (; srcecoord3.iY < aSrceRect.iBr.iY; srcecoord3.iY++,desty++,ditherorigin.iY++) + { + aSrce->GetScanLine(scanLineDes,srcecoord3,srceWidth,ETrue, + ditherorigin,dispMode,aBase,lineScanPos); + if (srcecoord3.iY==aSrceRect.iTl.iY) + { + aSrce->SetCompressionBookmark(lineScanPos, aBase,NULL); + } + drawDevice->WriteLine(destX,desty,restofline,scanLineBuffer,iDrawMode); + } + } + } + } + +void CFbsBitGc::DoBitBltMasked(const TPoint& aDest, + CBitwiseBitmap* aSourceBitmap, + TUint32* aSourceBase, + const TRect& aSourceRect, + CBitwiseBitmap* aMaskBitmap, + TUint32* aMaskBase, + TBool aInvertMask, + const TPoint& aDitherOrigin, + TInt aShadowMode) + { + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; +#ifdef _DEBUG + TRect deviceDestRect; + drawDevice->GetDrawRect(deviceDestRect); +#endif + BG_ASSERT_DEBUG(aDest.iX >= deviceDestRect.iTl.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(aDest.iY >= deviceDestRect.iTl.iY, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG((aDest.iX + aSourceRect.Width()) <= deviceDestRect.iBr.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG((aDest.iY + aSourceRect.Height()) <= deviceDestRect.iBr.iY, EBitgdiPanicOutOfBounds); + + 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, + iDrawMode, aShadowMode)==KErrNone) + { + return; + } + } + + const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice); + if (aMaskBitmap->DisplayMode() == EGray256) + { + DoBitBltAlpha(aDest,aSourceBitmap,aSourceBase,aSourceRect, + aMaskBitmap,aMaskBase,aSourceRect.iTl,aShadowMode, EFalse); + } + // if screen driver is 16MAP we avoid logical operator pen modes by using DoBitBltAlpha() for blitting + else if (dispMode == EColor16MAP) + { + DoBitBltAlpha(aDest,aSourceBitmap,aSourceBase,aSourceRect, + aMaskBitmap,aMaskBase,aSourceRect.iTl,aShadowMode, aInvertMask); + } + + else if (aSourceBitmap == aMaskBitmap) + { + const TInt width = aSourceRect.Width(); + TPoint ditherOrigin(aDitherOrigin + aDest); + const TDrawMode drawMode = aInvertMask ? EDrawModeAND : EDrawModeOR; + TPoint srcePoint(aSourceRect.iTl); + TInt destY = aDest.iY; + + TLineScanningPosition lineScanPos(aSourceBase); + + const TBool useScanLinePtr = (!aShadowMode) && (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++,ditherOrigin.iY++) + { + scanLineBuffer = GetScanLineOffsetPtr(aSourceBitmap, slptr, width, srcePoint, aSourceBase, lineScanPos, offset); + drawDevice->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 + { + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,drawMode); + scanLineBuffer = (TUint32*)((TUint8*)scanLineBuffer + stride); + destY++,srcePoint.iY++,ditherOrigin.iY++; + } + while ((srcePoint.iY < aSourceRect.iBr.iY) && (scanLineBuffer < lastScanLine)); + } + } + } + else + { + const TInt scanLineBytes = drawDevice->ScanLineBytes(); + TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); + TPtr8 scanLineDes((TUint8*)scanLineBuffer,scanLineBytes,scanLineBytes); + for (; srcePoint.iY < aSourceRect.iBr.iY; destY++,srcePoint.iY++,ditherOrigin.iY++) + { + aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width, + ETrue,ditherOrigin,dispMode,aSourceBase,lineScanPos); + + if (aShadowMode) + { + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + drawDevice->ShadowBuffer(width,scanLineBuffer); + drawDevice->SetShadowMode(CFbsDrawDevice::ENoShadow); + } + + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,drawMode); + } + } + } + else + { + if (iDevice->iBitBltMaskedBuffer) + { + if (iBrushStyle == ESolidBrush) + DoBitBltMaskedNonFlickerSolid(aDest,aSourceBitmap,aSourceBase,aSourceRect, + aMaskBitmap,aMaskBase,aInvertMask,aDitherOrigin, + aShadowMode); + else if (iBrushStyle == EPatternedBrush) + DoBitBltMaskedNonFlickerPatterned(aDest,aSourceBitmap,aSourceBase,aSourceRect, + aMaskBitmap,aMaskBase,aInvertMask, + aDitherOrigin,aShadowMode); + else + DoBitBltMaskedNonFlicker(aDest,aSourceBitmap,aSourceBase,aSourceRect, + aMaskBitmap,aMaskBase,aInvertMask,aDitherOrigin, + aShadowMode); + } + else + DoBitBltMaskedFlicker(aDest,aSourceBitmap,aSourceBase,aSourceRect,aMaskBitmap, + aMaskBase,aInvertMask,aDitherOrigin,aShadowMode); + } + } + +void CFbsBitGc::DoBitBltMaskedFlicker(const TPoint& aDest, + CBitwiseBitmap* aSourceBitmap, + TUint32* aSourceBase, + const TRect& aSourceRect, + CBitwiseBitmap* aMaskBitmap, + TUint32* aMaskBase, + TBool aInvertMask, + const TPoint& aDitherOrigin, + TInt aShadowMode) + { + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; + + 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) + return; // Out of memory so do not draw anything + lineScanPosMask.iScanLineBuffer = hBuf; + } + + TAny* interface=NULL; + if ( (srcFormat == EColor16MU || srcFormat == EColor64K ) && + maskFormat == EGray2 && + !aShadowMode && + aSourceBitmap->SizeInPixels().iWidth <= aMaskBitmap->SizeInPixels().iWidth && + aSourceBitmap->SizeInPixels().iHeight <= aMaskBitmap->SizeInPixels().iHeight && + drawDevice->GetInterface(KFastBlitInterfaceID, interface) == KErrNone ) + { + // Parameters allow optimised code path + TInt length = width; + TUint32* srcPtr=NULL; + TUint32* maskPtr=NULL; + MFastBlit* fastBlit = reinterpret_cast(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; + } + + TPoint ditherOrigin(aDitherOrigin + aDest); + const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice); + const TDrawMode drawMode = aInvertMask ? EDrawModeAND : EDrawModeANDNOT; + + TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); + const TInt scanLineBytes = drawDevice->ScanLineBytes(); + TPtr8 scanLineDes((TUint8*)scanLineBuffer,scanLineBytes,scanLineBytes); + + TLineScanningPosition lineScanPos2(aSourceBase); + + //scanline modifications required if using shadows, different modes, bits per pixel less than 8 + if ((!aShadowMode) && (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 != 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++,ditherOrigin.iY++) + { + scanLineBuffer = GetScanLineOffsetPtr(aSourceBitmap, slptr, width, srcePoint, aSourceBase, lineScanPos, offset); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,EDrawModeXOR); + scanLineBufferMask = GetScanLineOffsetPtr(aMaskBitmap, slptr, width, srcePoint, aMaskBase, lineScanPosMask, offset); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferMask,drawMode); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,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 + { + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,EDrawModeXOR); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferMask,drawMode); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,EDrawModeXOR); + destY++,srcePoint.iY++,ditherOrigin.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++,ditherOrigin.iY++) + { + scanLineBufferPtr = GetScanLineOffsetPtr(aSourceBitmap, slptr, width, srcePoint, aSourceBase, lineScanPos, offset); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferPtr,EDrawModeXOR); + aMaskBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse,ditherOrigin,dispMode, aMaskBase, lineScanPosMask); + ::TileScanLine(scanLineDes, width, srcePoint, aMaskBitmap, lineScanPosMask, aMaskBase, dispMode); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,drawMode); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferPtr,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 + { + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferPtr,EDrawModeXOR); + aMaskBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse,ditherOrigin,dispMode,aMaskBase, lineScanPosMask); + ::TileScanLine(scanLineDes, width, srcePoint, aMaskBitmap, lineScanPosMask, aMaskBase, dispMode); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,drawMode); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBufferPtr,EDrawModeXOR); + destY++,srcePoint.iY++,ditherOrigin.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++,ditherOrigin.iY++) + { + aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width,ETrue,ditherOrigin, + dispMode,aSourceBase,lineScanPos); + + if (aShadowMode) + { + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + drawDevice->ShadowBuffer(width,scanLineBuffer); + drawDevice->SetShadowMode(CFbsDrawDevice::ENoShadow); + } + + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,EDrawModeXOR); + + aMaskBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse,ditherOrigin,dispMode, + aMaskBase, lineScanPosMask); + ::TileScanLine(scanLineDes, width, srcePoint, aMaskBitmap, lineScanPosMask, + aMaskBase, dispMode); + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,drawMode); + + aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width,ETrue,ditherOrigin,dispMode, + aSourceBase,lineScanPos2); + + if(aShadowMode) + { + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + drawDevice->ShadowBuffer(width,scanLineBuffer); + drawDevice->SetShadowMode(CFbsDrawDevice::ENoShadow); + } + + drawDevice->WriteLine(aDest.iX,destY,width,scanLineBuffer,EDrawModeXOR); + } + } + } + +void CFbsBitGc::DoBitBltMaskedNonFlicker(const TPoint& aDest, + CBitwiseBitmap* aSourceBitmap, + TUint32* aSourceBase, + const TRect& aSourceRect, + CBitwiseBitmap* aMaskBitmap, + TUint32* aMaskBase, + TBool aInvertMask, + const TPoint& aDitherOrigin, + TInt aShadowMode) + { + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; + + 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) + return; // Out of memory so do not draw anything + lineScanPosMask.iScanLineBuffer = hBuf; + } + + TAny* interface=NULL; + if ( (srcFormat == EColor16MU || srcFormat == EColor64K ) && + maskFormat == EGray2 && + !aShadowMode && + aSourceBitmap->SizeInPixels().iWidth <= aMaskBitmap->SizeInPixels().iWidth && + aSourceBitmap->SizeInPixels().iHeight <= aMaskBitmap->SizeInPixels().iHeight && + drawDevice->GetInterface(KFastBlitInterfaceID, interface) == KErrNone ) + { + // Parameters allow optimised code path + TInt length = width; + TUint32* srcPtr=NULL; + TUint32* maskPtr=NULL; + MFastBlit* fastBlit = reinterpret_cast(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; + } + + TPoint ditherOrigin(aDitherOrigin + aDest); + + TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); + const TInt scanLineBytes = drawDevice->ScanLineBytes(); + TPtr8 scanLineDes((TUint8*)scanLineBuffer,scanLineBytes,scanLineBytes); + + TUint32* bitBltBuffer = (TUint32*)iDevice->iBitBltMaskedBuffer; + const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice); + const TInt bufferBytes = CFbsBitmap::ScanLineLength(width, dispMode); + TUint32* scanLineCopy = (TUint32*) new TUint8[bufferBytes]; + + TLineScanningPosition lineScanPos2(aSourceBase); + for (; srcePoint.iY < aSourceRect.iBr.iY; destY++,srcePoint.iY++,ditherOrigin.iY++) + { + drawDevice->ReadLine(aDest.iX,destY,width,bitBltBuffer,dispMode); + aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width,ETrue,ditherOrigin,dispMode, + aSourceBase,lineScanPos); + + if (scanLineCopy) + { + Mem::Copy(scanLineCopy,scanLineBuffer,bufferBytes); + } + + if (aShadowMode) + { + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + drawDevice->ShadowBuffer(width,scanLineBuffer); + drawDevice->SetShadowMode(CFbsDrawDevice::ENoShadow); + } + + XorBuffers(bitBltBuffer,scanLineBuffer,bufferBytes); + + aMaskBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse,ditherOrigin,dispMode, + aMaskBase,lineScanPosMask); + ::TileScanLine(scanLineDes, width, srcePoint, aMaskBitmap, lineScanPosMask, + aMaskBase, dispMode); + + if (!aInvertMask) + InvertBuffer(scanLineBuffer,bufferBytes); + AndBuffers(bitBltBuffer,scanLineBuffer,bufferBytes); + + // Slow call when memory low? + TUint32* scanLine; + if (!scanLineCopy) + { + aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width,ETrue,ditherOrigin, + dispMode,aSourceBase,lineScanPos2); + scanLine = scanLineBuffer; + } + else + scanLine = scanLineCopy; + + if(aShadowMode) + { + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + drawDevice->ShadowBuffer(width,scanLine); + drawDevice->SetShadowMode(CFbsDrawDevice::ENoShadow); + } + + XorBuffers(bitBltBuffer,scanLine,bufferBytes); + + drawDevice->WriteLine(aDest.iX,destY,width,bitBltBuffer,iDrawMode); + } + if (scanLineCopy) + { + delete[] scanLineCopy; + } + } + +void CFbsBitGc::DoBitBltMaskedNonFlickerSolid(const TPoint& aDest, + CBitwiseBitmap* aSourceBitmap, + TUint32* aSourceBase, + const TRect& aSourceRect, + CBitwiseBitmap* aMaskBitmap, + TUint32* aMaskBase, + TBool aInvertMask, + const TPoint& aDitherOrigin, + TInt aShadowMode) + { + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; + const TInt width = aSourceRect.Width(); + TPoint ditherOrigin(aDitherOrigin + aDest); + const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice); + TInt destY = aDest.iY; + TPoint srcePoint(aSourceRect.iTl); + + TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); + const TInt scanLineBytes = drawDevice->ScanLineBytes(); + TPtr8 scanLineDes((TUint8*)scanLineBuffer,scanLineBytes,scanLineBytes); + + TUint32* bitBltBuffer = (TUint32*)iDevice->iBitBltMaskedBuffer; + TUint32* backgroundBuffer = (TUint32*)(iDevice->iBitBltMaskedBuffer + scanLineBytes); + const TInt bufferBytes = CFbsBitmap::ScanLineLength(width, dispMode); + + drawDevice->WriteRgbMulti(aDest.iX,aDest.iY,width,1,iBrushColor,iDrawMode); + drawDevice->ReadLine(aDest.iX,destY,width,backgroundBuffer,dispMode); + + TLineScanningPosition lineScanPos(aSourceBase); + TLineScanningPosition lineScanPos2(aSourceBase); + TLineScanningPosition lineScanPosMask(aMaskBase); + + for (; srcePoint.iY < aSourceRect.iBr.iY; destY++,srcePoint.iY++,ditherOrigin.iY++) + { + Mem::Copy(bitBltBuffer,backgroundBuffer,bufferBytes); + + aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width,ETrue,ditherOrigin,dispMode, + aSourceBase,lineScanPos); + XorBuffers(bitBltBuffer,scanLineBuffer,bufferBytes); + + aMaskBitmap->GetScanLine(scanLineDes,srcePoint,width,EFalse,ditherOrigin,dispMode, + aMaskBase,lineScanPosMask); + ::TileScanLine(scanLineDes, width, srcePoint, aMaskBitmap, lineScanPosMask, + aMaskBase, dispMode); + + if (!aInvertMask) + InvertBuffer(scanLineBuffer,bufferBytes); + AndBuffers(bitBltBuffer,scanLineBuffer,bufferBytes); + aSourceBitmap->GetScanLine(scanLineDes,srcePoint,width,ETrue,ditherOrigin, + dispMode,aSourceBase,lineScanPos2); + + XorBuffers(bitBltBuffer,scanLineBuffer,bufferBytes); + + if(aShadowMode) + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + + drawDevice->WriteLine(aDest.iX,destY,width,bitBltBuffer,iDrawMode); + + if(aShadowMode) + drawDevice->SetShadowMode(CFbsDrawDevice::ENoShadow); + } + } + +void CFbsBitGc::DoBitBltMaskedNonFlickerPatterned(const TPoint& aDest, + CBitwiseBitmap* aSourceBitmap, + TUint32* aSourceBase, + const TRect& aSourceRect, + CBitwiseBitmap* aMaskBitmap, + TUint32* aMaskBase, + TBool aInvertMask, + const TPoint& aDitherOrigin, + TInt aShadowMode) + { + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; + const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice); + + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + + iBrushBitmap.BeginDataAccess(); + CBitwiseBitmap* brushBitmap = iBrushBitmap.Address(); + BG_ASSERT_ALWAYS(iBrushUsed, EBitgdiPanicInvalidBitmap); + BG_ASSERT_ALWAYS(brushBitmap != NULL, EBitgdiPanicInvalidBitmap); + + CFbsRasterizer* brushRasterizer = PrepareRasterizerForExtendedBitmap(iBrushBitmap); + TUint32* brushData = iBrushBitmap.DataAddress(); + TPoint brushSourcePoint(aDest - iBrushOrigin - iOrigin); + const TSize brushSize(iBrushBitmap.SizeInPixels()); + if (brushSourcePoint.iX < 0 || brushSourcePoint.iX >= brushSize.iWidth) + brushSourcePoint.iX %= brushSize.iWidth; + if (brushSourcePoint.iX < 0) + brushSourcePoint.iX += brushSize.iWidth; + + TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); + const TInt scanLineBytes = drawDevice->ScanLineBytes(); + TPtr8 scanLineDes((TUint8*)scanLineBuffer,scanLineBytes,scanLineBytes); + + TUint32* bitBltBuffer = (TUint32*)iDevice->iBitBltMaskedBuffer; + TPtr8 bitBltDes(iDevice->iBitBltMaskedBuffer, scanLineBytes, scanLineBytes); + + TInt widthRemaining = aSourceRect.Width(); + TPoint sourcePoint(aSourceRect.iTl); + TInt destX = aDest.iX; + + TInt width = Min(widthRemaining,brushSize.iWidth); + + if (brushSourcePoint.iX + widthRemaining > brushSize.iWidth) + width = brushSize.iWidth - brushSourcePoint.iX; + + while (widthRemaining > 0) + { + TInt destY = aDest.iY; + sourcePoint.iY = aSourceRect.iTl.iY; + brushSourcePoint.iY = aDest.iY - iBrushOrigin.iY - iOrigin.iY; + TPoint ditherOrigin(aDitherOrigin + TPoint(destX,aDest.iY)); + const TInt bufferBytes = CFbsBitmap::ScanLineLength(width, dispMode); + + TLineScanningPosition lineScanPosBrush(brushData); + TLineScanningPosition lineScanPosMask(aMaskBase); + TLineScanningPosition lineScanPosSrc(aSourceBase); + TLineScanningPosition lineScanPosSrc2(aSourceBase); + + for ( ;sourcePoint.iY < aSourceRect.iBr.iY; + destY++,sourcePoint.iY++,ditherOrigin.iY++,brushSourcePoint.iY++) + { + brushBitmap->GetScanLine(bitBltDes,brushSourcePoint,width,ETrue,ditherOrigin, + dispMode,brushData,lineScanPosBrush); + aSourceBitmap->GetScanLine(scanLineDes,sourcePoint,width,ETrue,ditherOrigin, + dispMode,aSourceBase,lineScanPosSrc); + XorBuffers(bitBltBuffer,scanLineBuffer,scanLineBytes); + + aMaskBitmap->GetScanLine(scanLineDes,sourcePoint,width,EFalse,ditherOrigin, + dispMode,aMaskBase,lineScanPosMask); + ::TileScanLine(scanLineDes, width, sourcePoint, aMaskBitmap, lineScanPosMask, + aMaskBase, dispMode); + + if (!aInvertMask) + InvertBuffer(scanLineBuffer,bufferBytes); + AndBuffers(bitBltBuffer,scanLineBuffer,bufferBytes); + + aSourceBitmap->GetScanLine(scanLineDes,sourcePoint,width,ETrue,ditherOrigin, + dispMode,aSourceBase,lineScanPosSrc2); + XorBuffers(bitBltBuffer,scanLineBuffer,bufferBytes); + + drawDevice->WriteLine(destX,destY,width,bitBltBuffer,iDrawMode); + } + + widthRemaining -= width; + sourcePoint.iX += width; + brushSourcePoint.iX += width; + destX += width; + + width = Min(widthRemaining,brushSize.iWidth); + } + if (brushRasterizer) + { + brushRasterizer->EndBitmap(iBrushBitmap.SerialNumber()); + } + iBrushBitmap.EndDataAccess(ETrue); + } + +void CFbsBitGc::DoBitBltAlpha(const TPoint& aDest,CBitwiseBitmap* aSourceBitmap, + TUint32* aSourceBase,const TRect& aSourceRect, + CBitwiseBitmap* aMaskBitmap,TUint32* aMaskBase, + const TPoint& aAlphaPoint,TInt aShadowMode, 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, + iDrawMode, aShadowMode)==KErrNone) + { + return; + } + } + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; + + 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); + + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + + const TSize sourceSize = aSourceBitmap->SizeInPixels(); + // Convert negative or large offsets into sensible positive ones. + TPoint alphaOffset(aAlphaPoint.iX % sourceSize.iWidth, aAlphaPoint.iY % sourceSize.iHeight); + if ( alphaOffset.iX < 0 ) + alphaOffset.iX += sourceSize.iWidth; + if ( alphaOffset.iY < 0 ) + alphaOffset.iY += sourceSize.iHeight; + + TInt srceY = aSourceRect.iTl.iY; + TInt destY = aDest.iY; + TInt alphaY = alphaOffset.iY; + + TLineScanningPosition lineScanPosSrc(aSourceBase); + TLineScanningPosition lineScanPosMask(aMaskBase); + + TDisplayMode sourceMode = aSourceBitmap->DisplayMode(); + + if (aMaskBitmap->IsCompressed()) + { + HBufC8* hBuf= CFbsBitmap::GetDecompressionBuffer(aMaskBitmap->DataStride()); + if (!hBuf) + { + return; // Out of memory so do not draw anything + } + 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 && + drawDevice->GetInterface(KFastBlitInterfaceID, interface) == KErrNone ) + { + TInt length = aSourceRect.Width(); + const TInt srceX = aSourceRect.iTl.iX; + const TInt alphaX = alphaOffset.iX; + const TInt destX = aDest.iX; + MFastBlit* fastBlit = reinterpret_cast(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 = ((!aShadowMode) && (EColor16MA == aSourceBitmap->DisplayMode())); + TUint32* slptr=NULL; + TUint offset = 0; + TDisplayMode srcMode = ERgb; + + while (srceY < aSourceRect.iBr.iY) + { + TInt srceX = aSourceRect.iTl.iX; + TInt destX = aDest.iX; + TInt alphaX = alphaOffset.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, + srcMode,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]; + } + drawDevice->WriteRgbAlphaLine(destX,destY,width,srceRgbBufferPtr,maskBuffer,iDrawMode); + + srceX += KScanLineLength; + destX += KScanLineLength; + alphaX += KScanLineLength; + } + + srceY++; + destY++; + alphaY++; + } + } + +/** +The method performs an alpha blending of the source data - aSrcBmp1 and aSrcBmp2, using +the data from aAlphaBmp as an alpha blending factor. +@internalComponent +@see CFbsBitGc::AlphaBlendBitmaps. +*/ +void CFbsBitGc::DoBitBltAlpha(const TPoint& aDestPt, + const CBitwiseBitmap* aSrcBmp1, + TUint32* aSrcBmpDataAddr1, + const CBitwiseBitmap* aSrcBmp2, + TUint32* aSrcBmpDataAddr2, + const CBitwiseBitmap* aAlphaBmp, + TUint32* aAlphaBmpDataAddr, + const TRect& aSrcRect1, + const TPoint& aSrcPt2, + const TPoint& aAlphaPt, + TInt aShadowMode) + { + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; +#ifdef _DEBUG + TRect deviceDestRect; + drawDevice->GetDrawRect(deviceDestRect); +#endif + //Check the destination point. + BG_ASSERT_DEBUG(aDestPt.iX >= deviceDestRect.iTl.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(aDestPt.iY >= deviceDestRect.iTl.iY, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG((aDestPt.iX + aSrcRect1.Width()) <= deviceDestRect.iBr.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG((aDestPt.iY + aSrcRect1.Height()) <= deviceDestRect.iBr.iY, EBitgdiPanicOutOfBounds); + + const TPoint KZeroPoint(0,0); + const TInt KScanLineLength = 256;//128 is not enough to fill buffer for 16MA and 16MU display modes + const TInt KRgbSize = 4; + + TUint8 srceRgbBuffer1[KScanLineLength * KRgbSize]; + TUint8 srceBuffer2[KScanLineLength * KRgbSize]; + TUint8 alphaBuffer[KScanLineLength]; + + TPtr8 srceRgbDes1(srceRgbBuffer1,KScanLineLength * KRgbSize,KScanLineLength * KRgbSize); + TPtr8 srceDes2(srceBuffer2,KScanLineLength * KRgbSize,KScanLineLength * KRgbSize); + TPtr8 alphaDes(alphaBuffer,KScanLineLength,KScanLineLength); + + const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice); + drawDevice->SetShadowMode(CFbsDrawDevice::TShadowMode(aShadowMode)); + + TInt srceY1 = aSrcRect1.iTl.iY; + TInt srceY2 = aSrcPt2.iY; + TInt alphaY = aAlphaPt.iY; + TInt destY = aDestPt.iY; + + TLineScanningPosition lineScanPosSrc1(aSrcBmpDataAddr1); + TLineScanningPosition lineScanPosSrc2(aSrcBmpDataAddr2); + TLineScanningPosition lineScanPosAlpha(aAlphaBmpDataAddr); + + while (srceY1 < aSrcRect1.iBr.iY) + { + TInt srceX1 = aSrcRect1.iTl.iX; + TInt srceX2 = aSrcPt2.iX; + TInt alphaX = aAlphaPt.iX; + TInt destX = aDestPt.iX; + + while (srceX1 < aSrcRect1.iBr.iX) + { + TPoint srcePoint1(srceX1,srceY1); + TPoint srcePoint2(srceX2,srceY2); + TPoint alphaPoint(alphaX,alphaY); + const TInt width = Min(KScanLineLength,aSrcRect1.iBr.iX - srceX1); + + aSrcBmp1->GetScanLine(srceRgbDes1,srcePoint1,width,EFalse,KZeroPoint,EColor16MU, + aSrcBmpDataAddr1,lineScanPosSrc1); + aSrcBmp2->GetScanLine(srceDes2,srcePoint2,width,EFalse,KZeroPoint,dispMode, + aSrcBmpDataAddr2,lineScanPosSrc2); + aAlphaBmp->GetScanLine(alphaDes,alphaPoint,width,EFalse,KZeroPoint,EGray256, + aAlphaBmpDataAddr,lineScanPosAlpha); + ::TileScanLine(alphaDes, width, alphaPoint, aAlphaBmp, lineScanPosAlpha, aAlphaBmpDataAddr, EGray256); + + drawDevice->WriteRgbAlphaLine(destX, + destY, + width, + srceRgbBuffer1, + srceBuffer2, + alphaBuffer, + iDrawMode); + + srceX1 += KScanLineLength; + srceX2 += KScanLineLength; + alphaX += KScanLineLength; + destX += KScanLineLength; + } + + srceY1++; + srceY2++; + alphaY++; + destY++; + } + } + +/** +The method performs an alpha blending of the source data - aSrcBmp1 and aSrcBmp2, using +the data from aAlphaBmp as an alpha blending factor. +The formula used for that, is: +(C1 * A + C2 * (255 - A)) / 255, where: +- C1 - a pixel from aSrcBmp1; +- C2 - a pixel from aSrcBmp2; +- A - a pixel from aAlphaBmp; +The content of source and alpha bitmap is preserved. +The calculated alpha blended pixels are written to the destination - the screen or a bitmap. +@publishedAll +@released +@param aDestPt Position in the target the result should be drawn to. +@param aSrcBmp1 A pointer to the source bitmap 1. +@param aSrcBmp2 A pointer to the source bitmap 2. +@param aAlphaBmp A pointer to the bitmap used as an alpha blending factor. +@param aSrcRect1 A part of bitmap 1 that should be used as a source for the alpha blending. +@param aSrcPt2 Position of the first pixel in bitmap 2 that should be used as a source + for the alpha blending. The size of the area is the same as the + bitmap 1 area - aSrcRect1 parameter. +@param aAlphaPt Position of the first pixel in the alpha bitmap that should be used as a source + for the alpha blending. The size of the area is the same as the + bitmap 1 area - aSrcRect1 parameter. +@pre !aSrcRect1.IsEmpty() +@pre aSrcBmp1 != NULL +@pre aSrcBmp1->Handle() != NULL +@pre aSrcBmp2 != NULL +@pre aSrcBmp2->Handle() != NULL +@pre aAlphaBmp != NULL +@pre aAlphaBmp->Handle() != NULL +@pre aAlphaBmp->DisplayMode() <= EGray256 +@return KErrNone If the call is successful, KErrArgument otherwise. +*/ +EXPORT_C TInt CFbsBitGc::AlphaBlendBitmaps(const TPoint& aDestPt, + const CFbsBitmap* aSrcBmp1, + const CFbsBitmap* aSrcBmp2, + const TRect& aSrcRect1, + const TPoint& aSrcPt2, + const CFbsBitmap* aAlphaBmp, + const TPoint& aAlphaPt) + { + //Check the bitmap pointers and handles. Check the CFbsDevice instance - + //it shouldn't be NULL - that means - CFbsBitGc instance (this pointer) + //should be created either using CFbsDevice::CreateContext() or CFbsBitGc::Activate() - + //before the method was called. + if(!aSrcBmp1 || !aSrcBmp1->Handle() || !aSrcBmp2 || !aSrcBmp2->Handle() || + !aAlphaBmp || !aAlphaBmp->Handle() || CheckDevice(aSrcRect1)) + { + return KErrArgument; + } + + aSrcBmp1->BeginDataAccess(); + aSrcBmp2->BeginDataAccess(); + aAlphaBmp->BeginDataAccess(); + + //Check display mode of the alpha bitmap. Bitmaps which display mode is greater than + //EGray256 can't be used as alpha bitmaps. + if(aAlphaBmp->DisplayMode() > EGray256) + { + aSrcBmp1->EndDataAccess(ETrue); + aSrcBmp2->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + return KErrArgument; + } + //Check source rect 1. Bitmap 1 must contain the whole source rect 1. + TRect srcRect1(aSrcRect1); + TRect area1(aSrcBmp1->SizeInPixels()); + srcRect1.Intersection(area1); + if(srcRect1 != aSrcRect1) + { + aSrcBmp1->EndDataAccess(ETrue); + aSrcBmp2->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + return KErrArgument; + } + //Create and check source rect 2. Bitmap 2 must contain the whole source rect 2. + TRect srcRect2(TSize(aSrcRect1.Width(), aSrcRect1.Height())); + srcRect2.Move(aSrcPt2); + TRect srcRect2t(srcRect2); + TRect area2(aSrcBmp2->SizeInPixels()); + srcRect2.Intersection(area2); + if(srcRect2 != srcRect2t) + { + aSrcBmp1->EndDataAccess(ETrue); + aSrcBmp2->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + return KErrArgument; + } + //Calculate the destination rect + TPoint destPt(aDestPt + iOrigin); + TRect destRect(destPt, srcRect1.Size()); + TPoint offset(srcRect1.iTl - destPt); + TPoint offset2(srcRect2.iTl - destPt); + TRect clippedDestRect(destRect); + AddRect(clippedDestRect); + if(UserClipRect(clippedDestRect)) + { + aSrcBmp1->EndDataAccess(ETrue); + aSrcBmp2->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + return KErrArgument; + } + //Save current shadow mode + TInt8 shadowMode = iShadowMode; + iShadowMode = CFbsDrawDevice::ENoShadow; + //Setup the device and prevent the bitmaps from being cleaned away by client code. + //Drawing begins. + SetupDevice(); + iDevice->DrawingBegin(); + CBitwiseBitmap* srcBmp1 = ((CFbsBitGcBitmap*)aSrcBmp1)->Address(); + CBitwiseBitmap* srcBmp2 = ((CFbsBitGcBitmap*)aSrcBmp2)->Address(); + CBitwiseBitmap* alphaBmp = ((CFbsBitGcBitmap*)aAlphaBmp)->Address(); + BG_ASSERT_DEBUG(srcBmp1, EBitgdiPanicInvalidBitmap); + BG_ASSERT_DEBUG(srcBmp2, EBitgdiPanicInvalidBitmap); + BG_ASSERT_DEBUG(alphaBmp, EBitgdiPanicInvalidBitmap); + + TUint32* srcDataAddr1 = aSrcBmp1->DataAddress(); + TUint32* srcDataAddr2 = aSrcBmp2->DataAddress(); + TUint32* alphaDataAddr = aAlphaBmp->DataAddress(); + + CFbsRasterizer* rasterizer1 = PrepareRasterizerForExtendedBitmap(*aSrcBmp1, clippedDestRect, offset); + CFbsRasterizer* rasterizer2 = PrepareRasterizerForExtendedBitmap(*aSrcBmp2, clippedDestRect, offset2); + CFbsRasterizer* alphaRasterizer; + if (aAlphaPt.iX >= 0 && aAlphaPt.iY >= 0 + && aAlphaPt.iX + aSrcRect1.Width() <= aAlphaBmp->SizeInPixels().iWidth + && aAlphaPt.iY + aSrcRect1.Height() <= aAlphaBmp->SizeInPixels().iHeight) + { + // Alpha blending bitmap is not tiled. Pass same region of interest as source bitmaps to rasterizer. + alphaRasterizer = PrepareRasterizerForExtendedBitmap(*aAlphaBmp, clippedDestRect, aAlphaPt - destPt); + } + else + { + // Alpha blending bitmap is tiled. Do not pass any region of interest to rasterizer. + alphaRasterizer = PrepareRasterizerForExtendedBitmap(*aAlphaBmp); + } + + //For each region - find the clipping rect and draw + TInt limit = iDefaultRegionPtr->Count(); + CGraphicsAccelerator* ga = GraphicsAccelerator(); + // Code for Graphics Accelerated Drawing + if(ga && (shadowMode == CFbsDrawDevice::ENoShadow)) + { + TInt gaOperationResult = KErrUnknown; + TAcceleratedBitmapSpec srcBmp1Spec(const_cast(aSrcBmp1)); + TAcceleratedBitmapSpec srcBmp2Spec(const_cast(aSrcBmp2)); + TAcceleratedBitmapSpec alphaBmpSpec(const_cast(aAlphaBmp)); + iDevice->DrawingEnd(); + + for(TInt count=0;count= 0, EBitgdiPanicNegativeShift); + BG_ASSERT_DEBUG(shift.iY >= 0, EBitgdiPanicNegativeShift); + + gaOperationResult = ga->Operation(TGopAlphaBlendTwoBitmaps(iClipRect.iTl,srcBmp1Spec,srcBmp2Spec,clippedSrcRect,aSrcPt2 + shift,alphaBmpSpec,aAlphaPt + shift)); + if(gaOperationResult != KErrNone) + break; + iDevice->iDrawDevice->UpdateRegion(iClipRect); + } + if(gaOperationResult == KErrNone) + goto finish; + iDevice->DrawingBegin(); + } + + // Code for non- Graphics Accelerated Drawing + for(TInt count=0;count= 0, EBitgdiPanicNegativeShift); + BG_ASSERT_DEBUG(shift.iY >= 0, EBitgdiPanicNegativeShift); + + TDrawMode drawMode = iDrawMode; + iDrawMode = EDrawModeWriteAlpha; // this is the only mode currently supported + DoBitBltAlpha(iClipRect.iTl, + srcBmp1, + srcDataAddr1, + srcBmp2, + srcDataAddr2, + alphaBmp, + alphaDataAddr, + clippedSrcRect, + aSrcPt2 + shift, + aAlphaPt + shift, + shadowMode); + iDrawMode = drawMode; // restore the previous draw mode + + iDevice->iDrawDevice->UpdateRegion(iClipRect); + } + + //Drawig ends. Restore the previous shadow mode + iDevice->DrawingEnd(); +finish: + if (rasterizer1) + { + rasterizer1->EndBitmap(aSrcBmp1->SerialNumber()); + } + if (rasterizer2) + { + rasterizer2->EndBitmap(aSrcBmp2->SerialNumber()); + } + if (alphaRasterizer) + { + alphaRasterizer->EndBitmap(aAlphaBmp->SerialNumber()); + } + aSrcBmp1->EndDataAccess(ETrue); + aSrcBmp2->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + iShadowMode = shadowMode; + + return KErrNone; + } + +/** +The method performs an alpha blending of the source data - aSrcBmp - with the existing image, using +the data from aAlphaBmp as an alpha blending factor. +The formula used for that, is: +(C * A + D * (255 - A)) / 255, where: +- C - a pixel from aSrcBmp; +- D - a pixel from the destination; +- A - a pixel from aAlphaBmp; +The content of source and alpha bitmap is preserved. +The calculated alpha blended pixels are written to the destination - the screen or a bitmap. +@publishedAll +@released +@param aDestPt Position in the target the result should be drawn to. +@param aSrcBmp A pointer to the source bitmap. +@param aAlphaBmp A pointer to the bitmap used as an alpha blending factor. +@param aSrcRect A part of aSrcBmp that should be used as a source for the alpha blending. + DISCLAIMER: if aSrcRect is bigger (width and/or height) the behaviour is undefined +@param aAlphaPt Position of the first pixel in the alpha bitmap that should be used as a source + for the alpha blending. The size of the area is + the same as the aSrcRect parameter (read DISCLAIMER above). +@pre !aSrcRect.IsEmpty() +@pre aSrcBmp != NULL +@pre aSrcBmp->Handle() != NULL +@pre aAlphaBmp != NULL +@pre aAlphaBmp->Handle() != NULL +@pre aAlphaBmp->DisplayMode() <= EGray256 +@return KErrNone If the call is successfull, KErrArgument otherwise. +*/ +EXPORT_C TInt CFbsBitGc::AlphaBlendBitmaps(const TPoint& aDestPt, + const CFbsBitmap* aSrcBmp, + const TRect& aSrcRect, + const CFbsBitmap* aAlphaBmp, + const TPoint& aAlphaPt) + { + //Check the bitmap pointers and handles. Check the CFbsDevice instance - + //it shouldn't be NULL - that means - CFbsBitGc instance (this pointer) + //should be created either using CFbsDevice::CreateContext() or CFbsBitGc::Activate() - + //before the method was called. + if(!aSrcBmp || !aSrcBmp->Handle() || + !aAlphaBmp || !aAlphaBmp->Handle() || CheckDevice(aSrcRect)) + { + return KErrArgument; + } + + aSrcBmp->BeginDataAccess(); + aAlphaBmp->BeginDataAccess(); + + //Check display mode of the alpha bitmap. Bitmaps which display mode is greater than + //EGray256 can't be used as alpha bitmaps. + if(aAlphaBmp->DisplayMode() > EGray256) + { + aSrcBmp->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + return KErrArgument; + } + //Taking the actual part of the source rect contained in the Bitmap. + TRect srcRect(aSrcRect); + TRect area(aSrcBmp->SizeInPixels()); + if(!srcRect.Intersects(area)) + { + aSrcBmp->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + return KErrArgument; + } + srcRect.Intersection(area); + //Calculate the destination rect + TPoint destPt(aDestPt + iOrigin); + TRect destRect(destPt, srcRect.Size()); + TPoint offset(srcRect.iTl - destPt); + TRect clippedDestRect(destRect); + AddRect(clippedDestRect); + if(UserClipRect(clippedDestRect)) + { + aSrcBmp->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + return KErrArgument; + } + //Save current shadow mode + TInt8 shadowMode = iShadowMode; + iShadowMode = CFbsDrawDevice::ENoShadow; + //Setup the device and prevent the bitmaps from being cleaned away by client code. + //Drawing begins. + SetupDevice(); + iDevice->DrawingBegin(); + + CBitwiseBitmap* srcBmp = ((CFbsBitGcBitmap*)aSrcBmp)->Address(); + CBitwiseBitmap* alphaBmp = ((CFbsBitGcBitmap*)aAlphaBmp)->Address(); + BG_ASSERT_DEBUG(srcBmp, EBitgdiPanicInvalidBitmap); + BG_ASSERT_DEBUG(alphaBmp, EBitgdiPanicInvalidBitmap); + TUint32* srcDataAddr = aSrcBmp->DataAddress(); + TUint32* alphaDataAddr = aAlphaBmp->DataAddress(); + + CFbsRasterizer* rasterizer = PrepareRasterizerForExtendedBitmap(*aSrcBmp, clippedDestRect, offset); + CFbsRasterizer* alphaRasterizer; + if (aAlphaPt.iX >= 0 && aAlphaPt.iY >= 0 + && aAlphaPt.iX + srcRect.Width() <= aAlphaBmp->SizeInPixels().iWidth + && aAlphaPt.iY + srcRect.Height() <= aAlphaBmp->SizeInPixels().iHeight) + { + // Alpha blending bitmap is not tiled. Pass same region of interest as source bitmap to rasterizer. + alphaRasterizer = PrepareRasterizerForExtendedBitmap(*aAlphaBmp, clippedDestRect, aAlphaPt - destPt); + } + else + { + // Alpha blending bitmap is tiled. Do not pass any region of interest to rasterizer. + alphaRasterizer = PrepareRasterizerForExtendedBitmap(*aAlphaBmp); + } + + //For each region - find the clipping rect and draw + TInt limit = iDefaultRegionPtr->Count(); + CGraphicsAccelerator* ga = GraphicsAccelerator(); + // Code for Graphics Accelerated Drawing + if(ga && (shadowMode == CFbsDrawDevice::ENoShadow)) + { + TInt gaOperationResult = KErrUnknown; + TAcceleratedBitmapSpec srcBmpSpec(const_cast(aSrcBmp)); + TAcceleratedBitmapSpec alphaBmpSpec(const_cast(aAlphaBmp)); + iDevice->DrawingEnd(); + + for(TInt count=0;count= 0, EBitgdiPanicNegativeShift); + BG_ASSERT_DEBUG(shift.iY >= 0, EBitgdiPanicNegativeShift); + + gaOperationResult = ga->Operation(TGopAlphaBlendOneBitmap(iClipRect.iTl,srcBmpSpec,clippedSrcRect,alphaBmpSpec,aAlphaPt + shift)); + if(gaOperationResult != KErrNone) + break; + iDevice->iDrawDevice->UpdateRegion(iClipRect); + } + if(gaOperationResult == KErrNone) + goto finish; + iDevice->DrawingBegin(); + } + + // Code for non- Graphics Accelerated Drawing + for(TInt count=0;count= 0, EBitgdiPanicNegativeShift); + BG_ASSERT_DEBUG(shift.iY >= 0, EBitgdiPanicNegativeShift); + DoBitBltAlpha(iClipRect.iTl, + srcBmp, + srcDataAddr, + clippedSrcRect, + alphaBmp, + alphaDataAddr, + aAlphaPt + shift, + shadowMode, + EFalse); + iDevice->iDrawDevice->UpdateRegion(iClipRect); + } + + // Drawing ends. Restore the previous shadow mode. + iDevice->DrawingEnd(); +finish: + if (rasterizer) + { + rasterizer->EndBitmap(aSrcBmp->SerialNumber()); + } + if (alphaRasterizer) + { + alphaRasterizer->EndBitmap(aAlphaBmp->SerialNumber()); + } + aSrcBmp->EndDataAccess(ETrue); + aAlphaBmp->EndDataAccess(ETrue); + iShadowMode = shadowMode; + + return KErrNone; + } + +GLDEF_C void XorBuffers(TUint32* aDestBuffer,const TUint32* aSrceBuffer,TInt aNumBytes) + { + // Round up to nearest word boundary + const TUint32* const destBufferLimit = aDestBuffer + ((aNumBytes + sizeof(TUint32) - 1) / sizeof(TUint32)); + + while (aDestBuffer < destBufferLimit) + *aDestBuffer++ ^= *aSrceBuffer++; + } + +GLDEF_C void AndBuffers(TUint32* aDestBuffer,const TUint32* aSrceBuffer,TInt aNumBytes) + { + // Round up to nearest word boundary + const TUint32* const destBufferLimit = aDestBuffer + ((aNumBytes + sizeof(TUint32) - 1) / sizeof(TUint32)); + + while (aDestBuffer < destBufferLimit) + *aDestBuffer++ &= *aSrceBuffer++; + } + +GLDEF_C void InvertBuffer(TUint32* aDestBuffer,TInt aNumBytes) + { + // Round up to nearest word boundary + const TUint32* const destBufferLimit = aDestBuffer + ((aNumBytes + sizeof(TUint32) - 1) / sizeof(TUint32)); + + while (aDestBuffer < destBufferLimit) + { + *aDestBuffer = *aDestBuffer ^ KMaxTUint32; + ++aDestBuffer; + } + } + +GLDEF_C void InvertBuffer(TUint8* aDestBuffer,TInt aNumBytes) + { + const TUint8* const destBufferLimit = aDestBuffer + aNumBytes; + + while (aDestBuffer < destBufferLimit) + { + *aDestBuffer = static_cast(*aDestBuffer ^ KMaxTUint8); + ++aDestBuffer; + } + } + +/** +The method tiles the scan line if its length in pixels is less than +aLengthInPixels argument. +@internalComponent +@param aScanLine A pointer to the scan line buffer. +@param aLengthInPixels The scan line buffer should have that count of pixels after the method call. +@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 optimizations. 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. +*/ +LOCAL_C void TileScanLine(TPtr8& aScanLine, + TInt aLengthInPixels, + const TPoint& aSrcPt, + const CBitwiseBitmap* aMaskBitmap, + TLineScanningPosition& aScanLinePos, + TUint32* aMaskBase, + TDisplayMode aDisplayMode + ) + { + TInt lengthInBytes = CFbsBitmap::ScanLineLength(aLengthInPixels, aDisplayMode); + BG_ASSERT_DEBUG(lengthInBytes <= aScanLine.MaxLength(), EBitgdiPanicInvalidArg); + 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 (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 (src) + scanLineLength; + for(;repeatCnt>0;dest+=scanLineLength,repeatCnt--) + { + Mem::Copy(dest, src, scanLineLength); + } + if(bytesLeft) + { + Mem::Copy(dest, src, bytesLeft); + } + aScanLine.SetLength(lengthInBytes); + } + +/** +The method draws a masked rectangular section of the source +bitmap and does a compress/stretch to fit a given destination +rectangle. +@internalComponent +*/ +void CFbsBitGc::DoDrawBitmapMasked(const TRect& aDestRect, + CBitwiseBitmap* aSourceBitmap, + TUint32* aSourceBase, + const TRect& aSourceRect, + CBitwiseBitmap* aMaskBitmap, + TUint32* aMaskBase, + TBool aInvertMask, const TPoint& aDitherOrigin) + { + CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; +#ifdef _DEBUG + TRect deviceDestRect; + drawDevice->GetDrawRect(deviceDestRect); + BG_ASSERT_DEBUG(iClipRect.iTl.iX >= deviceDestRect.iTl.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(iClipRect.iTl.iY >= deviceDestRect.iTl.iY, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(iClipRect.iBr.iX <= deviceDestRect.iBr.iX, EBitgdiPanicOutOfBounds); + BG_ASSERT_DEBUG(iClipRect.iBr.iY <= deviceDestRect.iBr.iY, EBitgdiPanicOutOfBounds); +#endif + + // The clipped version of the destination rectangle + TRect clippedDestRect(aDestRect); + clippedDestRect.Intersection(iClipRect); + + // 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, + aDitherOrigin, + CFbsDrawDevice::ENoShadow); + } + return; + } + MFastBlend* fastBlend=NULL; + if (FastBlendInterface(aSourceBitmap,aMaskBitmap,fastBlend)==KErrNone) + { + if (fastBlend->FastBlendBitmapMaskedScaled(iClipRect, aDestRect, aSourceRect, aSourceBase, aSourceBitmap->DataStride(), + aSourceBitmap->DisplayMode(),aSourceBitmap->SizeInPixels(), + aMaskBase, aMaskBitmap->DataStride(), aMaskBitmap->DisplayMode(), aMaskBitmap->SizeInPixels(), aInvertMask, + iDrawMode, iShadowMode)==KErrNone) + { + return; + } + } + + TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); + const TInt scanLineBytes = drawDevice->ScanLineBytes(); + TPtr8 scanLineDes(REINTERPRET_CAST(TUint8*,scanLineBuffer),scanLineBytes,scanLineBytes); + + // This constant is associated to the value used in TestGdi::DoDrawBitmapMaskedL, case #24. + // If this value is changed, then that one must be updated as well otherwise the test will no longer be valid. + 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); + TDrawMode drawMode = aInvertMask ? EDrawModeAND : 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 ? EDrawModeAND : 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); + + TPoint ditherOrigin(aDitherOrigin + clippedDestRect.iTl); + 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; + } + } + + 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,ditherOrigin,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(maskScanLinePtr32); + + // Outer loop over all KScanLineLengths + FOREVER + { + aSourceBitmap->StretchScanLine(sourceDes,startPt,clipIncStrch,clipWidthPart,destWidth, + aSourceRect.iTl.iX,srceWidth,ditherOrigin,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,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,ditherOrigin,dispMode,aSourceBase,lineScanPos2); + drawDevice->WriteLine(clippedDestRect.iTl.iX,yCoord.iY,clipWidth,scanLineBuffer,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,ditherOrigin,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,ditherOrigin,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,EDrawModeXOR); + } + yLine.NextStep(yCoord); + ditherOrigin.iY++; + } + } + +EXPORT_C TInt CFbsBitGc::AlphaBlendBitmaps(const TPoint& aDestPt, + const CWsBitmap* aSrcBmp, + const TRect& aSrcRect, + const CWsBitmap* aAlphaBmp, + const TPoint& aAlphaPt) + { + return AlphaBlendBitmaps(aDestPt, REINTERPRET_CAST(const CFbsBitmap*, aSrcBmp), aSrcRect, REINTERPRET_CAST(const CFbsBitmap*, aAlphaBmp), aAlphaPt); + } + +TInt CFbsBitGc::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=iDevice->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 CFbsBitGc::ScanLineBufferDisplayMode(CFbsDrawDevice* aDrawDevice) + { + return iDrawMode == EDrawModeWriteAlpha ? aDrawDevice->DisplayMode() : aDrawDevice->ScanLineDisplayMode(); + } + +/** Prepares the rasterizer to retrieve scan lines from a bitmap if it is an +extended bitmap. No region of interest is passed to the rasterizer. +This function calls CFbsRasterizer::BeginBitmap() with the appropriate +parameters. When finished retrieving scan lines from the extended bitmap, +CFbsRasterizer::EndBitmap() must be called. +@param aBitmap The bitmap to retrieve scan lines from. +@return A pointer to the rasterizer owned by this thread's FBServ session. +@return NULL if the rasterizer is not present or aBitmap is not an extended bitmap. +@see CFbsRasterizer +@internalComponent +*/ +CFbsRasterizer* CFbsBitGc::PrepareRasterizerForExtendedBitmap(const CFbsBitmap& aBitmap) + { + CFbsRasterizer* rasterizer = NULL; + CFbsRasterizer::TBitmapDesc desc; + desc.iDataType = aBitmap.ExtendedBitmapType(); + if (desc.iDataType != KNullUid) + { + rasterizer = CFbsBitmap::Rasterizer(); + if (rasterizer) + { + desc.iSizeInPixels = aBitmap.SizeInPixels(); + desc.iDispMode = aBitmap.DisplayMode(); + desc.iData = aBitmap.DataAddress(); + desc.iDataSize = aBitmap.DataSize(); + rasterizer->BeginBitmap(aBitmap.SerialNumber(), desc, NULL); + } + } + return rasterizer; + } + +/** Prepares the rasterizer to retrieve scan lines from a bitmap if it is an +extended bitmap. The region of interest passed to the rasterizer is the +intersection of the clipping region and the specified rectangle. +This function calls CFbsRasterizer::BeginBitmap() with the appropriate +parameters. When finished retrieving scan lines from the extended bitmap, +CFbsRasterizer::EndBitmap() must be called. +@param aBitmap The bitmap to retrieve scan lines from. +@param aDestRect A rectangle in coordinates relative to the graphics context that + bounds the area that aBitmap is to be blitted onto. +@param aOffset An offset that converts aDestRect into coordinates relative to + the source bitmap. +@return A pointer to the rasterizer owned by this thread's FBServ session. +@return NULL if the rasterizer is not present or aBitmap is not an extended bitmap. +@see CFbsRasterizer +@internalComponent +*/ +CFbsRasterizer* CFbsBitGc::PrepareRasterizerForExtendedBitmap(const CFbsBitmap& aBitmap, const TRect& aDestRect, const TPoint& aOffset) + { + CFbsRasterizer* rasterizer = NULL; + CFbsRasterizer::TBitmapDesc desc; + desc.iDataType = aBitmap.ExtendedBitmapType(); + if (desc.iDataType != KNullUid) + { + rasterizer = CFbsBitmap::Rasterizer(); + if (rasterizer) + { + desc.iSizeInPixels = aBitmap.SizeInPixels(); + desc.iDispMode = aBitmap.DisplayMode(); + desc.iData = aBitmap.DataAddress(); + desc.iDataSize = aBitmap.DataSize(); + RRegion rgn; + rgn.Copy(*iDefaultRegionPtr); + rgn.ClipRect(aDestRect); + rgn.Offset(aOffset); + BG_ASSERT_DEBUG(rgn.IsContainedBy(desc.iSizeInPixels), EBitgdiPanicOutOfBounds); + rasterizer->BeginBitmap(aBitmap.SerialNumber(), desc, &rgn); + rgn.Close(); + } + } + return rasterizer; + } + +/** Prepares the rasterizer to retrieve scan lines from a bitmap if it is an +extended bitmap. The region of interest passed to the rasterizer is the intersection +of the clipping region, the clipping rectangle and the specified rectangle. +This function calls CFbsRasterizer::BeginBitmap() with the appropriate +parameters. When finished retrieving scan lines from the extended bitmap, +CFbsRasterizer::EndBitmap() must be called. +@param aBitmap The bitmap to retrieve scan lines from. +@param aDestRect A rectangle in coordinates relative to the graphics context that + bounds the area that aBitmap is to be drawn onto. +@param aSourceRect A rectangle in coordinates relative to the source bitmap that maps + to aDestRect after scaling and translation. +@return A pointer to the rasterizer owned by this thread's FBServ session. +@return NULL if the rasterizer is not present or aBitmap is not an extended bitmap. +@see CFbsRasterizer +@internalComponent +*/ +CFbsRasterizer* CFbsBitGc::PrepareRasterizerForExtendedBitmap(const CFbsBitmap& aBitmap, const TRect& aDestRect, const TRect& aSourceRect) + { + CFbsRasterizer* rasterizer = NULL; + CFbsRasterizer::TBitmapDesc desc; + desc.iDataType = aBitmap.ExtendedBitmapType(); + if (desc.iDataType != KNullUid) + { + rasterizer = CFbsBitmap::Rasterizer(); + if (rasterizer) + { + desc.iSizeInPixels = aBitmap.SizeInPixels(); + desc.iDispMode = aBitmap.DisplayMode(); + desc.iData = aBitmap.DataAddress(); + desc.iDataSize = aBitmap.DataSize(); + RRegion rgn; + // Calculate the parameters for the linear DDA algorithm used to scale the region + // of interest before entering the rectangle loop, since they are invariant. + TLinearDDA xLine0, yLine0; + xLine0.Construct(TPoint(aSourceRect.iTl.iX, aDestRect.iTl.iX), + TPoint(aSourceRect.iBr.iX, aDestRect.iBr.iX), + TLinearDDA::ELeft); + yLine0.Construct(TPoint(aSourceRect.iTl.iY, aDestRect.iTl.iY), + TPoint(aSourceRect.iBr.iY, aDestRect.iBr.iY), + TLinearDDA::ELeft); + TInt n = iDefaultRegionPtr->Count(); + for (TInt i = 0; i < n; ++i) + { + TRect rect = (*iDefaultRegionPtr)[i]; + if (!rect.Intersects(iUserClipRect)) + { + continue; + } + rect.Intersection(iUserClipRect); + if (!rect.Intersects(aDestRect)) + { + continue; + } + rect.Intersection(aDestRect); + // Scale the region of interest from coordinates relative to the graphics + // context to coordinates relative to the bitmap, one rectangle at a time. + TLinearDDA xLine(xLine0), yLine(yLine0); + TInt ax, ay, bx, by; + xLine.JumpToYCoord(ax, rect.iTl.iX); + yLine.JumpToYCoord(ay, rect.iTl.iY); + xLine.JumpToYCoord(bx, rect.iBr.iX); + yLine.JumpToYCoord(by, rect.iBr.iY); + if (ax < bx && ay < by) + { + rgn.AddRect(TRect(ax, ay, bx, by)); + } + } + BG_ASSERT_DEBUG(rgn.IsContainedBy(desc.iSizeInPixels), EBitgdiPanicOutOfBounds); + rasterizer->BeginBitmap(aBitmap.SerialNumber(), desc, &rgn); + rgn.Close(); + } + } + return rasterizer; + }