/*
* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
#include "HuiFxEffectParser.h"
#include <stdarg.h>
#include <gmxmldocument.h>
#include <gmxmlelement.h>
#include <gmxmlnode.h>
#include <gmxmltext.h>
#include <gmxmlprocessinginstruction.h>
#include <gmxmlcdatasection.h>
#include "HuiFxConstants.h"
#include "HuiFxFilter.h"
#include "HuiFxGroupLayer.h"
#include "HuiFxFilterLayer.h"
#include "HuiFxVisualLayer.h"
#include "HuiFxEffect.h"
#include "HuiFxParameter.h"
#include "HuiFxScalarParameter.h"
#include "HuiFxColorParameter.h"
#include "uiacceltk/HuiVisual.h" // Class definition
#include "alflogger.h"
#include "huieffectable.h"
#include <stdlib.h>
//#define _HUI_FX_PARSER_LOGGING // Enable this, if you need to debug the xml parsing. otherwise leave this out, because the logging breaks the timing of effects
// Debugging macros
#if !defined(NDEBUG)
#define FAIL(CODE, MSG) FailL(CODE, MSG)
#define FAIL1(CODE, MSG, P1) FailL(CODE, MSG, P1)
#else
#define FAIL(CODE, MSG)
#define FAIL1(CODE, MSG, P1)
#endif
CHuiFxEffectParser* CHuiFxEffectParser::NewL(CHuiFxEngine& aEngine, MHuiEffectable* aVisual)
{
CHuiFxEffectParser* self = NewLC(aEngine, aVisual);
CleanupStack::Pop(self);
return self;
}
CHuiFxEffectParser* CHuiFxEffectParser::NewLC(CHuiFxEngine& aEngine, MHuiEffectable* aVisual)
{
CHuiFxEffectParser* self = new (ELeave) CHuiFxEffectParser( aEngine, aVisual );
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
void CHuiFxEffectParser::ConstructL()
{
iParser = CMDXMLParser::NewL( this ) ;
User::LeaveIfError( iFs.Connect() );
CActiveScheduler::Add( this );
}
CHuiFxEffectParser::CHuiFxEffectParser( CHuiFxEngine& aEngine, MHuiEffectable* aVisual ) :
CActive( EPriorityHigh ),
iEngine( aEngine ),
iVisual( aVisual ),
iParsingEndedObserver( NULL ), iParsingEndedHandle(0)
{
__ALFFXLOGSTRING2("CHuiFxEffectParser::CHuiFxEffectParser - this: 0x%x aVisual 0x%x", this, aVisual);
}
CHuiFxEffectParser::~CHuiFxEffectParser()
{
Cancel();
delete iParser;
iParser = NULL;
delete iDoc;
iDoc = NULL;
delete iEffect;
iEffect = NULL;
iFs.Close();
__ALFFXLOGSTRING1("CHuiFxEffectParser::~CHuiFxEffectParser - 0x%x ", this);
}
void CHuiFxEffectParser::ParseFileCompleteL()
{
TRequestStatus* status = &iStatus;
TInt err = KErrNone; // We don't get any error from the caller.
if ( iIsCancelled )
{
err = KErrCancel;
}
User::RequestComplete( status, err );
__ALFFXLOGSTRING1("CHuiFxEffectParser::ParseFileCompleteL - 0x%x",this);
}
void CHuiFxEffectParser::RunL()
{
__ALFFXLOGSTRING2("CHuiFxEffectParser::RunL - this 0x%x, status: %d", this, iStatus.Int());
// RunL will only be called once after the parsing completes
if ( iStatus.Int() == KErrNone )
{
BuildEffectL();
iEffect->SetEffectFlags( iFlags );
iFlags = 0;
// As soon as the visual gets the effect, it kills this effect parser.
// Therefore the effect must be stored into a temporary variable
// and the member of the parser set to null to prevent the fresly released visual
// from being destroyed immediately.
// CHuiVisual::SetEffect does dot leave, it just stores the pointer to its own data area,
// so this is a safe trick, and the boat does not leak.
if (iParsingEndedObserver)
{
iParsingEndedObserver->ParsingEnded(iParsingEndedHandle);
}
#ifndef HUIFX_EFFECTCACHE_ENABLED
CHuiFxEffect* tempEffect = iEffect;
#endif
iEffect = NULL;
if (iVisual)
{
iVisual->EffectSetOpacity(1.0f);
#ifndef HUIFX_EFFECTCACHE_ENABLED
iVisual->SetEffect( tempEffect );
#endif
}
}
else if ( iStatus.Int() != KErrCancel )
{
// some error during parsing - delete possible incomplete effect
// and set the effect in the visual to NULL as we did not succeed in creating
// a decent effect
if (iParsingEndedObserver)
{
iParsingEndedObserver->ParsingEnded(iParsingEndedHandle);
}
delete iEffect;
iEffect = NULL;
if (iVisual)
{
iVisual->EffectSetOpacity(1.0f);
iVisual->EffectSetEffect( NULL );
}
}
else // We got cancelled
{
delete iEffect;
iEffect = NULL;
}
delete this;
// MUST NOT DO ANYTHING AFTER THE delete this -line!
}
TInt CHuiFxEffectParser::RunError( TInt /*aError*/ )
{
// we signal that we handled the error
delete iEffect;
iEffect = NULL;
if ( iVisual )
{
iVisual->EffectSetEffect( NULL );
}
return KErrNone;
}
void CHuiFxEffectParser::DoCancel()
{
// cancel the parsing.
//
iIsCancelled = ETrue;
iParser->Cancel();
// parser should now call our ParseFileCompleteL()
// Unfortunately it will not tell us any error code.
// Therefore we must remember that we were cancelled.
// We can only be cancelled when CHuiFxEffectParser is deleted.
// We do not call iVisual->SetEffect any more in that case
// because in that case the parser gets deleted anyway.
// We don't want to be deleted twice - though setting the parser to NULL after
// deleting should take care of that anyway.
// Actually it seems that parser will not necessarily call us,
// so we must ensure ourselves that we are completed (but only once!)
// Otherwise then whole system will hang waiting for an event
TRequestStatus* status = &iStatus;
User::RequestComplete( status, KErrCancel );
__ALFFXLOGSTRING1("CHuiFxEffectParser::DoCancel - 0x%x",this);
}
void CHuiFxEffectParser::ParseL( const TDesC& aFile, TRect aExtRect )
{
__ALFFXLOGSTRING2("CHuiFxEffectParser::ParseL - 0x%x %S",this, &aFile);
iIsCancelled = EFalse;
iExtRect = aExtRect;
TInt err = iParser->ParseFile( iFs, aFile );
if ( err != KErrNone )
{
// If parsing fails, give up immediately
iVisual->EffectSetEffect( NULL );
User::Leave( err );
}
iStatus = KRequestPending;
SetActive();
// BuildEffectL is called in RunL when parser calls our callback which completes us.
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseL - activated ");
}
void CHuiFxEffectParser::Effect( CHuiFxEffect*& aEffect )
{
aEffect = iEffect;
iEffect = NULL;
}
void CHuiFxEffectParser::SetEffectEndObserver( MAlfGfxEffectObserver* aEffectEndObserver, TInt aHandle )
{
iEffectEndObserver = aEffectEndObserver;
iHandle = aHandle;
}
void CHuiFxEffectParser::SetParsingEndedObserver( MHuiFxParsingEndedObserver *aObserver, TInt aHandle )
{
iParsingEndedObserver = aObserver;
iParsingEndedHandle = aHandle;
}
void CHuiFxEffectParser::SetEffectFlags( TInt aFlags )
{
iFlags = aFlags;
}
void CHuiFxEffectParser::BuildEffectL()
{
__ALFFXLOGSTRING1("CHuiFxEffectParser::BuildEffectL - 0x%x",this);
iEffect = CHuiFxEffect::NewL( iEngine );
iEffect->SetEffectEndObserver( iEffectEndObserver, iHandle );
iEffectEndObserver = NULL;
iHandle = 0;
iDoc = iParser->DetachXMLDoc();
User::LeaveIfNull( iDoc );
CMDXMLElement* root = iDoc->DocumentElement();
User::LeaveIfNull( root );
CMDXMLNode* node = root->FirstChild();
if( node->NodeName().Compare( KLitLayers ) != 0 )
{
FAIL(KErrGeneral, _L("Layer list not found"));
}
for (node = node->FirstChild(); node; node = node->NextSibling())
{
ParseNodeL( node, NULL );
}
__ALFFXLOGSTRING("CHuiFxEffectParser::BuildEffectL - complete ");
}
void CHuiFxEffectParser::ParseNodeL( CMDXMLNode* aNode, CHuiFxLayer* aLayer)
{
switch( ResolveNode( aNode ) )
{
case ENodeTypeUnknown:
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseNodeL - ENodeTypeUnknown");
#endif
__ALFFXLOGSTRING1("CHuiFxEffectParser::ParseNodeL : WARNING - Node tag <%S> is not supported.", &(aNode->NodeName()));
break;
}
case ENodeTypeGroup:
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseNodeL - ENodeTypeGroup");
#endif
// can't have group layers inside group layer
if (aLayer && aLayer->Type() == ELayerTypeGroup)
{
FAIL(KErrGeneral, _L("Nested group layers not supported"));
}
CHuiFxGroupLayer* group = CHuiFxGroupLayer::NewL();
CleanupStack::PushL( group );
for (CMDXMLNode* node = aNode->FirstChild(); node; node = node->NextSibling())
{
ParseNodeL( node, group );
}
iEffect->AddLayerL( group ); // ownership transferred
CleanupStack::Pop( group );
break;
}
case ENodeTypeFilter:
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseNodeL - ENodeTypeFilter");
#endif
THuiFxFilterType filterType = GetFilterTypeL( aNode );
CHuiFxFilter* filter = iEngine.CreateFilterL( filterType );
CleanupStack::PushL( filter );
CHuiFxFilterLayer* filterLayer = CHuiFxFilterLayer::NewL( filter );
CleanupStack::Pop( filter );
CleanupStack::PushL( filterLayer );
if (aLayer && aLayer->Type() == ELayerTypeGroup)
{
CHuiFxGroupLayer* group = reinterpret_cast<CHuiFxGroupLayer*>(aLayer);
group->AddLayerL( filterLayer ); // ownership transferred
}
else
{
iEffect->AddLayerL( filterLayer ); // ownership transferred
}
CleanupStack::Pop( filterLayer );
if (filterType == EFilterTypeTransform)
{
filterLayer->SetTransformed(ETrue);
}
for (CMDXMLNode* node = aNode->FirstChild(); node; node = node->NextSibling())
{
ParseNodeL( node, filterLayer );
}
break;
}
case ENodeTypeVisual:
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseNodeL - ENodeTypeVisual");
#endif
TPtrC16 extBitmap;
THuiFxVisualSrcType srcType = GetSrcTypeL( aNode, extBitmap );
CHuiFxVisualLayer* visual = CHuiFxVisualLayer::NewL( *iVisual );
CleanupStack::PushL( visual );
visual->SetSourceType( srcType );
if ( srcType == EVisualSrcBitmap && extBitmap.Length() > 0 )
{
visual->SetExtBitmapFileL( extBitmap );
}
if (aLayer && aLayer->Type() == ELayerTypeGroup)
{
CHuiFxGroupLayer* group = reinterpret_cast<CHuiFxGroupLayer*>(aLayer);
group->AddLayerL( visual ); // ownership transferred
}
else
{
iEffect->AddLayerL( visual ); // ownership transferred
}
for (CMDXMLNode* node = aNode->FirstChild(); node; node = node->NextSibling())
{
ParseNodeL( node, visual );
}
CleanupStack::Pop( visual );
break;
}
case ENodeTypeBlending:
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseNodeL - ENodeTypeBlending");
#endif
CMDXMLNode* blendingNode = aNode->FirstChild();
if( blendingNode->NodeType() != CMDXMLNode::ETextNode )
{
FAIL(KErrGeneral, _L("Bad blending mode"));
}
TPtrC modePtr( ((CMDXMLText *)blendingNode)->Data() );
// set replace as default blending mode
THuiFxBlendingMode blendingMode = EBlendingModeReplace;
if( modePtr.Compare( KLitReplace ) == 0 )
{
blendingMode = EBlendingModeReplace;
}
else if( modePtr.Compare( KLitOver ) == 0 )
{
blendingMode = EBlendingModeOver;
}
else if( modePtr.Compare( KLitMultiply ) == 0 )
{
blendingMode = EBlendingModeMultiply;
}
else if( modePtr.Compare( KLitAdditive ) == 0 )
{
blendingMode = EBlendingModeAdditive;
}
else if( modePtr.Compare( KLitDarken ) == 0 )
{
blendingMode = EBlendingModeDarken;
}
else if( modePtr.Compare( KLitLighten ) == 0 )
{
blendingMode = EBlendingModeLighten;
}
else
{
FAIL(KErrGeneral, _L("Bad blending mode"));
}
if (aLayer && aLayer->Type() == ELayerTypeGroup)
{
aLayer->SetBlendingMode( blendingMode );
}
else
{
// TODO: should other layers have a blending mode?
FAIL(KErrGeneral, _L("Blending mode can only be set for a group layer"));
}
break;
}
case ENodeTypeParam:
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseNodeL - ENodeTypeParam");
#endif
ResolveParamL(aNode, aLayer);
break;
}
default:
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseNodeL - default??");
break;
}
}
CHuiFxEffectParser::TNodeType CHuiFxEffectParser::ResolveNode( CMDXMLNode* aNode )
{
TPtrC nodeName( aNode->NodeName() );
if( nodeName.Compare( KLitLayerGroup ) == 0 )
{
return ENodeTypeGroup;
}
else if( nodeName.Compare( KLitFilter ) == 0 )
{
return ENodeTypeFilter;
}
else if( nodeName.Compare( KLitVisual ) == 0 )
{
return ENodeTypeVisual;
}
else if( nodeName.Compare( KLitBlending ) == 0 )
{
return ENodeTypeBlending;
}
else if( nodeName.Compare( KLitParam ) == 0 )
{
return ENodeTypeParam;
}
else if( nodeName.Compare( KLitStyle ) == 0 )
{
return ENodeTypeStyle;
}
else if( nodeName.Compare( KLitDuration ) == 0 )
{
return ENodeTypeDuration;
}
else if( nodeName.Compare( KLitKeyFrame ) == 0 )
{
return ENodeTypeKeyFrame;
}
else if( nodeName.Compare( KLitMarker ) == 0 )
{
return ENodeTypeMarker;
}
else if( nodeName.Compare( KLitStart ) == 0 )
{
return ENodeTypeStart;
}
else if( nodeName.Compare( KLitEnd ) == 0 )
{
return ENodeTypeEnd;
}
else
{
return ENodeTypeUnknown;
}
}
// not locale dependent float parser
static TReal32 ParseFloatVal(TPtrC valuePtr)
{
HBufC8 *buf = HBufC8::New(valuePtr.Length()+1);
if (!buf) return 0.0;
CleanupStack::PushL(buf);
buf->Des().Copy(valuePtr);
TUint8 *buf2 = new TUint8[valuePtr.Length()+1];
if (!buf2) return 0.0;
int s = valuePtr.Length();
int i = 0;
for(;i<s;i++)
buf2[i] = buf->operator[](i);
buf2[i] = 0;
TReal32 v = atof((const char*)buf2);
delete [] buf2;
CleanupStack::PopAndDestroy(buf);
return v;
}
TReal32 CHuiFxEffectParser::ParseFloatAttributeL(CMDXMLNode* aNode, const TDesC& aName, TBool aMustExist)
{
TInt index = ((CMDXMLElement*)aNode)->FindIndex(aName);
if( index == KErrNotFound )
{
if (aMustExist)
{
FAIL1(KErrGeneral, _L("Attribute not found: %S"), &aName); // leaves
return 0.0f; // never reached. For completeness
}
else
{
return 0.0f;
}
}
TPtrC attributeValue;
TPtrC attributeName;
TReal32 value = 0.0f;
User::LeaveIfError(((CMDXMLElement*)aNode)->AttributeDetails( index, attributeName, attributeValue ));
value = ParseFloatVal(attributeValue);
return value;
}
TReal32 CHuiFxEffectParser::ParseFloatValueL(CMDXMLNode* aNode)
{
if ( !aNode || aNode->NodeType() != CMDXMLNode::ETextNode )
{
FAIL(KErrGeneral, _L("Text node expected while parsing a floating point value"));
}
TPtrC valuePtr( ((CMDXMLText *)aNode)->Data() );
TReal32 v = ParseFloatVal(valuePtr);
return v;
}
TRgb CHuiFxEffectParser::ParseColorValueL(CMDXMLNode* aNode)
{
// Parse color definition in HTML notation (#aarrggbb)
if ( !aNode || aNode->NodeType() != CMDXMLNode::ETextNode )
{
FAIL(KErrGeneral, _L("Text node expected while parsing a color value")); // leaves
return KRgbBlack; // never reached. For completeness
}
TPtrC valuePtr( ((CMDXMLText *)aNode)->Data() );
TLex parser(valuePtr);
if (parser.Get() != '#')
{
FAIL(KErrGeneral, _L("Invalid color specification")); // leaves
return KRgbBlack; // never reached. For completeness
}
TUint32 color;
parser.Val(color, EHex);
// Opaque alpha by default
if (valuePtr.Length() <= 7)
{
color |= 0xff000000;
}
TUint32 r = (color & 0x00ff0000) >> 16;
TUint32 g = (color & 0x0000ff00) >> 8;
TUint32 b = (color & 0x000000ff);
TUint32 a = (color & 0xff000000) >> 24;
return TRgb(r, g, b, a);
}
template <>
TReal32 CHuiFxEffectParser::ParseAnimationKeyFrameValueL(CMDXMLNode* aNode, RHuiFxScalarTimeLine& /*aTimeLine*/)
{
return ParseFloatValueL(aNode);
}
template <>
TRgb CHuiFxEffectParser::ParseAnimationKeyFrameValueL(CMDXMLNode* aNode, RHuiFxColorTimeLine& /*aTimeLine*/)
{
return ParseColorValueL(aNode);
}
template <typename PARAM_TYPE, typename TIMELINE_TYPE, typename VALUE_TYPE>
void CHuiFxEffectParser::ParseAnimationNodeL(CMDXMLNode* aNode, PARAM_TYPE& aParam, TIMELINE_TYPE& aTimeLine)
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING1("CHuiFxEffectParser::ParseAnimationNodeL - 0x%x", this);
#endif
switch( ResolveNode( aNode ) )
{
case ENodeTypeDuration:
{
aTimeLine.SetDuration(ParseFloatValueL(aNode->FirstChild()));
}
break;
case ENodeTypeStyle:
{
CMDXMLNode* styleNode = aNode->FirstChild();
if (styleNode->NodeType() != CMDXMLNode::ETextNode)
{
FAIL(KErrGeneral, _L("Text node expected while parsing an interpolation mode"));
}
TPtrC modePtr( ((CMDXMLText *)styleNode)->Data() );
if( modePtr.Compare( KLitHold ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeHold);
}
else if( modePtr.Compare( KLitLinear ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeLinear);
}
else if( modePtr.Compare( KLitInQuad ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeInQuad);
}
else if( modePtr.Compare( KLitOutQuad ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeOutQuad);
}
else if( modePtr.Compare( KLitInOutQuad ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeInOutQuad);
}
else if( modePtr.Compare( KLitOutInQuad ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeOutInQuad);
}
else if( modePtr.Compare( KLitInBack ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeInBack);
}
else if( modePtr.Compare( KLitOutBack ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeOutBack);
}
else if( modePtr.Compare( KLitInOutBack ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeInOutBack);
}
else if( modePtr.Compare( KLitOutInBack ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeOutInBack);
}
else if( modePtr.Compare( KLitQuadraticBezier ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeQuadraticBezier);
}
else if( modePtr.Compare( KLitCubicBezier ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeCubicBezier);
}
/*
else if( modePtr.Compare( KLitDeclerate ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeDecelerate);
}
else if( modePtr.Compare( KLitAccelerate ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeAccelerate);
}
else if( modePtr.Compare( KLitImpulse ) == 0 )
{
aTimeLine.SetInterpolationMode(EInterpolationModeImpulse);
}
*/
else
{
// unknown (unsupported) interpolation modes default to linear
// (at least during testing when we add modes)
aTimeLine.SetInterpolationMode(EInterpolationModeLinear);
// FAIL(KErrGeneral, _L("Unknown interpolation mode"));
}
break;
}
case ENodeTypeMarker:
{
TReal32 time = ParseFloatAttributeL(aNode, KLitAt);
TInt typeIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitType );
if (typeIndex == KErrNotFound)
{
FAIL(KErrGeneral, _L("Marker name not found"));
}
TPtrC attributeValue;
TPtrC attributeName;
User::LeaveIfError(((CMDXMLElement*)aNode)->AttributeDetails( typeIndex, attributeName, attributeValue ));
// TODO: Should this be controllable?
aTimeLine.SetLoopingMode(ELoopingModeRepeat);
if (attributeValue.Compare(KLitLoopStart) == 0)
{
aTimeLine.SetLoopStart(time);
}
else if (attributeValue.Compare(KLitLoopEnd) == 0)
{
aTimeLine.SetLoopEnd(time);
}
else
{
FAIL(KErrGeneral, _L("Unsupported marker type"));
}
break;
}
case ENodeTypeKeyFrame:
{
TReal32 time = ParseFloatAttributeL(aNode, KLitAt);
TReal32 aux1 = ParseFloatAttributeL(aNode, KLitAux1, EFalse);
TReal32 aux2 = ParseFloatAttributeL(aNode, KLitAux2, EFalse);
VALUE_TYPE value = ParseAnimationKeyFrameValueL<PARAM_TYPE::ValueType, TIMELINE_TYPE>(aNode->FirstChild(), aTimeLine);
TRAPD(err, aTimeLine.AppendKeyFrameL(time, value, aux1, aux2));
if (err != KErrNone)
{
FAIL(KErrGeneral, _L("Unable to append new key frame to timeline"));
}
}
break;
case ENodeTypeStart:
{
TInt refIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitRef );
TReal32 refValue = 0;
TBool needRefValue = EFalse;
THuiFxReferencePoint ref = EReferencePointUndefined;
if ( refIndex != KErrNotFound )
{
ref = GetReferencePointL( aNode, refValue, needRefValue );
}
aParam.SetStartReference( ref );
if ( needRefValue )
{
aParam.SetStartValue( refValue );
}
if ( aParam.StartReference() != EReferencePointUndefined &&
aParam.EndReference() != EReferencePointUndefined )
{
aParam.SetReferencePoint( EReferencePointUndefined );
}
float value = ParseFloatValueL(aNode->FirstChild());
aParam.SetStartMultiplier( value );
}
break;
case ENodeTypeEnd:
{
TInt refIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitRef );
TReal32 refValue = 0;
TBool needRefValue = EFalse;
THuiFxReferencePoint ref = EReferencePointUndefined;
if ( refIndex != KErrNotFound )
{
ref = GetReferencePointL( aNode, refValue, needRefValue );
}
aParam.SetEndReference( ref );
if ( needRefValue )
{
aParam.SetEndValue( refValue );
}
if ( aParam.StartReference() != EReferencePointUndefined &&
aParam.EndReference() != EReferencePointUndefined )
{
aParam.SetReferencePoint( EReferencePointUndefined );
}
float value = ParseFloatValueL(aNode->FirstChild());
aParam.SetEndMultiplier( value );
}
break;
}
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING("CHuiFxEffectParser::ParseAnimationNodeL - out");
#endif
}
void CHuiFxEffectParser::ResolveParamL( CMDXMLNode* aNode, CHuiFxLayer* aLayer )
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING1("CHuiFxEffectParser::ResolveParamL - 0x%x",this);
#endif
ASSERT(aNode->NodeType() == CMDXMLNode::EElementNode);
TInt nameIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitName );
TInt typeIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitType );
TInt refIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitRef );
if( nameIndex == KErrNotFound )
{
FAIL(KErrGeneral, _L("Parameter name not found"));
}
THuiFxReferencePoint ref = EReferencePointIdentity;
TBool isAnimated = EFalse;
TPtrC paramName;
TPtrC attributeName;
User::LeaveIfError(((CMDXMLElement*)aNode)->AttributeDetails(nameIndex, attributeName, paramName));
if (typeIndex != KErrNotFound)
{
TPtrC paramType;
User::LeaveIfError(((CMDXMLElement*)aNode)->AttributeDetails(typeIndex, attributeName, paramType));
if( paramType.Compare( KLitAnim ) == 0 )
{
isAnimated = ETrue;
aLayer->SetAnimated(ETrue);
}
else
{
FAIL(KErrGeneral, _L("Unsupported parameter type"));
}
}
TReal32 refValue;
TBool needRefValue = EFalse;
if ( refIndex != KErrNotFound )
{
ref = GetReferencePointL( aNode, refValue, needRefValue );
if ( ref == EReferencePointUndefined )
{
// For the parameters an undefined reference point means no value for the change
ref = EReferencePointIdentity;
}
}
MHuiFxParameter* param = NULL;
if (aLayer && aLayer->Type() == ELayerTypeFilter)
{
CHuiFxFilterLayer* filterLayer = reinterpret_cast<CHuiFxFilterLayer*>(aLayer);
// We must check if we really have a filter.
// If the filter type was incorrect, a filter was not created
// We should not crash or panic even if the effect file is not syntactically correct.
// An incorrect file should simply produce no effect.
CHuiFxFilter& filter = filterLayer->Filter();
if ( &filter )
{
param = filter.Parameter( paramName );
}
}
else if (aLayer && aLayer->Type() == ELayerTypeVisual)
{
CHuiFxVisualLayer* visualLayer = reinterpret_cast<CHuiFxVisualLayer*>(aLayer);
param = visualLayer->Parameter(paramName);
}
if (!param)
{
FAIL(KErrNotFound, _L("Parameter name not recognized")); // leaves
return; // never reached. For completeness
}
param->SetReferencePoint(ref);
if ( needRefValue )
{
param->SetReferenceValue( refValue );
}
if (isAnimated)
{
// Collect animation keyframes and other parameters
switch (param->Type())
{
case EParameterTypeScalar:
{
RHuiFxScalarTimeLine* t = new (ELeave) RHuiFxScalarTimeLine();
CHuiFxScalarParameter* p = static_cast<CHuiFxScalarParameter*>(param);
CleanupStack::PushL(t);
for (CMDXMLNode* child = aNode->FirstChild(); child; child = child->NextSibling())
{
ParseAnimationNodeL<CHuiFxScalarParameter, RHuiFxScalarTimeLine, CHuiFxScalarParameter::ValueType>(child, *p, *t);
}
CleanupStack::Pop(t);
p->SetTimeLine(t);
if ( p->ReferencePoint() == EReferencePointUndefined )
{
if ( paramName.Compare( KLitScaleX ) == 0 )
{
p->SetReferencePoint( EReferencePointVisualWidth );
}
else if ( paramName.Compare( KLitScaleY ) == 0 )
{
p->SetReferencePoint( EReferencePointVisualHeight );
}
else
{
p->SetReferencePoint( EReferencePointIdentity );
}
}
break;
}
case EParameterTypeColor:
{
RHuiFxColorTimeLine* t = new (ELeave) RHuiFxColorTimeLine();
CHuiFxColorParameter* p = static_cast<CHuiFxColorParameter*>(param);
CleanupStack::PushL(t);
for (CMDXMLNode* child = aNode->FirstChild(); child; child = child->NextSibling())
{
ParseAnimationNodeL<CHuiFxColorParameter, RHuiFxColorTimeLine, CHuiFxColorParameter::ValueType>(child, *p, *t);
}
CleanupStack::Pop(t);
p->SetTimeLine(t);
if ( p->ReferencePoint() == EReferencePointUndefined )
{
p->SetReferencePoint( EReferencePointIdentity );
}
break;
}
}
}
else
{
switch (param->Type())
{
case EParameterTypeScalar:
{
CHuiFxScalarParameter* p = static_cast<CHuiFxScalarParameter*>(param);
p->SetValue(ParseFloatValueL(aNode->FirstChild()));
break;
}
case EParameterTypeColor:
{
CHuiFxColorParameter* p = static_cast<CHuiFxColorParameter*>(param);
p->SetValue(ParseColorValueL(aNode->FirstChild()));
break;
}
}
}
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING("CHuiFxEffectParser::ResolveParamL - out ");
#endif
}
THuiFxFilterType CHuiFxEffectParser::GetFilterTypeL( CMDXMLNode* aNode )
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING1("CHuiFxEffectParser::GetFilterTypeL - 0x%x",this);
#endif
if (aNode->NodeType() != CMDXMLNode::EElementNode)
{
FAIL(KErrGeneral, _L("Text node expected while reading filter type"));
}
TInt attributeIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitType );
if (attributeIndex == KErrNotFound)
{
FAIL(KErrGeneral, _L("Filter type not found"));
}
TPtrC attributeValue;
TPtrC attributeName;
User::LeaveIfError(((CMDXMLElement*)aNode)->AttributeDetails( attributeIndex, attributeName, attributeValue));
if( attributeValue.Compare( KLitDesaturate ) == 0 )
{
return EFilterTypeDesaturate;
}
else if( attributeValue.Compare( KLitBlur ) == 0 )
{
return EFilterTypeBlur;
}
else if( attributeValue.Compare( KLitGlow ) == 0 )
{
return EFilterTypeGlow;
}
else if( attributeValue.Compare( KLitBrightnessContrast ) == 0 )
{
return EFilterTypeBrightnessContrast;
}
else if( attributeValue.Compare( KlitHSL ) == 0 )
{
return EFilterTypeHSL;
}
else if( attributeValue.Compare( KlitColorize ) == 0 )
{
return EFilterTypeColorize;
}
else if( attributeValue.Compare( KlitOutline ) == 0 )
{
return EFilterTypeOutline;
}
else if( attributeValue.Compare( KLitDropShadow ) == 0 )
{
// drop shadow is generated using outline filter
return EFilterTypeOutline;
}
else if( attributeValue.Compare( KlitBevel ) == 0 )
{
return EFilterTypeBevel;
}
else if ( attributeValue.Compare ( KlitTransform ) == 0 )
{
return EFilterTypeTransform;
}
else
{
return EFilterTypeUnknown;
}
}
THuiFxReferencePoint CHuiFxEffectParser::GetReferencePointL( CMDXMLNode* aNode, TReal32& aRefValue, TBool& aNeedRefValue )
{
__ALFFXLOGSTRING1("CHuiFxEffectParser::GetReferencePointL - 0x%x",this);
if (aNode->NodeType() != CMDXMLNode::EElementNode)
{
FAIL(KErrGeneral, _L("Text node expected while reading ref type"));
}
TInt attributeIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitRef );
THuiFxReferencePoint ref = EReferencePointIdentity;
if (attributeIndex == KErrNotFound)
{
ref = EReferencePointUndefined;
return ref;
}
aRefValue = 0;
TPtrC attributeName;
TPtrC paramRef;
User::LeaveIfError(((CMDXMLElement*)aNode)->AttributeDetails( attributeIndex, attributeName, paramRef));
TReal32 refValue = 0;
TBool needRefValue = EFalse;
if ( paramRef.Compare( KLitVisualWidth ) == 0 )
{
ref = EReferencePointVisualWidth;
}
else if ( paramRef.Compare( KLitVisualHeight ) == 0 )
{
ref = EReferencePointVisualHeight;
}
else if ( paramRef.Compare( KLitVisualTop ) == 0 )
{
ref = EReferencePointVisualTop;
}
else if ( paramRef.Compare( KLitVisualBottom ) == 0 )
{
ref = EReferencePointVisualBottom;
}
else if ( paramRef.Compare( KLitVisualLeft ) == 0 )
{
ref = EReferencePointVisualLeft;
}
else if ( paramRef.Compare( KLitVisualRight ) == 0 )
{
ref = EReferencePointVisualRight;
}
else if ( paramRef.Compare( KLitDisplayWidth ) == 0 )
{
ref = EReferencePointDisplayWidth;
}
else if ( paramRef.Compare( KLitDisplayHeight ) == 0 )
{
ref = EReferencePointDisplayHeight;
}
else if ( paramRef.Compare( KLitDisplayHeightMinusVisualTop ) == 0 )
{
ref = EReferencePointDisplayHeightMinusVisualTop;
}
else if ( paramRef.Compare( KLitDisplayTop ) == 0 )
{
ref = EReferencePointDisplayTop;
}
else if ( paramRef.Compare( KLitDisplayBottom ) == 0 )
{
ref = EReferencePointDisplayBottom;
}
else if ( paramRef.Compare( KLitDisplayLeft ) == 0 )
{
ref = EReferencePointDisplayLeft;
}
else if ( paramRef.Compare( KLitDisplayRight ) == 0 )
{
ref = EReferencePointDisplayRight;
}
else if ( paramRef.Compare( KLitExtRectWidth ) == 0 )
{
needRefValue = ETrue;
ref = EReferencePointExtRectWidth;
refValue = iExtRect.Width();
}
else if ( paramRef.Compare( KLitExtRectHeight ) == 0 )
{
needRefValue = ETrue;
ref = EReferencePointExtRectHeight;
refValue = iExtRect.Height();
}
else if ( paramRef.Compare( KLitExtRectTop ) == 0 )
{
needRefValue = ETrue;
ref = EReferencePointExtRectTop;
refValue = iExtRect.iTl.iY;
}
else if ( paramRef.Compare( KLitExtRectBottom ) == 0 )
{
needRefValue = ETrue;
ref = EReferencePointExtRectBottom;
refValue = iExtRect.iBr.iY;
}
else if ( paramRef.Compare( KLitExtRectLeft ) == 0 )
{
needRefValue = ETrue;
ref = EReferencePointExtRectLeft;
refValue = iExtRect.iTl.iX;
}
else if ( paramRef.Compare( KLitExtRectRight ) == 0 )
{
needRefValue = ETrue;
ref = EReferencePointExtRectRight;
refValue = iExtRect.iBr.iX;
}
// these are deprecated
else if (paramRef.Compare(KLitVisualWidth1) == 0)
{
ref = EReferencePointVisualWidth;
}
else if (paramRef.Compare(KLitVisualHeight1) == 0)
{
ref = EReferencePointVisualHeight;
}
else if (paramRef.Compare(KLitDisplayWidth1) == 0)
{
ref = EReferencePointDisplayWidth;
}
else if (paramRef.Compare(KLitDisplayHeight1) == 0)
{
ref = EReferencePointDisplayHeight;
}
else
{
FAIL(KErrGeneral, _L("Unsupported parameter reference point"));
}
aRefValue = refValue;
aNeedRefValue = needRefValue;
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING1("CHuiFxEffectParser::GetReferencePointL - return %d",ref);
#endif
return ref;
}
THuiFxVisualSrcType CHuiFxEffectParser::GetSrcTypeL( CMDXMLNode* aNode, TPtrC16& aBitmap )
{
#ifdef _HUI_FX_PARSER_LOGGING
__ALFFXLOGSTRING1("CHuiFxEffectParser::GetSrcTypeL - 0x%x ",this);
#endif
if (aNode->NodeType() != CMDXMLNode::EElementNode)
{
FAIL(KErrGeneral, _L("Text node expected while reading visual source type"));
}
TInt attributeIndex = ((CMDXMLElement*)aNode)->FindIndex( KLitSrc );
if (attributeIndex == KErrNotFound)
{
// If src not found, the source defaults to visual itself
return EVisualSrcVisual;
}
TPtrC attributeValue;
TPtrC attributeName;
User::LeaveIfError(((CMDXMLElement*)aNode)->AttributeDetails( attributeIndex, attributeName, attributeValue ));
if( attributeValue.Compare( KLitItem ) == 0 )
{
return EVisualSrcVisual;
}
else if ( attributeValue.Compare( KLitInput1 ) == 0 )
{
// This means that the source is given as a parameter to the effect
return EVisualSrcInput1;
}
else if ( attributeValue.Compare( KLitInput2 ) == 0 )
{
// This means that the source is given as a parameter to the effect
return EVisualSrcInput2;
}
else
{
// if nothing else is defined, the src represents an external file (bitmap)
aBitmap.Set( attributeValue );
return EVisualSrcBitmap;
}
}
void CHuiFxEffectParser::FailL(TInt aCode, TRefByValue<const TDesC> aFormat, ...)
{
TBuf<512> message;
VA_LIST args;
VA_START(args, aFormat);
message.Append(_L("CHuiFxEffectParser::Fail(): "));
message.AppendFormatList(aFormat, args);
VA_END(args);
__ALFFXLOGSTRING1("CHuiFxEffectParser::FailL %S", &message);
User::InfoPrint( message );
User::Leave(aCode);
}