diff -r f5050f1da672 -r 04becd199f91 javauis/m2g_akn/src/CM2GRenderContext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/m2g_akn/src/CM2GRenderContext.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,589 @@ +/* +* Copyright (c) 2005-2006 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: Render context implementation +* +*/ + +// INCLUDE FILES +#include // CCoeEnv + +#include "CMIDGraphics.h" +#include "CM2GRenderContext.h" +#include "MM2GSVGProxy.h" + +M2G_NS_START + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS +/* static */ const TReal32 MM2GRenderContext::KFullOpaque = 1.0; +/* static */ +const TReal32 MM2GRenderContext::KFullTransparency = 0.0; +/* static */ +const TUint8 MM2GRenderContext::KMaxAlphaValue = 255; +/* static */ +const TDisplayMode MM2GRenderContext::KDefaultDisplayMode = EColor16MA; +/* static */ +const TDisplayMode MM2GRenderContext::KMaskDisplayMode = EGray256; + +// MACROS + +// LOCAL CONSTANTS AND MACROS + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES + +// FORWARD DECLARATIONS + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::CM2GRenderContext +// ----------------------------------------------------------------------------- +CM2GRenderContext::CM2GRenderContext() + : CBase(), + iProxy(NULL), + iEngineHandle(M2G_INVALID_HANDLE), + iAlpha(MM2GRenderContext::KFullOpaque), + iScaledAlpha(MM2GRenderContext::KMaxAlphaValue), + iMaskBmp(NULL), + iTargetBmp(NULL), + iImgBmp(NULL) +{ + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::CM2GRenderContext"); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::NewL +// ----------------------------------------------------------------------------- +CM2GRenderContext* CM2GRenderContext::NewL(MM2GSVGProxy* aProxy) +{ + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::NewL()"); + + CM2GRenderContext* self = new(ELeave) CM2GRenderContext; + CleanupStack::PushL(self); + + self->ConstructL(aProxy); + + CleanupStack::Pop(); + + return self; +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::~CM2GRenderContext +// ----------------------------------------------------------------------------- +CM2GRenderContext::~CM2GRenderContext() +{ + M2G_DEBUG_2("M2G_DEBUG: CM2GRenderContext::~CM2GRenderContext() - proxy=%d, engine=%d", iProxy, iEngineHandle); + if ((iEngineHandle != M2G_INVALID_HANDLE) && (iProxy != NULL)) + { + TRAP_IGNORE(iProxy->DeleteSvgEngineL(iEngineHandle)); + } + delete iImgBmp; + delete iMaskBmp; + iFbsSession.Disconnect(); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::BindL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::BindL(TInt& aTargetHandle, TBool aUiToolKit) +{ + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::BindL()"); + if (!aUiToolKit) + { + // Current Ui Toolkit is LCDUI + // Set target graphics bitmap + CMIDGraphics* graphics = MIDUnhand(aTargetHandle); + iTargetBmp = graphics->Bitmap(); + User::LeaveIfNull(iTargetBmp); +#ifdef RD_JAVA_NGA_ENABLED + iTargetCanvas = graphics->GetTargetCanvas(); +#endif // RD_JAVA_NGA_ENABLED + } + // initialize the svg image bitmap (on which we will render later during RenderL()) + InitImageBitmapL(); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::GetImgHandleL +// ----------------------------------------------------------------------------- +TM2GBitmapHandle CM2GRenderContext::GetImgHandleL() const +{ + User::LeaveIfNull(iImgBmp); + + return REINTERPRET_CAST(TM2GBitmapHandle, iImgBmp); +} +// ----------------------------------------------------------------------------- +// CM2GRenderContext::InitImageBitmapL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::InitImageBitmapL() +{ + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::InitImageBitmapL() - begin"); + + // get the screen size + TSize screenSize = CEikonEnv::Static()->ScreenDevice()->SizeInPixels(); + + if (iImgBmp == NULL || (iImgBmp && iImgBmp->SizeInPixels() != screenSize)) + { + M2G_DEBUG_2("M2G_DEBUG: CM2GRenderContext::InitImageBitmapL() - new bitmap: w=%d, h=%d", screenSize.iWidth, screenSize.iHeight); + // Create a new svg surface if first time + // or the size of the screen is different than the actual buffer size + + delete iImgBmp; + iImgBmp = NULL; + + iImgBmp = new(ELeave) CFbsBitmap(); + + User::LeaveIfError( + iImgBmp->Create(screenSize, KDefaultDisplayMode)); + } + + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::InitImageBitmapL() - end"); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::InitMaskL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::InitMaskL(TSize aSize) +{ + M2G_DEBUG_2("M2G_DEBUG: CM2GRenderContext::InitMaskL( w=%d, h=%d ) - begin", aSize.iWidth, aSize.iHeight); + + if (iMaskBmp == NULL || (iMaskBmp && iMaskBmp->SizeInPixels() != aSize)) + { + // Create a new mask but first delete the previous one if allocated + delete iMaskBmp; + iMaskBmp = NULL; + + M2G_DEBUG_0(" M2G_DEBUG: >CM2GRenderContext::InitMaskL() creates new mask "); + + iMaskBmp = new(ELeave) CFbsBitmap(); + + User::LeaveIfError( + iMaskBmp->Create(aSize, KMaskDisplayMode)); + } + + User::LeaveIfNull(iMaskBmp); + + // Mask is filled with the current alpha factor + FillBitmapL(iMaskBmp, iScaledAlpha); + + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::InitMaskL() - end"); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::ReleaseL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::ReleaseL() +{ + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::ReleaseL() - begin"); + iTargetBmp = NULL; +#ifdef RD_JAVA_NGA_ENABLED + iTargetCanvas = NULL; +#endif // RD_JAVA_NGA_ENABLED + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::ReleaseL() - end"); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::RenderL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::RenderLCDUIL( + TM2GSvgDocumentHandle& aSvgDocHandle, + const TReal32 aCurrentTime, + TInt aSvgW, TInt aSvgH, + TM2GRenderRect& aRect +) +{ + // prepare viewbox + TRect viewbox; + TPoint anchor; + + PrepareViewbox(aRect, aSvgW, aSvgH, viewbox, anchor); + + RenderLCDUIL(aSvgDocHandle, aCurrentTime, viewbox, anchor); +#ifdef RD_JAVA_NGA_ENABLED + if (iTargetCanvas && iTargetCanvas->IsEglAvailable()) + { + iTargetCanvas->UpdateRect(TRect(anchor, viewbox.Size())); + } +#endif // RD_JAVA_NGA_ENABLED + +} + +// ----------------------------------------------------------------------------- +void CM2GRenderContext::RenderESWTL( + TM2GSvgDocumentHandle& aSvgDocHandle, + const TReal32 aCurrentTime, + TInt aSvgW, TInt aSvgH, + TM2GRenderRect& aRect, + MSwtClient* aClientHandle, + TBool aUseNativeClear, + TInt* aReturnData) +{ + // prepare viewbox + TRect viewbox; + TPoint anchor; + + PrepareViewbox(aRect, aSvgW, aSvgH, viewbox, anchor); + + aReturnData[0] = 0; + aReturnData[1] = 0; + aReturnData[2] = 0; + aReturnData[3] = 0; + aReturnData[4] = anchor.iX; + aReturnData[5] = anchor.iY; + aReturnData[6] = viewbox.iTl.iX; + aReturnData[7] = viewbox.iTl.iY; + aReturnData[8] = viewbox.Width(); + aReturnData[9] = viewbox.Height(); + + RenderESWTL(aSvgDocHandle, aCurrentTime, viewbox, anchor, aClientHandle, aUseNativeClear, aReturnData); + + return; +} +// CM2GRenderContext::SetRenderingQualityL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::SetRenderingQualityL(TInt aMode) +{ + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::SetRenderingQualityL()"); + User::LeaveIfNull(iProxy); + iProxy->RenderQualityL(iEngineHandle, aMode); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::SetTransparencyL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::SetTransparency(TReal32 aAlpha) +{ + iAlpha = aAlpha; + iScaledAlpha = STATIC_CAST(TUint8, (aAlpha * MM2GRenderContext::KMaxAlphaValue)); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::ConstructL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::ConstructL(MM2GSVGProxy* aProxy) +{ + // Init member variables + SetTransparency(MM2GRenderContext::KFullOpaque); + + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::ConstructL() - begin"); + + if (aProxy) + { + iProxy = aProxy; + iProxy->CreateSvgEngineL(iEngineHandle); + M2G_DEBUG_2("M2G_DEBUG: CM2GRenderContext::ConstructL() - proxy: %d, new engine: %d", iProxy, iEngineHandle); + } + else + { + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::ConstructL() - proxy is invalid"); + M2G_THROW(KM2GArgNotOk); + } + + User::LeaveIfError(iFbsSession.Connect()); + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::ConstructL() - end"); +} +// ----------------------------------------------------------------------------- +// CM2GRenderContext::PrepareViewbox +// ----------------------------------------------------------------------------- +void CM2GRenderContext::PrepareViewbox( + TM2GRenderRect& aRr, + TInt aSvgW, TInt aSvgH, + TRect& aViewbox, TPoint& aAnchor) +{ + M2G_DEBUG_6("M2G_DEBUG: CM2GRenderContext::PrepareViewbox() cX=%d, cY=%d, cW=%d, cH=%d, anchorX=%d, anchorY=%d - begin", aRr.GetClipX(), aRr.GetClipY(), aRr.GetClipW(), aRr.GetClipH(), aRr.GetAnchorX(), aRr.GetAnchorY()); + + // Create an anchor point and an svg render area rect + aAnchor.SetXY(aRr.GetAnchorX(), aRr.GetAnchorY()); + aViewbox.SetRect(aAnchor, TSize(aSvgW, aSvgH)); + + // NOTE: It's already verified in Java side that the SVG render area and + // the clip area intersects each other + aViewbox.Intersection(aRr); + + // Check if the clip rect has changes the svg rect + if (aViewbox.iTl != aAnchor) + { + // Update anchor position + TPoint oldAnchor(aAnchor); + aAnchor = aViewbox.iTl; + + // Update svg rect + aViewbox.Move((-oldAnchor.iX), (-oldAnchor.iY)); + } + else + { + // The clip rect has not changed the svg rect. Only the + // anchor position need to be updated + aViewbox.Move(-aAnchor.iX, -aAnchor.iY); + } + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::PrepareViewbox() - end"); +} +// ----------------------------------------------------------------------------- +// CM2GRenderContext::RenderL +// ----------------------------------------------------------------------------- +/** + * @see CBitmapContext::BitBltMasked() + * @note CBitmapContext::BitBltMasked() does alpha blending if the provided mask is 256 and not null, + * and simply blits otherwise + */ +void CM2GRenderContext::RenderLCDUIL( + TM2GSvgDocumentHandle& aSvgDocHandle, + TReal32 aCurrentTime, + const TRect& aViewbox, + const TPoint& aAnchor +) +{ + M2G_DEBUG_4("M2G_DEBUG: CM2GRenderContext::RenderL() viewbox: x=%d, y=%d, w=%d, h=%d begin", aViewbox.iTl.iX, aViewbox.iTl.iY, aViewbox.Size().iWidth, aViewbox.Size().iHeight); + + // No need to render if content is fully transparency (i.e. alpha=0) + if (iScaledAlpha == 0) + { + return; + } + + // 0: clear the previous rendered image + ClearBitmapL(iImgBmp); + + // 1: render the svg document on the iImgBmp + iProxy->RenderDocumentL( + iEngineHandle, + aSvgDocHandle, + GetImgHandleL(), NULL, aCurrentTime); + + CFbsBitmap* mask = NULL; + + // 2: calculate mask if alpha-blending is used + if (iScaledAlpha < MM2GRenderContext::KMaxAlphaValue) + { + // mask is always the same size as the viewbox + CreateAlphaBlendMaskL(aViewbox.Size()); + + mask = iMaskBmp; // use this mask for alpha blending + } + + // 3: blit the rendered image on the target bitmap + // it will do alpha blending when mask is not null + M2GBitmapUtils::BitBlt(*iTargetBmp, + *iImgBmp, + aAnchor, + &aViewbox, + mask); + + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::RenderL() end"); +} + +// ----------------------------------------------------------------------------- +void CM2GRenderContext::RenderESWTL( + TM2GSvgDocumentHandle& aSvgDocHandle, + TReal32 aCurrentTime, + const TRect& aViewbox, + const TPoint& aAnchor, + MSwtClient* /*aClientHandle*/, + TBool /*aUseNativeClear*/, + TInt* aReturnData) +{ + M2G_DEBUG_4("M2G_DEBUG: CM2GRenderContext::RenderL() viewbox: x=%d, y=%d, w=%d, h=%d begin", aViewbox.iTl.iX, aViewbox.iTl.iY, aViewbox.Size().iWidth, aViewbox.Size().iHeight); + + // No need to render if content is fully transparency (i.e. alpha=0) + if (iScaledAlpha == 0) + { + return; + } + + // 0: clear the previous rendered image + ClearBitmapL(iImgBmp); + + // 1: render the svg document on the iImgBmp + iProxy->RenderDocumentL( + iEngineHandle, + aSvgDocHandle, + GetImgHandleL(), NULL, aCurrentTime); + + CFbsBitmapHack* tempImgBmp = new(ELeave) CFbsBitmapHack(); + tempImgBmp->Create(aViewbox.Size(), iImgBmp->DisplayMode()); + ClearBitmapL(tempImgBmp); + + M2GBitmapUtils::BitBlt(*tempImgBmp, + *iImgBmp, + aAnchor, + &aViewbox, + NULL); + aReturnData[0] = tempImgBmp->Handle(); + aReturnData[1] = tempImgBmp->GetMyHandle(); + tempImgBmp = NULL; + + // 2: calculate mask if alpha-blending is used + if (iScaledAlpha < MM2GRenderContext::KMaxAlphaValue) + { + // mask is always the same size as the viewbox + CreateAlphaBlendMaskL(aViewbox.Size()); + + if (iMaskBmp) + { + CFbsBitmapHack* tempMaskBmp = new(ELeave) CFbsBitmapHack(); + tempMaskBmp->Create(aViewbox.Size(), iMaskBmp->DisplayMode()); + ClearBitmapL(tempMaskBmp); + + M2GBitmapUtils::BitBlt(*tempMaskBmp, + *iMaskBmp, + aAnchor, + &aViewbox, + NULL); + + aReturnData[2] = tempMaskBmp->Handle(); + aReturnData[3] = tempMaskBmp->GetMyHandle(); + tempMaskBmp = NULL; + } + } + + // Is this needed ?? + //iImgBmp = NULL; + //iMaskBmp = NULL; + + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::RenderL() end"); +} +// CM2GRenderContext::CreateAlphaBlendMask +// ----------------------------------------------------------------------------- +/** + *
  • mask is initialized with iScaledAlpha for all pixels. + *
  • reset the mask for those pixels that are not rendered (a = 0). + *
  • due to anti-aliasing (a != 1), + * recompute the mask by combining the pixel's alpha with the whole image alpha + * + * @note The svg backbuffer area is larger than the viewbox + * @note The size of the mask is the same as for SVG backbuffer + */ +void CM2GRenderContext::CreateAlphaBlendMaskL(const TSize& aViewBox) +{ + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::CreateAlphaBlendMaskL() - begin"); + + // the mask will have the same size as the svg image bitmap + // allocate memory for mask according to the size + // and initializes it with iScaledAlpha for each pixel ( i.e. Mem::Fill() = fast operation ) + InitMaskL(iImgBmp->SizeInPixels()); + + // lock svg buffer and mask bitmaps + TM2GBitmapLock maskLock(iMaskBmp); + TM2GBitmapLock imgLock(iImgBmp); + + TUint8* maskDataPtr = REINTERPRET_CAST(TUint8*, iMaskBmp->DataAddress()); + const TUint32* imgDataPtr = iImgBmp->DataAddress(); + + // Each row of CFbsBitmap is aligned to a 4 bytes boundary + // if the mask width in pixels is not a multiple of 4, then we must align the pointer + // to the correct address corresponding to the first pixel on the line below + + TInt maskMaxWidthBytes = iMaskBmp->ScanLineLength( + iMaskBmp->SizeInPixels().iWidth, KMaskDisplayMode); + + const TInt maskDeltaIndex = maskMaxWidthBytes - aViewBox.iWidth; + + // the svg backbuffer width could be larger than the viewbox width + const TInt imgDeltaIndex = iImgBmp->SizeInPixels().iWidth - aViewBox.iWidth; + + // how many pixels from the viewbox will be rechecked for alpha value + const TUint32 countViewBoxPixels = aViewBox.iHeight * aViewBox.iWidth; + + TUint32 imgAlphaMSB; + TUint32 imgAlpha32; + TUint32 index = 0; + + while (index < countViewBoxPixels) + { + // get the alpha channel in the most left octet (MSB) within a 4 octet + imgAlphaMSB = *imgDataPtr & 0xFF000000; + + if (imgAlphaMSB == 0x0) + { + // pixel is not rendered so we mask it out + *maskDataPtr = 0x0; + } + else if (imgAlphaMSB != 0xFF000000) + { + // combine the pixel's alpha with the whole image's alpha (iScaledAlpha) + // we are not sure if shifting to right pads it with 0 to the left + + imgAlpha32 = (imgAlphaMSB >> 24) & 0xFF; + + // compute the combined alpha on 32b because of possible overflow, + // and then downcast to TUint8 + // iScaledAlpha = 8b, KMaxAlphaValue = 8b + + *maskDataPtr = TUint8( + (imgAlpha32 * iScaledAlpha) / MM2GRenderContext::KMaxAlphaValue); + } + + imgDataPtr++; + maskDataPtr++; + index++; + + // synchronize the image and mask indexes because the viewbox could be smaller than the image/mask + if (index % aViewBox.iWidth == 0) + { + imgDataPtr += imgDeltaIndex; + maskDataPtr += maskDeltaIndex; + } + } + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::CreateAlphaBlendMaskL() - end"); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::ClearBitmapL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::ClearBitmapL(CFbsBitmap* aBmp) +{ + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::ClearBitmap - begin"); + + User::LeaveIfNull(aBmp); + + TM2GBitmapLock lock(aBmp); + + TSize size = aBmp->SizeInPixels(); + TInt scanlineLength = aBmp->ScanLineLength(size.iWidth, aBmp->DisplayMode()); + + TUint32* buf = aBmp->DataAddress(); + char* bufBytes = REINTERPRET_CAST(char*, buf); + + Mem::FillZ(bufBytes, size.iHeight * scanlineLength); + + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::ClearBitmap - end"); +} + +// ----------------------------------------------------------------------------- +// CM2GRenderContext::FillBitmapL +// ----------------------------------------------------------------------------- +void CM2GRenderContext::FillBitmapL(CFbsBitmap* aBmp, const TUint8& aChar) +{ + M2G_DEBUG_1("M2G_DEBUG: CM2GRenderContext::FillBitmap() filled with=%d - begin", aChar); + + User::LeaveIfNull(aBmp); + + TM2GBitmapLock lock(aBmp); + + TSize size = aBmp->SizeInPixels(); + TInt scanlineLength = aBmp->ScanLineLength(size.iWidth, aBmp->DisplayMode()); + + TUint32* buf = aBmp->DataAddress(); + char* bufBytes = REINTERPRET_CAST(char*, buf); + + Mem::Fill(bufBytes, size.iHeight * scanlineLength, aChar); + + M2G_DEBUG_0("M2G_DEBUG: CM2GRenderContext::FillBitmap - end"); +} + +M2G_NS_END