svgtopt/SVG/SVGImpl/src/SVGUseElementImpl.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 07 Jan 2010 16:19:02 +0200
changeset 0 d46562c3d99d
permissions -rw-r--r--
Revision: 200951 Kit: 201001

/*
* 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:  SVG Implementation source file
 *
*/


#if !defined(__E32BASE_H__)
#include <e32base.h>
#endif

#include "SVGUseElementImpl.h"
#include "SVGElementImpl.h"
#include "SVGDocumentImpl.h"

#include "GfxAffineTransform.h"

#include "SVGImageElementImpl.h"

_LIT( XLINKHREF, "xlink:href" );
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------

CSvgUseElementImpl* CSvgUseElementImpl::NewL(  const TUint8 aElemID,
                                              CSvgDocumentImpl* aDoc )
    {
    CSvgUseElementImpl* self    = new ( ELeave ) CSvgUseElementImpl( aDoc );
    CleanupStack::PushL( self );
    self->ConstructL(  aElemID );

    CleanupStack::Pop();

    return self;
    }

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------

CSvgUseElementImpl* CSvgUseElementImpl::NewLC(  const TUint8 aElemID,
                                              CSvgDocumentImpl* aDoc )

	{
    CSvgUseElementImpl* self    = new ( ELeave ) CSvgUseElementImpl( aDoc );
    CleanupStack::PushL( self );
    self->ConstructL( aElemID );

    return self;
    }


// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
void CSvgUseElementImpl::ConstructL( const TUint8 aElemID)
	{
    CSvgElementImpl::InitializeL( aElemID );

	iSvgStyleProperties = new(ELeave) RPointerArray<CCssValue>(KCSS_MAX_ATTR);
	User::LeaveIfError( iSvgStyleProperties->Append( NULL ) );
	iSvgStyleProperties->Remove( 0 );
    iSvgTransformable = CSvgTransformableImpl::NewL();
    iSvgUriReferenceImpl = CSvgUriReferenceImpl::NewL();

	#ifdef SVG_FLOAT_BUILD
    iX = 0 ;
    iY = 0 ;
	#else
    iX.operator = ( 0 );
    iY.operator = ( 0 );
	#endif
    //iXSet = EFalse;
    //iYSet = EFalse;

	iReqAttrFlag = KAtrXlinkhref;
    }
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
CSvgUseElementImpl::~CSvgUseElementImpl()
    {

	if ( iSvgUriReferenceImpl )
		{
		delete iSvgUriReferenceImpl;
		iSvgUriReferenceImpl = NULL;
        }

	if ( iSvgStyleProperties )
		{
		iSvgStyleProperties->Close();
		delete iSvgStyleProperties;
		iSvgStyleProperties = NULL;
		}
	if ( iUseHRef )
	    {
		delete iUseHRef;
		iUseHRef = NULL;
		}	
    }

// *******************************************************
// From SVG DOM

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TFloatFixPt CSvgUseElementImpl::X()
    {
    return iX;
    }

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TFloatFixPt CSvgUseElementImpl::Y()
    {
    return iY;
    }

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TFloatFixPt CSvgUseElementImpl::Width()
    {
    return iWidth;
    }

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TFloatFixPt CSvgUseElementImpl::Height()
    {
    return iHeight;
    }

// *******************************************************
// SVG Implementation


// *******************************************************
// From MXmlElement

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TInt CSvgUseElementImpl::SetAttributeL( const TDesC& aName,
                                        const TDesC& aValue )
    {

	CSvgElementImpl::SetAttributeL(aName,aValue);
    // Get the path from the xlink
    _LIT( KXLink, "xlink:href" );
    if ( aName == KXLink )
        {
        iReqAttrFlag = 0;

        // STEP 1 - Get the reference element
        // If the first char is '#' then remove it
        // This is possible if coming from cXML parser and not CVG Decoder
        
        TInt pos1 = aValue.Locate('/');
        
        if ( pos1 != KErrNotFound)
        {
        	if (iOwnerDocument)
        	{
        			_LIT( KMsg, "Non-local valid URI in <use> element" );
                			((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, aValue );
                    		((CSvgDocumentImpl*)iOwnerDocument)->SetIsWarning( ETrue );
        	}
        }
        
        TInt pos = aValue.Locate( '#' );
        if ( pos != KErrNotFound && pos == 0 )
            {
            TPtrC ptr( &aValue[1], aValue.Length() - 1);
            
            // Maintain one more class level member for JSR
            // This member will contain the value starting with '#'
            if ( iUseHRef )
			    {
				delete iUseHRef;
				iUseHRef = NULL;
			    }
			    
		    iUseHRef = aValue.AllocL();

            if ( this->SetXlinkAttributeL( aName, ptr ) )
                {
                ireferenceEl = NULL;
                if ( iOwnerDocument )
                    {
                    ireferenceEl = (CSvgElementImpl*)((CSvgDocumentImpl*)iOwnerDocument)->GetElementById( ptr );

                    if ( ireferenceEl && ireferenceEl->ElemID() == KSvgUseElement)
                    {
                    	((CSvgUseElementImpl*)ireferenceEl)->iUseElementThatUsesThisUse = this;

                    	if ( ((CSvgUseElementImpl*)ireferenceEl)->iUseElementThatUsesThisUse == iUseElementThatUsesThisUse )
                    	{
                    		//then there are use elements in recursion
                    		// Set error in document
                			_LIT( KMsg, "URI in <use> causes recursion loop with another <use>: " );
                			((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, aValue );
                    		((CSvgDocumentImpl*)iOwnerDocument)->SetIsWarning( EFalse );

                    		//get rid of the loop by removing this one
                    		ireferenceEl = NULL;
                    	}
                    }


                    }
                if(ireferenceEl == NULL)
                    {
                    // Set error in document
                    if ( iOwnerDocument && ((CSvgDocumentImpl*)iOwnerDocument)->iFinishedParsing )
                        {
                        _LIT( KMsg, "Invalid URI in <use> element: " );
                        ((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, aValue );
                        }
                    return KErrReferencedElementNotFound; // failure in finding the referenced element
                    }
                }
            }
        else if ( pos > 0 && iOwnerDocument && ((CSvgDocumentImpl*)iOwnerDocument)->iFinishedParsing )
            {
            // Set error in document
            _LIT( KMsg, "Non-local valid URI in <use> element: " );
            ((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, aValue );
            }
        else if( pos == KErrNotFound )
            {
            
            // Maintain one more class level member for JSR
            // This member will contain the value starting with '#'
            if ( iUseHRef )
		        {
			    delete iUseHRef;
			    iUseHRef = NULL;
			    }
			        
		    iUseHRef = aValue.AllocL();
            TPtrC ptr( &aValue[0], aValue.Length());
            this->SetXlinkAttributeL( aName, ptr);
            }
        }
    return KErrNone;
    }

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TInt CSvgUseElementImpl::SetAttributeDesL( const TInt aNameId,
                                        const TDesC& aValue )
{
    switch ( aNameId )
        {
        case KAtrXlinkhref:
            {
            iReqAttrFlag = 0;

            // STEP 1 - Get the reference element
            // If the first char is '#' then remove it
            // This is possible if coming from cXML parser and not CVG Decoder
            TInt pos1 = aValue.Locate('/');
        
        	if ( pos1 != KErrNotFound)
        	{
        		if (iOwnerDocument)
        		{
        			_LIT( KMsg, "Non-local valid URI in <use> element" );
                			((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, aValue );
                    		((CSvgDocumentImpl*)iOwnerDocument)->SetIsWarning( ETrue );
        		}
        	}
        
            
            TInt pos = aValue.Locate( '#' );
            if ( pos != KErrNotFound && pos == 0 )
                {

                TPtrC ptr( &aValue[1], aValue.Length() - 1);
                // Maintain one more class level member for JSR
                // This member will contain the value starting with '#'
			    if ( iUseHRef )
			       {
				   delete iUseHRef;
				   iUseHRef = NULL;
			       }
		     	iUseHRef = aValue.AllocL();

                if ( this->SetXlinkAttributeL( XLINKHREF, ptr ) )
                    {
                    ireferenceEl = NULL;
                    if ( iOwnerDocument )
                        {
                        ireferenceEl = (CSvgElementImpl*)((CSvgDocumentImpl*)iOwnerDocument)->GetElementById( ptr );

                        if (ireferenceEl && ireferenceEl->ElemID() == KSvgUseElement)
                            {
                    	    ((CSvgUseElementImpl*)ireferenceEl)->iUseElementThatUsesThisUse = this;

                        	if ( ((CSvgUseElementImpl*)ireferenceEl)->iUseElementThatUsesThisUse == iUseElementThatUsesThisUse )
                    	        {
                    	    	//then there are use elements in recursion
                    		    _LIT( KMsg, "URI in <use> causes recursion loop with another <use>: " );
                			    ((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, aValue );
                    		    ((CSvgDocumentImpl*)iOwnerDocument)->SetIsWarning( EFalse );

                    	     	//get rid of the loop by removing this one
                    		    ireferenceEl = NULL;
                        	    }
                            }

                        }
                if(ireferenceEl == NULL)
                    {
                    // Set error in document
                    if ( iOwnerDocument && ((CSvgDocumentImpl*)iOwnerDocument)->iFinishedParsing)
                        {
                        _LIT( KMsg, "Invalid URI in <use> element: " );
                        ((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, aValue );
                        }
                    return KErrReferencedElementNotFound; // failure in finding the referenced element
                    }
                }
            }
        else if ( pos > 0 && iOwnerDocument && ((CSvgDocumentImpl*)iOwnerDocument)->iFinishedParsing )
                {
                // Set error in document
                _LIT( KMsg, "Non-local valid URI in <use> element: " );
                ((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, aValue );
                }
        else if( pos == KErrNotFound )
                {
                // Maintain one more class level member for JSR
                // This member will contain the value starting with '#'
                if ( iUseHRef )
			        {
				    delete iUseHRef;
				    iUseHRef = NULL;
			        }
			    
		        iUseHRef = aValue.AllocL();
		        
            	TPtrC ptr( &aValue[0], aValue.Length());
            	this->SetXlinkAttributeL( XLINKHREF, ptr);
                }
            return KErrNone;
            }

        default:
            {
            return CSvgElementImpl::SetAttributeDesL( aNameId, aValue );
            }
        }
    }


// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TInt CSvgUseElementImpl::GetAttributeDes( const TInt aNameId, TPtrC16& aValue )
    {
 
    if ( aNameId == KAtrXlinkhref )
       	{
       	// iUseHRef contains value starting with '#'
       	if ( iUseHRef )
       	{
       		aValue.Set( *iUseHRef );
		    return KErrNone;
       	}
       	
       	if ( iSvgUriReferenceImpl )
       	{
       		aValue.Set( iSvgUriReferenceImpl->Href());
       		return KErrNone;
       	}
       
       }

    return CSvgElementImpl::GetAttributeDes( aNameId, aValue );

    }



// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TInt CSvgUseElementImpl::SetAttributeFloatL( const TInt aNameId,
                                              const TFloatFixPt aValue )
    {
    switch ( aNameId )
        {
        case KAtrX:
					iX = aValue;
					//iXSet = ETrue;
			        break;
        case KAtrY:

					iY = aValue;
					//iYSet = ETrue;
				    break;
        case KAtrWidth:
					iWidth = aValue;
			        break;

        case KAtrHeight:
					iHeight = aValue;
			        break;
        default:
        return CSvgElementImpl::SetAttributeFloatL( aNameId, aValue );
        }
    return KErrNone;
    }


// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TInt CSvgUseElementImpl::GetAttributeFloat( const TInt aNameId,
                                             TFloatFixPt& aValue )
    {
    switch ( aNameId )
        {
        case KAtrX:
				 aValue =	iX ;
			     break;
        case KAtrY:

				aValue =	iY ;
			    break;
        case KAtrWidth:
				aValue =	iWidth ;
		        break;

        case KAtrHeight:
				 aValue = 	iHeight ;
		        break;
        default:
        return CSvgElementImpl::GetAttributeFloat( aNameId, aValue );
        }
    return KErrNone;
    }


// *******************************************************
// From MXmlElementOpt

// *******************************************************
// From CSvgElementImpl

// perform a deep clone of this object
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
MXmlElement* CSvgUseElementImpl::CloneL(MXmlElement* aParentElement)
    {

	CSvgUseElementImpl* newElement = CSvgUseElementImpl::NewL(  this->ElemID(),
										((CSvgDocumentImpl*)iOwnerDocument) );
		CleanupStack::PushL(newElement);

	newElement->iParentNode = aParentElement;
    // copy everything over
    this->CopyL(newElement);
CleanupStack::Pop();
    return newElement;
    }

//---------------------------------------------------------------------------
// perform a deep copy of this object
//
//---------------------------------------------------------------------------
void CSvgUseElementImpl::CopyL( CSvgUseElementImpl* aDestElement )
    {
    	if(aDestElement)
		{
	    // copy stuff from superclass
	    this->CSvgElementImpl::CopyL(aDestElement);

	    // copy iRectangle items special to circle
	    aDestElement->iX = this->iX;
	    aDestElement->iY = this->iY;
	    aDestElement->iHeight = this->iHeight;
	    aDestElement->iWidth = this->iWidth;

		aDestElement->ireferenceEl = this->ireferenceEl;
		aDestElement->iUseElementThatUsesThisUse = this->iUseElementThatUsesThisUse;

		 // copy the reference to idoc (CSvgDocumentImpl)
	    aDestElement->iOwnerDocument = this->iOwnerDocument;
		}
    }

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
TBool CSvgUseElementImpl::DrawL( CGfx2dGc* /* aGc */,
                                 CSvgElementImpl* /* aElement */ )
    {
    return ETrue;
    }

// *******************************************************
// Private



// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
CSvgUseElementImpl::CSvgUseElementImpl( CSvgDocumentImpl* aDoc )
    {
	SetOwnerDocument(aDoc);
    }

/*
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
void CSvgUseElementImpl::DeepClone( MXmlElement* aReferenceEl )
    {
    CSvgElementImpl*aNewElement = ( CSvgElementImpl* )
                                  aReferenceEl->FirstChild();
    while ( aNewElement )
        {
        DeepClone( aNewElement );
        aNewElement = ( CSvgElementImpl * ) aNewElement->NextSibling();
        }
    }
*/

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
void CSvgUseElementImpl::SetReferenceElementL()
    {
	if( ireferenceEl != NULL )
		{
 		CSvgElementImpl* theElement = (CSvgElementImpl *)ireferenceEl->CloneL((MXmlElement*)this);
 		CleanupStack::PushL(theElement);
		this->CXmlElementImpl::AppendChildL(theElement);
		CleanupStack::Pop();

		//if reference element is a use element check for recursion loop
		if (ireferenceEl->ElemID() == KSvgUseElement)
            {
        	((CSvgUseElementImpl*)ireferenceEl)->iUseElementThatUsesThisUse = this;

        	if ( ireferenceEl == iUseElementThatUsesThisUse )
            	{
        		//then there are use elements in recursion
        		_LIT( KMsg, "URI in <use> causes recursion loop with another <use>: " );
    			((CSvgDocumentImpl*)iOwnerDocument)->SetError( KErrNotFound, KMsg, Href() );
        		((CSvgDocumentImpl*)iOwnerDocument)->SetIsWarning( EFalse );

        		//get rid of the loop by removing this one
        		ireferenceEl = NULL;
            	}
            }
        }
    }
    
    
CSvgElementImpl* CSvgUseElementImpl::GetReferenceElementL()
{
	return ireferenceEl;
}

TInt  CSvgUseElementImpl::SetRefElemById(const TDesC& aName)
    {
     ireferenceEl = ( CSvgElementImpl * )
        ((CSvgDocumentImpl*)iOwnerDocument)->GetElementById( aName );
    iReqAttrFlag = 0;

     return ( ireferenceEl == NULL ) ? KErrNotFound : KErrNone;
    }

void CSvgUseElementImpl::GetUnscaledBBox( TGfxRectangle2D& aBbox )
{
	TGfxRectangle2D lReferenceBbox;
	if (ireferenceEl != NULL)
	{
		((CSvgElementImpl*)ireferenceEl)->GetUnscaledBBox(lReferenceBbox);
	}

	// width and height
	aBbox.iX = lReferenceBbox.iX + X();
	aBbox.iY = lReferenceBbox.iY + Y();
	aBbox.iWidth = lReferenceBbox.iWidth;
	aBbox.iHeight = lReferenceBbox.iHeight;
}

TBool CSvgUseElementImpl::IsViewable( )
{
	if (ireferenceEl)
	{
		return ireferenceEl->IsViewable();
	}

	return EFalse;
}

void CSvgUseElementImpl::GetBBox( TGfxRectangle2D& aBbox )
{
	TGfxRectangle2D lReferenceBbox;
	if (ireferenceEl)
	{
		((CSvgElementImpl*)ireferenceEl)->GetBBox(lReferenceBbox);
	}

	// width and height
	aBbox.iX = lReferenceBbox.iX + X();
	aBbox.iY = lReferenceBbox.iY + Y();
	aBbox.iWidth = lReferenceBbox.iWidth;
	aBbox.iHeight = lReferenceBbox.iHeight;

}

void CSvgUseElementImpl::Print( TBool aIsEncodeOn )
{
	if (!aIsEncodeOn)
	{
		#ifdef _DEBUG
		RDebug::Printf("<use x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"hmm\">", (int)iX, (int)iY, (int)iWidth, (int)iHeight/*, Href()*/);
		#endif
	}
}
// new function
void CSvgUseElementImpl::GetBoundingBox( TGfxRectangle2D& aBbox ) 
{
	TGfxRectangle2D lReferenceBbox;
	if (ireferenceEl != NULL)
	{
	TGfxAffineTransform lTempCTM = ((CSvgElementImpl*)ireferenceEl)->GetCTM();
	TGfxAffineTransform lElementCTM = ((CSvgElementImpl*)this)->GetCTM();
	MSvgTransformList*  trList;
    TGfxAffineTransform lElementTransform;
    ((CSvgElementImpl*)ireferenceEl)->GetTransform( trList);
    lElementTransform = trList->Consolidate( ((CSvgElementImpl*)ireferenceEl)->IsOverwriteTransforms() );
	lElementTransform.Concatenate(lElementCTM);
	
	((CSvgElementImpl*)ireferenceEl)->SetCTM(lElementTransform);
    //((CSvgElementImpl*)ireferenceEl)->GetBBox(lReferenceBbox);
	((CSvgElementImpl*)ireferenceEl)->GetUnscaledBBox(lReferenceBbox);
	lReferenceBbox.GetBounds(lElementTransform, lReferenceBbox);
	
    ((CSvgElementImpl*)ireferenceEl)->SetCTM(lTempCTM);
	}
	// width and height
	aBbox.iX = lReferenceBbox.iX + X();
	aBbox.iY = lReferenceBbox.iY + Y();
	aBbox.iWidth = lReferenceBbox.iWidth;
	aBbox.iHeight = lReferenceBbox.iHeight;

}