/*
* Copyright (c) 2003 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: SVGT Plugin Implementation source file
*
*/
#include <e32std.h>
#include <eikenv.h>
#include <barsread.h>
#include <fbs.h>
#include <gdi.h>
#include <f32file.h>
#include <featmgr.h>
#include <eikappui.h>
#include <SVGEngineInterfaceImpl.h>
#include "Svgtplugin.h"
#include "VolumeKeyListener.h"
#include "RepositoryVolumeListener.h"
_LIT(KWidth, "width");
_LIT(KHeight, "height");
CSvgtPlugin* CSvgtPlugin::NewL(NPP anInstance)
{
CSvgtPlugin *self = new (ELeave) CSvgtPlugin;
CleanupStack::PushL( self );
self->ConstructL(anInstance);
CleanupStack::Pop();
return self;
}
CSvgtPlugin::~CSvgtPlugin()
{
if ( iControl )
{
delete iControl;
iControl=NULL;
}
if ( iSvgModule )
{
iSvgModule->Stop();
delete iSvgModule;
iSvgModule = NULL;
}
if ( iRenderBuffer )
{
delete iRenderBuffer;
iRenderBuffer = NULL;
}
iImageUrlInfoList.ResetAndDestroy();
iImageUrlInfoList.Close();
if(iKeyListener)
{
delete iKeyListener;
iKeyListener = NULL;
}
if(iRepositoryListener)
{
delete iRepositoryListener;
iRepositoryListener = NULL;
}
}
void CSvgtPlugin::PrepareToExitL()
{
if (iPluginAdapter)
iPluginAdapter->PluginFinishedL();
}
void CSvgtPlugin::ConstructL(NPP anInstance)
{
iInstance=anInstance;
iRenderBuffer = new ( ELeave ) CFbsBitmap();
iObjectWidth = 0;
iObjectHeight = 0;
// By default obj height is not in percentage
iObjHeightInPercentage = EFalse;
// By default obj width is not in percentage
iObjWidthInPercentage = EFalse;
iExpectedDefaultSize = EFalse;
//While parsing are object width height are specified or not
iObjectWidthSpecified = EFalse;
iObjectHeightSpecified = EFalse;
TFontSpec lFontSpec;
iSvgModule = CSvgEngineInterfaceImpl::NewL( iRenderBuffer, this, lFontSpec );
// Clear background white
iSvgModule->SetBackgroundColor(0xffffffff);
iSvgModule->AddHyperlinkListener( this );
iAdjusted = EFalse;
if (FeatureManager::FeatureSupported(KFeatureIdSideVolumeKeys))
{
User::InfoPrint(_L("Volume Key supported"));
iKeyListener = CVolumeKeyListener::NewL(this);
}
else
{
User::InfoPrint(_L("Key not supported"));
iRepositoryListener = CRepositoryVolumeListener::NewL(this);
}
}
void CSvgtPlugin::SetWindowL(const NPWindow *aWindow,const TRect& aRect)
{
iCurrentWindow.x = aWindow->x;
iCurrentWindow.y = aWindow->y;
iCurrentWindow.window = aWindow->window;
iCurrentWindow.clipRect = aWindow->clipRect;
iCurrentWindow.type = aWindow->type;
iCurrentWindow.width = aWindow->width;
iCurrentWindow.height = aWindow->height;
iPluginAdapter = static_cast<MPluginAdapter*>(aWindow->window);
iParentControl = iPluginAdapter->GetParentControl();
if (iControl == NULL)
{
iControl = new (ELeave) CSvgtPluginControl;
iControl->ConstructL(this,iParentControl);
iPluginAdapter->PluginConstructedL(iControl);
iPluginAdapter->SetPluginNotifier(iControl);
}
if ( !iControl || !iSvgModule || aRect.Width() <= 0 || aRect.Height() <= 0 )
{
return;
}
iSetWindowCalled = ETrue;
iControl->SetRect(aRect);
if ( iRenderWidth != aRect.Width() ||
iRenderHeight != aRect.Height() )
{
iRenderWidth = aRect.Width();
iRenderHeight = aRect.Height();
// Browser initially sends width/height as zero
// if width/height are not specified
// Later if svg is available to us we call resize after adjustDimention
// But if we dont do adjustDimention quick enough
// Browser sends default width/Height as 300x150
// To Ensure that we are setting the object width/height and
// browser is not setting default width/height ahead of us doing resize
// In adjustDimention if width/height are specified at the browser level
// iAdjusted is set to false, the second condition is to ensure that
// if the browser does a resize at a later point it should be allowed
if(iAdjusted || (iObjectWidthSpecified && iObjectHeightSpecified))
{
iObjectWidth = iRenderWidth;
iObjectHeight = iRenderHeight;
}
iSvgModule->Pause(); //fix for CGSR-7CN7T7
User::LeaveIfError( iRenderBuffer->Create(
TSize( iRenderWidth, iRenderHeight ), EColor64K ) );
iSvgModule->SetFrameBuffer( iRenderBuffer );
iSvgModule->Resume(); // fix for CGSR-7CN7T7
}
if ( iExpectedDefaultSize )
{
iExpectedDefaultSize = EFalse;
AdjustDimention(ETrue,ETrue);
}
if(iControlSize != aRect.Size())
{
iRenderWidth = aRect.Width();
iRenderHeight = aRect.Height();
CFbsBitmap * lTempRenderBuffer = new (ELeave) CFbsBitmap();
CleanupStack::PushL(lTempRenderBuffer);
User::LeaveIfError( lTempRenderBuffer->Create( TSize(iRenderWidth,iRenderHeight), EColor64K ));
iSvgModule->SetFrameBuffer(lTempRenderBuffer);
delete iRenderBuffer;
iRenderBuffer = lTempRenderBuffer;
CleanupStack::Pop(lTempRenderBuffer);
lTempRenderBuffer = NULL;
iControlSize = aRect.Size();
iControl->iContentDimension = iSvgModule->ContentDimensions();
}
// For autoloading feature.
if ( iControl->IsAsFileCalled() && iControl->GetFilename().Length() > 0 &&
!iStartCalled )
{
TBool widthInPercentage;
TBool heightInPercentage;
iControl->iContentDimension = iSvgModule->ContentDimensionsInPercentage();
if(iControl->iContentDimension.iWidth == -1 )
{
widthInPercentage = EFalse;
if(iSvgModule->SvgDocument())
{
iControl->iContentDimension.iWidth = iSvgModule->GetViewportWidth(iSvgModule->SvgDocument());
}
else
{
return;
}
}
else
{
widthInPercentage = ETrue;
}
if(iControl->iContentDimension.iHeight == -1)
{
heightInPercentage = EFalse;
if(iSvgModule->SvgDocument())
{
iControl->iContentDimension.iHeight = iSvgModule->GetViewportHeight(iSvgModule->SvgDocument());
}
else
{
return;
}
}
else
{
heightInPercentage = ETrue;
}
// After loading the content, the width & height will be visible to plugin.
// It is time to adjust the size if needed.
if ( AdjustDimention(widthInPercentage,heightInPercentage) )
{
// dimention change is needed so return and notify Browser.
return;
}
iSvgModule->Start();
iStartCalled = ETrue;
}
}
CSvgtPluginControl* CSvgtPlugin::Control()
{
return iControl;
}
NPP CSvgtPlugin::Instance()
{
return iInstance;
}
void CSvgtPlugin::GetSizeOfRenderBuffer(TSize& aSize)
{
if ( iRenderBuffer )
{
aSize = iRenderBuffer->SizeInPixels();
}
else
{
aSize = TSize ( 0, 0 );
}
}
/**********************************************************************/
// implements MSvgRequestObserver
/**********************************************************************/
void CSvgtPlugin::UpdateScreen()
{
iControl->DrawNow();
}
TBool CSvgtPlugin::ScriptCall( const TDesC& /*aScript*/,
CSvgElementImpl* /*aCallerElement*/ )
{
return EFalse;
}
TBool CSvgtPlugin::LinkEntered( const TDesC& /* aUri */ )
{
// update mouse pointer here
return ETrue;
}
TBool CSvgtPlugin::LinkExited( const TDesC& /* aUri */ )
{
// update mouse pointer here
return ETrue;
}
TBool CSvgtPlugin::LinkActivated( const TDesC& aUrl )
{
CSvgtPluginEcomMain* lSvgtPluginEcomMain = (CSvgtPluginEcomMain*) Dll :: Tls ();
NPNetscapeFuncs* lNetscapeFuncs = lSvgtPluginEcomMain->Funcs();
if(lNetscapeFuncs)
{
TPtrC lTarget('\0',0);
lTarget.Set(_L("_parent"));
lNetscapeFuncs->geturl(iInstance,aUrl,&lTarget);
}
return ETrue;
}
void CSvgtPlugin::VolumeChanged(TInt aNewValue)
{
RDebug::Print(_L("Volume level: %d"), aNewValue);
aNewValue *= 10; //to make the volume in percentage
iSvgModule->SetAudioVolume( aNewValue );
}
TInt CSvgtPlugin::FetchImage(const TDesC& aUri, RFs& /*aSession*/, RFile& /*aFileHandle*/ )
{
TRAPD(err,FetchImageL(aUri));
return err;
}
void CSvgtPlugin::FetchImageL(const TDesC& aUri)
{
TInt lCount = iImageUrlInfoList.Count();
HBufC* lListItem = NULL;
HBufC* lUrl = NULL;
//checks whether the request is already made for same Uri.
for(TInt i = 0; i < lCount; i++)
{
lListItem = HBufC::NewLC(iImageUrlInfoList[i]->Length());
lUrl = aUri.AllocLC();
*lListItem = *iImageUrlInfoList[i];
// Convert the List Item to Lower case
TPtr lListItemPtr = lListItem->Des();
lListItemPtr.LowerCase();
// Convert the Url to Lower case
TPtr lUrlPtr = lUrl->Des();
lUrlPtr.LowerCase();
if( lListItemPtr.Compare(lUrlPtr) == 0 )
{
CleanupStack::PopAndDestroy(2);
lListItem = NULL;
lUrl = NULL;
// Same Url is already requested in the past, no need to continue.
User::Leave(KErrAlreadyExists); // Indicates the download is pending
}
CleanupStack::PopAndDestroy(2);
lListItem = NULL;
lUrl = NULL;
}
// --------------------------------------
// Request file from browser
// --------------------------------------
CSvgtPluginEcomMain* lSvgtPluginEcomMain = (CSvgtPluginEcomMain*) Dll :: Tls ();
NPNetscapeFuncs* lNetscapeFuncs = lSvgtPluginEcomMain->Funcs();
if(lNetscapeFuncs)
{
TPtrC lTarget('\0',0);
lUrl = aUri.AllocL();
// Current count is used as a context data.
void* contextptr = (void*)(lCount);
NPError error = lNetscapeFuncs->geturlnotify(iInstance,aUri,NULL,contextptr);
// Add the Url and RequestID to the List
iImageUrlInfoList.Append(lUrl);
if ( error != 0 )
{
#ifdef _DEBUG
lNetscapeFuncs->status(iInstance,_L("Image failed"));
#endif
User::LeaveIfError(error);
}
#ifdef _DEBUG
lNetscapeFuncs->status(iInstance,_L("Downloading Image"));
#endif
}
User::Leave(KRequestPending); // Indicate the download is pending
}
TInt CSvgtPlugin::FetchFont( const TDesC& /* aUri */, RFs& /* aSession */, RFile& /* aFileHandle */)
{
// Fix for ANAE-775B7E. There is a limitaiton. For rendering text with
// external font synchronous fetching of the file is needed. But the
// external font file is fetched asynchronously by browser when we say
// geturlnotify(). There is no API to pass the font data after fetching
// asynchronously. Hence the code here is removed by returning an error.
return KErrNotFound;
}
TBool CSvgtPlugin::LinkActivatedWithShow(const TDesC& aUri,const TDesC& /*aShow*/)
{
CSvgtPluginEcomMain* lSvgtPluginEcomMain = (CSvgtPluginEcomMain*) Dll :: Tls ();
NPNetscapeFuncs* lNetscapeFuncs = lSvgtPluginEcomMain->Funcs();
if(lNetscapeFuncs)
{
TPtrC lTarget('\0',0);
lTarget.Set(_L("_parent"));
lNetscapeFuncs->geturl(iInstance,aUri,&lTarget);
}
return ETrue;
}
void CSvgtPlugin::GetSmilFitValue(TDes16 &aSmilValue)
{
aSmilValue.Copy(_L("meet"));
}
void CSvgtPlugin::UpdatePresentation(const TInt32& aNoOfAnimation)
{
if (iTotalNumerOfAnimation < 0)
{
if (aNoOfAnimation != 0)
{
iStaticContent = EFalse;
iTotalNumerOfAnimation = aNoOfAnimation;
}
else
{
iStaticContent = ETrue;
}
}
else
{
iTotalNumerOfAnimation--;
}
}
void CSvgtPlugin::GetViewPort(TInt /*getWidth*/, TInt /*getHeight*/, TBool /*isWidthInPer*/, TBool /*isHeightInPer*/, TInt &setWidth, TInt &setHeight)
{
setWidth = iRenderWidth;
setHeight = iRenderHeight;
iViewPortWidth = setWidth;
iViewPortHeight = setHeight;
}
// ---------------------------------------------------------------------------
// This function extracts attributes from the list that is passed from Browser.
// Use to check if width & height are defined in XHTML tag
// ---------------------------------------------------------------------------
//
NPError CSvgtPlugin::SvgPluginNew(NPMIMEType /*pluginType*/, NPP instance,
uint16 /*mode*/, CDesC16Array* argn, CDesC16Array* argv, NPSavedData* )
{
if (instance->pdata != this)
{
return NPERR_INVALID_INSTANCE_ERROR;
}
for (TInt i = 0; i < argn->Count(); i++)
{
TPtrC16 namePtr((*argn)[i]);
TPtrC16 valPtr((*argv)[i]);
if (KWidth().FindF(namePtr) == 0)
{
TLex lString( valPtr );
lString.SkipSpace();
TInt result = lString.Val(iRenderWidth);
// Check if object width was specified as
// percentage value.
if ( valPtr.Locate( '%' ) != KErrNotFound )
{
// Do not store the value, browser takes
// care of computing the width
iObjWidthInPercentage = ETrue;
}
if (( result != KErrNone) || (iRenderWidth < 0))
{
iObjectWidth = 0;
}
else
{
iObjectWidth = iRenderWidth;
}
iObjectWidthSpecified = ETrue;
}
else if (KHeight().FindF(namePtr) == 0)
{
TLex lString( valPtr );
lString.SkipSpace();
TInt result = lString.Val(iRenderHeight);
// Check if object height was specified as a
// percentage value.
if ( valPtr.Locate( '%' ) != KErrNotFound )
{
// Do not store the value, browser takes
// care of computing the height
iObjHeightInPercentage = ETrue;
}
if (( result != KErrNone) || ( iRenderHeight < 0 ))
{
iObjectHeight = 0;
}
else
{
iObjectHeight = iRenderHeight;
}
iObjectHeightSpecified = ETrue ;
}
}
return NPERR_NO_ERROR;
}
// ---------------------------------------------------------------------------
// ResizeWindow() This function is to notify that a new set of dimention value
// should be taken into consideration. The new w&h is determined from
// AdjustDimention().
//
// ---------------------------------------------------------------------------
//
void CSvgtPlugin::ResizeWindow(TInt aWidth, TInt aHeight)
{
NPPVariable variable;
CSvgtPluginEcomMain* lSvgtPluginEcomMain = (CSvgtPluginEcomMain*) Dll::Tls();
NPNetscapeFuncs* lNetscapeFuncs = lSvgtPluginEcomMain->Funcs();
NPWindow newWindow;
variable = NPPVpluginWindowSize;
newWindow.x = iCurrentWindow.x;
newWindow.y = iCurrentWindow.y;
newWindow.window = iCurrentWindow.window;
newWindow.clipRect = iCurrentWindow.clipRect;
newWindow.type = iCurrentWindow.type;
newWindow.width = aWidth;
newWindow.height = aHeight;
TInt err = lNetscapeFuncs->setvalue(iInstance, variable, (void*)&newWindow);
}
// ---------------------------------------------------------------------------
// AdjustDimention() This function does the logic to check if width & height
// is needed to be adjusted
// ---------------------------------------------------------------------------
//
TBool CSvgtPlugin::AdjustDimention( TBool aWidthInPercentage, TBool aHeightInPercentage)
{
iSvgModule->AddListener( static_cast < MSvgViewPortListener*>(this), ESvgViewPortListener );
if ( iAdjusted )
return EFalse;
// we set the width height in all cases except when width/height has been
// explicitly specified in the browser hence its set here for all cases
iAdjusted = ETrue;
// html provides absolute width, no height
// svg provides absolute width and absolute height
if (
( iObjectWidthSpecified && !iObjWidthInPercentage && !iObjectHeightSpecified )
&& ( !aWidthInPercentage && !aHeightInPercentage)
)
{
// only iObjectWidth is valid
// Adjust missing object value as per aspect ratio of
// svg's viewport
if(iControl->iContentDimension.iWidth)
{
TReal newHeight = (TInt)((TReal32)iObjectWidth *
( (TReal32)iControl->iContentDimension.iHeight /
(TReal32)iControl->iContentDimension.iWidth));
ResizeWindow(iObjectWidth, newHeight);
}
return ETrue;
}
// html provides no width and absolute height
// svg provides absolute width and absolute height
else if (
( !iObjectWidthSpecified && iObjectHeightSpecified && !iObjHeightInPercentage )
&& ( !aWidthInPercentage && !aHeightInPercentage)
)
{
// only iObjectHeight is valid
// Adjust missing object value as per aspect ratio of
// svg's viewport
if(iControl->iContentDimension.iHeight)
{
TInt newWidth = (TInt)((TReal32)iObjectHeight *
( (TReal32)iControl->iContentDimension.iWidth /
(TReal32)iControl->iContentDimension.iHeight));
ResizeWindow(newWidth, iObjectHeight);
}
return ETrue;
}
// html provides no width and no height
// svg provides absolute width and absolute height
else if(
(!iObjectWidthSpecified && !iObjectHeightSpecified)
&& ( !aWidthInPercentage && !aHeightInPercentage)
)
{
ResizeWindow(iControl->iContentDimension.iWidth, iControl->iContentDimension.iHeight);
return ETrue;
}
// html provides width and height be it percentages or absolute values
else if(iObjectWidthSpecified && iObjectHeightSpecified)
{
iAdjusted = EFalse;
return EFalse;
}
else
{
TReal newWidth = 0.0f;
TReal newHeight = 0.0f;
CEikonEnv* lEnv = STATIC_CAST( CEikonEnv*, iControl->ControlEnv() );
TRect lClientRect = TRect( TPoint( 0,0 ), lEnv->EikAppUi()->ClientRect().Size());
// if the browser has specified a valid absolute value width
if ( !iObjWidthInPercentage && iObjectWidthSpecified)
{
newWidth = iObjectWidth;
}
// if the browser has specified a valid percentage value width
else if (iObjWidthInPercentage && iObjectWidthSpecified )
{
// Compute the new dimension by scaling clientRect dimension
newWidth = lClientRect.Width() * iObjectWidth / 100;
}
// if the browser has specified a valid absolute value height
if ( !iObjHeightInPercentage && iObjectHeightSpecified)
{
newHeight = iObjectHeight;
}
// if the browser has specified a valid percentage value Height
else if(iObjHeightInPercentage && iObjectHeightSpecified)
{
// Compute the new dimension by scaling clientRect dimension
newHeight = lClientRect.Height() * iObjectHeight / 100;
}
// if the browser has not specified the width
if(!iObjectWidthSpecified)
{
if(aWidthInPercentage)
{
newWidth = lClientRect.Width() * iControl->iContentDimension.iWidth / 100;
}
else
{
newWidth = iControl->iContentDimension.iWidth;
}
}
// if the browser has not specified the height
if(!iObjectHeightSpecified)
{
if(aHeightInPercentage)
{
newHeight = lClientRect.Height() * iControl->iContentDimension.iHeight / 100;
}
else
{
newHeight = iControl->iContentDimension.iHeight;
}
}
ResizeWindow(newWidth, newHeight);
return ETrue;
}
}
TBool CSvgtPlugin::LoadSvgFile( const TDesC& aFilename )
{
if ( !iSvgModule )
{
return EFalse;
}
MSvgError* error = iSvgModule->Load( aFilename );
if ( !error )
{
return EFalse;
}
// Loading error
if ( error->HasError() && !error->IsWarning() )
{
return EFalse;
}
TInt currentVolume;
if (FeatureManager::FeatureSupported(KFeatureIdSideVolumeKeys))
{
currentVolume = iKeyListener->GetCurrentVolume();
}
else
{
currentVolume = iRepositoryListener->GetCurrentVolume();
}
VolumeChanged(currentVolume );
iTotalNumerOfAnimation = -1;
return ETrue;
}