uigraphics/AknIcon/SvgtFbsRasterizer/src/SvgtFbsRasterizer.cpp
changeset 0 05e9090e2422
child 1 ba33815114d6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uigraphics/AknIcon/SvgtFbsRasterizer/src/SvgtFbsRasterizer.cpp	Thu Dec 17 09:14:12 2009 +0200
@@ -0,0 +1,675 @@
+/*
+* 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:    CSvgtFbsRasterizer implementation.
+*
+*/
+
+#include "svgtfbsrasterizer.h"
+#include "fbsrasterizerpanics.h"
+#include "SvgtRegisteredBitmap.h"
+#include "svgtgraphicsinterface.h"
+#include <e32std.h>
+#include <nvg.h>
+#include <AknIconHeader.h>
+#include <AknIconUtils.h>
+#include <vgcontext.h>
+
+#include <bitstd.h>
+#include <bitdev.h>
+
+TBool operator==(const CFbsRasterizer::TBitmapDesc& aBitmapDesc1, 
+				 const CFbsRasterizer::TBitmapDesc& aBitmapDesc2)
+	{
+	return ((&aBitmapDesc1 == &aBitmapDesc2)
+			|| (aBitmapDesc1.iSizeInPixels == aBitmapDesc2.iSizeInPixels
+				&& aBitmapDesc1.iDispMode == aBitmapDesc2.iDispMode
+				&& aBitmapDesc1.iDataType == aBitmapDesc2.iDataType
+				&& aBitmapDesc1.iData == aBitmapDesc2.iData
+				&& aBitmapDesc1.iDataSize == aBitmapDesc2.iDataSize));	
+	}
+
+void CleanupVGImage( TAny* aObj )
+    {
+    VGImage * imageToDestroy = reinterpret_cast<VGImage *>(aObj); 
+    if (imageToDestroy && *imageToDestroy != VG_INVALID_HANDLE)
+        {
+        vgDestroyImage(*imageToDestroy);
+        }
+    }
+
+/** Create a new rasterizer.
+@return A pointer to a newly constructed CFbsRasterizer object if successful,
+or NULL if no memory is available.
+ */
+EXPORT_C CFbsRasterizer* CSvgtFbsRasterizer::New()
+	{
+	CSvgtFbsRasterizer* self = new CSvgtFbsRasterizer;
+	if ( self )
+	    {
+	    self->InitializeRasterizer();
+	    }
+	return self;
+	}
+
+/** Constructor */
+CSvgtFbsRasterizer::CSvgtFbsRasterizer()
+    :iRegisteredBmps(_FOFF(CSvgtRegisteredBitmap, iLink)), iRecentBmps(_FOFF(CSvgtRegisteredBitmap, iLink))
+	{
+	    RProcess currentProcess;
+	    TFileName exeFileName = currentProcess.FileName();
+	    exeFileName.Copy(exeFileName.Mid(11));
+	    exeFileName.Copy(exeFileName.Left(exeFileName.Length()-4));
+	    
+	    if(exeFileName.Compare(_L("peninputserver"))==0)
+	        {
+	        iCacheLimit = 0x133333;
+	        iSpecialProcess = TRUE;	        
+	        }
+	    else
+	        {
+	        iCacheLimit = KMaxRecentBmpCacheSize;
+	        iSpecialProcess = FALSE;            
+	        }
+	}
+
+CSvgtFbsRasterizer::~CSvgtFbsRasterizer()
+    {
+    while (!iRegisteredBmps.IsEmpty())
+        {
+        delete iRegisteredBmps.First();
+        }
+    while (!iRecentBmps.IsEmpty())
+        {
+        delete iRecentBmps.First();
+        }
+    delete iIdle;
+    
+    delete iNvgEngine;
+    delete iGraphicsInterface;
+    if ( iMatricesUpdated )
+        {
+        RestoreMatrices();
+        }
+    }
+
+/** Register a bitmap with this rasterizer for rendering. In this example the extended 
+bitmap data is just a buffer that is copied when BeginBitmap() is called and deleted when
+EndBitmap() is called for the same bitmap. The only display modes supported by this example
+raterizer are EColor16MU and EColor16MA
+*/
+void CSvgtFbsRasterizer::BeginBitmap(TInt64 aBitmapId, const TBitmapDesc& aBitmapDesc, const TRegion* aRegionOfInterest)
+	{
+	TRAPD(beginErr, DoBeginBitmapL(aBitmapId, aBitmapDesc, aRegionOfInterest));
+	// If there is error in begin, the consecutive fulction calls should be invalid.
+	iIsRasterizerValidState = ( beginErr == KErrNone); 
+	}
+
+void CSvgtFbsRasterizer::DoBeginBitmapL(TInt64 aBitmapId, const TBitmapDesc& aBitmapDesc,
+        const TRegion* /* aRegionOfInterest */)
+    {
+    // Check that the passed extended bitmap description is valid
+    if ((aBitmapDesc.iSizeInPixels.iWidth <= 0) || (aBitmapDesc.iSizeInPixels.iHeight <= 0)
+            || (aBitmapDesc.iDataType != KUidNvgProprietaryFormat)
+            || (!aBitmapDesc.iData )
+            || (aBitmapDesc.iDataSize <= 0))
+        {
+        return;
+        }
+    // Check if the bitmap is already registered
+    CSvgtRegisteredBitmap* foundRegBmp = RegisteredBitmap(aBitmapId);
+    if (!foundRegBmp)
+        {
+        // Not registered: check if the bitmap is in the cache of recently used bitmaps
+        foundRegBmp = RecentBitmap(aBitmapId);
+        if (foundRegBmp)
+            {
+            // Take the bitmap out of the cache and put it in the list of registered bitmaps
+            foundRegBmp->iLink.Deque();
+            iTotalRecentBmpSize -= foundRegBmp->DataSize();
+            iRegisteredBmps.AddLast(*foundRegBmp);
+            }
+        }
+    if (foundRegBmp)
+        {
+        // This bitmap is already registered, just increment its reference count and return
+        foundRegBmp->iRefCount++;
+        return;
+        }
+    
+    CSvgtRegisteredBitmap* regBmp = new CSvgtRegisteredBitmap(aBitmapId);
+    if (!regBmp)
+        {
+        return;
+        }
+    TRAPD(err, RenderL(aBitmapDesc, *regBmp));
+    if (err != KErrNone)
+        {
+        delete regBmp;
+        return;
+        }
+    // Success
+    iRegisteredBmps.AddLast(*regBmp);
+    regBmp->iRefCount = 1;
+    }
+
+/** Unregister an extended bitmap from this rasterizer. 
+@see CFbsRasterizer::EndBitmap()
+@see BeginBitmap()
+ */
+void CSvgtFbsRasterizer::EndBitmap(TInt64 aBitmapId)
+	{
+	CSvgtRegisteredBitmap* regBmp = RegisteredBitmap(aBitmapId);
+	    if (regBmp)
+	        {
+	        if (--regBmp->iRefCount == 0)
+	            {
+	            // Put unregistered bitmap in the cache of recently used bitmaps if wholly pre-rendered
+	            // and there is an active scheduler to add the idle-time clean-up active object to
+	            if (CActiveScheduler::Current())
+	                {
+	                if (!iIdle)
+	                    {
+	                    iIdle = CIdle::New(CActive::EPriorityIdle);
+	                    if (!iIdle)
+	                        {
+	                        delete regBmp;
+	                        return;
+	                        }
+	                    }
+	                regBmp->iLink.Deque();
+	                if (regBmp->DataSize() <= iCacheLimit)
+	                    {
+	                    iRecentBmps.AddFirst(*regBmp);
+	                    iTotalRecentBmpSize += regBmp->DataSize();
+	                    }
+	                // Delete the least recently used bitmaps if the maximum size of the cache is exceeded
+	                while (iTotalRecentBmpSize > iCacheLimit)
+	                    {
+	                    regBmp = iRecentBmps.Last();
+	                    iTotalRecentBmpSize -= regBmp->DataSize();
+	                    delete regBmp;
+	                    }
+	                // If the cache is not empty make sure the idle-time clean-up active object is scheduled to run
+	                if (!iRecentBmps.IsEmpty() && !iIdle->IsActive())
+	                    {
+	                    iIdle->Start(TCallBack(IdleFunction, this));
+	                    }
+	                }  
+	            else
+	                {
+	                delete regBmp;
+	                }
+	            }
+	        }
+	}
+
+/** Return a scanline from the passed extended bitmap given it's bitmap id. 
+ */
+const TUint32* CSvgtFbsRasterizer::ScanLine(TInt64 aBitmapId, const TPoint& aPixel, TInt aLength)
+	{
+	CSvgtRegisteredBitmap* regBmp = RegisteredBitmap(aBitmapId);
+    if (!regBmp)
+        {
+        return NULL;
+        }
+    if (!TRect(regBmp->SizeInPixels()).Contains(aPixel)
+        || (aLength > (regBmp->SizeInPixels().iWidth - aPixel.iX)))
+        {
+        return NULL;
+        }
+
+    return PtrAdd(regBmp->DataAddress(), aPixel.iY * regBmp->DataStride());
+	}
+
+/**  No extension interaces are available, KErrNotSupported for all aInterfaceId passed.
+@see CFbsRasterizer::GetInterface()
+ */
+TInt CSvgtFbsRasterizer::GetInterface(TUid /*aInterfaceId*/, TAny*& aInterface)
+	{
+	aInterface = NULL;
+	return KErrExtensionNotSupported;
+	}
+
+
+/** Gets a bitmap that has been registered with this rasterizer.
+
+@param aBitmapId The ID of the bitmap to check for.
+
+@return A pointer to the registered bitmap if found, NULL otherwise.
+ */
+CSvgtRegisteredBitmap* CSvgtFbsRasterizer::RegisteredBitmap(TInt64 aBitmapId)
+    {
+    TDblQueIter<CSvgtRegisteredBitmap> iter(iRegisteredBmps);
+    while (CSvgtRegisteredBitmap* regBmp = iter++)
+        {
+        if (regBmp->iBitmapId == aBitmapId)
+            {
+            return regBmp;
+            }
+        }
+    return NULL;
+    }
+
+/** Gets a bitmap that has been recently used with this rasterizer.
+
+@param aBitmapId The ID of the bitmap to check for.
+
+@return A pointer to the recently used bitmap if found, NULL otherwise.
+ */
+CSvgtRegisteredBitmap* CSvgtFbsRasterizer::RecentBitmap(TInt64 aBitmapId)
+    {
+    TDblQueIter<CSvgtRegisteredBitmap> iter(iRecentBmps);
+    while (CSvgtRegisteredBitmap* regBmp = iter++)
+        {
+        if (regBmp->iBitmapId == aBitmapId)
+            {
+            return regBmp;
+            }
+        }
+    return NULL;
+    }
+
+TInt CSvgtFbsRasterizer::IdleFunction(TAny* aPtr)
+    {
+     CSvgtFbsRasterizer* self = static_cast<CSvgtFbsRasterizer*>(aPtr);    
+    if(self->iSpecialProcess!=true)
+        {
+       
+        while (!self->iRecentBmps.IsEmpty())
+            {
+            delete self->iRecentBmps.First();
+            }
+        self->iTotalRecentBmpSize = 0;        
+        }
+    return 0;
+    }
+
+void CSvgtFbsRasterizer::InitializeRasterizer()
+    {
+    }
+
+void CSvgtFbsRasterizer::RenderBitmapL(CSvgtRegisteredBitmap& aPixMap, CFbsBitmap * aMask, 
+                                        const TBitmapDesc& aBitmapDesc, TPtr8& aDataPtr8, TAknIconHeader& aIconHeader)
+    {
+    TSize newSize = aBitmapDesc.iSizeInPixels;
+    UpdateMatrices();
+    iMatricesUpdated = ETrue;
+    TBool isMargin = aIconHeader.IsMarginCorrection();
+    
+    VGImage vgImage = VG_INVALID_HANDLE;
+        
+    if (isMargin)
+        {
+        vgImage = vgCreateImage((VGImageFormat)  VG_sRGBA_8888_PRE , aBitmapDesc.iSizeInPixels.iWidth,
+                                    aBitmapDesc.iSizeInPixels.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
+        if (vgImage == VG_INVALID_HANDLE)
+            {
+            User::LeaveIfError(MapOpenVgErrorCodeToSymbian(vgGetError()));
+            }
+        CleanupStack::PushL( TCleanupItem( CleanupVGImage, &vgImage ) );
+        iGraphicsInterface->BindClientBuffer(vgImage);
+        }
+    User::LeaveIfError(iNvgEngine->DrawNvg(aDataPtr8, newSize, &aPixMap, aMask));
+   
+    if(isMargin)
+        {
+        iGraphicsInterface->UnBindClientBuffer(); 
+        newSize = ApplyMarginL(vgImage, aBitmapDesc.iSizeInPixels);
+        if(newSize!=aBitmapDesc.iSizeInPixels)
+        		{
+        		User::LeaveIfError(iNvgEngine->DrawNvg(aDataPtr8, newSize, &aPixMap, aMask));
+       		  }
+       	else
+       		  {
+       		  vgDrawImage(vgImage);
+       		  User::LeaveIfError(MapOpenVgErrorCodeToSymbian(vgGetError()));
+            }
+        	
+        CleanupStack::PopAndDestroy();
+        }
+    iGraphicsInterface->CopyBitmapL(&aPixMap, aMask);
+    
+    TUint32 iconColor = aIconHeader.GetIconColor();
+    
+    if (iconColor & 0xFFFFFF)
+        {
+        CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( &aPixMap );
+        CleanupStack::PushL( dev );
+        CFbsBitGc* gc = NULL;
+        User::LeaveIfError( dev->CreateContext( gc ) );
+        CleanupStack::PushL( gc );
+        TRgb color(iconColor);          
+        gc->SetBrushColor( color );
+        gc->SetPenStyle( CGraphicsContext::ENullPen );
+        gc->SetBrushStyle( CGraphicsContext::ESolidBrush );
+        // Fill icon with the given color, mask defines the icon shape.
+        TPoint origin(0, 0);
+        if (newSize != aBitmapDesc.iSizeInPixels)
+            {
+            origin = TPoint((aBitmapDesc.iSizeInPixels.iWidth - newSize.iWidth)/2 , (aBitmapDesc.iSizeInPixels.iHeight - newSize.iHeight)/2  );
+            }
+        gc->DrawRect( TRect( origin, newSize ) );
+        CleanupStack::PopAndDestroy( 2 ); // dev, gc
+        }
+    }
+
+void CSvgtFbsRasterizer::RenderMaskL(CSvgtRegisteredBitmap& aPixMap, CFbsBitmap * aMask, 
+                                      const TBitmapDesc& aBitmapDesc, TPtr8& aDataPtr8, TAknIconHeader& aIconHeader)
+    {
+    UpdateMatrices();
+    iMatricesUpdated = ETrue;
+    TBool isMargin = aIconHeader.IsMarginCorrection();
+    
+    VGImage vgImage = VG_INVALID_HANDLE;
+    if (isMargin)
+        {
+        vgImage = vgCreateImage((VGImageFormat)  VG_sRGBA_8888_PRE , aBitmapDesc.iSizeInPixels.iWidth, 
+                                     aBitmapDesc.iSizeInPixels.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
+        if (vgImage == VG_INVALID_HANDLE)
+            {
+            User::LeaveIfError(MapOpenVgErrorCodeToSymbian(vgGetError()));
+            }
+        CleanupStack::PushL( TCleanupItem( CleanupVGImage, &vgImage ) );
+        iGraphicsInterface->BindClientBuffer(vgImage);
+        }
+        
+    VGfloat color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+    vgSeti(VG_SCISSORING, VG_FALSE);
+    vgSetfv(VG_CLEAR_COLOR, 4, color);
+    vgClear(0, 0, aBitmapDesc.iSizeInPixels.iWidth, aBitmapDesc.iSizeInPixels.iHeight);
+
+    User::LeaveIfError(iNvgEngine->DrawNvg(aDataPtr8, aBitmapDesc.iSizeInPixels, &aPixMap, aMask));
+    if (isMargin)
+        {
+        iGraphicsInterface->UnBindClientBuffer();
+        TSize newSize = ApplyMarginL(vgImage, aBitmapDesc.iSizeInPixels);
+        if(newSize!=aBitmapDesc.iSizeInPixels)
+        		{
+        		User::LeaveIfError(iNvgEngine->DrawNvg(aDataPtr8, newSize, &aPixMap, aMask));
+       		  }
+       	else
+       		  {
+       		  vgDrawImage(vgImage);
+       		  User::LeaveIfError(MapOpenVgErrorCodeToSymbian(vgGetError()));
+            }
+        CleanupStack::PopAndDestroy();
+        }
+    
+    TSize bitmapSize = aPixMap.SizeInPixels();
+
+    const TInt KOriginalFilterMasks = vgGeti( VG_FILTER_CHANNEL_MASK );
+    vgSeti( VG_FILTER_CHANNEL_MASK, VG_ALPHA );
+
+    const TInt KStride = CFbsBitmap::ScanLineLength(bitmapSize.iWidth, aPixMap.DisplayMode());
+    VGImageFormat format = ( aPixMap.DisplayMode() == EGray256 ) ? VG_A_8 : VG_BW_1;
+    
+    aPixMap.BeginDataAccess();
+    TUint * data = (TUint*)((TUint)aPixMap.DataAddress() + ( KStride * ( aPixMap.SizeInPixels().iHeight - 1  ) ) );
+    vgReadPixels( data, -KStride, format, 0, 0, bitmapSize.iWidth, bitmapSize.iHeight );
+    aPixMap.EndDataAccess();
+
+    vgSeti( VG_FILTER_CHANNEL_MASK, KOriginalFilterMasks );
+
+    }
+
+void CSvgtFbsRasterizer::RenderL( const TBitmapDesc& aBitmapDesc, CSvgtRegisteredBitmap& aBitmap  )
+    {
+    
+    iIsRasterizerValidState = EFalse;
+
+    User::LeaveIfError(aBitmap.Create(aBitmapDesc.iSizeInPixels, aBitmapDesc.iDispMode));
+    
+    if (!iGraphicsInterface)
+        {
+        iGraphicsInterface = CSvgtGraphicsInterface::CreateImplementationL();
+        }
+    
+    iGraphicsInterface->InitializeL(aBitmapDesc.iSizeInPixels);
+    iIsRasterizerValidState  = ETrue;
+
+    TPtr8 bmpDataPtr8((TUint8*)aBitmapDesc.iData, aBitmapDesc.iDataSize);
+    
+    if (!iNvgEngine)
+        {
+        iNvgEngine = CNvgEngine::NewL();
+        }
+        
+    iNvgEngine->SetVGImageBinder(iGraphicsInterface);
+    
+    TUint8 *temp = (TUint8 *)bmpDataPtr8.Ptr();
+    TPtr8 IconHeaderPtr(temp, KIconHeaderLength, KIconHeaderLength);
+
+    TAknIconHeader iconheader(IconHeaderPtr);
+    //skipping header bytes
+    temp = temp + KIconHeaderLength;
+    TPtr8 newDataPtr8(temp, (bmpDataPtr8.MaxLength() - KIconHeaderLength), (bmpDataPtr8.MaxLength() - KIconHeaderLength));
+
+    CFbsBitmap* mask = NULL;
+    
+    VGfloat color[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
+    vgSeti(VG_SCISSORING, VG_FALSE);
+    vgSetfv(VG_CLEAR_COLOR, 4, color);
+    vgClear(0, 0, aBitmapDesc.iSizeInPixels.iWidth, aBitmapDesc.iSizeInPixels.iHeight);
+    TInt rotAngle = iconheader.GetRotation();
+    // setting the rotation angle
+    iNvgEngine->Rotate(-rotAngle,  aBitmapDesc.iSizeInPixels.iWidth >> 1,aBitmapDesc.iSizeInPixels.iHeight >>1);
+    
+    //setting preserve aspect ratio
+    TNvgAlignStatusType alignTypeValue = ENvgPreserveAspectRatio_XmidYmid;
+    TNvgMeetOrSliceType meetOrSliceTypeValue = ENvgMeet;
+    
+    switch ( iconheader.GetScaleMode() )
+        {
+        case EAspectRatioPreserved: // fall through
+            {
+            // use default
+            break;
+            }
+            // Ensures NVG content fully covers the area of the icon whilst preserving aspect ratio.
+        case EAspectRatioPreservedSlice:
+            {
+            // alignTypeValue use default
+            meetOrSliceTypeValue = ENvgSlice;
+            break;
+            } 
+            /* EAspectRatioPreservedAndUnusedSpaceRemoved is mapped to the same values as EAspectRatioNotPreserved
+             * because we already have a frame buffer with the dimensions that preserves the aspect ratio.
+             * This mapping ensures that NVG engine does not calculate aspect ratio twice and potentially resulting in precision loss.*/
+        case EAspectRatioPreservedAndUnusedSpaceRemoved:                        
+        case EAspectRatioNotPreserved:
+            {            
+            alignTypeValue = ENvgPreserveAspectRatio_None;
+            // meetOrSliceTypeValue use default
+            break;
+            }
+        default:
+            {
+            User::Leave(KErrCorrupt);
+            }
+        }    
+    iNvgEngine->SetPreserveAspectRatio(alignTypeValue, meetOrSliceTypeValue);
+
+    iMatricesUpdated = EFalse;
+    if (iconheader.IsMask())
+        {
+        RenderMaskL(aBitmap, mask, aBitmapDesc, newDataPtr8, iconheader);
+        }
+    else
+        {
+        RenderBitmapL(aBitmap, mask, aBitmapDesc, newDataPtr8, iconheader);
+        }
+    
+    if ( iMatricesUpdated )
+        {
+        RestoreMatrices();
+        iMatricesUpdated = EFalse;
+        }
+    }
+
+void CSvgtFbsRasterizer::UpdateMatrices()
+    {
+    iUserStrokePaint = vgGetPaint(VG_STROKE_PATH);
+    
+    iUserFillPaint = vgGetPaint(VG_FILL_PATH);
+    
+    iMatrixMode = vgGeti(VG_MATRIX_MODE);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+    
+    vgGetMatrix(iPathMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+    
+    vgGetMatrix(iImageMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
+    
+    vgGetMatrix(iFillPaintMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER);
+    
+    vgGetMatrix(iStrokePaintMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, iMatrixMode);
+    
+    }
+
+void CSvgtFbsRasterizer::RestoreMatrices()
+    {
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+    
+    vgLoadMatrix(iPathMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+    
+    vgLoadMatrix(iImageMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
+    
+    vgLoadMatrix(iFillPaintMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER);
+    
+    vgLoadMatrix(iStrokePaintMatrix);
+    
+    vgSeti(VG_MATRIX_MODE, iMatrixMode);
+    
+    vgSetPaint(iUserStrokePaint, VG_STROKE_PATH);
+    
+    vgSetPaint(iUserFillPaint, VG_FILL_PATH);
+    }
+
+
+TSize CSvgtFbsRasterizer::ApplyMarginL(VGImage aVgImage, TSize aSize)
+    {
+    HBufC8* buf = HBufC8::NewL(aSize.iWidth* sizeof(TUint32));
+    TUint32* ptr = (TUint32*)(buf->Des()).Ptr();
+    
+    const TInt validMargin = aSize.iHeight * 12 / 100;
+    
+    const TInt Ha = aSize.iHeight;
+    TInt hTa = 0;
+    TInt hNT = 0;
+    TInt C = 0;
+    TInt hNTN = Ha - 2.0 * 0.12 * Ha;   
+    TReal R = 1.0;
+    TInt HaN = Ha;
+    
+    const TInt lastColumn = aSize.iHeight - 1;
+    for ( TInt curRow = 0; curRow < validMargin; curRow++ )
+        {
+        const TInt y = (aSize.iHeight - 1) - curRow; // h - 1 is the last line
+        
+        vgGetImageSubData(aVgImage, ptr, sizeof(TUint)*aSize.iWidth, VG_sRGBA_8888_PRE, 0, y, aSize.iWidth, 1);
+                                
+        for ( TInt s = lastColumn; s >= 0; --s )
+            {
+            if ( ptr[s] & 0x000000FF ) 
+                {
+                hTa = curRow;
+                hNT = Ha - 2 * hTa;
+                C = 2 * hTa;
+                R = ( ( (TReal)hNTN / (TReal)hNT ) > 1.0 ) ? 1 : (TReal)hNTN / (TReal)hNT;
+                HaN = Ha * R - C * R + C;
+                curRow = validMargin; // to exit the outer loop
+                break; // to exit the inner
+                }
+            
+            }
+        }
+    
+    delete buf;
+        
+    if(aSize.iHeight > HaN)
+        {
+        
+        VGfloat color[4] = { 1.0f, 1.0f, 1.0f, 0.0f }; 
+        
+        vgSetfv(VG_CLEAR_COLOR, 4, color);
+        vgClear(0, 0, aSize.iWidth,aSize.iHeight);
+        
+        vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);   
+        VGfloat Hr = (VGfloat)HaN/(aSize.iHeight);
+        
+        TInt WaN = aSize.iWidth*Hr;
+        
+        VGfloat Tx = (aSize.iHeight-HaN)/2;
+        VGfloat Ty = (aSize.iWidth-WaN)/2;
+        vgTranslate(Tx,Ty);
+        
+        return( TSize(HaN,WaN));    
+        }
+    return aSize;
+    
+    }
+
+
+
+TInt CSvgtFbsRasterizer::MapOpenVgErrorCodeToSymbian(TInt aErrorCode)
+    {
+    switch( aErrorCode )
+        {
+        case VGI_OK:
+            return KErrNone;
+            
+        case VGI_ERROR_OUT_OF_MEMORY:
+            return KErrNoMemory;
+            
+        case VGI_ERROR_INVALID_ARGUMENTS:
+            return KErrArgument;
+            
+        case VGI_ERROR_ALREADY_EXISTS:
+            return KErrAlreadyExists;
+            
+        case VGI_ERROR_COLORSPACE_NOT_SUPPORTED:
+            return KErrNotSupported;
+            
+        case VGI_ERROR_NOT_SUPPORTED:
+            return KErrNotSupported;
+
+        case VGI_ERROR_ILLEGAL_IMAGE_HANDLE:
+            return KErrBadHandle;
+
+        case VGI_ERROR_IMAGE_IN_USE:
+            return KErrInUse;
+
+        case VGI_ERROR_ILLEGAL_OPERATION:
+            return KErrPermissionDenied;
+
+        default:
+            return KErrUnknown;
+        }
+
+    }
+