diff -r 000000000000 -r 88edb906c587 svgtopt/gfx2d/src/GfxGc/Gfx2dGcOpenVG.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svgtopt/gfx2d/src/GfxGc/Gfx2dGcOpenVG.cpp Wed Nov 03 18:56:10 2010 +0200 @@ -0,0 +1,2989 @@ +/* +* Copyright (c) 2002 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: Graphics Extension Library source file +* +*/ + + +#include "Gfx2dGcOpenVG.h" +//#include "Gfx2dDevice.h" +#include "GfxLine2D.h" +#include "GfxStroke.h" +#include "GfxGeneralPath.h" +#include "GfxFlatteningPathIterator.h" +#include "GfxColor.h" +#include "GfxImageTransformer.h" +//#include "hal.h" +//#include "hal_data.h" + +#include "gdi.h" +#include "biditext.h" + +#include "GfxFloatFixPt.h" +#include "GfxShape.h" +#include "GfxEllipse2D.h" +#include "GfxRoundRectangle2D.h" +//#include "svgBackendStd.h" +//#include "gulutil.h" +#include +//#include +//#include +#include +#include//NGA +#include +// OpenVG Includes +#include +#include +// OpenVG API Binding Symbian specific +#include + +// For allocating path segment type array +// Found 130 to be max size at bootup +const TInt KPathSegmentTypeInitialSize = 130; +const TInt KPathSegmentTypeMaxSize = 1000; + +const TInt KRenderQualityLow = 1; +const TInt KRenderQualityHigh = 2; +_LIT( KDefaultFont, "serif" ); // Similar changes should be applied to \ + //SvgTextElementImpl.cpp file + +// -------------------------------------------------------------------------- +// CGfx2dGcOpenVG::CGfx2dGcOpenVG() : iScale( 1 ), +// --------------------------------------------------------------------------- +CGfx2dGcOpenVG::CGfx2dGcOpenVG( TBool /* aIsMainContext */ ) : + iFillOpacity( 1 ), + iScale( 1 ), + iStrokeColor( 0 ), + iStrokeOpacity( 1 ), + iBackgroundColor( 0xffffff ), + iFontSize( 10 ), + iFontWeight( -1 ), + iFontStyle( -1 ), + iFamilies( NULL ), + iTextAnchor( EGfxTextAnchorNone ), + iTextDecoration( EGfxTextDecorationNone ), + iGraphicsContextCreated( EFalse ), + iRenderQuality(VG_RENDERING_QUALITY_BETTER), + iCurrentRendererType(ESVGRendererSW) + + { + } +// +// ========================================================================== +// Create a new instance. +// ========================================================================== +// -------------------------------------------------------------------------- +// CGfx2dGcOpenVG* CGfx2dGcOpenVG::NewL( CFbsBitmap* aFrameBuffer, TFontSpec& aFontSpec ) +// --------------------------------------------------------------------------- + CGfx2dGcOpenVG* CGfx2dGcOpenVG::NewL( const TSize aBufferSize, TFontSpec& aFontSpec, CSvgBitmapFontProvider* aSvgBitmapFontProvider, TBool aIsMainContext ) + { + CGfx2dGcOpenVG* self = new( ELeave ) CGfx2dGcOpenVG( aIsMainContext ); + CleanupStack::PushL( self ); + self->ConstructL( aBufferSize, aFontSpec, aSvgBitmapFontProvider); + CleanupStack::Pop(); + return self; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::ConstructL( CFbsBitmap* aFrameBuffer, TFontSpec& aFontSpec ) +// --------------------------------------------------------------------------- +void CGfx2dGcOpenVG::ConstructL( const TSize aBufferSize, TFontSpec& aFontSpec, CSvgBitmapFontProvider* aSvgBitmapFontProvider ) + { + /* iApacAvailable = EFalse; + FeatureManager::InitializeLibL(); + iApacAvailable = ( AknLayoutUtils::Variant() == EApacVariant ); + FeatureManager::UnInitializeLib();*/ + + + iFontSpec = aFontSpec; + + if (iFontSpec.iTypeface.iName.Length() == 0) + { + //just for a safety check in case client didnt put it in + iFontSpec = TFontSpec(KDefaultFont, 100); + } + + + iSvgBitmapFontProvider = aSvgBitmapFontProvider ; + + // Allocate path segment type array + iPathSegmentTypeCount = KPathSegmentTypeInitialSize; + iPathSegmentTypes = new (ELeave) VGubyte[KPathSegmentTypeInitialSize]; + + iDashArray = new ( ELeave ) CArrayFixFlat( 32 ); + + iVgRenderer = CVGRenderer::NewL(ESVGRendererSW, 0); + iVgSurface = iVgRenderer->GetCurrentSurface(); + ChangeBufferSizeL( aBufferSize ); + } +//NGA +// -------------------------------------------------------------------------- +// CGfx2dGcOpenVG* CGfx2dGcOpenVG::NewL( CFbsBitmap* aFrameBuffer, TFontSpec& aFontSpec ) +// --------------------------------------------------------------------------- + CGfx2dGcOpenVG* CGfx2dGcOpenVG::NewL( const TSize aBufferSize, TFontSpec& aFontSpec, CSvgBitmapFontProvider* aSvgBitmapFontProvider,SVGRendererId aRendererType,TBool aIsMainContext ) + { + CGfx2dGcOpenVG* self = new( ELeave ) CGfx2dGcOpenVG( aIsMainContext ); + CleanupStack::PushL( self ); + self->ConstructL( aBufferSize, aFontSpec, aSvgBitmapFontProvider,aRendererType); + CleanupStack::Pop(); + return self; + } +//NGA +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::ConstructL( CFbsBitmap* aFrameBuffer, TFontSpec& aFontSpec ) +// --------------------------------------------------------------------------- +void CGfx2dGcOpenVG::ConstructL( const TSize aBufferSize, TFontSpec& aFontSpec, CSvgBitmapFontProvider* aSvgBitmapFontProvider,SVGRendererId aRendererType ) + { + + iFontSpec = aFontSpec; + + if (iFontSpec.iTypeface.iName.Length() == 0) + { + //just for a safety check in case client didnt put it in + iFontSpec = TFontSpec(KDefaultFont, 100); + } + iSvgBitmapFontProvider = aSvgBitmapFontProvider ; + + // Allocate path segment type array + iPathSegmentTypeCount = KPathSegmentTypeInitialSize; + iPathSegmentTypes = new (ELeave) VGubyte[KPathSegmentTypeInitialSize]; + + iDashArray = new ( ELeave ) CArrayFixFlat( 32 ); + iCurrentRendererType = aRendererType; + iVgRenderer = CVGRenderer::NewL(aRendererType, 0); + iVgSurface = iVgRenderer->GetCurrentSurface(); + + iVgSurface->InitializeSurface( aBufferSize, VGI_COLORSPACE_SRGB ); + iVgSurface->CreateSurface(EColor16MA, 0, 0); + + ChangeBufferSizeL( aBufferSize ); + + } +// ========================================================================== +// Destructor. +// ========================================================================== +// -------------------------------------------------------------------------- +// CGfx2dGcOpenVG::~CGfx2dGcOpenVG() +// --------------------------------------------------------------------------- + CGfx2dGcOpenVG::~CGfx2dGcOpenVG() + { + if ( iDashArray ) + { + delete iDashArray; + iDashArray = NULL; + } + + // This is no longer needed, the Font is owned by TextElement + // now as each text element may have its own specific font + // and keeping one copy at Gc level will not work. + // Gc is just refering to the Font from Textelement, so + // now need to free it here. + // + //if (iFont && iWsScreenDevice) + // { + // iWsScreenDevice->ReleaseFont(iFont); + // iFont = NULL; + // } + + + DestroyContext(); + + iGroupOpacityImages.Close(); + + TInt bufferCount = iGroupOpacityBuffers.Count(); + for ( TInt i = 0; i < bufferCount; i++ ) + { + delete [] iGroupOpacityBuffers[i]; + } + iGroupOpacityBuffers.Close(); + + if ( iPathSegmentTypes ) + { + delete [] iPathSegmentTypes; + } + delete iVgRenderer; + + } + +// private method +void CGfx2dGcOpenVG::DestroyContext() + { + if ( iGraphicsContextCreated ) + { + // Destroy OpenVG context + iVgSurface->TerminateSurface(); + ResetContextHandle(); + iFillOpacity = 1; + iScale = 1; + iStrokeOpacity = 1; + } + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetFrameBufferL( CFbsBitmap* aFrameBuffer ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::ChangeBufferSizeL( const TSize aBufferSize ) + { + if ( aBufferSize.iWidth <= 0 || aBufferSize.iHeight <= 0 || aBufferSize == iColorBufferSize ) + { + return; + } + + iColorBufferSize = aBufferSize; + + // First time: creating OpenVG context + if( !iGraphicsContextCreated ) + { + // Create OpenVG context + TInt err = iVgSurface->InitializeSurface( iColorBufferSize, VGI_COLORSPACE_SRGB ); + if (!((err == KErrNone) || (err == KErrAlreadyExists))) + { + #ifdef _DEBUG + RDebug::Printf("SVG can't initialize OpenVG Context %d", err); + #endif //_DEBUG + iGraphicsContextCreated = EFalse; + User::Leave(err); + } + iGraphicsContextCreated = ETrue; + // By default the Rendering quality is VG_RENDERING_QUALITY_BETTER + iVgRenderer->vgSeti( VG_RENDERING_QUALITY, iRenderQuality ); + } + // Only need to update context with color-buffer info + // when frame buffer size changes + else + { + TInt err = iVgSurface->ResizeSurface( iColorBufferSize ); + + if( err != KErrNone ) + { + if(err == KErrNoMemory ) + { + #ifdef _DEBUG + RDebug::Printf("OpenVG Context destroyed %d", err); + #endif //_DEBUG + // This indicates that OpenVG has destroyed the current context handle + // and also the Path, StrokePaint and FillPaint handles are no more valid. + // Thus reinitialize them to 0, so that they can be recreated. + ResetContextHandle(); + } + + #ifdef _DEBUG + RDebug::Printf("SVG can't RESIZE OpenVG Context %d", err); + #endif //_DEBUG + User::Leave(err); + } + } + + iRenderInfo.SetDevice( 0, /*this parameter will be ignored */ + iColorBufferSize.iWidth, + iColorBufferSize.iHeight, + 0 /*this parameter will be ignored */); + } + +// -------------------------------------------------------------------------- +// TInt CGfx2dGcOpenVG::OpenVGErrorToSymbianError( int aError ) +// --------------------------------------------------------------------------- +TInt CGfx2dGcOpenVG::OpenVGErrorToSymbianError( TInt aError ) +{ + TInt error = KErrNone; + switch( aError ) + { + case VGI_OK: + { + error = KErrNone; + break; + } + + case VGU_OUT_OF_MEMORY_ERROR: + case VG_OUT_OF_MEMORY_ERROR: + case VGI_ERROR_OUT_OF_MEMORY: + { + error = KErrNoMemory; + break; + } + + case VG_ILLEGAL_ARGUMENT_ERROR: + case VGI_ERROR_INVALID_ARGUMENTS: + case VGU_ILLEGAL_ARGUMENT_ERROR: + { + error = KErrArgument; + break; + } + + case VGI_ERROR_ALREADY_EXISTS: + { + error = KErrAlreadyExists; + break; + } + + case VG_UNSUPPORTED_PATH_FORMAT_ERROR: + case VGI_ERROR_COLORSPACE_NOT_SUPPORTED: + case VG_UNSUPPORTED_IMAGE_FORMAT_ERROR: + case VGI_ERROR_NOT_SUPPORTED: + { + error = KErrNotSupported; + break; + } + + case VGI_ERROR_ILLEGAL_IMAGE_HANDLE: + { + error = KErrBadHandle; + break; + } + + case VG_IMAGE_IN_USE_ERROR: + case VGI_ERROR_IMAGE_IN_USE: + { + error = KErrInUse; + break; + } + + case VGI_ERROR_ILLEGAL_OPERATION: + { + error = KErrPermissionDenied; + break; + } + + case VG_BAD_HANDLE_ERROR: + case VG_PATH_CAPABILITY_ERROR: + case VGU_PATH_CAPABILITY_ERROR: + case VGU_BAD_WARP_ERROR: + case VGU_BAD_HANDLE_ERROR: + { + error = KErrUnknown; + break; + } + + default: + { + error = KErrUnknown; + } + } + + return error; +} +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::DoDrawL( MGfxShape* aShape ) +// --------------------------------------------------------------------------- +void CGfx2dGcOpenVG::DoDrawL( MGfxShape* aShape ) + { + VGbitfield drawMode = 0x0; + VGUErrorCode vguret; + + // Do not render if both stroke and fill are none + if ( iStrokeColor.GetARGB() == KGfxColorNull && iFillColor == NULL ) + return; + + iVgRenderer->vgSeti( VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE ); + + if ( !iPath ) + { + const float KScale = 1.0f / 65536.0f; + iPath = iVgRenderer->vgCreatePath( VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_S_32, KScale, 0.0f, 0, 0, + VG_PATH_CAPABILITY_APPEND_TO ); + if ( iPath == VG_INVALID_HANDLE ) + { + VGErrorCode error = (VGErrorCode)iVgRenderer->vgGetError(); + if (error == VG_OUT_OF_MEMORY_ERROR) + { + #ifdef _DEBUG + RDebug::Printf("OOM: vgCreatePath"); + #endif + User::Leave(KErrNoMemory); + } + // handle other errors... + #ifdef _DEBUG + RDebug::Printf("SVG GFX2D Error: vgCreatePath"); + #endif + } + } + + if (iFillColor) + { + if(!iFillPaint) + { + iFillPaint = iVgRenderer->vgCreatePaint(); + if ( iFillPaint == VG_INVALID_HANDLE ) + { + VGErrorCode error = (VGErrorCode)iVgRenderer->vgGetError(); + if (error == VG_OUT_OF_MEMORY_ERROR) + { + RDebug::Printf("SVG GFX2D Error OOMs: vgCreatePaint"); + User::Leave(KErrNoMemory); + } + // handle other errors... + #ifdef _DEBUG + RDebug::Printf("SVG GFX2D Error: vgCreatePaint"); + #endif + } + } + } + + if(iStrokeColor.GetARGB() != KGfxColorNull) + { + if(!iStrokePaint) + { + iStrokePaint = iVgRenderer->vgCreatePaint(); + if ( iStrokePaint == VG_INVALID_HANDLE ) + { + VGErrorCode error = (VGErrorCode)iVgRenderer->vgGetError(); + if (error == VG_OUT_OF_MEMORY_ERROR) + { + RDebug::Printf("SVGT CGfx2dGcOpenVG::DoDrawL vgCreatePaint OOM"); + User::Leave(KErrNoMemory); + } + #ifdef _DEBUG + RDebug::Printf("SVGT CGfx2dGcOpenVG::DoDrawL vgCreatePaint failed %d", error); + #endif + } + } + } + + TGfxRectangle2D bbRect; + TGfxAffineTransform identityMat; + + //vgClear( 0, 0, VG_MAXINT, VG_MAXINT ); + switch(aShape->ShapeType()) + { + case MGfxShape::ERect: + { + TGfxRectangle2D* rect = (TGfxRectangle2D*)aShape; + + rect->GetBounds( identityMat, bbRect ); + drawMode = SetFillStroke(iFillPaint, iStrokePaint, bbRect); + + vguret = (VGUErrorCode)iVgRenderer->vguRect( + iPath, + (VGfloat)rect->iX, + (VGfloat)rect->iY, + (VGfloat)rect->iWidth, + (VGfloat)rect->iHeight ); + + if( vguret != KErrNone ) + { + User::LeaveIfError(OpenVGErrorToSymbianError(vguret)); + } + iVgRenderer->vgDrawPath( iPath, drawMode ); + } + break; + + case MGfxShape::ERoundRect: + { + float rx, ry; + TGfxRoundRectangle2D* rect = (TGfxRoundRectangle2D*)aShape; + + TFloatFixPt tWidth = rect->iArcWidth; + TFloatFixPt tHeight = rect->iArcHeight; + + tWidth.iValue <<= 1; + tHeight.iValue <<= 1; + + rx = (VGfloat)tWidth; + ry = (VGfloat)tHeight; + + //If a properly specified value is provided for ry but not for rx, + // then the user agent must process the 'rect' element with the + // effective value for rx as equal to ry. However clamp to 0. + if ( rx <= 0 ) + { + rx = ry; + } + if ( ry <= 0) + { + ry = rx; + } + + if(rx < 0) + { + rx = 0; + } + if(ry < 0) + { + ry = 0; + } + + rect->GetBounds( identityMat, bbRect ); + drawMode = SetFillStroke(iFillPaint, iStrokePaint, bbRect); + + // Rounded rectangle + if ( rx == 0.0f && ry == 0.0f ) + { + vguret = (VGUErrorCode)iVgRenderer->vguRect(iPath, + (VGfloat)rect->iX, (VGfloat)rect->iY, + (VGfloat)rect->iWidth, (VGfloat)rect->iHeight ); + } + else + { + vguret = (VGUErrorCode)iVgRenderer->vguRoundRect( iPath, + (VGfloat)rect->iX, (VGfloat)rect->iY, + (VGfloat)rect->iWidth, (VGfloat)rect->iHeight, + rx, ry ); + } + if( vguret != KErrNone ) + { + User::LeaveIfError(OpenVGErrorToSymbianError(vguret)); + } + iVgRenderer->vgDrawPath( iPath, drawMode ); + } + break; + + case MGfxShape::EEllipse: + { + TGfxEllipse2D* ellipse = (TGfxEllipse2D*)aShape; + #ifdef SVG_FLOAT_BUILD + TFloatFixPt rx = ellipse->iWidth * TFloatFixPt(.5f); + TFloatFixPt ry = ellipse->iHeight * TFloatFixPt(.5f); + #else + TFloatFixPt rx = ellipse->iWidth >> 1; // rx = width / 2 + TFloatFixPt ry = ellipse->iHeight >> 1; // ry = height / 2 + #endif + ellipse->GetBounds( identityMat, bbRect ); + drawMode = SetFillStroke(iFillPaint, iStrokePaint, bbRect); + + // Element + vguret = (VGUErrorCode)iVgRenderer->vguEllipse(iPath, + (VGfloat)(ellipse->iX + rx), + (VGfloat)(ellipse->iY + ry), + (VGfloat)ellipse->iWidth, + (VGfloat)ellipse->iHeight); + if( vguret != KErrNone ) + { + User::LeaveIfError(OpenVGErrorToSymbianError(vguret)); + } + iVgRenderer->vgDrawPath(iPath,drawMode); + } + break; + + + case MGfxShape::EPath: + { + CGfxGeneralPath* gPath = (CGfxGeneralPath*)aShape; + RArray* coordArray = gPath->PointCoordsArrayAll(); + if (coordArray->Count() > 0) + { + TFloatFixPt* coord = gPath->PointCoordsArray(); + TUint8 count = gPath->Count(); + RArray* type = gPath->PointTypeArray(); + TInt typeCount = type->Count(); + if(count && ( typeCount == count)) + { + iVgRenderer->vgAppendPathData(iPath, count,gPath->PathSegmentTypeArray(),coord); + } + else + { + //RArray* type = gPath->PointTypeArray(); + //TInt typeCount = type->Count(); + // this is a multi path + // Using non-ELeave version and checking for NULL to avoid (ELeave) and TRAP + if ( iPathSegmentTypeCount < typeCount ) + { + if ( iPathSegmentTypes ) + { + delete [] iPathSegmentTypes; + iPathSegmentTypes = NULL; + } + iPathSegmentTypes = new VGubyte[typeCount]; + iPathSegmentTypeCount = typeCount; + } + if ( !iPathSegmentTypes ) + { + break; + } + for (TInt i=0; i < typeCount; i++) + { + iPathSegmentTypes[i] = (TGfxSegType) (*type)[i]; + } + iVgRenderer->vgAppendPathData(iPath, typeCount, iPathSegmentTypes, coord); + } + gPath->GetBounds( identityMat, bbRect ); + drawMode = SetFillStroke(iFillPaint, iStrokePaint, bbRect); + iVgRenderer->vgDrawPath(iPath,drawMode); + } + } + break; + + case MGfxShape::ELine: + { + TGfxLine2D* line = (TGfxLine2D*)aShape; + + // Force Stroke color... if not present + if(iFillColor && iStrokeColor.GetARGB() == KGfxColorNull) + { + iStrokeColor = iFillColor->GetColor(); + } + + line->GetBounds( identityMat, bbRect ); + drawMode = SetFillStroke(iFillPaint, iStrokePaint, bbRect); + + vguret = (VGUErrorCode)iVgRenderer->vguLine( + iPath, + (VGfloat)line->iX1, + (VGfloat)line->iY1, + (VGfloat)line->iX2, + (VGfloat)line->iY2); + + if( vguret != KErrNone ) + { + User::LeaveIfError(OpenVGErrorToSymbianError(vguret)); + } + + iVgRenderer->vgDrawPath(iPath,drawMode); + } + break; + } + iVgRenderer->vgClearPath( iPath, VG_PATH_CAPABILITY_APPEND_TO ); + + // Delete path segment type array to avoid large memory to persist, + // created by some content, but the larget size is not needed later. + if ( iPathSegmentTypeCount > KPathSegmentTypeMaxSize ) + { + if ( iPathSegmentTypes ) + { + delete [] iPathSegmentTypes; + iPathSegmentTypes = NULL; + iPathSegmentTypeCount = 0; + } + } + + // Turn off any settings that are not needed by default + PostDraw(); + } + +void CGfx2dGcOpenVG::PostDraw() +{ + if ( iDashArray && iDashArray->Count() > 0 ) + { + iVgRenderer->vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL); + iDashArray->Reset(); + } +} + +// -------------------------------------------------------------------------- +// VGbitfield CGfx2dGcOpenVG::SetFillStroke(VGPaint aFillPaint, VGPaint aStrokePaint, TGfxRectangle2D& bBox) +// --------------------------------------------------------------------------- +VGbitfield CGfx2dGcOpenVG::SetFillStroke(VGPaint aFillPaint, VGPaint aStrokePaint, TGfxRectangle2D& bBox) +{ + VGbitfield returnVal = 0x0; + + // Fill Color + if (iFillColor) + { + if( aFillPaint != VG_INVALID_HANDLE ) + { + iFillColor->SetFill(aFillPaint, bBox, iFillOpacity, iVgRenderer); + returnVal |= VG_FILL_PATH; + } + } + + // + // Color Correction for Symbian->OpenVG + // Symbian argb + // OpenVg rgba + // + // Stroke + // + if( iStrokeColor.GetARGB() != KGfxColorNull && iStrokeColor.GetARGB() != 0x1ffffff ) + { + iVgRenderer->vgSetf( VG_STROKE_LINE_WIDTH, (VGfloat)iStroke.StrokeWidth() ); + + //SET LINECAP INFORMATION + SVGLineCap lineCap = (SVGLineCap)iStroke.StrokeCap(); + + if (lineCap == SVG_CAP_ROUND) + { + iVgRenderer->vgSeti( VG_STROKE_CAP_STYLE, VG_CAP_ROUND); + } + else if ( lineCap == SVG_CAP_SQUARE ) + { + iVgRenderer->vgSeti( VG_STROKE_CAP_STYLE, VG_CAP_SQUARE); + } + else + { + iVgRenderer->vgSeti( VG_STROKE_CAP_STYLE, VG_CAP_BUTT); + } + + //SET LINEJOIN INFORMATION + SVGLineJoin linejoin = (SVGLineJoin)iStroke.StrokeJoin(); + if (linejoin == SVG_JOIN_ROUND) + { + iVgRenderer->vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND); + } + else if (linejoin == SVG_JOIN_BEVEL) + { + iVgRenderer->vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL); + } + else + { + iVgRenderer->vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER); + } + + iVgRenderer->vgSetf( VG_STROKE_MITER_LIMIT, (VGfloat)iStroke.StrokeMiterLimit() ); + if(aStrokePaint != VG_INVALID_HANDLE) + { + iVgRenderer->vgSetParameteri( aStrokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR ); + TUint32 opacity = (TInt)(iStrokeOpacity * TFloatFixPt(255.0f)); + iVgRenderer->vgSetColor( aStrokePaint, iStrokeColor.GetARGB() << 8 | opacity ); + iVgRenderer->vgSetPaint( aStrokePaint, VG_STROKE_PATH ); + returnVal |= VG_STROKE_PATH; + } + } + + return returnVal; +} + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetWindingRule( TGfxWindingRule aRule ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetWindingRule( TGfxWindingRule aRule ) + { + if ( aRule == EGfxWindEvenOdd ) + { + iVgRenderer->vgSeti(VG_FILL_RULE, VG_EVEN_ODD); + } + else + { + iVgRenderer->vgSeti(VG_FILL_RULE, VG_NON_ZERO); + } + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::Draw( MGfxShape* aShape ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::DrawL( MGfxShape* aShape ) + { + DoDrawL( aShape ); + } + + + +// -------------------------------------------------------------------------- +// TGfxColor CGfx2dGcOpenVG::ForegroundColor() +// --------------------------------------------------------------------------- + TGfxColor CGfx2dGcOpenVG::ForegroundColor() + { + return iStrokeColor; + } + + +// -------------------------------------------------------------------------- +// MGfxPaint* CGfx2dGcOpenVG::Paint() +// --------------------------------------------------------------------------- + MGfxPaint* CGfx2dGcOpenVG::Paint() + { + return iFillColor; + } + +// -------------------------------------------------------------------------- +// TGfxRenderingHints* CGfx2dGcOpenVG::RenderingHints() +// --------------------------------------------------------------------------- + TGfxRenderingHints* CGfx2dGcOpenVG::RenderingHints() + { + //return &iRenderingHints; + return NULL; + } + +// -------------------------------------------------------------------------- +// TGfxStroke CGfx2dGcOpenVG::Stroke() +// --------------------------------------------------------------------------- + TGfxStroke CGfx2dGcOpenVG::Stroke() + { + return iStroke; + } + + + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetDashOffset( TFloatFixPt aDashOffset ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetDashOffset( TFloatFixPt aDashOffset ) +{ + iDashOffset = aDashOffset; + iVgRenderer->vgSetf(VG_STROKE_DASH_PHASE, (VGfloat)iDashOffset); +// svgSetStrokeDashOffset(iHyb2dContext, svgScalarFromFloat(iDashOffset)); +} + + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetForegroundColor( const TGfxColor& aColor ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetForegroundColor( const TGfxColor& aColor ) + { + // Both GDI and Gfx2D need to keep color value... + iStrokeColor = aColor; + } +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetStrokeWidth( const TGfxStroke& aColor ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetStrokeWidth( const TFloatFixPt& aWidth ) + { + // Both GDI and Gfx2D need to keep stroke-width value... + iStroke.SetStrokeWidth(aWidth); + + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetBackgroundColor( const TGfxColor& aColor ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetBackgroundColor( const TGfxColor& aColor ) + { + // Only Gfx2D need to keep background color value. + iBackgroundColor = aColor; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetPaint( MGfxPaint* aPaint ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetPaint( MGfxPaint* aPaint ) + { + iFillColor = aPaint; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetStroke( TGfxStroke aStroke ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetStroke( TGfxStroke aStroke ) + { + iStroke = aStroke; + iVgRenderer->vgSetf( VG_STROKE_LINE_WIDTH, (VGfloat)iStroke.StrokeWidth() ); + + //SET LINECAP INFORMATION + SVGLineCap lineCap = (SVGLineCap)iStroke.StrokeCap(); + + if (lineCap == SVG_CAP_ROUND) + { + iVgRenderer->vgSeti( VG_STROKE_CAP_STYLE, VG_CAP_ROUND); + } + else if ( lineCap == SVG_CAP_SQUARE ) + { + iVgRenderer->vgSeti( VG_STROKE_CAP_STYLE, VG_CAP_SQUARE); + } + else + { + iVgRenderer->vgSeti( VG_STROKE_CAP_STYLE, VG_CAP_BUTT); + } + + //SET LINEJOIN INFORMATION + SVGLineJoin linejoin = (SVGLineJoin)iStroke.StrokeJoin(); + if (linejoin == SVG_JOIN_ROUND) + { + iVgRenderer->vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND); + } + else if (linejoin == SVG_JOIN_BEVEL) + { + iVgRenderer->vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL); + } + else + { + iVgRenderer->vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER); + } + + iVgRenderer->vgSetf( VG_STROKE_MITER_LIMIT, (VGfloat)iStroke.StrokeMiterLimit() ); + + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetRenderingHints( const TGfxRenderingHints& aRenderingHints ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetRenderingHints( const TGfxRenderingHints& /*aRenderingHints*/ ) + { + //iRenderingHints = aRenderingHints; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetTransform( const TGfxAffineTransform& aTransform ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetTransform( const TGfxAffineTransform& aTransform ) + { + iTransform = aTransform; + + // Calculate scale + TGfxPoint2D ep( 1, 0 ), org( 2, 0 ); + iTransform.Transform( &ep, & ep, 1 ); + iTransform.Transform( &org, & org, 1 ); + ep.iX -= org.iX; + ep.iY -= org.iY; + iScale = TFloatFixPt::Sqrt( ep.iX * ep.iX + ep.iY * ep.iY ); + + // activate Graphics 2D engine + // set viewport coordinate system to map from canvas coordinates to pixels + // in order to provide resolution independent results + // SVGMatrix2x3 vmat; + // svgMatrix2x3Set( &vmat, + // iTransform.iM00.iValue, + // iTransform.iM01.iValue, + // iTransform.iM02.iValue, + // iTransform.iM10.iValue, + // iTransform.iM11.iValue, + // iTransform.iM12.iValue + // ); +// svgSetViewportCoordinateSystem( iHyb2dContext, vmat.matrix ); + ApplyTransform(iTransform); + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetClip( const TGfxRectangle2D& aClip ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetClip( const TGfxRectangle2D& aClip ) + { + iClip = aClip; + TFloatFixPt newY = iColorBufferSize.iHeight - (TInt)aClip.iHeight - (TInt)aClip.iY; + VGint clipRect[4] = + { + (TInt)aClip.iX, (TInt)newY, (TInt)aClip.iWidth, (TInt)aClip.iHeight + }; + + // Set VG_SCISSORING to True + iVgRenderer->vgSeti(VG_SCISSORING, VG_TRUE); + + // Set Clippling rectangle + iVgRenderer->vgSetiv(VG_SCISSOR_RECTS, 4,(const TInt*) clipRect); + } + + void CGfx2dGcOpenVG::SetClipMediaElement( TSize aSize ) + { + TFloatFixPt width = (TFloatFixPt)aSize.iWidth; + TFloatFixPt height = (TFloatFixPt)aSize.iHeight; + TFloatFixPt x = (TFloatFixPt)0; + TFloatFixPt y = (TFloatFixPt)0; + TGfxRectangle2D aClip(x,y,width,height); + iClipMain = iClip; + iClip = aClip; + // TFloatFixPt newY = aSize.iHeight - (TInt)aClip.iHeight - (TInt)aClip.iY; + VGint clipRect[4] = + { + (TInt)aClip.iX, (TInt)aClip.iY, (TInt)aClip.iWidth, (TInt)aClip.iHeight + }; + + // Set VG_SCISSORING to True + iVgRenderer->vgSeti(VG_SCISSORING, VG_TRUE); + + // Set Clippling rectangle + iVgRenderer->vgSetiv(VG_SCISSOR_RECTS, 4, (const TInt*)clipRect); + + } +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetDashArrayL( CArrayFix* aArray ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetDashArrayL( CArrayFix* aArray ) + { + if ( !aArray || !iDashArray ) + { + return; + } + + TInt32 count = aArray->Count(); + + if ( count == 0 ) + { + return; + } + + if ( iDashArray->Count() > 0 ) + { + iDashArray->Reset(); + } + + for ( TInt32 i = 0; i < count; i++ ) + { + iDashArray->AppendL( (VGfloat)aArray->At( i ) ); + } + + if ( count & 0x00000001 ) + { + //count was odd so we need to duplicate the current ones on the array + for (TInt32 i=0; i < count; i++) + { + iDashArray->AppendL( (VGfloat)aArray->At( i ) ); + } + } + + iVgRenderer->vgSetfv(VG_STROKE_DASH_PATTERN, iDashArray->Count(), (VGfloat*)&(*iDashArray)[0] ); + } + +// -------------------------------------------------------------------------- +// TSize CGfx2dGcOpenVG::DeviceBounds() +// --------------------------------------------------------------------------- + TSize CGfx2dGcOpenVG::DeviceBounds() + { + return iColorBufferSize; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetAntialiasingMode( const TInt32 /*aAntialiasingEnable*/) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetAntialiasingMode( const TInt32 aAntialiasingMode ) + { + + // JSR226 has two values for Render Quality + //-------------------------------------------------------------------------------- + // JSR226/M2G Values : TInt Value : OpenVG Constants + //-------------------------------------------------------------------------------- + // RENDERING_QUALITY_LOW : = 1 = : VG_RENDERING_QUALITY_NONANTIALIASED + // RENDERING_QUALITY_HIGH : = 2 = : VG_RENDERING_QUALITY_BETTER + //--------------------------------------------------------------------------------. + + if( aAntialiasingMode == KRenderQualityLow ) // RENDERING_QUALITY_LOW + { + iRenderQuality = VG_RENDERING_QUALITY_NONANTIALIASED ; + } + else if( aAntialiasingMode == KRenderQualityHigh ) // RENDERING_QUALITY_HIGH + { + iRenderQuality = VG_RENDERING_QUALITY_BETTER ; + } + + iVgRenderer->vgSeti(VG_RENDERING_QUALITY, iRenderQuality ); + + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetFont( const CFont* aFont ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetFont( const CFont* aFont ) + { + iFont = (CFont*)aFont; + } +// -------------------------------------------------------------------------- +// CFont* CGfx2dGcOpenVG::Font() +// --------------------------------------------------------------------------- + CFont* CGfx2dGcOpenVG::Font() + { + if (iFont == NULL) + { + iSvgBitmapFontProvider->GetNearestFontToDesignHeightInTwips( iFont, iFontSpec ); + + } + return iFont; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::GetSystemFontScaled(TFloatFixPt aHeight, +// const TDesC& aTypefaceName, +// CFont*& aFont, +// TFontSpec& aFontSpec ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::GetFontScaled( TFloatFixPt /* aHeight */, + const TDesC& /* aTypefaceName */, + CFont*& /* aFont */, + TFontSpec& /* aFontSpec */ ) +{ +} + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetFontSize( const TFloatFixPt aFontSize ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetFontSize( const TFloatFixPt aFontSize ) + { + iFontSize = aFontSize; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetFontWeight( const TInt32 aFontWeight ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetFontWeight( const TInt32 aFontWeight ) + { + iFontWeight = aFontWeight; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetFontStyle( const TInt32 aFontStyle ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetFontStyle( const TInt32 aFontStyle ) + { + iFontStyle = aFontStyle; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetFontFamily( CDesCArrayFlat* aFamilies ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetFontFamily( CDesCArrayFlat* aFamilies ) + { + iFamilies = aFamilies; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetTextanchor( const TInt32 aTextAnchor ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetTextanchor( const TInt32 aTextAnchor ) + { + iTextAnchor = (TGfxTextAnchor)aTextAnchor; + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetTextDecoration( const TInt32 aTextDecoration ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetTextDecoration( const TInt32 aTextDecoration ) + { + iTextDecoration = (TGfxTextDecoration)aTextDecoration; + } +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::GetBBoxForSystemText( TSvgFourPointRect& aFourPointBbox ) +// --------------------------------------------------------------------------- +TGfxRectangle2D CGfx2dGcOpenVG::GetBBoxForSystemText( const TDesC& aText, + TFloatFixPt aX, + TFloatFixPt aY ) +{ + //bbox for bitmap fonts + TGfxRectangle2D lBbox; + TGfxPoint2D pt(aX,aY); + //iScale = GetCurrentScale(); + + //scaled already for bitmap text... + + TInt textAdvance = iFont->TextWidthInPixels( aText ); + TInt fontMaxHeight = iFont->FontMaxHeight(); + TFloatFixPt lascent = iFont->AscentInPixels(); + TFloatFixPt ldescent = TFloatFixPt(fontMaxHeight) - (TFloatFixPt)iFont->AscentInPixels(); + + + lBbox.iWidth = textAdvance; + lBbox.iHeight = fontMaxHeight; + + //need to work in the rotation factor somehow... + //without doing the scaling again + //at this point the bbox already scaled,translated but not rotated + + //should we create 1/scale factor or create with scale factor then get inverse + //iScale scaling factor from the graphics context + TReal32 linverseScale = 1.0/(TReal)iScale; + TGfxAffineTransform lInverseScaleMat = TGfxAffineTransform::GetScaleInstance(linverseScale, linverseScale); + + //this is with scale and rotation + TGfxPoint2D transformedPoint( pt.iX, pt.iY ); + + const TGfxAffineTransform& ctm = iTransform; + ctm.Transform(&pt, &transformedPoint, 1); + + //remove the double scaling effect that we would have + TGfxAffineTransform ctmWithoutScale = iTransform; + ctmWithoutScale.Concatenate(lInverseScaleMat); + + TGfxPoint2D scaledPoint( pt.iX * iScale, pt.iY * iScale ); + + //set up the initial box with just scale in it and not rotation. + // The base line is position at x,y co-ordinate of the text, but + // the bottom of bound box would be further below by amount ldescent. + TGfxPoint2D lTopLeftCorner(scaledPoint.iX, scaledPoint.iY + ldescent ); + TGfxPoint2D lTopRightCorner(scaledPoint.iX + lBbox.iWidth , scaledPoint.iY + ldescent ); + TGfxPoint2D lBottomLeftCorner(scaledPoint.iX, scaledPoint.iY - lascent); + TGfxPoint2D lBottomRightCorner(scaledPoint.iX + lBbox.iWidth, scaledPoint.iY - lascent ); + + TGfxPoint2D lTransTopLeftCorner; + TGfxPoint2D lTransBottomLeftCorner; + TGfxPoint2D lTransTopRightCorner; + TGfxPoint2D lTransBottomRightCorner; + + //applying current rotation transform without the scale. + ctmWithoutScale.Transform(&lTopLeftCorner, &lTransTopLeftCorner,1); + ctmWithoutScale.Transform(&lTopRightCorner, &lTransTopRightCorner,1); + ctmWithoutScale.Transform(&lBottomLeftCorner, &lTransBottomLeftCorner,1); + ctmWithoutScale.Transform(&lBottomRightCorner, &lTransBottomRightCorner,1); + + TFloatFixPt lXTranslation = transformedPoint.iX - lTransTopLeftCorner.iX; + //TFixPt lXTranslation = transformedPoint.iX - iPoint.iX; + + TFloatFixPt lYTranslation = transformedPoint.iY - lTransTopLeftCorner.iY; + //TFixPt lYTranslation = transformedPoint.iY - iPoint.iY; + + // X position is affected by anchor + switch( iTextAnchor ) + { + case EGfxTextAnchorMiddle: + lXTranslation = lXTranslation - ( lBbox.iWidth / TFloatFixPt( 2 ) ); + break; + case EGfxTextAnchorEnd: + lXTranslation = lXTranslation - lBbox.iWidth; + break; + default: + //do nothing + break; + } + + lTransTopLeftCorner.iX += lXTranslation; + lTransTopLeftCorner.iY += lYTranslation; + + lTransTopRightCorner.iX += lXTranslation; + lTransTopRightCorner.iY += lYTranslation; + + lTransBottomLeftCorner.iX += lXTranslation; + lTransBottomLeftCorner.iY += lYTranslation; + + lTransBottomRightCorner.iX += lXTranslation; + lTransBottomRightCorner.iY += lYTranslation; + + //at this point I have the exact path coordinates of the bbox + //aFourPointBbox.SetRectPoints(lTransTopLeftCorner, lTransTopRightCorner, lTransBottomLeftCorner, lTransBottomRightCorner); + return GetTRect(lTransTopLeftCorner, lTransTopRightCorner, lTransBottomLeftCorner, lTransBottomRightCorner); +} + + +TGfxRectangle2D CGfx2dGcOpenVG::GetTRect(TGfxPoint2D lTransTopLeftCorner,TGfxPoint2D lTransTopRightCorner,TGfxPoint2D lTransBottomLeftCorner,TGfxPoint2D lTransBottomRightCorner) +{ + TFloatFixPt lMaxX = lTransTopLeftCorner.iX; + + if (lTransTopRightCorner.iX > lMaxX) + { + lMaxX = lTransTopRightCorner.iX; + } + if (lTransBottomLeftCorner.iX > lMaxX) + { + lMaxX = lTransBottomLeftCorner.iX; + } + if (lTransBottomRightCorner.iX > lMaxX) + { + lMaxX = lTransBottomRightCorner.iX; + } + + TFloatFixPt lMaxY = lTransTopLeftCorner.iY; + + if (lTransTopRightCorner.iY > lMaxY) + { + lMaxY = lTransTopRightCorner.iY; + } + if (lTransBottomLeftCorner.iY > lMaxY) + { + lMaxY = lTransBottomLeftCorner.iY; + } + if (lTransBottomRightCorner.iY > lMaxY) + { + lMaxY = lTransBottomRightCorner.iY; + } + + TFloatFixPt lMinX = lTransTopLeftCorner.iX; + + if (lTransTopRightCorner.iX < lMinX) + { + lMinX = lTransTopRightCorner.iX; + } + if (lTransBottomLeftCorner.iX < lMinX) + { + lMinX = lTransBottomLeftCorner.iX; + } + if (lTransBottomRightCorner.iX < lMinX) + { + lMinX = lTransBottomRightCorner.iX; + } + + TFloatFixPt lMinY = lTransTopLeftCorner.iY; + + if (lTransTopRightCorner.iY < lMinY) + { + lMinY = lTransTopRightCorner.iY; + } + if (lTransBottomLeftCorner.iY < lMinY) + { + lMinY = lTransBottomLeftCorner.iY; + } + if (lTransBottomRightCorner.iY < lMinY) + { + lMinY = lTransBottomRightCorner.iY; + } + TGfxRectangle2D aRect; + aRect.iX = lMinX; + aRect.iY = lMinY; + aRect.iWidth = lMaxX - lMinX; + aRect.iHeight = lMaxY - lMinY; + return aRect; + +} + +// Text Drawing +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::DrawStringL( const TDesC& aDesc, +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::DrawStringL( const TDesC& aDesc, + TFloatFixPt aX, + TFloatFixPt aY, + TInt8 ,// aTextAnchor + TInt8 ,// aTextDecoration + CDesCArrayFlat*, // aFamilies, + TReal aWordSpacing, + TReal aLetterSpacing, + CArrayFix* aArrayRotate, + CArrayFix* aArrayX, + CArrayFix* aArrayY, + TSize& aBoundingBox, + CFont*& aFont, + TFontSpec& /* aFontSpec */ ) + { + + if ( iStrokeColor.GetARGB() == KGfxColorNull && + iFillColor == NULL ) + return; + + if(iFillOpacity == TFloatFixPt(0)) + return; + + if ( aDesc.Length() <= 0 ) + return; + + TPtrC outputText; + if ( *( aDesc.Right( 1 ).Ptr() ) < ' ' ) + outputText.Set( aDesc.Left( aDesc.Length() - 1 ) ); + else + outputText.Set( aDesc ); + + TBool rtl=EFalse; + if(TBidiText::TextDirectionality(outputText) == TBidiText::ERightToLeft) + { + rtl=ETrue; + } + + if ( aFont == NULL ) + { + return; + } + iFont = aFont; + + float aFloat = 0.5; + + //put in .50 for rounding issues 10.99 was going to 10 + // iFontSize has been initialised at the SetGCL time for the + // this specific text element in question. + TInt32 fontsize = (TInt32)( iScale * iFontSize + TFloatFixPt(aFloat) ); + + if ( fontsize == 0 ) + { + return; + } + + + CFont::TMeasureTextOutput myTextOutput; + + TInt textAdvance = iFont->TextWidthInPixels( outputText ); + if ( textAdvance == 0 ) + { + return; + } + TInt fontMaxHeight = iFont->FontMaxHeight() + 2; //Tweak factor needed + TInt fontMaxAscent = iFont->FontMaxAscent() + 1; //Tweak factor needed + TInt fontAscent = iFont->AscentInPixels(); + TInt fontDescent = iFont->DescentInPixels(); + TInt maxDescent = fontMaxHeight-fontMaxAscent; //iFont->FontMaxDescent(); + TInt fontHeightInPixels = iFont->HeightInPixels(); + //added to correct for text clipping that system font has + TInt fontTweakFactor = (TInt)(TFloatFixPt( 1.5f ) * iScale); + TInt fontHorizontalTweakFactor = (TInt)(TFloatFixPt( 5.0f ) * iScale); + TInt numSpaces = myTextOutput.iSpaces; + TInt numChars = myTextOutput.iChars; + TGfxRectangle2D tempRect( aX, + aY, + textAdvance, + fontMaxHeight ); + + /****************************************************************** + * Boundary Check to see if the Text to be drawn is within Bounds. * + ******************************************************************/ + + TGfxAffineTransform tMatrix; + tMatrix = iTransform; + TInt32 transx = tMatrix.TranslateX(); + TInt32 transy = tMatrix.TranslateY(); + TGfxRectangle2D aRect = GetBBoxForSystemText( outputText , aX , aY ); + + TInt32 rectmaxx = aRect.MaxX(); //+ (TFloatFixPt)transx; + TInt32 rectmaxy = aRect.MaxY();//- (TFloatFixPt)fontMaxAscent; //+ (TFloatFixPt)transy; + TInt32 rectminx = aRect.MinX(); //- (TFloatFixPt)transx; + TInt32 rectminy = aRect.MinY();// - (TFloatFixPt)fontMaxHeight;//- (TFloatFixPt)fontMaxAscent; //- (TFloatFixPt)transy; + TInt32 clipminx = iRenderInfo.iClipMinX;// + transx; + TInt32 clipmaxx = iRenderInfo.iClipMaxX;// + transx; + TInt32 clipmaxy = iRenderInfo.iClipMaxY;// + transy; + TInt32 clipminy = iRenderInfo.iClipMinY;// + transy; + + TInt advanceWidth = 0; + TInt advanceX = 0; + TInt excessSpace = 0; + TInt aMultipleXY = 0; + + //Checking for multiple XY values. + if ( aArrayX != NULL && aArrayY != NULL ) + { + if ( ( aArrayX->Count() > 1 ) || ( aArrayY->Count() > 1 ) ) + aMultipleXY = 1; + } + + // setting the boundbox for simple text with no xy and rotate + //this is set here because bound box should get always set as it is used in GetBBoxForSystemText in TextElement. + if ( ( aArrayRotate == NULL ) && + ( aMultipleXY == 0 ) && + ( aLetterSpacing == 0.0 ) && + ( aWordSpacing == 0.0 ) ) + { + aBoundingBox.iWidth = textAdvance; + aBoundingBox.iHeight = fontMaxHeight; + } + + if( rectmaxx < clipminx || rectmaxy < clipminy || + rectminx > clipmaxx || rectminy > clipmaxy ) + return; + + /**************************************************************************** + * Code to Draw Simple Text with only x, y and transform values and return.* + ****************************************************************************/ + + if ( ( aArrayRotate == NULL ) && + ( aMultipleXY == 0 ) && + ( aLetterSpacing == 0.0 ) && + ( aWordSpacing == 0.0 ) ) + { + CFbsBitmap* offScreenBitmap = new ( ELeave ) CFbsBitmap(); + + User::LeaveIfError( offScreenBitmap->Create( TSize( textAdvance, fontMaxHeight), EGray256 ) ); +// User::LeaveIfError( offScreenBitmap->Create( TSize( textAdvance + fontHorizontalTweakFactor, fontMaxHeight + fontTweakFactor ), EGray256 ) ); + CleanupStack::PushL( offScreenBitmap ); + + CGraphicsContext* bitmapContext = NULL; + CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL( offScreenBitmap ); + + CleanupStack::PushL( bitmapDevice ); + User::LeaveIfError( bitmapDevice->CreateContext( bitmapContext ) ); + CleanupStack::PushL( bitmapContext ); + + bitmapContext->SetBrushStyle( CGraphicsContext::ESolidBrush ); + bitmapContext->SetBrushColor( 0x000000 ); + bitmapContext->DrawRect( TRect( TPoint( 0, 0 ), offScreenBitmap->SizeInPixels() ) ); + bitmapContext->UseFont( iFont ); + bitmapContext->SetPenSize( TSize( 1, 1 ) ); + bitmapContext->SetPenColor( 0xFFFFFF ); + bitmapContext->SetPenStyle( CGraphicsContext::ESolidPen ); + bitmapContext->SetBrushStyle( CGraphicsContext::ENullBrush ); + + if (iTextAnchor == EGfxTextAnchorEnd) + { + aX -= TFloatFixPt(textAdvance) / iScale; + } + if (iTextAnchor == EGfxTextAnchorMiddle) + { + aX -= (TFloatFixPt(textAdvance) / iScale) / TFloatFixPt(2); + } + + // While drawing the text which has both arabic & normal left-to-right + // characters the DrawTextExtended should be used since there is no way + // to split the text according to the directionality. + + CGraphicsContext::TDrawTextExtendedParam param; + param.iParRightToLeft = rtl; + bitmapContext->DrawTextExtended(outputText, + TPoint( 0, fontMaxAscent ), param); + + VGint width = offScreenBitmap->SizeInPixels().iWidth; + VGint height = offScreenBitmap->SizeInPixels().iHeight; + + /* The bilinear causes the text to blur a bit, but rotated (& scaled) text will look better, of course */ + VGImage img = iVgRenderer->vgCreateImage( VG_A_8, width, height, VG_IMAGE_QUALITY_NONANTIALIASED ); + //VGImage img = vgCreateImage( VG_A_8, width, height, VG_IMAGE_QUALITY_BETTER ); + //VGImage img = vgCreateImage( VG_A_8, width, height, VG_IMAGE_QUALITY_FASTER ); + + VGPaint paint = iVgRenderer->vgCreatePaint(); + + if( img && paint ) + { + offScreenBitmap->LockHeap(); + + /* OpenVG images have their y-axis flipped, + that is why when calling vgImageSubData we pass the address of offScreenBitmap's last scanline, + and use a negated stride value */ + VGint stride = CFbsBitmap::ScanLineLength( width, EGray256 ); /* EGray256 == offScreenBitmap->DisplayMode() */ + VGbyte *lastScanline = ( (VGbyte*)offScreenBitmap->DataAddress() ) + ( height - 1 ) * stride; + + iVgRenderer->vgImageSubData( img, lastScanline, -stride, VG_A_8, 0, 0, width, height ); + + offScreenBitmap->UnlockHeap(); + + TGfxColor color( iFillColor ? iFillColor->GetColor() : iStrokeColor.GetColor() ); + VGuint argb = color.GetARGB() | ( 0xff000000 ); /* set alpha to 255 */ + VGfloat rgba_f[4]; + + int tr, tg, tb; + + tr = (argb >> 16) & 0xff; + tg = (argb >> 8 ) & 0xff; + tb = (argb ) & 0xff; + + rgba_f[0] = tr / 255.0f; + rgba_f[1] = tg / 255.0f; + rgba_f[2] = tb / 255.0f; + //rgba_f[3] = ( ( argb >> 24 ) & 0xff ) / 255.0f; + rgba_f[3] = 1.0f; /* was set to 255 */ + if( paint != VG_INVALID_HANDLE ) + { + iVgRenderer->vgSetParameteri( paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR ); + iVgRenderer->vgSetParameterfv( paint, VG_PAINT_COLOR, 4, rgba_f ); + iVgRenderer->vgSetPaint( paint, VG_FILL_PATH ); + } + + // Get the current blend mode (set back at end of operation) + const TInt KBlendModeValue = iVgRenderer->vgGeti( VG_BLEND_MODE ); + const TInt KImageModeValue = iVgRenderer->vgGeti( VG_IMAGE_MODE ); + + + iVgRenderer->vgSeti( VG_BLEND_MODE, VG_BLEND_SRC_OVER ); + iVgRenderer->vgSeti( VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY ); + VGfloat mat[9]; + + /* Retreive the Path transformation matrix */ + GetMatrix( mat ); + iVgRenderer->vgSeti( VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE ); + + + iVgRenderer->vgSeti( VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE ); + + /* Since the text rendering has to match AA done by ext, we'll round the transformation. + Seems like Symbian does not have a 32-bit float round... */ + + TReal tx = mat[6], ty = mat[7]; + Math::Round(tx, tx, 0); Math::Round(ty, ty, 0); + + mat[6] = (VGfloat)tx; + mat[7] = (VGfloat)ty; + + /* Load Path transformation matrix to Image transformation matrix */ +/*nga vgLoadMatrix( mat ); + +// TFloatFixPt aY1( aY * iScale ); +// aY -= ( iFont->AscentInPixels()); + //vgTranslate( (VGfloat)aX, (VGfloat)aY + fontTweakFactor); + vgTranslate( (VGfloat)aX, (VGfloat)aY ); + vgScale( 1.0f/(VGfloat)iScale, -1.0f/(VGfloat)iScale ); + vgTranslate( (VGfloat)0, -(VGfloat)maxDescent); + vgDrawImage( img ); + + vgSeti( VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE ); + vgLoadIdentity(); + + vgSeti( VG_IMAGE_MODE, KImageModeValue ); + vgSeti( VG_BLEND_MODE, KBlendModeValue );*/ + iVgRenderer->vgLoadMatrix( mat ); + iVgRenderer->vgTranslate( (VGfloat)aX, (VGfloat)aY ); + iVgRenderer->vgScale( 1.0f/(VGfloat)iScale, -1.0f/(VGfloat)iScale ); + iVgRenderer->vgTranslate( (VGfloat)0, -(VGfloat)maxDescent); + iVgRenderer->vgDrawImage( img ); + + iVgRenderer->vgSeti( VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE ); + iVgRenderer->vgLoadIdentity(); + + iVgRenderer->vgSeti( VG_IMAGE_MODE, KImageModeValue ); + iVgRenderer->vgSeti( VG_BLEND_MODE, KBlendModeValue ); + } + + if( img ) + { + iVgRenderer->vgDestroyImage( img ); + } + if( paint ) + { + iVgRenderer->vgDestroyPaint( paint ); + } + + bitmapContext->DiscardFont(); + + CleanupStack::PopAndDestroy( 3 ); + + if ( iTextDecoration == EGfxTextDecorationUnderLine ) + { + TGfxLine2D aLine( aX, + aY, + (aX + ( TFloatFixPt )textAdvance / iScale ), + aY); //+ ( TFloatFixPt )(2)); + DrawL( &aLine ); + } + else if ( iTextDecoration == EGfxTextDecorationOverLine ) + { + TGfxLine2D aLine( aX, +// aY - ( TFloatFixPt )fontMaxHeight / iScale, + aY, + (aX + ( TFloatFixPt )textAdvance / iScale ), + aY);// - ( TFloatFixPt )fontMaxHeight / iScale ); + DrawL( &aLine ); + } + else if ( iTextDecoration == EGfxTextDecorationLineThrough ) + { + TGfxLine2D aLine( aX , + aY - ( TFloatFixPt )( fontMaxHeight / 2 ) / iScale, + (aX + ( TFloatFixPt )textAdvance /iScale ), + aY - ( TFloatFixPt )( fontMaxHeight / 2 ) / iScale ); + DrawL( &aLine ); + } + + //----------------------------------------------------------------- + return; + } + + + //Check Word/Letter Spacing. + if ( aWordSpacing > 0.0 ) + excessSpace += ( TInt ) + ( aWordSpacing * ( TReal ) iScale ) * numSpaces; + if ( aLetterSpacing > 0.0 ) + excessSpace += ( TInt ) + ( aLetterSpacing * ( TReal ) iScale ) * numChars; + + textAdvance += excessSpace; + + /***************************************************************************** + * Drawing one glyph(character) at a time for multiple XY and rotation Values.* + ******************************************************************************/ + if (rtl) + { + TBidiText* biditext = TBidiText::NewL(outputText,1); + biditext->WrapText(textAdvance,*iFont,0,1); + outputText.Set(biditext->DisplayText()); + delete biditext; + biditext = NULL; + + } + TLex aOutputText( outputText ); + for ( TInt count = 0; count < outputText.Length() ; count++ ) + { + TPtrC outputChar; + TChar ch( aOutputText.Get() ); + outputChar.Set( &( outputText.operator[]( count ) ), 1 ); + + TInt charWidth = iFont->CharWidthInPixels( ch ); + + CFbsBitmap* offScreenBitmap = new ( ELeave ) CFbsBitmap(); + User::LeaveIfError( offScreenBitmap->Create( TSize( charWidth, + fontMaxHeight + fontTweakFactor ), + EColor16MU ) ); + CleanupStack::PushL( offScreenBitmap ); + + CGraphicsContext* bitmapContext = NULL; + CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL( offScreenBitmap ); + + CleanupStack::PushL( bitmapDevice ); + User::LeaveIfError( bitmapDevice->CreateContext( bitmapContext ) ); + CleanupStack::PushL( bitmapContext ); + + TBool isWhite = EFalse; + if ( iFillColor != NULL ) + { + if ( ( ( TGfxColor * ) iFillColor )->GetARGB() == 0xffffff ) + isWhite = ETrue; + } + else + { + if ( iStrokeColor.GetARGB() == 0xffffff ) + isWhite = ETrue; + } + if ( isWhite ) + { + // Fill with black if text color is white + TRect bmprect( 0, 0, charWidth, fontMaxHeight ); + bitmapContext->SetBrushStyle( CGraphicsContext::ESolidBrush ); + bitmapContext->SetBrushColor( 0x000000 ); + bitmapContext->SetPenColor( 0x000000 ); + bitmapContext->DrawRect( bmprect ); + } + + bitmapContext->UseFont( iFont ); + bitmapContext->SetPenSize( TSize( 1, 1 ) ); + if ( iFillColor != NULL ) + { + TGfxColor lColor(iFillColor->GetColor()); + bitmapContext->SetBrushColor( lColor.GetABGR() ); + bitmapContext->SetPenColor( lColor.GetABGR() ); + } + else + { + bitmapContext->SetBrushColor( iStrokeColor.GetABGR() ); + bitmapContext->SetPenColor( iStrokeColor.GetABGR() ); + } + + bitmapContext->SetPenStyle( CGraphicsContext::ESolidPen ); + bitmapContext->SetBrushStyle( CGraphicsContext::ENullBrush ); + + + if ( ( aArrayX != NULL ) && ( count < aArrayX->Count() ) ) + aX = aArrayX->At( count ); + + if ( ( aArrayY != NULL ) && ( count < aArrayY->Count() ) ) + aY = aArrayY->At( count ); + + TFloatFixPt aY1( aY * iScale ), aX1( aX * iScale ); + + TFloatFixPt ScaleAA; + TGfxAffineTransform tempMatrix; + tempMatrix = iTransform; + + ScaleAA = 1; + + #ifdef SVG_FLOAT_BUILD + tempMatrix.Scale( ( TFloatFixPt( 1 ) / ( iScale ) ), + ( TFloatFixPt( 1 ) / ( iScale ) )); + #else + tempMatrix.Scale( ( TFloatFixPt( 0x10000,ETrue ) / ( iScale ) ), + ( TFloatFixPt( 0x10000,ETrue ) / ( iScale ) )); + #endif + + + + if ( aMultipleXY == 1 ) + { + aX1 = aX1 + ( TFloatFixPt ) advanceX; + } + else + aX1 = aX1 + ( TFloatFixPt ) advanceWidth; + + aY1 -= ( iFont->AscentInPixels() ); + + if ( aMultipleXY == 0 ) + { + if ( iTextAnchor == EGfxTextAnchorMiddle ) + { + aX1 -= textAdvance / 2; + } + else if ( iTextAnchor == EGfxTextAnchorEnd ) + { + aX1 -= textAdvance; + } + } + + TGfxPoint2D p( aX1, aY1 ); + + TFloatFixPt trnsx, trnsy; + + trnsx = aX1 ; + trnsy = aY1 + ( TFloatFixPt ) ( (fontMaxHeight / 2) + fontDescent); + + //"rotate" Attribute Implementation + // If only one value is present, it is applied to all the glyphs + //otherwise, one-to-one mapping is taken. Any extra values are ignored! + if ( aArrayRotate != NULL ) + { + if(count < aArrayRotate->Count()) + { + TFloatFixPt KZero; + tempMatrix.Translate( trnsx, trnsy ); + TReal32 aAngle( ( TReal32 ) aArrayRotate->At( count ) ); + tempMatrix.Rotate( aAngle * 3.1415926f / 180.0f ); + TFloatFixPt negX( KZero - trnsx ); + TFloatFixPt negY( KZero - trnsy ); + tempMatrix.Translate( negX, negY ); + } + } + + TGfxImageTransformer imgtrns( &tempMatrix, iVgRenderer); + + + TRect clip(iClip.iX, iClip.iY, + iClip.iWidth + iClip.iX, iClip.iHeight + iClip.iY); + + p.iY -= fontTweakFactor; + imgtrns.ImageBlend( offScreenBitmap, + p, + iRenderInfo.iWidth, + iRenderInfo.iHeight, + clip, + ETrue); + + if (rtl) // IsRightToLeft(outputText) + { + CGraphicsContext::TDrawTextExtendedParam param; + param.iParRightToLeft = ETrue; + + bitmapContext->DrawTextExtended(outputText, + TPoint( 0, fontHeightInPixels - fontDescent + fontTweakFactor ), param); + } + else + { + bitmapContext->DrawText( outputChar, TPoint( 0, fontMaxAscent ) ); +// bitmapContext->DrawText( outputChar, TPoint( 0, fontHeightInPixels - fontDescent + fontTweakFactor )); + } + TGfxRectangle2D textRect(p.iX, p.iY, textAdvance, fontMaxHeight); + + imgtrns.ImageBlend( offScreenBitmap, + p, + iRenderInfo.iWidth, + iRenderInfo.iHeight, + clip); + + bitmapContext->DiscardFont(); + CleanupStack::PopAndDestroy( 3 ); + + if ( aMultipleXY == 0 ) + { + TInt aSpacing = 0; + if ( aLetterSpacing > 0.0 ) + { + if ( ch != 0x0020 ) + aSpacing += ( TInt ) + ( aLetterSpacing * ( TReal ) iScale ) ; + } + if ( aWordSpacing > 0.0 ) + { + if ( ch == 0x0020 ) + aSpacing += ( TInt ) ( aWordSpacing * ( TReal ) iScale ) ; + } + + if ( iStrokeColor.GetARGB() == KGfxColorNull ) + { + if ( iFillColor != NULL ) + this->iStrokeColor = TGfxColor( iFillColor->GetColor() ); + } + + if ( iTextDecoration == EGfxTextDecorationUnderLine ) + { + if ( iTextAnchor == EGfxTextAnchorMiddle ) + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + ( advanceWidth - textAdvance / 2 ) / + iScale), + aY, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing - textAdvance / 2 ) / + iScale ) ) ), + aY ); + DrawL( &aLine ); + } + else if ( iTextAnchor == EGfxTextAnchorEnd ) + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + ( advanceWidth - textAdvance ) / + iScale), + aY, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing - textAdvance ) / + iScale ) ) ), + aY ); + DrawL( &aLine ); + } + else //Start + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + advanceWidth / + iScale), + aY, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing ) / + iScale ) ) ), + aY ); + DrawL( &aLine ); + } + } + if ( iTextDecoration == EGfxTextDecorationOverLine ) + { + if ( iTextAnchor == EGfxTextAnchorMiddle ) + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + ( advanceWidth - textAdvance / 2 ) / + iScale), + aY - + ( TFloatFixPt ) + fontMaxHeight / + iScale, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing - textAdvance / 2 ) / + iScale ) ) ), + aY - + ( TFloatFixPt ) + fontMaxHeight / + iScale ); + DrawL( &aLine ); + } + else if ( iTextAnchor == EGfxTextAnchorEnd ) + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + ( advanceWidth - textAdvance ) / + iScale), + aY - + ( TFloatFixPt ) + fontMaxHeight / + iScale, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing - textAdvance ) / + iScale ) ) ), + aY - + ( TFloatFixPt ) + fontMaxHeight / + iScale ); + DrawL( &aLine ); + } + else //Start + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + advanceWidth / + iScale), + aY - + ( TFloatFixPt ) + fontMaxHeight / + iScale, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing ) / + iScale ) ) ), + aY - + ( TFloatFixPt ) + fontMaxHeight / + iScale ); + DrawL( &aLine ); + } + } + if ( iTextDecoration == EGfxTextDecorationLineThrough ) + { + if ( iTextAnchor == EGfxTextAnchorMiddle ) + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + ( advanceWidth - (textAdvance >> 1) ) / + iScale), + aY - + ( TFloatFixPt ) + ( fontMaxHeight >> 1 ) / + iScale, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing - ( textAdvance >> 1 )) / + iScale ) ) ), + aY - + ( TFloatFixPt ) + ( fontMaxHeight >> 1 ) / + iScale ); + DrawL( &aLine ); + } + else if ( iTextAnchor == EGfxTextAnchorEnd ) + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + ( advanceWidth - textAdvance ) / + iScale), + aY - + ( TFloatFixPt ) + ( fontMaxHeight >> 1 ) / + iScale, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing - textAdvance ) / + iScale ) ) ), + aY - + ( TFloatFixPt ) + ( fontMaxHeight >> 1 ) / + iScale ); + DrawL( &aLine ); + } + else //Start + { + TGfxLine2D aLine( aX + (ScaleAA * + ( TFloatFixPt ) + advanceWidth / + iScale), + aY - + ( TFloatFixPt ) + ( fontMaxHeight >> 1 ) / + iScale, + ( aX + (ScaleAA * ( ( TFloatFixPt ) + ( advanceWidth + charWidth + aSpacing ) / + iScale ) ) ), + aY - + ( TFloatFixPt ) + ( fontMaxHeight >> 1 ) / + iScale ); + DrawL( &aLine ); + } + } + advanceWidth += charWidth + aSpacing; + } + + if ( aMultipleXY == 1 ) + { + if ( count >= aArrayX->Count() - 1 ) + advanceX += charWidth; + } + } //end for(Drawing single glyph) + } + +// Raster image drawing +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::DrawImage( CFbsBitmap* aImage, +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::DrawImage( CFbsBitmap* aImage, + const TGfxRectangle2D& aImageRect, + TBool aHasAlpha ) + { + if ( !aImage ) + return; + + TSize imageSize = aImage->SizeInPixels(); + + aImage->LockHeap(); + VGImage vgImage = CreateVGImage( aImage->DataAddress(), imageSize, aImage->DisplayMode(), EFalse ); + + aImage->UnlockHeap(); + + // Transform to flip drawing to be like screen drawing (from Cartesian) + TGfxAffineTransform flipTransform = TGfxAffineTransform::GetScaleInstance( 1.0f, -1.0f ); + + // Shift x=0 line to top of screen (buffer) + flipTransform.Translate( TFloatFixPt ( 0 ), TFloatFixPt ( -iColorBufferSize.iHeight ) ); + + // Application transformations from element + flipTransform.Concatenate( iTransform ); + + // Set the topleft corner of image to draw + flipTransform.Translate( aImageRect.iX, aImageRect.iY ); + + // Caller to DrawImage already check for image size zero + float scaleX = (VGfloat)( TFloatFixPt ( aImageRect.iWidth ) / TFloatFixPt ( imageSize.iWidth ) ); + float scaleY = (VGfloat)( TFloatFixPt ( aImageRect.iHeight ) / TFloatFixPt ( imageSize.iHeight ) ); + + // Scale to fit image to drawing area + flipTransform.Scale( scaleX, scaleY ); + + VGfloat matrix[] = { (VGfloat)flipTransform.iM00, (VGfloat)flipTransform.iM10, 0, + (VGfloat)flipTransform.iM01, (VGfloat)flipTransform.iM11, 0, + (VGfloat)flipTransform.iM02, (VGfloat)flipTransform.iM12, 1 }; + + iVgRenderer->vgSeti( VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE ); + iVgRenderer->vgLoadMatrix( matrix ); + + // Get current blend-mode + const TInt KBlendMode = iVgRenderer->vgGeti( VG_BLEND_MODE ); + + iVgRenderer->vgSeti( VG_BLEND_MODE, aHasAlpha ? VG_BLEND_SRC_OVER : VG_BLEND_SRC ); + + /* Disable bilinear filtering -> faster, but lower rendering quality */ + iVgRenderer->vgSeti( VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_NONANTIALIASED ); + + iVgRenderer->vgDrawImage( vgImage ); + + iVgRenderer->vgSeti( VG_BLEND_MODE, KBlendMode ); + + iVgRenderer->vgDestroyImage( vgImage ); + } + + +// ========================================================================== +// Clear the whole graphics context with the background color +// ========================================================================== +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::Clear(TUint32 aRGBA8888Color) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::Clear(TUint32 aARGB ) + { + TUint32 rgba = ( aARGB << 8 ) | ( aARGB >> 24 ); + TInt32 r, g, b, a; + r = (TInt)((rgba & 0xFF000000) >> 24); + g = (TInt)((rgba & 0x00FF0000) >> 16); + b = (TInt)((rgba & 0x0000FF00) >> 8); + a = (TInt)( rgba & 0x000000FF); + + r += r >> 7; g += g >> 7; b += b >> 7; a += a >> 7; + + const TFloatFixPt KInverse255 = TFloatFixPt ( 1.0f/256.0f ); + const VGfloat clearColor[4] = { (VGfloat)(KInverse255 * TFloatFixPt (r)), + (VGfloat)(KInverse255 * TFloatFixPt (g)), + (VGfloat)(KInverse255 * TFloatFixPt (b)), + (VGfloat)(KInverse255 * TFloatFixPt (a)) }; + + iVgRenderer->vgSeti( VG_SCISSORING, VG_FALSE ); + iVgRenderer->vgSetfv( VG_CLEAR_COLOR, 4, clearColor ); + iVgRenderer->vgClear( 0, 0, iColorBufferSize.iWidth, iColorBufferSize.iHeight ); + iVgRenderer->vgSeti( VG_SCISSORING, VG_TRUE ); + } + +// ========================================================================== +// This method copies the internal RGBA8888 framebuffer to CfbsBitmap that +// is specified in constructor. The CfbsBitmap could be 4k color (RGB0444), +// 64k color (RGB565), or 16M color (RGB888). +// ========================================================================== +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::UpdateFramebufferL() +// -------------------------------------------------------------------------- +void CGfx2dGcOpenVG::UpdateFramebufferL( CFbsBitmap* aBitmap, CFbsBitmap* aMask) + { + if ( !aBitmap || aBitmap->SizeInPixels() != iColorBufferSize ) + { + return; + } + + const TDisplayMode KBitmapDisplayMode = aBitmap->DisplayMode(); + // This check just before VGISymbianCopyToBitmap avoid putting lot + // many similar error checks in the code. If there is any problem + // during OpenVG call we simply leave without drawing any thing. + VGErrorCode vgret = (VGErrorCode)iVgRenderer->vgGetError(); + + if(vgret != VG_NO_ERROR ) + { + User::LeaveIfError(OpenVGErrorToSymbianError(vgret)); + } + + // EGray2 is not support in VGISymbianCopyToBitmap API + if ( KBitmapDisplayMode == EGray2 ) + { + const TInt KStride = CFbsBitmap::ScanLineLength( iColorBufferSize.iWidth, KBitmapDisplayMode ); + + aBitmap->LockHeap(); + + // Get data address of last line and move upwards (negative stride) + // OpenVG uses Cartesian coordinate system and Symbian uses Screen coordinate system. + TUint* data = (TUint*)((TUint)aBitmap->DataAddress() + ( KStride * ( iColorBufferSize.iHeight - 1 ) ) ); + + iVgRenderer->vgReadPixels( data, -KStride, VG_BW_1, 0, 0, + iColorBufferSize.iWidth, iColorBufferSize.iHeight ); + + aBitmap->UnlockHeap(); + + if ( aMask ) + { + GenerateMask( aMask ); + } + } + // All other color modes + else + { + // No Mask -- to be generated in GenerateMask + TInt error=KErrNone; + + //In cases, where the mask/aMaskBitmap != NULL, the hint should be defined as VGI_SKIP_TRANSPARENT_PIXELS. + //In all other cases, i.e., when mask/aMaskBitmap == NULL, the definition should be VGI_COPY_TRANSPARENT_PIXELS + error = iVgSurface->CopyBitmap(ENone,ENone, aBitmap, aMask, iColorBufferSize); + + if ( error != KErrNone ) + { + #ifdef _DEBUG + RDebug::Printf("VGISymbianCopyToBitmap failed: error code: %d", error ); + RDebug::Printf(" - Color mode: %d", aBitmap->DisplayMode() ); + RDebug::Printf(" - Bitmap size: %dx%d", iColorBufferSize.iWidth, iColorBufferSize.iHeight ); + #endif + User::LeaveIfError(error); + } + + // VGISymbianCopyToBitmap only generates Gray256 mask + if ( aMask && aMask->DisplayMode() == EGray2 ) + { + GenerateMask( aMask ); + } + } + } +//NGA +// --------------------------------------------------------------------------------------------------------------------------------------- +//void UpdateFramebufferL( CFbsBitmap* aBitmap, CFbsBitmap* aMask,TSize BitmapSize,TDisplayMode aBitmapDspMode,TDisplayMode aMaskDspMode ) +// --------------------------------------------------------------------------------------------------------------------------------------- + +void CGfx2dGcOpenVG::UpdateFramebufferL( CFbsBitmap* aBitmap, CFbsBitmap* aMask,TSize /*BitmapSize*/,TDisplayMode aBitmapDspMode,TDisplayMode aMaskDspMode ) + { + if ( !aBitmap) + { + return; + } + + const TDisplayMode KBitmapDisplayMode = aBitmap->DisplayMode(); + // This check just before VGISymbianCopyToBitmap avoid putting lot + // many similar error checks in the code. If there is any problem + // during OpenVG call we simply leave without drawing any thing. + VGErrorCode vgret = (VGErrorCode)iVgRenderer->vgGetError(); + + if(vgret != VG_NO_ERROR ) + { + User::LeaveIfError(OpenVGErrorToSymbianError(vgret)); + } + + // EGray2 is not support in VGISymbianCopyToBitmap API + if ( KBitmapDisplayMode == EGray2 ) + { + const TInt KStride = CFbsBitmap::ScanLineLength( iColorBufferSize.iWidth, KBitmapDisplayMode ); + + aBitmap->LockHeap(); + + // Get data address of last line and move upwards (negative stride) + // OpenVG uses Cartesian coordinate system and Symbian uses Screen coordinate system. + TUint* data = (TUint*)((TUint)aBitmap->DataAddress() + ( KStride * ( iColorBufferSize.iHeight - 1 ) ) ); + + + iVgRenderer->vgReadPixels( data, -KStride, VG_BW_1, 0, 0, + iColorBufferSize.iWidth, iColorBufferSize.iHeight ); + + aBitmap->UnlockHeap(); + + if ( aMask ) + { + GenerateMask( aMask ); + } + } + // All other color modes + else + { + // No Mask -- to be generated in GenerateMask + TInt error=KErrNone; + + //In cases, where the mask/aMaskBitmap != NULL, the hint should be defined as VGI_SKIP_TRANSPARENT_PIXELS. + //In all other cases, i.e., when mask/aMaskBitmap == NULL, the definition should be VGI_COPY_TRANSPARENT_PIXELS + + error = iVgSurface->CopyBitmap(aBitmapDspMode, aMaskDspMode, aBitmap, aMask, iColorBufferSize); + + if ( error != KErrNone ) + { + #ifdef _DEBUG + RDebug::Printf("VGISymbianCopyToBitmap failed: error code: %d", error ); + RDebug::Printf(" - Color mode: %d", aBitmap->DisplayMode() ); + RDebug::Printf(" - Bitmap size: %dx%d", iColorBufferSize.iWidth, iColorBufferSize.iHeight ); + #endif + User::LeaveIfError(error); + } + + // VGISymbianCopyToBitmap only generates Gray256 mask + if ( aMask && aMask->DisplayMode() == EGray2 ) + { + GenerateMask( aMask ); + } + } + } + +// ==================================================================================== +// Blend bitmap with background according to group opacity +// This function gets called with the opacity framebuffer and the group opacity value +// The opacity buffer is initialized with the 0xAA55AA55 value. The pixels not matching +// the initialiazation value are the pixels that have to be blended with the background. +// ==================================================================================== + +// -------------------------------------------------------------------------- +// void CGfx2dGcVGR::BlendWithBackground(TUint32* aFrameBuffer, TReal32 aOpacity) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::BlendWithBackground(TUint32* /* aColorBuffer */, TReal32 /* aOpacity */) + { +/* + if ( !iColorBuffer || !aColorBuffer ) + { + return; + } + + TReal32 inverseAlpha = 1.0f - aOpacity; + const TInt KMax = iColorBufferSize.iWidth * iColorBufferSize.iHeight; + TUint32* dst = iColorBuffer; + TUint32* src = aColorBuffer; + + for ( TInt i = KMax - 1; i >= 0; i-- ) + { + TUint32 srcColor = src[i]; + TUint32 dstColor = dst[i]; + if ( srcColor != dstColor ) + { + dst[i] = ((((TUint)((srcColor >> 24 ) * aOpacity) + + (TUint)((dstColor >> 24 ) * inverseAlpha))) << 24) | // red + ((((TUint)((srcColor >> 16 & 0xff) * aOpacity) + + (TUint)((dstColor >> 16 & 0xff) * inverseAlpha))) << 16) | // green + ((((TUint)((srcColor >> 8 & 0xff) * aOpacity) + + (TUint)((dstColor >> 8 & 0xff) * inverseAlpha))) << 8 ) | // blue + (srcColor & 0x000000FF); // keep orignal alpha + } + } +*/ + } + +// ========================================================================== +// Generate 8 bit gray or 1bit B/W mask from internal ARGB8888 frame buffer. +// ========================================================================== +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::GenerateMask(CFbsBitmap* aMask) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::GenerateMask(CFbsBitmap* aMask) + { + if ( !aMask || aMask->SizeInPixels() != iColorBufferSize ) + { + return; + } + + const TDisplayMode KMaskDisplayMode = aMask->DisplayMode(); + + if ( KMaskDisplayMode != EGray256 && KMaskDisplayMode != EGray2 ) + { + return; + } + + const TInt KOriginalFilterMasks = iVgRenderer->vgGeti( VG_FILTER_CHANNEL_MASK );// + const TInt KStride = CFbsBitmap::ScanLineLength( iColorBufferSize.iWidth, KMaskDisplayMode ); + + // Change to get alpha values from OpenVG + iVgRenderer->vgSeti( VG_FILTER_CHANNEL_MASK, VG_ALPHA ); + + VGImageFormat format = ( KMaskDisplayMode == EGray256 ) ? VG_A_8 : VG_BW_1; + + aMask->LockHeap(); + + // Get data address of last line and move upwards (negative stride) + // OpenVG uses Cartesian coordinate system and Symbian uses Screen coordinate system. + TUint* data = (TUint*)((TUint)aMask->DataAddress() + ( KStride * ( iColorBufferSize.iHeight - 1 ) ) ); + + iVgRenderer->vgReadPixels( data, -KStride, format, 0, 0, + iColorBufferSize.iWidth, iColorBufferSize.iHeight ); + aMask->UnlockHeap(); + + // Set back the original filter-masks + iVgRenderer->vgSeti( VG_FILTER_CHANNEL_MASK, KOriginalFilterMasks ); + } + + +// ========================================================================== +// This function calls the low level function to set fill opacity value +// ========================================================================== + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetFillOpacity(TFloatFixPt aFillOpacity) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetFillOpacity(TFloatFixPt aFillOpacity) + { + iFillOpacity = aFillOpacity; + } +// ========================================================================== +// This function calls the low level function to set stroke opacity value +// ========================================================================== + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetStrokeOpacity(TFloatFixPt aStrokeOpacity) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetStrokeOpacity(TFloatFixPt aStrokeOpacity) + { + iStrokeOpacity = aStrokeOpacity; + } +// ========================================================================== +// This function is called to set the dithering flag +// ========================================================================== + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::SetDoDithering( TBool aDoDithering ) +// --------------------------------------------------------------------------- + void CGfx2dGcOpenVG::SetDoDithering( TBool /*aDoDithering*/ ) + { + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::ApplyTransform +// --------------------------------------------------------------------------- +void CGfx2dGcOpenVG::ApplyTransform( TGfxAffineTransform& aAffineTransform ) + { + iVgRenderer->vgSeti( VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE ); + + TUint transformType = aAffineTransform.iTransType; + + // Only translation is applied + if ( transformType == KTransformTranslate ) + { + iVgRenderer->vgLoadIdentity(); + iVgRenderer->vgScale( 1.0f, -1.0f ); + iVgRenderer->vgTranslate( (VGfloat)aAffineTransform.iM02, + (VGfloat)(TFloatFixPt (-iColorBufferSize.iHeight) + aAffineTransform.iM12 ) ); + } + // General case: Rotate and/or scaling, translation + else + { + TGfxAffineTransform flipTransform = TGfxAffineTransform::GetScaleInstance( 1.0f, -1.0f ); + flipTransform.Translate( TFloatFixPt ( 0 ), TFloatFixPt ( -iColorBufferSize.iHeight ) ); + flipTransform.Concatenate( aAffineTransform ); + + VGfloat matrix[] = { (VGfloat)flipTransform.iM00, (VGfloat)flipTransform.iM10, 0, + (VGfloat)flipTransform.iM01, (VGfloat)flipTransform.iM11, 0, + (VGfloat)flipTransform.iM02, (VGfloat)flipTransform.iM12, 1 }; + iVgRenderer->vgLoadMatrix( matrix ); + } + } + void CGfx2dGcOpenVG::ApplyTransformMediaElement( const TGfxAffineTransform& aAffineTransform,TSize& /*aSize*/ ) + { + iVgRenderer->vgSeti( VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE ); + + // TUint transformType = aAffineTransform.iTransType; + + // Only translation is applied + /* if ( transformType == KTransformTranslate ) + { + vgLoadIdentity(); + vgScale( 1.0f, -1.0f ); + vgTranslate( (VGfloat)aAffineTransform.iM02, + (VGfloat)(TFloatFixPt (-iColorBufferSize.iHeight) + aAffineTransform.iM12 ) ); + } + // General case: Rotate and/or scaling, translation + else + { + TGfxAffineTransform flipTransform = TGfxAffineTransform::GetScaleInstance( 1.0f, -1.0f ); + flipTransform.Translate( TFloatFixPt ( 0 ), TFloatFixPt ( -iColorBufferSize.iHeight ) ); + flipTransform.Concatenate( aAffineTransform ); + + VGfloat matrix[] = { (VGfloat)flipTransform.iM00, (VGfloat)flipTransform.iM10, 0, + (VGfloat)flipTransform.iM01, (VGfloat)flipTransform.iM11, 0, + (VGfloat)flipTransform.iM02, (VGfloat)flipTransform.iM12, 1 }; + vgLoadMatrix( matrix ); + }*/ + TGfxAffineTransform flipTransform = TGfxAffineTransform::GetScaleInstance( 1.0f, -1.0f ); + flipTransform.Translate( TFloatFixPt ( 0 ), TFloatFixPt ( -iColorBufferSize.iHeight ) ); + //flipTransform.Concatenate( aAffineTransform ); + TGfxAffineTransform flipTransformTemp = aAffineTransform; + flipTransformTemp.Concatenate( flipTransform ); + flipTransform.Concatenate( flipTransformTemp ); + + + VGfloat matrix[] = { (VGfloat)flipTransform.iM00, (VGfloat)flipTransform.iM10, 0, + (VGfloat)flipTransform.iM01, (VGfloat)flipTransform.iM11, 0, + (VGfloat)flipTransform.iM02, (VGfloat)flipTransform.iM12, 1 }; + iVgRenderer->vgLoadMatrix( matrix ); + } + +VGImage CGfx2dGcOpenVG::CreateVGImage( void* aBuffer, TSize aSize, TDisplayMode aDisplayMode, TBool aPreMultiplied ) + { + VGImage vgImage = VGImage( -1 ); + + if ( aBuffer ) + { + VGint stride = CFbsBitmap::ScanLineLength( aSize.iWidth, aDisplayMode ); + + if ( aDisplayMode == EColor64K ) + { + vgImage = iVgRenderer->vgCreateImage( VG_sRGB_565, aSize.iWidth, aSize.iHeight, VG_IMAGE_QUALITY_FASTER ); + iVgRenderer->vgImageSubData( vgImage, aBuffer, stride, VG_sRGB_565, + 0, 0, aSize.iWidth, aSize.iHeight ); + } + else if ( aDisplayMode == EColor16MU ) + { + VGImageFormat format = aPreMultiplied ? VG_sRGBA_8888_PRE :VG_sRGBA_8888; + vgImage = iVgRenderer->vgCreateImage( format, aSize.iWidth, aSize.iHeight, VG_IMAGE_QUALITY_FASTER ); + iVgRenderer->vgImageSubData( vgImage, aBuffer, stride, format, + 0, 0, aSize.iWidth, aSize.iHeight ); + } + else + { + #ifdef _DEBUG + RDebug::Printf("SVGT CreateVGImage:: Color Mode not supported: %d ", aDisplayMode ); + #endif + } + } + + return vgImage; + } + + void CGfx2dGcOpenVG::BindToImageL() + { + TUint32* buffer = NULL; + buffer = new (ELeave) TUint32[ iColorBufferSize.iWidth * iColorBufferSize.iHeight ] ; + + iVgSurface->PrepareToBindClientBuffer(); + //VGImage vgImage = CreateVGImage( buffer, iColorBufferSize, EColor16MU, ETrue ); + VGImage vgImage = iVgRenderer->vgCreateImage( VG_sRGBA_8888_PRE,iColorBufferSize.iWidth, iColorBufferSize.iHeight, VG_IMAGE_QUALITY_FASTER ); + //Clear VGImage + VGfloat color[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; + iVgRenderer->vgSetfv(VG_CLEAR_COLOR, 4, color); +iVgRenderer->vgClearImage(vgImage,0,0,iColorBufferSize.iWidth,iColorBufferSize.iHeight); + //Clear VGImage + TInt error = iVgSurface->BindClientBuffer( vgImage ); + if ( error != KErrNone ) + { + #ifdef _DEBUG + RDebug::Printf("SVGT CGfx2dGcOpenVG::BindToImageL--VGISymbianBindToImageL failed: %d", error); + #endif + + iVgRenderer->vgDestroyImage(vgImage) ; + // Delete color-buffer to match count with vgImage + delete[] buffer; + + if( error == KErrNoMemory ) + { + // Need to reset values at our side as OpenVG calls VGISymbianTerminate. + ResetContextHandle(); + } + + User::Leave(error); + } + + iGroupOpacityBuffers.Append( buffer ); + iGroupOpacityImages.Append( vgImage ); + + iVgRenderer->vgLoadIdentity(); + } + + + void CGfx2dGcOpenVG::BindToMediaImageL(TInt aWidth, TInt aHeight) + { + TUint32* buffer = NULL; + buffer = new (ELeave) TUint32[ iColorBufferSize.iWidth * iColorBufferSize.iHeight ]; + + iVgSurface->PrepareToBindClientBuffer(); + VGImage vgImage = CreateVGImage( buffer, iColorBufferSize, EColor16MU, ETrue ); + VGfloat color[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; + iVgRenderer->vgSetfv(VG_CLEAR_COLOR, 4, color); + iVgRenderer->vgClearImage(vgImage,0,0,iColorBufferSize.iWidth,iColorBufferSize.iHeight); + //vgClearImage(vgImage,0,0,aWidth,aHeight); + TInt error = iVgSurface->BindClientBuffer( vgImage ); + if ( error != KErrNone ) + { + #ifdef _DEBUG + RDebug::Printf("SVGT CGfx2dGcOpenVG::BindToImage--VGISymbianBindToImage failed: %d", error); + #endif + + iVgRenderer->vgDestroyImage(vgImage) ; + // Delete color-buffer to match count with vgImage + delete[] buffer; + + if( error == KErrNoMemory ) + { + // Need to reset values at our side as OpenVG calls VGISymbianTerminate. + ResetContextHandle(); + } + + User::Leave(error); + } + + iGroupOpacityBuffers.Append( buffer ); + iGroupOpacityImages.Append( vgImage ); + iVgRenderer->vgLoadIdentity(); + + TGfxRectangle2D aClip(0,0,aWidth,aHeight); + iClipMain = iClip; + SetClip(aClip); + } + + void CGfx2dGcOpenVG::UnbindFromImageL( TReal32 aOpacity ) + { + if ( iGroupOpacityImages.Count() == 0 ) + { + return; + } + + TInt error = iVgSurface->UnBindClientBuffer(); + if ( error != KErrNone ) + { + #ifdef _DEBUG + RDebug::Printf("SVGT CGfx2dGcOpenVG::UnbindFromImage--VGISymbianUnBindImage failed: %d", error); + #endif + + if( error == KErrNoMemory ) + { + // Need to reset values at our side as OpenVG calls VGITerminate. + ResetContextHandle(); + } + User::LeaveIfError(error); + } + + // Need to bind to previous level image + // Else VGISymbianUnBindImage binds to non-image + if ( iGroupOpacityImages.Count() > 1 ) + { + iVgSurface->PrepareToBindClientBuffer(); + TInt error = iVgSurface->BindClientBuffer( iGroupOpacityImages[iGroupOpacityImages.Count()-2] ); + if ( error != KErrNone ) + { + #ifdef _DEBUG + RDebug::Printf("SVGT CGfx2dGcOpenVG::UnbindFromImage--VGISymbianBindToImage failed: %d", error); + #endif + + iVgSurface->UnBindClientBuffer(); + + // Remove and Destroy all the previous images and buffer + TInt iIndex = iGroupOpacityImages.Count()-1; + for( ;iIndex >= 0 ; iIndex-- ) + { + iVgRenderer->vgDestroyImage( iGroupOpacityImages[ iIndex ] ); + iGroupOpacityImages.Remove( iIndex ); + } + + iIndex = iGroupOpacityBuffers.Count()-1; + for( ;iIndex >= 0 ; iIndex-- ) + { + delete [] iGroupOpacityBuffers[ iIndex ]; + iGroupOpacityBuffers.Remove( iIndex ); + } + + if( error == KErrNoMemory ) + { + // Need to reset values at our side as OpenVG calls VGISymbianTerminate. + ResetContextHandle(); + } + + User::LeaveIfError(error); + } + } + + // Check if default fill paint needs to be created + if ( iFillPaint == VG_INVALID_HANDLE ) + { + iFillPaint = iVgRenderer->vgCreatePaint(); + } + + // Check if default stroke paint needs to be created + if ( iStrokePaint == VG_INVALID_HANDLE ) + { + iStrokePaint = iVgRenderer->vgCreatePaint(); + } + + VGfloat opaquePaint[] = { 1.0f, 1.0f, 1.0f, aOpacity }; + + // Create paint object + VGPaint paint = iVgRenderer->vgCreatePaint(); + + if ( paint != VG_INVALID_HANDLE ) + { + + // Set solid paint of opacity + iVgRenderer->vgSetParameteri( paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + iVgRenderer->vgSetParameterfv( paint, VG_PAINT_COLOR, 4, opaquePaint); + iVgRenderer->vgSetPaint( paint, VG_FILL_PATH | VG_STROKE_PATH ); + + // Set image mode to multiply + iVgRenderer->vgSeti( VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY ); + + // Draw opacity image + iVgRenderer->vgSeti( VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE ); + iVgRenderer->vgLoadIdentity(); + iVgRenderer->vgDrawImage( iGroupOpacityImages[iGroupOpacityImages.Count()-1] ); + + // Reset the image draw mode + iVgRenderer->vgSeti( VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL ); + + // Restore the fill and paint + if ( iFillPaint != VG_INVALID_HANDLE ) + { + iVgRenderer->vgSetPaint( iFillPaint, VG_FILL_PATH ); + } + + if ( iStrokePaint != VG_INVALID_HANDLE ) + { + iVgRenderer->vgSetPaint( iStrokePaint, VG_STROKE_PATH ); + } + + iVgRenderer->vgDestroyPaint( paint ); + } + else + { + VGErrorCode error = (VGErrorCode)iVgRenderer->vgGetError(); + if (error == VG_OUT_OF_MEMORY_ERROR) + { + RDebug::Printf("SVGT CGfx2dGcOpenVG::UnbindFromImage vgCreatePaint OOM"); + // Remove and Destroy all the previous images and buffer + TInt iIndex = iGroupOpacityImages.Count()-1; + for( ;iIndex >= 0 ; iIndex-- ) + { + iVgRenderer->vgDestroyImage( iGroupOpacityImages[ iIndex ] ); + iGroupOpacityImages.Remove( iIndex ); + } + + iIndex = iGroupOpacityBuffers.Count()-1; + for( ;iIndex >= 0 ; iIndex-- ) + { + delete [] iGroupOpacityBuffers[ iIndex ]; + iGroupOpacityBuffers.Remove( iIndex ); + } + ResetContextHandle(); + User::Leave(KErrNoMemory); + } + #ifdef _DEBUG + RDebug::Printf("SVGT CGfx2dGcOpenVG::UnbindFromImage vgCreatePaint failed"); + #endif + } + + // Remove/Delete OpenVG Image object + TInt imageIndex = iGroupOpacityImages.Count() - 1; + if ( imageIndex >= 0 ) + { + iVgRenderer->vgDestroyImage( iGroupOpacityImages[ imageIndex ] ); + iGroupOpacityImages.Remove( imageIndex ); + } + + // Remove/Delete color-buffer + TInt bufferIndex = iGroupOpacityBuffers.Count() - 1; + if ( bufferIndex >= 0 ) + { + delete [] iGroupOpacityBuffers[ bufferIndex ]; + iGroupOpacityBuffers.Remove( bufferIndex ); + } + + } + +// -------------------------------------------------------------------------- +// void CGfx2dGcOpenVG::UnbindFromMediaImageL( +// const TGfxAffineTransform& aAffineTransform, +// TReal32 aOpacity, +// TInt aWidth, +// TInt aHeight ) +// --------------------------------------------------------------------------- +void CGfx2dGcOpenVG::UnbindFromMediaImageL( + const TGfxAffineTransform& aAffineTransform, + TReal32 aOpacity, + TInt aWidth, + TInt aHeight, TInt aDraw ) + { + if ( iGroupOpacityImages.Count() == 0 ) + { + return; + } + + TInt error = iVgSurface->UnBindClientBuffer(); + if ( error != KErrNone ) + { + #ifdef _DEBUG + RDebug::Printf( "SVGT CGfx2dGcOpenVG::UnbindFromMediaImage--VGISymbianUnBindImage failed: %d", error); + #endif + if( error == KErrNoMemory ) + { + // Need to reset values at our side as OpenVG calls + // VGITerminate. + ResetContextHandle(); + } + User::LeaveIfError(error); + } + + // Restore the clipping window back to main window + SetClip(iClipMain); + + // Need to bind to previous level image + // Else VGISymbianUnBindImage binds to non-image + if ( iGroupOpacityImages.Count() > 1 ) + { + iVgSurface->PrepareToBindClientBuffer(); + TInt error = iVgSurface->BindClientBuffer( iGroupOpacityImages[iGroupOpacityImages.Count()-2] ); + if ( error != KErrNone ) + { + #ifdef _DEBUG + RDebug::Printf("SVGT CGfx2dGcOpenVG::UnbindFromMediaImage--VGISymbianBindToImage failed: %d", error); + #endif + + iVgSurface->UnBindClientBuffer(); + + // Remove and Destroy all the previous images and buffer + TInt iIndex = iGroupOpacityImages.Count()-1; + for( ;iIndex >= 0 ; iIndex-- ) + { + iVgRenderer->vgDestroyImage( iGroupOpacityImages[ iIndex ] ); + iGroupOpacityImages.Remove( iIndex ); + } + + iIndex = iGroupOpacityBuffers.Count()-1; + for( ;iIndex >= 0 ; iIndex-- ) + { + delete [] iGroupOpacityBuffers[ iIndex ]; + iGroupOpacityBuffers.Remove( iIndex ); + } + + // Destroy the Previous two Opacity buffer + if( error == KErrNoMemory ) + { + // Need to reset values at our side as OpenVG calls VGISymbianTerminate. + ResetContextHandle(); + } + + User::LeaveIfError(error); + } + } + + // Create opaque paint + VGfloat opaquePaint[] = { 1.0f, 1.0f, 1.0f, aOpacity }; + + // Check if default fill paint needs to be created + if ( iFillPaint == VG_INVALID_HANDLE ) + { + iFillPaint = iVgRenderer->vgCreatePaint(); + } + + // Check if default stroke paint needs to be created + if ( iStrokePaint == VG_INVALID_HANDLE ) + { + iStrokePaint = iVgRenderer->vgCreatePaint(); + } + + // Create paint object + VGPaint paint = iVgRenderer->vgCreatePaint(); + + if ( paint != VG_INVALID_HANDLE ) + { + // Set solid paint of opacity + iVgRenderer->vgSetParameteri( paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + iVgRenderer->vgSetParameterfv( paint, VG_PAINT_COLOR, 4, opaquePaint); + iVgRenderer->vgSetPaint( paint, VG_FILL_PATH | VG_STROKE_PATH ); + + // Set image mode to normal + iVgRenderer->vgSeti( VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL ); + + // Draw the animation element with transforms applied on the + // main colour buffer + TSize size(aWidth,aHeight); + ApplyTransformMediaElement(aAffineTransform,size); + + // Check so that animation element is drawn only when animation has started + if ( aDraw == KMediaAnimationVisible ) + { + iVgRenderer->vgDrawImage( iGroupOpacityImages[iGroupOpacityImages.Count()-1] ); + } + + + // Restore the fill and paint + if ( iFillPaint != VG_INVALID_HANDLE ) + { + iVgRenderer->vgSetPaint( iFillPaint, VG_FILL_PATH ); + } + + if ( iStrokePaint != VG_INVALID_HANDLE ) + { + iVgRenderer->vgSetPaint( iStrokePaint, VG_STROKE_PATH ); + } + + iVgRenderer->vgDestroyPaint( paint ); + } + else + { + VGErrorCode error = (VGErrorCode)iVgRenderer->vgGetError(); + if (error == VG_OUT_OF_MEMORY_ERROR) + { + RDebug::Printf("SVGT CGfx2dGcOpenVG::UnbindFromMediaImage vgCreatePaint OOM"); + // Remove and Destroy all the previous images and buffer + TInt iIndex = iGroupOpacityImages.Count()-1; + for( ;iIndex >= 0 ; iIndex-- ) + { + iVgRenderer->vgDestroyImage( iGroupOpacityImages[ iIndex ] ); + iGroupOpacityImages.Remove( iIndex ); + } + + iIndex = iGroupOpacityBuffers.Count()-1; + for( ;iIndex >= 0 ; iIndex-- ) + { + delete [] iGroupOpacityBuffers[ iIndex ]; + iGroupOpacityBuffers.Remove( iIndex ); + } + ResetContextHandle(); + User::Leave(KErrNoMemory); + } + #ifdef _DEBUG + RDebug::Printf("SVGT CGfx2dGcOpenVG::UnbindFromMediaImage vgCreatePaint failed"); + #endif + } + // Remove/Delete OpenVG Image object + TInt imageIndex = iGroupOpacityImages.Count() - 1; + if ( imageIndex >= 0 ) + { + iVgRenderer->vgDestroyImage( iGroupOpacityImages[ imageIndex ] ); + iGroupOpacityImages.Remove( imageIndex ); + } + + // Remove/Delete color-buffer + TInt bufferIndex = iGroupOpacityBuffers.Count() - 1; + if ( bufferIndex >= 0 ) + { + delete [] iGroupOpacityBuffers[ bufferIndex ]; + iGroupOpacityBuffers.Remove( bufferIndex ); + } + + } +// These are for work-around for OpenVG to simulate multiple contexts +void CGfx2dGcOpenVG::SetupContextL() +{ + // Ensure OpenVG is initialized: could have been terminated by another Svg engine + // Returns immediately if already initialized + TInt err = iVgSurface->InitializeSurface( iColorBufferSize, VGI_COLORSPACE_SRGB ); + if (!((err == KErrNone) || (err == KErrAlreadyExists))) + { + #ifdef _DEBUG + RDebug::Printf("SVG can't initialize OpenVG Context %d", err); + #endif + iGraphicsContextCreated = EFalse; + User::Leave(err); + } + + iGraphicsContextCreated = ETrue; + // Ensure context size is correct: could have been change by another Svg engine + // Returns immediately if size is the same + + err = iVgSurface->ResizeSurface( iColorBufferSize ); + + if( err != KErrNone ) + { + if(err == KErrNoMemory ) + { + #ifdef _DEBUG + RDebug::Printf("OpenVG Context destroyed %d", err); + #endif //_DEBUG + // This indicates that OpenVG has destroyed the current context handle + // and also the Path, StrokePaint and FillPaint handles are no more valid. + // Thus reinitialize them to 0, so that they can be recreated. + ResetContextHandle(); + } + + #ifdef _DEBUG + RDebug::Printf("SVG can't RESIZE OpenVG Context %d", err); + #endif //_DEBUG + User::Leave(err); + } +} + +void CGfx2dGcOpenVG::Flush() + { + if (iCurrentRendererType == ESVGRendererTLV) + { + iPath = VG_INVALID_HANDLE; + iFillPaint = VG_INVALID_HANDLE; + iStrokePaint = VG_INVALID_HANDLE; + } + + iVgRenderer->vgFlush(); + } +/** +* Sets the Paint,Stroke and Path handle back to VG_INVALID_HANDLE +* +* @since +* @return void +*/ +void CGfx2dGcOpenVG::ResetContextHandle() + { + iPath = VG_INVALID_HANDLE; + iFillPaint = VG_INVALID_HANDLE; + iStrokePaint = VG_INVALID_HANDLE; + iGraphicsContextCreated = EFalse; + } + +void CGfx2dGcOpenVG::GetMatrix(TReal32 * m) + { + //Below is the replacement for vgGetMatrix + TGfxAffineTransform flipTransform; + if ( iTransform.iTransType == KTransformTranslate ) + { + + flipTransform = TGfxAffineTransform::GetScaleInstance( 1.0f, -1.0f );//get and identity matrix and scale the x,y axis to (1,-1) + flipTransform.Translate((VGfloat)iTransform.iM02, (VGfloat)(TFloatFixPt (-iColorBufferSize.iHeight) + iTransform.iM12 ) ); + + m[0] = (VGfloat)flipTransform.iM00; + m[1] = (VGfloat)flipTransform.iM10; + m[2] = 0; + m[3] = (VGfloat)flipTransform.iM01; + m[4] = (VGfloat)flipTransform.iM11; + m[5] = 0; + m[6] = (VGfloat)flipTransform.iM02; + m[7] = (VGfloat)flipTransform.iM12; + m[8] = 1; + + } + // General case: Rotate and/or scaling, translation + else + { + flipTransform = TGfxAffineTransform::GetScaleInstance( 1.0f, -1.0f ); + flipTransform.Translate( TFloatFixPt ( 0 ), TFloatFixPt ( -iColorBufferSize.iHeight ) ); + flipTransform.Concatenate( iTransform ); + + m[0] = (VGfloat)flipTransform.iM00; + m[1] = (VGfloat)flipTransform.iM10; + m[2] = 0; + m[3] = (VGfloat)flipTransform.iM01; + m[4] = (VGfloat)flipTransform.iM11; + m[5] = 0; + m[6] = (VGfloat)flipTransform.iM02; + m[7] = (VGfloat)flipTransform.iM12; + m[8] = 1; + + } + + } + +void CGfx2dGcOpenVG::SetBitmapHeader(const TDesC* aHeaderData) + { + iVgSurface->SetConfiguration(CVGSurface::BTIMAP_HEADER, aHeaderData); + } + +const TPtrC8 CGfx2dGcOpenVG::TLVEncodedData() const + { + return(iVgRenderer->TLVEncodedData()); + }