diff options
author | Rüdiger Timm <rt@openoffice.org> | 2004-11-26 13:26:43 +0000 |
---|---|---|
committer | Rüdiger Timm <rt@openoffice.org> | 2004-11-26 13:26:43 +0000 |
commit | 861699fb8977371be8ae8bb5d41980844fb9d4c2 (patch) | |
tree | 27fd39b12c1b5c710a5be4825cfa147514deef5d /svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx | |
parent | 8689e5533a7a0abb5f00df3b6c29869458631fe2 (diff) |
INTEGRATION: CWS sj12 (1.1.2); FILE ADDED
2004/11/17 11:11:40 sj 1.1.2.5: fixed some link problems
2004/11/11 01:23:02 sj 1.1.2.4: #i36002# file format change
2004/11/05 16:27:23 sj 1.1.2.3: #i36003,i36002# file format changes for custom shapes
2004/11/04 20:23:15 sj 1.1.2.2: initial version
2004/11/01 17:21:29 sj 1.1.2.1: #i36003# initial version
Diffstat (limited to 'svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx')
-rw-r--r-- | svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx b/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx new file mode 100644 index 000000000000..b12586685457 --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx @@ -0,0 +1,1127 @@ +/************************************************************************* + * + * $RCSfile: EnhancedCustomShapeFunctionParser.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: rt $ $Date: 2004-11-26 14:26:43 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +// must be first +#include <EnhancedCustomShapeFunctionParser.hxx> +#ifndef _ENHANCEDCUSTOMSHAPE2D_HXX +#include "EnhancedCustomShape2d.hxx" +#endif +#ifndef _RTL_USTRING_HXX_ +#include <rtl/ustring.hxx> +#endif +#ifndef _FRACT_HXX +#include <tools/fract.hxx> +#endif + +// Makes parser a static resource, +// we're synchronized externally. +// But watch out, the parser might have +// state not visible to this code! +#define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE +#if defined(VERBOSE) && defined(DBG_UTIL) +#include <typeinfo> +#define BOOST_SPIRIT_DEBUG +#endif +#include <boost/spirit/core.hpp> + +#include <iostream> +#include <functional> +#include <algorithm> +#include <stack> +using namespace com::sun::star; +using namespace drafts::com::sun::star::drawing; + +void FillEquationParameter( const EnhancedCustomShapeParameter& rSource, const sal_Int32 nDestPara, EnhancedCustomShapeEquation& rDest ) +{ + sal_Int32 nValue = 0; + if ( rSource.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fValue; + if ( rSource.Value >>= fValue ) + nValue = (sal_Int32)fValue; + } + else + rSource.Value >>= nValue; + + switch( rSource.Type ) + { + case drafts::com::sun::star::drawing::EnhancedCustomShapeParameterType::EQUATION : + { + if ( nValue & 0x40000000 ) + { + nValue ^= 0x40000000; + rDest.nOperation |= 0x20000000 << nDestPara; // the bit is indicating that this value has to be adjusted later + } + nValue |= 0x400; + } + break; + case drafts::com::sun::star::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT : nValue += DFF_Prop_adjustValue; break; + case drafts::com::sun::star::drawing::EnhancedCustomShapeParameterType::BOTTOM : nValue = DFF_Prop_geoBottom; break; + case drafts::com::sun::star::drawing::EnhancedCustomShapeParameterType::RIGHT : nValue = DFF_Prop_geoRight; break; + case drafts::com::sun::star::drawing::EnhancedCustomShapeParameterType::TOP : nValue = DFF_Prop_geoTop; break; + case drafts::com::sun::star::drawing::EnhancedCustomShapeParameterType::LEFT : nValue = DFF_Prop_geoLeft; break; + } + if ( rSource.Type != drafts::com::sun::star::drawing::EnhancedCustomShapeParameterType::NORMAL ) + rDest.nOperation |= ( 0x2000 << nDestPara ); + rDest.nPara[ nDestPara ] = nValue; +} + +namespace +{ + +////////////////////// +////////////////////// +// EXPRESSION NODES +////////////////////// +////////////////////// +class ConstantValueExpression : public ExpressionNode +{ + double maValue; + +public: + + ConstantValueExpression( double rValue ) : + maValue( rValue ) + { + } + virtual double operator()() const + { + return maValue; + } + virtual bool isConstant() const + { + return true; + } + virtual ExpressionFunct getType() const + { + return FUNC_CONST; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* mpOptionalArg = NULL ) + { + EnhancedCustomShapeParameter aRet; + Fraction aFract( maValue ); + if ( aFract.GetDenominator() == 1 ) + { + aRet.Type = EnhancedCustomShapeParameterType::NORMAL; + aRet.Value <<= (sal_Int32)aFract.GetNumerator(); + } + else + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation = 1; + aEquation.nPara[ 0 ] = 1; + aEquation.nPara[ 1 ] = (sal_Int16)aFract.GetNumerator(); + aEquation.nPara[ 2 ] = (sal_Int16)aFract.GetDenominator(); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + return aRet; + } +}; + +class AdjustmentExpression : public ExpressionNode +{ + sal_Int32 mnIndex; + const EnhancedCustomShape2d& mrCustoShape; + +public: + + AdjustmentExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex ) : + mrCustoShape( rCustoShape ), + mnIndex ( nIndex ) + { + } + virtual double operator()() const + { + return mrCustoShape.GetAdjustValueAsDouble( mnIndex ); + } + virtual bool isConstant() const + { + return false; + } + virtual ExpressionFunct getType() const + { + return ENUM_FUNC_ADJUSTMENT; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* mpOptionalArg = NULL ) + { + EnhancedCustomShapeParameter aRet; + aRet.Type = EnhancedCustomShapeParameterType::ADJUSTMENT; + aRet.Value <<= mnIndex; + return aRet; + } +}; + +class EquationExpression : public ExpressionNode +{ + sal_Int32 mnIndex; + const EnhancedCustomShape2d& mrCustoShape; + +public: + + EquationExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex ) : + mrCustoShape( rCustoShape ), + mnIndex ( nIndex ) + { + } + virtual double operator()() const + { + return mrCustoShape.GetEquationValueAsDouble( mnIndex ); + } + virtual bool isConstant() const + { + return false; + } + virtual ExpressionFunct getType() const + { + return ENUM_FUNC_EQUATION; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* mpOptionalArg = NULL ) + { + EnhancedCustomShapeParameter aRet; + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= mnIndex | 0x40000000; // the bit is indicating that this equation needs to be adjusted later + return aRet; + } +}; + +class EnumValueExpression : public ExpressionNode +{ + const ExpressionFunct meFunct; + const EnhancedCustomShape2d& mrCustoShape; + +public: + + EnumValueExpression( const EnhancedCustomShape2d& rCustoShape, const ExpressionFunct eFunct ) : + mrCustoShape ( rCustoShape ), + meFunct ( eFunct ) + { + } + static double getValue( const EnhancedCustomShape2d& rCustoShape, const ExpressionFunct eFunc ) + { + EnhancedCustomShape2d::EnumFunc eF; + switch( eFunc ) + { + case ENUM_FUNC_PI : eF = EnhancedCustomShape2d::ENUM_FUNC_PI; break; + case ENUM_FUNC_LEFT : eF = EnhancedCustomShape2d::ENUM_FUNC_LEFT; break; + case ENUM_FUNC_TOP : eF = EnhancedCustomShape2d::ENUM_FUNC_TOP; break; + case ENUM_FUNC_RIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_RIGHT; break; + case ENUM_FUNC_BOTTOM : eF = EnhancedCustomShape2d::ENUM_FUNC_BOTTOM; break; + case ENUM_FUNC_XSTRETCH : eF = EnhancedCustomShape2d::ENUM_FUNC_XSTRETCH; break; + case ENUM_FUNC_YSTRETCH : eF = EnhancedCustomShape2d::ENUM_FUNC_YSTRETCH; break; + case ENUM_FUNC_HASSTROKE : eF = EnhancedCustomShape2d::ENUM_FUNC_HASSTROKE; break; + case ENUM_FUNC_HASFILL : eF = EnhancedCustomShape2d::ENUM_FUNC_HASFILL; break; + case ENUM_FUNC_WIDTH : eF = EnhancedCustomShape2d::ENUM_FUNC_WIDTH; break; + case ENUM_FUNC_HEIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_HEIGHT; break; + case ENUM_FUNC_LOGWIDTH : eF = EnhancedCustomShape2d::ENUM_FUNC_LOGWIDTH; break; + case ENUM_FUNC_LOGHEIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_LOGHEIGHT; break; + + default : + return 0.0; + } + return rCustoShape.GetEnumFunc( eF ); + } + virtual double operator()() const + { + return getValue( mrCustoShape, meFunct ); + } + virtual bool isConstant() const + { + return false; + } + virtual ExpressionFunct getType() const + { + return meFunct; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* mpOptionalArg = NULL ) + { + EnhancedCustomShapeParameter aRet; + + sal_Int32 nDummy = 1; + aRet.Value <<= nDummy; + + switch( meFunct ) + { + case ENUM_FUNC_WIDTH : // TODO: do not use this as constant value + case ENUM_FUNC_HEIGHT : + case ENUM_FUNC_LOGWIDTH : + case ENUM_FUNC_LOGHEIGHT : + case ENUM_FUNC_PI : + { + ConstantValueExpression aConstantValue( getValue( mrCustoShape, meFunct ) ); + aRet = aConstantValue.fillNode( rEquations ); + } + break; + case ENUM_FUNC_LEFT : aRet.Type = EnhancedCustomShapeParameterType::LEFT; break; + case ENUM_FUNC_TOP : aRet.Type = EnhancedCustomShapeParameterType::TOP; break; + case ENUM_FUNC_RIGHT : aRet.Type = EnhancedCustomShapeParameterType::RIGHT; break; + case ENUM_FUNC_BOTTOM : aRet.Type = EnhancedCustomShapeParameterType::BOTTOM; break; + + // not implemented so far + case ENUM_FUNC_XSTRETCH : + case ENUM_FUNC_YSTRETCH : + case ENUM_FUNC_HASSTROKE : + case ENUM_FUNC_HASFILL : aRet.Type = EnhancedCustomShapeParameterType::NORMAL; break; + } + return aRet; + } +}; + +/** ExpressionNode implementation for unary + function over one ExpressionNode + */ +class UnaryFunctionExpression : public ExpressionNode +{ + const ExpressionFunct meFunct; + ExpressionNodeSharedPtr mpArg; + +public: + UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) : + meFunct( eFunct ), + mpArg( rArg ) + { + } + static double getValue( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) + { + double fRet = 0; + switch( eFunct ) + { + case UNARY_FUNC_ABS : fRet = fabs( (*rArg)() ); break; + case UNARY_FUNC_SQRT: fRet = sqrt( (*rArg)() ); break; + case UNARY_FUNC_SIN : fRet = sin( (*rArg)() ); break; + case UNARY_FUNC_COS : fRet = cos( (*rArg)() ); break; + case UNARY_FUNC_TAN : fRet = tan( (*rArg)() ); break; + case UNARY_FUNC_ATAN: fRet = atan( (*rArg)() ); break; + case UNARY_FUNC_NEG : fRet = ::std::negate<double>()( (*rArg)() ); break; + } + return fRet; + } + virtual double operator()() const + { + return getValue( meFunct, mpArg ); + } + virtual bool isConstant() const + { + return mpArg->isConstant(); + } + virtual ExpressionFunct getType() const + { + return meFunct; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* mpOptionalArg = NULL ) + { + EnhancedCustomShapeParameter aRet; + switch( meFunct ) + { + case UNARY_FUNC_ABS : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 3; + FillEquationParameter( mpArg->fillNode( rEquations ), 0, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_SQRT: + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 13; + FillEquationParameter( mpArg->fillNode( rEquations ), 0, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_SIN : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 9; + if ( mpOptionalArg ) + FillEquationParameter( mpOptionalArg->fillNode( rEquations ), 0, aEquation ); + else + aEquation.nPara[ 0 ] = 1; + FillEquationParameter( mpArg->fillNode( rEquations ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_COS : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 10; + if ( mpOptionalArg ) + FillEquationParameter( mpOptionalArg->fillNode( rEquations ), 0, aEquation ); + else + aEquation.nPara[ 0 ] = 1; + FillEquationParameter( mpArg->fillNode( rEquations ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_TAN : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 16; + if ( mpOptionalArg ) + FillEquationParameter( mpOptionalArg->fillNode( rEquations ), 0, aEquation ); + else + aEquation.nPara[ 0 ] = 1; + FillEquationParameter( mpArg->fillNode( rEquations ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_ATAN: + { +// TODO: + aRet.Type = EnhancedCustomShapeParameterType::NORMAL; + } + break; + case UNARY_FUNC_NEG: + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 1; + aEquation.nPara[ 1 ] = -1; + aEquation.nPara[ 2 ] = 1; + FillEquationParameter( mpArg->fillNode( rEquations ), 0, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + } + return aRet; + } +}; + +/** ExpressionNode implementation for unary + function over two ExpressionNodes + */ +class BinaryFunctionExpression : public ExpressionNode +{ + const ExpressionFunct meFunct; + ExpressionNodeSharedPtr mpFirstArg; + ExpressionNodeSharedPtr mpSecondArg; + +public: + + BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) : + meFunct( eFunct ), + mpFirstArg( rFirstArg ), + mpSecondArg( rSecondArg ) + { + } + static double getValue( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) + { + double fRet = 0; + switch( eFunct ) + { + case BINARY_FUNC_PLUS : fRet = (*rFirstArg)() + (*rSecondArg)(); break; + case BINARY_FUNC_MINUS: fRet = (*rFirstArg)() - (*rSecondArg)(); break; + case BINARY_FUNC_MUL : fRet = (*rFirstArg)() * (*rSecondArg)(); break; + case BINARY_FUNC_DIV : fRet = (*rFirstArg)() / (*rSecondArg)(); break; + case BINARY_FUNC_MIN : fRet = ::std::min( (*rFirstArg)(), (*rSecondArg)() ); break; + case BINARY_FUNC_MAX : fRet = ::std::max( (*rFirstArg)(), (*rSecondArg)() ); break; + case BINARY_FUNC_ATAN2: fRet = atan2( (*rFirstArg)(), (*rSecondArg)() ); break; + } + return fRet; + } + virtual double operator()() const + { + return getValue( meFunct, mpFirstArg, mpSecondArg ); + } + virtual bool isConstant() const + { + return mpFirstArg->isConstant() && mpSecondArg->isConstant(); + } + virtual ExpressionFunct getType() const + { + return meFunct; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* mpOptionalArg = NULL ) + { + EnhancedCustomShapeParameter aRet; + switch( meFunct ) + { + case BINARY_FUNC_PLUS : + { + sal_Bool bFirstIsEmpty = mpFirstArg->isConstant() && ( (*mpFirstArg)() == 0 ); + sal_Bool bSecondIsEmpty = mpSecondArg->isConstant() && ( (*mpSecondArg)() == 0 ); + + if ( bFirstIsEmpty ) + aRet = mpSecondArg->fillNode( rEquations ); + else if ( bSecondIsEmpty ) + aRet = mpFirstArg->fillNode( rEquations ); + else + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 0; + FillEquationParameter( mpFirstArg->fillNode( rEquations ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + } + break; + case BINARY_FUNC_MINUS: + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 0; + FillEquationParameter( mpFirstArg->fillNode( rEquations ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations ), 2, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case BINARY_FUNC_MUL : + { + + // in the dest. format the cos function is using integer as result :-( + // so we can't use the generic algorithm + if ( ( mpFirstArg->getType() == UNARY_FUNC_SIN ) || ( mpFirstArg->getType() == UNARY_FUNC_COS ) || ( mpFirstArg->getType() == UNARY_FUNC_TAN ) ) + aRet = mpFirstArg->fillNode( rEquations, mpSecondArg.get() ); + else if ( ( mpSecondArg->getType() == UNARY_FUNC_SIN ) || ( mpSecondArg->getType() == UNARY_FUNC_COS ) || ( mpSecondArg->getType() == UNARY_FUNC_TAN ) ) + aRet = mpSecondArg->fillNode( rEquations, mpFirstArg.get() ); + else + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 1; + FillEquationParameter( mpFirstArg->fillNode( rEquations ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations ), 1, aEquation ); + aEquation.nPara[ 2 ] = 1; + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + } + break; + case BINARY_FUNC_DIV : + { + EnhancedCustomShapeEquation aEquation; + if ( ( mpFirstArg->getType() == ENUM_FUNC_PI ) && ( mpSecondArg->getType() == FUNC_CONST ) ) + { + sal_Int32 nVal = 1; // a quick DEG<->RAD conversion->has to be improved + aRet.Type = EnhancedCustomShapeParameterType::NORMAL; + aRet.Value <<= nVal; + } + else + { + aEquation.nOperation |= 1; + FillEquationParameter( mpFirstArg->fillNode( rEquations ), 0, aEquation ); + aEquation.nPara[ 1 ] = 1; + FillEquationParameter( mpSecondArg->fillNode( rEquations ), 2, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + } + break; + case BINARY_FUNC_MIN : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 4; + FillEquationParameter( mpFirstArg->fillNode( rEquations ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case BINARY_FUNC_MAX : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 5; + FillEquationParameter( mpFirstArg->fillNode( rEquations ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case BINARY_FUNC_ATAN2: + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 8; + FillEquationParameter( mpSecondArg->fillNode( rEquations ), 0, aEquation ); + FillEquationParameter( mpFirstArg->fillNode( rEquations ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + } + return aRet; + } +}; + +class IfExpression : public ExpressionNode +{ + ExpressionNodeSharedPtr mpFirstArg; + ExpressionNodeSharedPtr mpSecondArg; + ExpressionNodeSharedPtr mpThirdArg; + +public: + + IfExpression( const ExpressionNodeSharedPtr& rFirstArg, + const ExpressionNodeSharedPtr& rSecondArg, + const ExpressionNodeSharedPtr& rThirdArg ) : + mpFirstArg( rFirstArg ), + mpSecondArg( rSecondArg ), + mpThirdArg( rThirdArg ) + { + } + virtual bool isConstant() const + { + return + mpFirstArg->isConstant() && + mpSecondArg->isConstant() && + mpThirdArg->isConstant(); + } + virtual double operator()() const + { + return (*mpFirstArg)() > 0 ? (*mpSecondArg)() : (*mpThirdArg)(); + } + virtual ExpressionFunct getType() const + { + return TERNARY_FUNC_IF; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* mpOptionalArg = NULL ) + { + EnhancedCustomShapeParameter aRet; + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 6; + FillEquationParameter( mpFirstArg->fillNode( rEquations ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations ), 1, aEquation ); + FillEquationParameter( mpThirdArg->fillNode( rEquations ), 2, aEquation ); + rEquations.push_back( aEquation ); + } + return aRet; + } +}; + +//////////////////////// +//////////////////////// +// FUNCTION PARSER +//////////////////////// +//////////////////////// + +typedef const sal_Char* StringIteratorT; + +struct ParserContext +{ + typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack; + + // stores a stack of not-yet-evaluated operands. This is used + // by the operators (i.e. '+', '*', 'sin' etc.) to pop their + // arguments from. If all arguments to an operator are constant, + // the operator pushes a precalculated result on the stack, and + // a composite ExpressionNode otherwise. + OperandStack maOperandStack; + + const EnhancedCustomShape2d* mpCustoShape; + +}; + +typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr; + +/** Generate apriori constant value + */ + +class ConstantFunctor +{ + const double mnValue; + ParserContextSharedPtr mpContext; + +public: + + ConstantFunctor( double rValue, const ParserContextSharedPtr& rContext ) : + mnValue( rValue ), + mpContext( rContext ) + { + } + void operator()( StringIteratorT rFirst, StringIteratorT rSecond ) const + { + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( mnValue ) ) ); + } +}; + +/** Generate parse-dependent-but-then-constant value + */ +class DoubleConstantFunctor +{ + ParserContextSharedPtr mpContext; + +public: + DoubleConstantFunctor( const ParserContextSharedPtr& rContext ) : + mpContext( rContext ) + { + } + void operator()( double n ) const + { + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( n ) ) ); + } +}; + +class EnumFunctor +{ + const ExpressionFunct meFunct; + double mnValue; + ParserContextSharedPtr mpContext; + +public: + + EnumFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : + mnValue( 0 ), + mpContext( rContext ), + meFunct( eFunct ) + { + } + void operator()( StringIteratorT rFirst, StringIteratorT rSecond ) const + { + double nVal = mnValue; + switch( meFunct ) + { + case ENUM_FUNC_ADJUSTMENT : + { + rtl::OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new AdjustmentExpression( *mpContext->mpCustoShape, aVal.toInt32() ) ) ); + } + break; + case ENUM_FUNC_EQUATION : + { + rtl::OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new EquationExpression( *mpContext->mpCustoShape, aVal.toInt32() ) ) ); + } + break; + default: + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new EnumValueExpression( *mpContext->mpCustoShape, meFunct ) ) ); + } + } +}; + +class UnaryFunctionFunctor +{ + const ExpressionFunct meFunct; + ParserContextSharedPtr mpContext; + +public : + + UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : + meFunct( eFunct ), + mpContext( rContext ) + { + } + void operator()( StringIteratorT, StringIteratorT ) const + { + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.size() < 1 ) + throw ParseError( "Not enough arguments for unary operator" ); + + // retrieve arguments + ExpressionNodeSharedPtr pArg( rNodeStack.top() ); + rNodeStack.pop(); + + if( pArg->isConstant() ) // check for constness + rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( UnaryFunctionExpression::getValue( meFunct, pArg ) ) ) ); + else // push complex node, that calcs the value on demand + rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) ); + } +}; + +/** Implements a binary function over two ExpressionNodes + + @tpl Generator + Generator functor, to generate an ExpressionNode of + appropriate type + + */ +class BinaryFunctionFunctor +{ + const ExpressionFunct meFunct; + ParserContextSharedPtr mpContext; + +public: + + BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : + meFunct( eFunct ), + mpContext( rContext ) + { + } + + void operator()( StringIteratorT, StringIteratorT ) const + { + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.size() < 2 ) + throw ParseError( "Not enough arguments for binary operator" ); + + // retrieve arguments + ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() ); + rNodeStack.pop(); + ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() ); + rNodeStack.pop(); + + // create combined ExpressionNode + ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) ); + // check for constness + if( pFirstArg->isConstant() && pSecondArg->isConstant() ) // call the operator() at pNode, store result in constant value ExpressionNode. + rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( (*pNode)() ) ) ); + else // push complex node, that calcs the value on demand + rNodeStack.push( pNode ); + } +}; + +class IfFunctor +{ + ParserContextSharedPtr mpContext; + +public : + + IfFunctor( const ParserContextSharedPtr& rContext ) : + mpContext( rContext ) + { + } + void operator()( StringIteratorT, StringIteratorT ) const + { + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.size() < 3 ) + throw ParseError( "Not enough arguments for ternary operator" ); + + // retrieve arguments + ExpressionNodeSharedPtr pThirdArg( rNodeStack.top() ); + rNodeStack.pop(); + ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() ); + rNodeStack.pop(); + ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() ); + rNodeStack.pop(); + + // create combined ExpressionNode + ExpressionNodeSharedPtr pNode( new IfExpression( pFirstArg, pSecondArg, pThirdArg ) ); + // check for constness + if( pFirstArg->isConstant() && pSecondArg->isConstant() && pThirdArg->isConstant() ) + rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( (*pNode)() ) ) ); // call the operator() at pNode, store result in constant value ExpressionNode. + else + rNodeStack.push( pNode ); // push complex node, that calcs the value on demand + } +}; + +// Workaround for MSVC compiler anomaly (stack trashing) +// +// The default ureal_parser_policies implementation of parse_exp +// triggers a really weird error in MSVC7 (Version 13.00.9466), in +// that the real_parser_impl::parse_main() call of parse_exp() +// overwrites the frame pointer _on the stack_ (EBP of the calling +// function gets overwritten while lying on the stack). +// +// For the time being, our parser thus can only read the 1.0E10 +// notation, not the 1.0e10 one. +// +// TODO(F1): Also handle the 1.0e10 case here. +template< typename T > struct custom_real_parser_policies : public ::boost::spirit::ureal_parser_policies<T> +{ + template< typename ScannerT > + static typename ::boost::spirit::parser_result< ::boost::spirit::chlit<>, ScannerT >::type + parse_exp(ScannerT& scan) + { + // as_lower_d somehow breaks MSVC7 + return ::boost::spirit::ch_p('E').parse(scan); + } +}; + +/* This class implements the following grammar (more or + less literally written down below, only slightly + obfuscated by the parser actions): + + identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height' + + function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log' + + basic_expression = + number | + identifier | + function '(' additive_expression ')' | + '(' additive_expression ')' + + unary_expression = + '-' basic_expression | + basic_expression + + multiplicative_expression = + unary_expression ( ( '*' unary_expression )* | + ( '/' unary_expression )* ) + + additive_expression = + multiplicative_expression ( ( '+' multiplicative_expression )* | + ( '-' multiplicative_expression )* ) + + */ +class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar > +{ +public: + /** Create an arithmetic expression grammar + + @param rParserContext + Contains context info for the parser + */ + ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) : + mpParserContext( rParserContext ) + { + } + + template< typename ScannerT > class definition + { + public: + // grammar definition + definition( const ExpressionGrammar& self ) + { + using ::boost::spirit::str_p; + using ::boost::spirit::range_p; + using ::boost::spirit::lexeme_d; + using ::boost::spirit::real_parser; + using ::boost::spirit::chseq_p; + + identifier = + str_p( "pi" )[ EnumFunctor(ENUM_FUNC_PI, self.getContext() ) ] + | str_p( "left" )[ EnumFunctor(ENUM_FUNC_LEFT, self.getContext() ) ] + | str_p( "top" )[ EnumFunctor(ENUM_FUNC_TOP, self.getContext() ) ] + | str_p( "right" )[ EnumFunctor(ENUM_FUNC_RIGHT, self.getContext() ) ] + | str_p( "bottom" )[ EnumFunctor(ENUM_FUNC_BOTTOM, self.getContext() ) ] + | str_p( "xstretch" )[ EnumFunctor(ENUM_FUNC_XSTRETCH, self.getContext() ) ] + | str_p( "ystretch" )[ EnumFunctor(ENUM_FUNC_YSTRETCH, self.getContext() ) ] + | str_p( "hasstroke" )[ EnumFunctor(ENUM_FUNC_HASSTROKE, self.getContext() ) ] + | str_p( "hasfill" )[ EnumFunctor(ENUM_FUNC_HASFILL, self.getContext() ) ] + | str_p( "width" )[ EnumFunctor(ENUM_FUNC_WIDTH, self.getContext() ) ] + | str_p( "height" )[ EnumFunctor(ENUM_FUNC_HEIGHT, self.getContext() ) ] + | str_p( "logwidth" )[ EnumFunctor(ENUM_FUNC_LOGWIDTH, self.getContext() ) ] + | str_p( "logheight" )[ EnumFunctor(ENUM_FUNC_LOGHEIGHT, self.getContext() ) ] + ; + + unaryFunction = + (str_p( "abs" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_ABS, self.getContext()) ] + | (str_p( "sqrt" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_SQRT, self.getContext()) ] + | (str_p( "sin" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_SIN, self.getContext()) ] + | (str_p( "cos" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_COS, self.getContext()) ] + | (str_p( "tan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_TAN, self.getContext()) ] + | (str_p( "atan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_ATAN, self.getContext()) ] + ; + + binaryFunction = + (str_p( "min" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_MIN, self.getContext()) ] + | (str_p( "max" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_MAX, self.getContext()) ] + | (str_p( "atan2") >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_ATAN2,self.getContext()) ] + ; + + ternaryFunction = + (str_p( "if" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ IfFunctor( self.getContext() ) ] + ; + + funcRef_decl = + lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]; + + functionReference = + (str_p( "?" ) >> funcRef_decl )[ EnumFunctor( ENUM_FUNC_EQUATION, self.getContext() ) ]; + + modRef_decl = + lexeme_d[ +( range_p('0','9') ) ]; + + modifierReference = + (str_p( "$" ) >> modRef_decl )[ EnumFunctor( ENUM_FUNC_ADJUSTMENT, self.getContext() ) ]; + + basicExpression = + real_parser<double, custom_real_parser_policies<double> >()[ DoubleConstantFunctor(self.getContext()) ] + | identifier + | functionReference + | modifierReference + | unaryFunction + | binaryFunction + | ternaryFunction + | '(' >> additiveExpression >> ')' + ; + + unaryExpression = + ('-' >> basicExpression)[ UnaryFunctionFunctor( UNARY_FUNC_NEG, self.getContext()) ] + | basicExpression + ; + + multiplicativeExpression = + unaryExpression + >> *( ('*' >> unaryExpression)[ BinaryFunctionFunctor( BINARY_FUNC_MUL, self.getContext()) ] + | ('/' >> unaryExpression)[ BinaryFunctionFunctor( BINARY_FUNC_DIV, self.getContext()) ] + ) + ; + + additiveExpression = + multiplicativeExpression + >> *( ('+' >> multiplicativeExpression)[ BinaryFunctionFunctor( BINARY_FUNC_PLUS, self.getContext()) ] + | ('-' >> multiplicativeExpression)[ BinaryFunctionFunctor( BINARY_FUNC_MINUS, self.getContext()) ] + ) + ; + + BOOST_SPIRIT_DEBUG_RULE(additiveExpression); + BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression); + BOOST_SPIRIT_DEBUG_RULE(unaryExpression); + BOOST_SPIRIT_DEBUG_RULE(basicExpression); + BOOST_SPIRIT_DEBUG_RULE(unaryFunction); + BOOST_SPIRIT_DEBUG_RULE(binaryFunction); + BOOST_SPIRIT_DEBUG_RULE(ternaryFunction); + BOOST_SPIRIT_DEBUG_RULE(identifier); + } + + const ::boost::spirit::rule< ScannerT >& start() const + { + return additiveExpression; + } + + private: + // the constituents of the Spirit arithmetic expression grammar. + // For the sake of readability, without 'ma' prefix. + ::boost::spirit::rule< ScannerT > additiveExpression; + ::boost::spirit::rule< ScannerT > multiplicativeExpression; + ::boost::spirit::rule< ScannerT > unaryExpression; + ::boost::spirit::rule< ScannerT > basicExpression; + ::boost::spirit::rule< ScannerT > unaryFunction; + ::boost::spirit::rule< ScannerT > binaryFunction; + ::boost::spirit::rule< ScannerT > ternaryFunction; + ::boost::spirit::rule< ScannerT > funcRef_decl; + ::boost::spirit::rule< ScannerT > functionReference; + ::boost::spirit::rule< ScannerT > modRef_decl; + ::boost::spirit::rule< ScannerT > modifierReference; + ::boost::spirit::rule< ScannerT > identifier; + }; + + const ParserContextSharedPtr& getContext() const + { + return mpParserContext; + } + +private: + ParserContextSharedPtr mpParserContext; // might get modified during parsing +}; + +#ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE +const ParserContextSharedPtr& getParserContext() +{ + static ParserContextSharedPtr lcl_parserContext( new ParserContext() ); + + // clear node stack (since we reuse the static object, that's + // the whole point here) + while( !lcl_parserContext->maOperandStack.empty() ) + lcl_parserContext->maOperandStack.pop(); + + return lcl_parserContext; +} +#endif + +}; + +ExpressionNodeSharedPtr EnhancedCustomShapeFunctionParser::parseFunction( const ::rtl::OUString& rFunction, const EnhancedCustomShape2d& rCustoShape ) +{ + // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* + // gives better conversion robustness here (we might want to map space + // etc. to ASCII space here) + const ::rtl::OString& rAsciiFunction( + rtl::OUStringToOString( rFunction, RTL_TEXTENCODING_ASCII_US ) ); + + StringIteratorT aStart( rAsciiFunction.getStr() ); + StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() ); + + ParserContextSharedPtr pContext; + +#ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE + // static parser context, because the actual + // Spirit parser is also a static object + pContext = getParserContext(); +#else + pContext.reset( new ParserContext() ); +#endif + pContext->mpCustoShape = &rCustoShape; + + ExpressionGrammar aExpressionGrammer( pContext ); + const ::boost::spirit::parse_info<StringIteratorT> aParseInfo( + ::boost::spirit::parse( aStart, + aEnd, + aExpressionGrammer, + ::boost::spirit::space_p ) ); + OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync + + // input fully congested by the parser? + if( !aParseInfo.full ) + throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): string not fully parseable" ); + + // parser's state stack now must contain exactly _one_ ExpressionNode, + // which represents our formula. + if( pContext->maOperandStack.size() != 1 ) + throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): incomplete or empty expression" ); + + return pContext->maOperandStack.top(); +} |