1*70f497fbSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*70f497fbSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*70f497fbSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*70f497fbSAndrew Rist * distributed with this work for additional information 6*70f497fbSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*70f497fbSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*70f497fbSAndrew Rist * "License"); you may not use this file except in compliance 9*70f497fbSAndrew Rist * with the License. You may obtain a copy of the License at 10*70f497fbSAndrew Rist * 11*70f497fbSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12*70f497fbSAndrew Rist * 13*70f497fbSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*70f497fbSAndrew Rist * software distributed under the License is distributed on an 15*70f497fbSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*70f497fbSAndrew Rist * KIND, either express or implied. See the License for the 17*70f497fbSAndrew Rist * specific language governing permissions and limitations 18*70f497fbSAndrew Rist * under the License. 19*70f497fbSAndrew Rist * 20*70f497fbSAndrew Rist *************************************************************/ 21*70f497fbSAndrew Rist 22*70f497fbSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir // must be first 28cdf0e10cSrcweir #include <canvas/debug.hxx> 29cdf0e10cSrcweir #include <tools/diagnose_ex.h> 30cdf0e10cSrcweir 31cdf0e10cSrcweir #include <rtl/math.hxx> 32cdf0e10cSrcweir 33cdf0e10cSrcweir #include <smilfunctionparser.hxx> 34cdf0e10cSrcweir #include <expressionnodefactory.hxx> 35cdf0e10cSrcweir 36cdf0e10cSrcweir #include <rtl/ustring.hxx> 37cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 38cdf0e10cSrcweir 39cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 40cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 41cdf0e10cSrcweir 42cdf0e10cSrcweir // Makes parser a static resource, 43cdf0e10cSrcweir // we're synchronized externally. 44cdf0e10cSrcweir // But watch out, the parser might have 45cdf0e10cSrcweir // state not visible to this code! 46cdf0e10cSrcweir #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE 47cdf0e10cSrcweir #if defined(VERBOSE) && defined(DBG_UTIL) 48cdf0e10cSrcweir #include <typeinfo> 49cdf0e10cSrcweir #define BOOST_SPIRIT_DEBUG 50cdf0e10cSrcweir #endif 51cdf0e10cSrcweir #include <boost/spirit/include/classic_core.hpp> 52cdf0e10cSrcweir 53cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0 54cdf0e10cSrcweir #include <iostream> 55cdf0e10cSrcweir #endif 56cdf0e10cSrcweir #include <functional> 57cdf0e10cSrcweir #include <algorithm> 58cdf0e10cSrcweir #include <stack> 59cdf0e10cSrcweir 60cdf0e10cSrcweir 61cdf0e10cSrcweir 62cdf0e10cSrcweir /* Implementation of SmilFunctionParser class */ 63cdf0e10cSrcweir 64cdf0e10cSrcweir namespace slideshow 65cdf0e10cSrcweir { 66cdf0e10cSrcweir namespace internal 67cdf0e10cSrcweir { 68cdf0e10cSrcweir namespace 69cdf0e10cSrcweir { 70cdf0e10cSrcweir typedef const sal_Char* StringIteratorT; 71cdf0e10cSrcweir 72cdf0e10cSrcweir struct ParserContext 73cdf0e10cSrcweir { 74cdf0e10cSrcweir typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack; 75cdf0e10cSrcweir 76cdf0e10cSrcweir // stores a stack of not-yet-evaluated operands. This is used 77cdf0e10cSrcweir // by the operators (i.e. '+', '*', 'sin' etc.) to pop their 78cdf0e10cSrcweir // arguments from. If all arguments to an operator are constant, 79cdf0e10cSrcweir // the operator pushes a precalculated result on the stack, and 80cdf0e10cSrcweir // a composite ExpressionNode otherwise. 81cdf0e10cSrcweir OperandStack maOperandStack; 82cdf0e10cSrcweir 83cdf0e10cSrcweir // bounds of the shape this expression is associated with 84cdf0e10cSrcweir ::basegfx::B2DRectangle maShapeBounds; 85cdf0e10cSrcweir 86cdf0e10cSrcweir // when true, enable usage of time-dependent variable '$' 87cdf0e10cSrcweir // in expressions 88cdf0e10cSrcweir bool mbParseAnimationFunction; 89cdf0e10cSrcweir }; 90cdf0e10cSrcweir 91cdf0e10cSrcweir typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr; 92cdf0e10cSrcweir 93cdf0e10cSrcweir 94cdf0e10cSrcweir template< typename Generator > class ShapeBoundsFunctor 95cdf0e10cSrcweir { 96cdf0e10cSrcweir public: ShapeBoundsFunctor(Generator aGenerator,const ParserContextSharedPtr & rContext)97cdf0e10cSrcweir ShapeBoundsFunctor( Generator aGenerator, 98cdf0e10cSrcweir const ParserContextSharedPtr& rContext ) : 99cdf0e10cSrcweir maGenerator( aGenerator ), 100cdf0e10cSrcweir mpContext( rContext ) 101cdf0e10cSrcweir { 102cdf0e10cSrcweir ENSURE_OR_THROW( mpContext, 103cdf0e10cSrcweir "ShapeBoundsFunctor::ShapeBoundsFunctor(): Invalid context" ); 104cdf0e10cSrcweir } 105cdf0e10cSrcweir operator ()(StringIteratorT,StringIteratorT) const106cdf0e10cSrcweir void operator()( StringIteratorT, StringIteratorT ) const 107cdf0e10cSrcweir { 108cdf0e10cSrcweir mpContext->maOperandStack.push( 109cdf0e10cSrcweir ExpressionNodeFactory::createConstantValueExpression( 110cdf0e10cSrcweir maGenerator( mpContext->maShapeBounds ) ) ); 111cdf0e10cSrcweir } 112cdf0e10cSrcweir 113cdf0e10cSrcweir private: 114cdf0e10cSrcweir Generator maGenerator; 115cdf0e10cSrcweir ParserContextSharedPtr mpContext; 116cdf0e10cSrcweir }; 117cdf0e10cSrcweir 118cdf0e10cSrcweir template< typename Generator > ShapeBoundsFunctor< Generator > makeShapeBoundsFunctor(const Generator & rGenerator,const ParserContextSharedPtr & rContext)119cdf0e10cSrcweir makeShapeBoundsFunctor( const Generator& rGenerator, 120cdf0e10cSrcweir const ParserContextSharedPtr& rContext ) 121cdf0e10cSrcweir { 122cdf0e10cSrcweir return ShapeBoundsFunctor<Generator>(rGenerator, rContext); 123cdf0e10cSrcweir } 124cdf0e10cSrcweir 125cdf0e10cSrcweir /** Generate apriori constant value 126cdf0e10cSrcweir */ 127cdf0e10cSrcweir class ConstantFunctor 128cdf0e10cSrcweir { 129cdf0e10cSrcweir public: ConstantFunctor(double rValue,const ParserContextSharedPtr & rContext)130cdf0e10cSrcweir ConstantFunctor( double rValue, 131cdf0e10cSrcweir const ParserContextSharedPtr& rContext ) : 132cdf0e10cSrcweir mnValue( rValue ), 133cdf0e10cSrcweir mpContext( rContext ) 134cdf0e10cSrcweir { 135cdf0e10cSrcweir ENSURE_OR_THROW( mpContext, 136cdf0e10cSrcweir "ConstantFunctor::ConstantFunctor(): Invalid context" ); 137cdf0e10cSrcweir } 138cdf0e10cSrcweir operator ()(StringIteratorT,StringIteratorT) const139cdf0e10cSrcweir void operator()( StringIteratorT, StringIteratorT ) const 140cdf0e10cSrcweir { 141cdf0e10cSrcweir mpContext->maOperandStack.push( 142cdf0e10cSrcweir ExpressionNodeFactory::createConstantValueExpression( mnValue ) ); 143cdf0e10cSrcweir } 144cdf0e10cSrcweir 145cdf0e10cSrcweir private: 146cdf0e10cSrcweir const double mnValue; 147cdf0e10cSrcweir ParserContextSharedPtr mpContext; 148cdf0e10cSrcweir }; 149cdf0e10cSrcweir 150cdf0e10cSrcweir /** Generate parse-dependent-but-then-constant value 151cdf0e10cSrcweir */ 152cdf0e10cSrcweir class DoubleConstantFunctor 153cdf0e10cSrcweir { 154cdf0e10cSrcweir public: DoubleConstantFunctor(const ParserContextSharedPtr & rContext)155cdf0e10cSrcweir DoubleConstantFunctor( const ParserContextSharedPtr& rContext ) : 156cdf0e10cSrcweir mpContext( rContext ) 157cdf0e10cSrcweir { 158cdf0e10cSrcweir ENSURE_OR_THROW( mpContext, 159cdf0e10cSrcweir "DoubleConstantFunctor::DoubleConstantFunctor(): Invalid context" ); 160cdf0e10cSrcweir } 161cdf0e10cSrcweir operator ()(double n) const162cdf0e10cSrcweir void operator()( double n ) const 163cdf0e10cSrcweir { 164cdf0e10cSrcweir // push constant value expression to the stack 165cdf0e10cSrcweir mpContext->maOperandStack.push( 166cdf0e10cSrcweir ExpressionNodeFactory::createConstantValueExpression( n ) ); 167cdf0e10cSrcweir } 168cdf0e10cSrcweir 169cdf0e10cSrcweir private: 170cdf0e10cSrcweir ParserContextSharedPtr mpContext; 171cdf0e10cSrcweir }; 172cdf0e10cSrcweir 173cdf0e10cSrcweir /** Generate special t value expression node 174cdf0e10cSrcweir */ 175cdf0e10cSrcweir class ValueTFunctor 176cdf0e10cSrcweir { 177cdf0e10cSrcweir public: ValueTFunctor(const ParserContextSharedPtr & rContext)178cdf0e10cSrcweir ValueTFunctor( const ParserContextSharedPtr& rContext ) : 179cdf0e10cSrcweir mpContext( rContext ) 180cdf0e10cSrcweir { 181cdf0e10cSrcweir ENSURE_OR_THROW( mpContext, 182cdf0e10cSrcweir "ValueTFunctor::ValueTFunctor(): Invalid context" ); 183cdf0e10cSrcweir } 184cdf0e10cSrcweir operator ()(StringIteratorT,StringIteratorT) const185cdf0e10cSrcweir void operator()( StringIteratorT, StringIteratorT ) const 186cdf0e10cSrcweir { 187cdf0e10cSrcweir if( !mpContext->mbParseAnimationFunction ) 188cdf0e10cSrcweir { 189cdf0e10cSrcweir OSL_ENSURE( false, 190cdf0e10cSrcweir "ValueTFunctor::operator(): variable encountered, but we're not parsing a function here" ); 191cdf0e10cSrcweir throw ParseError(); 192cdf0e10cSrcweir } 193cdf0e10cSrcweir 194cdf0e10cSrcweir // push special t value expression to the stack 195cdf0e10cSrcweir mpContext->maOperandStack.push( 196cdf0e10cSrcweir ExpressionNodeFactory::createValueTExpression() ); 197cdf0e10cSrcweir } 198cdf0e10cSrcweir 199cdf0e10cSrcweir private: 200cdf0e10cSrcweir ParserContextSharedPtr mpContext; 201cdf0e10cSrcweir }; 202cdf0e10cSrcweir 203cdf0e10cSrcweir template< typename Functor > class UnaryFunctionFunctor 204cdf0e10cSrcweir { 205cdf0e10cSrcweir private: 206cdf0e10cSrcweir /** ExpressionNode implementation for unary 207cdf0e10cSrcweir function over one ExpressionNode 208cdf0e10cSrcweir */ 209cdf0e10cSrcweir class UnaryFunctionExpression : public ExpressionNode 210cdf0e10cSrcweir { 211cdf0e10cSrcweir public: UnaryFunctionExpression(const Functor & rFunctor,const ExpressionNodeSharedPtr & rArg)212cdf0e10cSrcweir UnaryFunctionExpression( const Functor& rFunctor, 213cdf0e10cSrcweir const ExpressionNodeSharedPtr& rArg ) : 214cdf0e10cSrcweir maFunctor( rFunctor ), 215cdf0e10cSrcweir mpArg( rArg ) 216cdf0e10cSrcweir { 217cdf0e10cSrcweir } 218cdf0e10cSrcweir operator ()(double t) const219cdf0e10cSrcweir virtual double operator()( double t ) const 220cdf0e10cSrcweir { 221cdf0e10cSrcweir return maFunctor( (*mpArg)(t) ); 222cdf0e10cSrcweir } 223cdf0e10cSrcweir isConstant() const224cdf0e10cSrcweir virtual bool isConstant() const 225cdf0e10cSrcweir { 226cdf0e10cSrcweir return mpArg->isConstant(); 227cdf0e10cSrcweir } 228cdf0e10cSrcweir 229cdf0e10cSrcweir private: 230cdf0e10cSrcweir Functor maFunctor; 231cdf0e10cSrcweir ExpressionNodeSharedPtr mpArg; 232cdf0e10cSrcweir }; 233cdf0e10cSrcweir 234cdf0e10cSrcweir public: UnaryFunctionFunctor(const Functor & rFunctor,const ParserContextSharedPtr & rContext)235cdf0e10cSrcweir UnaryFunctionFunctor( const Functor& rFunctor, 236cdf0e10cSrcweir const ParserContextSharedPtr& rContext ) : 237cdf0e10cSrcweir maFunctor( rFunctor ), 238cdf0e10cSrcweir mpContext( rContext ) 239cdf0e10cSrcweir { 240cdf0e10cSrcweir ENSURE_OR_THROW( mpContext, 241cdf0e10cSrcweir "UnaryFunctionFunctor::UnaryFunctionFunctor(): Invalid context" ); 242cdf0e10cSrcweir } 243cdf0e10cSrcweir operator ()(StringIteratorT,StringIteratorT) const244cdf0e10cSrcweir void operator()( StringIteratorT, StringIteratorT ) const 245cdf0e10cSrcweir { 246cdf0e10cSrcweir ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); 247cdf0e10cSrcweir 248cdf0e10cSrcweir if( rNodeStack.size() < 1 ) 249cdf0e10cSrcweir throw ParseError( "Not enough arguments for unary operator" ); 250cdf0e10cSrcweir 251cdf0e10cSrcweir // retrieve arguments 252cdf0e10cSrcweir ExpressionNodeSharedPtr pArg( rNodeStack.top() ); 253cdf0e10cSrcweir rNodeStack.pop(); 254cdf0e10cSrcweir 255cdf0e10cSrcweir // check for constness 256cdf0e10cSrcweir if( pArg->isConstant() ) 257cdf0e10cSrcweir { 258cdf0e10cSrcweir rNodeStack.push( 259cdf0e10cSrcweir ExpressionNodeFactory::createConstantValueExpression( 260cdf0e10cSrcweir maFunctor( (*pArg)(0.0) ) ) ); 261cdf0e10cSrcweir } 262cdf0e10cSrcweir else 263cdf0e10cSrcweir { 264cdf0e10cSrcweir // push complex node, that calcs the value on demand 265cdf0e10cSrcweir rNodeStack.push( 266cdf0e10cSrcweir ExpressionNodeSharedPtr( 267cdf0e10cSrcweir new UnaryFunctionExpression( 268cdf0e10cSrcweir maFunctor, 269cdf0e10cSrcweir pArg ) ) ); 270cdf0e10cSrcweir } 271cdf0e10cSrcweir } 272cdf0e10cSrcweir 273cdf0e10cSrcweir private: 274cdf0e10cSrcweir Functor maFunctor; 275cdf0e10cSrcweir ParserContextSharedPtr mpContext; 276cdf0e10cSrcweir }; 277cdf0e10cSrcweir 278cdf0e10cSrcweir // TODO(Q2): Refactor makeUnaryFunctionFunctor, 279cdf0e10cSrcweir // makeBinaryFunctionFunctor and the whole 280cdf0e10cSrcweir // ExpressionNodeFactory, to use a generic 281cdf0e10cSrcweir // makeFunctionFunctor template, which is overloaded for 282cdf0e10cSrcweir // unary, binary, ternary, etc. function pointers. 283cdf0e10cSrcweir template< typename Functor > UnaryFunctionFunctor<Functor> makeUnaryFunctionFunctor(const Functor & rFunctor,const ParserContextSharedPtr & rContext)284cdf0e10cSrcweir makeUnaryFunctionFunctor( const Functor& rFunctor, 285cdf0e10cSrcweir const ParserContextSharedPtr& rContext ) 286cdf0e10cSrcweir { 287cdf0e10cSrcweir return UnaryFunctionFunctor<Functor>( rFunctor, rContext ); 288cdf0e10cSrcweir } 289cdf0e10cSrcweir 290cdf0e10cSrcweir // MSVC has problems instantiating above template function with plain function 291cdf0e10cSrcweir // pointers (doesn't like the const reference there). Thus, provide it with 292cdf0e10cSrcweir // a dedicated overload here. 293cdf0e10cSrcweir UnaryFunctionFunctor< double (*)(double) > makeUnaryFunctionFunctor(double (* pFunc)(double),const ParserContextSharedPtr & rContext)294cdf0e10cSrcweir makeUnaryFunctionFunctor( double (*pFunc)(double), 295cdf0e10cSrcweir const ParserContextSharedPtr& rContext ) 296cdf0e10cSrcweir { 297cdf0e10cSrcweir return UnaryFunctionFunctor< double (*)(double) >( pFunc, rContext ); 298cdf0e10cSrcweir } 299cdf0e10cSrcweir 300cdf0e10cSrcweir /** Implements a binary function over two ExpressionNodes 301cdf0e10cSrcweir 302cdf0e10cSrcweir @tpl Generator 303cdf0e10cSrcweir Generator functor, to generate an ExpressionNode of 304cdf0e10cSrcweir appropriate type 305cdf0e10cSrcweir 306cdf0e10cSrcweir */ 307cdf0e10cSrcweir template< class Generator > class BinaryFunctionFunctor 308cdf0e10cSrcweir { 309cdf0e10cSrcweir public: BinaryFunctionFunctor(const Generator & rGenerator,const ParserContextSharedPtr & rContext)310cdf0e10cSrcweir BinaryFunctionFunctor( const Generator& rGenerator, 311cdf0e10cSrcweir const ParserContextSharedPtr& rContext ) : 312cdf0e10cSrcweir maGenerator( rGenerator ), 313cdf0e10cSrcweir mpContext( rContext ) 314cdf0e10cSrcweir { 315cdf0e10cSrcweir ENSURE_OR_THROW( mpContext, 316cdf0e10cSrcweir "BinaryFunctionFunctor::BinaryFunctionFunctor(): Invalid context" ); 317cdf0e10cSrcweir } 318cdf0e10cSrcweir operator ()(StringIteratorT,StringIteratorT) const319cdf0e10cSrcweir void operator()( StringIteratorT, StringIteratorT ) const 320cdf0e10cSrcweir { 321cdf0e10cSrcweir ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); 322cdf0e10cSrcweir 323cdf0e10cSrcweir if( rNodeStack.size() < 2 ) 324cdf0e10cSrcweir throw ParseError( "Not enough arguments for binary operator" ); 325cdf0e10cSrcweir 326cdf0e10cSrcweir // retrieve arguments 327cdf0e10cSrcweir ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() ); 328cdf0e10cSrcweir rNodeStack.pop(); 329cdf0e10cSrcweir ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() ); 330cdf0e10cSrcweir rNodeStack.pop(); 331cdf0e10cSrcweir 332cdf0e10cSrcweir // create combined ExpressionNode 333cdf0e10cSrcweir ExpressionNodeSharedPtr pNode( maGenerator( pFirstArg, 334cdf0e10cSrcweir pSecondArg ) ); 335cdf0e10cSrcweir // check for constness 336cdf0e10cSrcweir if( pFirstArg->isConstant() && 337cdf0e10cSrcweir pSecondArg->isConstant() ) 338cdf0e10cSrcweir { 339cdf0e10cSrcweir // call the operator() at pNode, store result 340cdf0e10cSrcweir // in constant value ExpressionNode. 341cdf0e10cSrcweir rNodeStack.push( 342cdf0e10cSrcweir ExpressionNodeFactory::createConstantValueExpression( 343cdf0e10cSrcweir (*pNode)( 0.0 ) ) ); 344cdf0e10cSrcweir } 345cdf0e10cSrcweir else 346cdf0e10cSrcweir { 347cdf0e10cSrcweir // push complex node, that calcs the value on demand 348cdf0e10cSrcweir rNodeStack.push( pNode ); 349cdf0e10cSrcweir } 350cdf0e10cSrcweir } 351cdf0e10cSrcweir 352cdf0e10cSrcweir private: 353cdf0e10cSrcweir Generator maGenerator; 354cdf0e10cSrcweir ParserContextSharedPtr mpContext; 355cdf0e10cSrcweir }; 356cdf0e10cSrcweir 357cdf0e10cSrcweir template< typename Generator > BinaryFunctionFunctor<Generator> makeBinaryFunctionFunctor(const Generator & rGenerator,const ParserContextSharedPtr & rContext)358cdf0e10cSrcweir makeBinaryFunctionFunctor( const Generator& rGenerator, 359cdf0e10cSrcweir const ParserContextSharedPtr& rContext ) 360cdf0e10cSrcweir { 361cdf0e10cSrcweir return BinaryFunctionFunctor<Generator>( rGenerator, rContext ); 362cdf0e10cSrcweir } 363cdf0e10cSrcweir 364cdf0e10cSrcweir 365cdf0e10cSrcweir // Workaround for MSVC compiler anomaly (stack trashing) 366cdf0e10cSrcweir // 367cdf0e10cSrcweir // The default ureal_parser_policies implementation of parse_exp 368cdf0e10cSrcweir // triggers a really weird error in MSVC7 (Version 13.00.9466), in 369cdf0e10cSrcweir // that the real_parser_impl::parse_main() call of parse_exp() 370cdf0e10cSrcweir // overwrites the frame pointer _on the stack_ (EBP of the calling 371cdf0e10cSrcweir // function gets overwritten while lying on the stack). 372cdf0e10cSrcweir // 373cdf0e10cSrcweir // For the time being, our parser thus can only read the 1.0E10 374cdf0e10cSrcweir // notation, not the 1.0e10 one. 375cdf0e10cSrcweir // 376cdf0e10cSrcweir // TODO(F1): Also handle the 1.0e10 case here. 377cdf0e10cSrcweir template< typename T > struct custom_real_parser_policies : public ::boost::spirit::ureal_parser_policies<T> 378cdf0e10cSrcweir { 379cdf0e10cSrcweir template< typename ScannerT > 380cdf0e10cSrcweir static typename ::boost::spirit::parser_result< ::boost::spirit::chlit<>, ScannerT >::type parse_expslideshow::internal::__anon00cb2da60111::custom_real_parser_policies381cdf0e10cSrcweir parse_exp(ScannerT& scan) 382cdf0e10cSrcweir { 383cdf0e10cSrcweir // as_lower_d somehow breaks MSVC7 384cdf0e10cSrcweir return ::boost::spirit::ch_p('E').parse(scan); 385cdf0e10cSrcweir } 386cdf0e10cSrcweir }; 387cdf0e10cSrcweir 388cdf0e10cSrcweir /* This class implements the following grammar (more or 389cdf0e10cSrcweir less literally written down below, only slightly 390cdf0e10cSrcweir obfuscated by the parser actions): 391cdf0e10cSrcweir 392cdf0e10cSrcweir identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height' 393cdf0e10cSrcweir 394cdf0e10cSrcweir function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log' 395cdf0e10cSrcweir 396cdf0e10cSrcweir basic_expression = 397cdf0e10cSrcweir number | 398cdf0e10cSrcweir identifier | 399cdf0e10cSrcweir function '(' additive_expression ')' | 400cdf0e10cSrcweir '(' additive_expression ')' 401cdf0e10cSrcweir 402cdf0e10cSrcweir unary_expression = 403cdf0e10cSrcweir '-' basic_expression | 404cdf0e10cSrcweir basic_expression 405cdf0e10cSrcweir 406cdf0e10cSrcweir multiplicative_expression = 407cdf0e10cSrcweir unary_expression ( ( '*' unary_expression )* | 408cdf0e10cSrcweir ( '/' unary_expression )* ) 409cdf0e10cSrcweir 410cdf0e10cSrcweir additive_expression = 411cdf0e10cSrcweir multiplicative_expression ( ( '+' multiplicative_expression )* | 412cdf0e10cSrcweir ( '-' multiplicative_expression )* ) 413cdf0e10cSrcweir 414cdf0e10cSrcweir */ 415cdf0e10cSrcweir class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar > 416cdf0e10cSrcweir { 417cdf0e10cSrcweir public: 418cdf0e10cSrcweir /** Create an arithmetic expression grammar 419cdf0e10cSrcweir 420cdf0e10cSrcweir @param rParserContext 421cdf0e10cSrcweir Contains context info for the parser 422cdf0e10cSrcweir */ ExpressionGrammar(const ParserContextSharedPtr & rParserContext)423cdf0e10cSrcweir ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) : 424cdf0e10cSrcweir mpParserContext( rParserContext ) 425cdf0e10cSrcweir { 426cdf0e10cSrcweir } 427cdf0e10cSrcweir 428cdf0e10cSrcweir template< typename ScannerT > class definition 429cdf0e10cSrcweir { 430cdf0e10cSrcweir public: 431cdf0e10cSrcweir // grammar definition definition(const ExpressionGrammar & self)432cdf0e10cSrcweir definition( const ExpressionGrammar& self ) 433cdf0e10cSrcweir { 434cdf0e10cSrcweir using ::boost::spirit::str_p; 435cdf0e10cSrcweir using ::boost::spirit::real_parser; 436cdf0e10cSrcweir 437cdf0e10cSrcweir identifier = 438cdf0e10cSrcweir str_p( "$" )[ ValueTFunctor( self.getContext()) ] 439cdf0e10cSrcweir | str_p( "pi" )[ ConstantFunctor(M_PI, self.getContext()) ] 440cdf0e10cSrcweir | str_p( "e" )[ ConstantFunctor(M_E, self.getContext()) ] 441cdf0e10cSrcweir | str_p( "x" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getCenterX),self.getContext()) ] 442cdf0e10cSrcweir | str_p( "y" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getCenterY),self.getContext()) ] 443cdf0e10cSrcweir | str_p( "width" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getWidth), self.getContext()) ] 444cdf0e10cSrcweir | str_p( "height" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getHeight), self.getContext()) ] 445cdf0e10cSrcweir ; 446cdf0e10cSrcweir 447cdf0e10cSrcweir unaryFunction = 448cdf0e10cSrcweir (str_p( "abs" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&fabs, self.getContext()) ] 449cdf0e10cSrcweir | (str_p( "sqrt" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&sqrt, self.getContext()) ] 450cdf0e10cSrcweir | (str_p( "sin" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&sin, self.getContext()) ] 451cdf0e10cSrcweir | (str_p( "cos" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&cos, self.getContext()) ] 452cdf0e10cSrcweir | (str_p( "tan" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&tan, self.getContext()) ] 453cdf0e10cSrcweir | (str_p( "atan" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&atan, self.getContext()) ] 454cdf0e10cSrcweir | (str_p( "acos" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&acos, self.getContext()) ] 455cdf0e10cSrcweir | (str_p( "asin" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&asin, self.getContext()) ] 456cdf0e10cSrcweir | (str_p( "exp" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&exp, self.getContext()) ] 457cdf0e10cSrcweir | (str_p( "log" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&log, self.getContext()) ] 458cdf0e10cSrcweir ; 459cdf0e10cSrcweir 460cdf0e10cSrcweir binaryFunction = 461cdf0e10cSrcweir (str_p( "min" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMinExpression, self.getContext()) ] 462cdf0e10cSrcweir | (str_p( "max" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMaxExpression, self.getContext()) ] 463cdf0e10cSrcweir ; 464cdf0e10cSrcweir 465cdf0e10cSrcweir basicExpression = 466cdf0e10cSrcweir real_parser<double, custom_real_parser_policies<double> >()[ DoubleConstantFunctor(self.getContext()) ] 467cdf0e10cSrcweir | identifier 468cdf0e10cSrcweir | unaryFunction 469cdf0e10cSrcweir | binaryFunction 470cdf0e10cSrcweir | '(' >> additiveExpression >> ')' 471cdf0e10cSrcweir ; 472cdf0e10cSrcweir 473cdf0e10cSrcweir unaryExpression = 474cdf0e10cSrcweir ('-' >> basicExpression)[ makeUnaryFunctionFunctor(::std::negate<double>(), self.getContext()) ] 475cdf0e10cSrcweir | basicExpression 476cdf0e10cSrcweir ; 477cdf0e10cSrcweir 478cdf0e10cSrcweir multiplicativeExpression = 479cdf0e10cSrcweir unaryExpression 480cdf0e10cSrcweir >> *( ('*' >> unaryExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMultipliesExpression, self.getContext()) ] 481cdf0e10cSrcweir | ('/' >> unaryExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createDividesExpression, self.getContext()) ] 482cdf0e10cSrcweir ) 483cdf0e10cSrcweir ; 484cdf0e10cSrcweir 485cdf0e10cSrcweir additiveExpression = 486cdf0e10cSrcweir multiplicativeExpression 487cdf0e10cSrcweir >> *( ('+' >> multiplicativeExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createPlusExpression, self.getContext()) ] 488cdf0e10cSrcweir | ('-' >> multiplicativeExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMinusExpression, self.getContext()) ] 489cdf0e10cSrcweir ) 490cdf0e10cSrcweir ; 491cdf0e10cSrcweir 492cdf0e10cSrcweir BOOST_SPIRIT_DEBUG_RULE(additiveExpression); 493cdf0e10cSrcweir BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression); 494cdf0e10cSrcweir BOOST_SPIRIT_DEBUG_RULE(unaryExpression); 495cdf0e10cSrcweir BOOST_SPIRIT_DEBUG_RULE(basicExpression); 496cdf0e10cSrcweir BOOST_SPIRIT_DEBUG_RULE(unaryFunction); 497cdf0e10cSrcweir BOOST_SPIRIT_DEBUG_RULE(binaryFunction); 498cdf0e10cSrcweir BOOST_SPIRIT_DEBUG_RULE(identifier); 499cdf0e10cSrcweir } 500cdf0e10cSrcweir start() const501cdf0e10cSrcweir const ::boost::spirit::rule< ScannerT >& start() const 502cdf0e10cSrcweir { 503cdf0e10cSrcweir return additiveExpression; 504cdf0e10cSrcweir } 505cdf0e10cSrcweir 506cdf0e10cSrcweir private: 507cdf0e10cSrcweir // the constituents of the Spirit arithmetic expression grammar. 508cdf0e10cSrcweir // For the sake of readability, without 'ma' prefix. 509cdf0e10cSrcweir ::boost::spirit::rule< ScannerT > additiveExpression; 510cdf0e10cSrcweir ::boost::spirit::rule< ScannerT > multiplicativeExpression; 511cdf0e10cSrcweir ::boost::spirit::rule< ScannerT > unaryExpression; 512cdf0e10cSrcweir ::boost::spirit::rule< ScannerT > basicExpression; 513cdf0e10cSrcweir ::boost::spirit::rule< ScannerT > unaryFunction; 514cdf0e10cSrcweir ::boost::spirit::rule< ScannerT > binaryFunction; 515cdf0e10cSrcweir ::boost::spirit::rule< ScannerT > identifier; 516cdf0e10cSrcweir }; 517cdf0e10cSrcweir getContext() const518cdf0e10cSrcweir const ParserContextSharedPtr& getContext() const 519cdf0e10cSrcweir { 520cdf0e10cSrcweir return mpParserContext; 521cdf0e10cSrcweir } 522cdf0e10cSrcweir 523cdf0e10cSrcweir private: 524cdf0e10cSrcweir ParserContextSharedPtr mpParserContext; // might get modified during parsing 525cdf0e10cSrcweir }; 526cdf0e10cSrcweir 527cdf0e10cSrcweir #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE getParserContext()528cdf0e10cSrcweir const ParserContextSharedPtr& getParserContext() 529cdf0e10cSrcweir { 530cdf0e10cSrcweir static ParserContextSharedPtr lcl_parserContext( new ParserContext() ); 531cdf0e10cSrcweir 532cdf0e10cSrcweir // clear node stack (since we reuse the static object, that's 533cdf0e10cSrcweir // the whole point here) 534cdf0e10cSrcweir while( !lcl_parserContext->maOperandStack.empty() ) 535cdf0e10cSrcweir lcl_parserContext->maOperandStack.pop(); 536cdf0e10cSrcweir 537cdf0e10cSrcweir return lcl_parserContext; 538cdf0e10cSrcweir } 539cdf0e10cSrcweir #endif 540cdf0e10cSrcweir } 541cdf0e10cSrcweir parseSmilValue(const::rtl::OUString & rSmilValue,const::basegfx::B2DRectangle & rRelativeShapeBounds)542cdf0e10cSrcweir ExpressionNodeSharedPtr SmilFunctionParser::parseSmilValue( const ::rtl::OUString& rSmilValue, 543cdf0e10cSrcweir const ::basegfx::B2DRectangle& rRelativeShapeBounds ) 544cdf0e10cSrcweir { 545cdf0e10cSrcweir // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* 546cdf0e10cSrcweir // gives better conversion robustness here (we might want to map space 547cdf0e10cSrcweir // etc. to ASCII space here) 548cdf0e10cSrcweir const ::rtl::OString& rAsciiSmilValue( 549cdf0e10cSrcweir rtl::OUStringToOString( rSmilValue, RTL_TEXTENCODING_ASCII_US ) ); 550cdf0e10cSrcweir 551cdf0e10cSrcweir StringIteratorT aStart( rAsciiSmilValue.getStr() ); 552cdf0e10cSrcweir StringIteratorT aEnd( rAsciiSmilValue.getStr()+rAsciiSmilValue.getLength() ); 553cdf0e10cSrcweir 554cdf0e10cSrcweir ParserContextSharedPtr pContext; 555cdf0e10cSrcweir 556cdf0e10cSrcweir #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE 557cdf0e10cSrcweir // static parser context, because the actual 558cdf0e10cSrcweir // Spirit parser is also a static object 559cdf0e10cSrcweir pContext = getParserContext(); 560cdf0e10cSrcweir #else 561cdf0e10cSrcweir pContext.reset( new ParserContext() ); 562cdf0e10cSrcweir #endif 563cdf0e10cSrcweir 564cdf0e10cSrcweir pContext->maShapeBounds = rRelativeShapeBounds; 565cdf0e10cSrcweir pContext->mbParseAnimationFunction = false; // parse with '$' disabled 566cdf0e10cSrcweir 567cdf0e10cSrcweir 568cdf0e10cSrcweir ExpressionGrammar aExpressionGrammer( pContext ); 569cdf0e10cSrcweir const ::boost::spirit::parse_info<StringIteratorT> aParseInfo( 570cdf0e10cSrcweir ::boost::spirit::parse( aStart, 571cdf0e10cSrcweir aEnd, 572cdf0e10cSrcweir aExpressionGrammer, 573cdf0e10cSrcweir ::boost::spirit::space_p ) ); 574cdf0e10cSrcweir OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync 575cdf0e10cSrcweir 576cdf0e10cSrcweir // input fully congested by the parser? 577cdf0e10cSrcweir if( !aParseInfo.full ) 578cdf0e10cSrcweir throw ParseError( "SmilFunctionParser::parseSmilValue(): string not fully parseable" ); 579cdf0e10cSrcweir 580cdf0e10cSrcweir // parser's state stack now must contain exactly _one_ ExpressionNode, 581cdf0e10cSrcweir // which represents our formula. 582cdf0e10cSrcweir if( pContext->maOperandStack.size() != 1 ) 583cdf0e10cSrcweir throw ParseError( "SmilFunctionParser::parseSmilValue(): incomplete or empty expression" ); 584cdf0e10cSrcweir 585cdf0e10cSrcweir return pContext->maOperandStack.top(); 586cdf0e10cSrcweir } 587cdf0e10cSrcweir parseSmilFunction(const::rtl::OUString & rSmilFunction,const::basegfx::B2DRectangle & rRelativeShapeBounds)588cdf0e10cSrcweir ExpressionNodeSharedPtr SmilFunctionParser::parseSmilFunction( const ::rtl::OUString& rSmilFunction, 589cdf0e10cSrcweir const ::basegfx::B2DRectangle& rRelativeShapeBounds ) 590cdf0e10cSrcweir { 591cdf0e10cSrcweir // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* 592cdf0e10cSrcweir // gives better conversion robustness here (we might want to map space 593cdf0e10cSrcweir // etc. to ASCII space here) 594cdf0e10cSrcweir const ::rtl::OString& rAsciiSmilFunction( 595cdf0e10cSrcweir rtl::OUStringToOString( rSmilFunction, RTL_TEXTENCODING_ASCII_US ) ); 596cdf0e10cSrcweir 597cdf0e10cSrcweir StringIteratorT aStart( rAsciiSmilFunction.getStr() ); 598cdf0e10cSrcweir StringIteratorT aEnd( rAsciiSmilFunction.getStr()+rAsciiSmilFunction.getLength() ); 599cdf0e10cSrcweir 600cdf0e10cSrcweir ParserContextSharedPtr pContext; 601cdf0e10cSrcweir 602cdf0e10cSrcweir #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE 603cdf0e10cSrcweir // static parser context, because the actual 604cdf0e10cSrcweir // Spirit parser is also a static object 605cdf0e10cSrcweir pContext = getParserContext(); 606cdf0e10cSrcweir #else 607cdf0e10cSrcweir pContext.reset( new ParserContext() ); 608cdf0e10cSrcweir #endif 609cdf0e10cSrcweir 610cdf0e10cSrcweir pContext->maShapeBounds = rRelativeShapeBounds; 611cdf0e10cSrcweir pContext->mbParseAnimationFunction = true; // parse with '$' enabled 612cdf0e10cSrcweir 613cdf0e10cSrcweir 614cdf0e10cSrcweir ExpressionGrammar aExpressionGrammer( pContext ); 615cdf0e10cSrcweir const ::boost::spirit::parse_info<StringIteratorT> aParseInfo( 616cdf0e10cSrcweir ::boost::spirit::parse( aStart, 617cdf0e10cSrcweir aEnd, 618cdf0e10cSrcweir aExpressionGrammer >> ::boost::spirit::end_p, 619cdf0e10cSrcweir ::boost::spirit::space_p ) ); 620cdf0e10cSrcweir OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync 621cdf0e10cSrcweir 622cdf0e10cSrcweir // input fully congested by the parser? 623cdf0e10cSrcweir if( !aParseInfo.full ) 624cdf0e10cSrcweir throw ParseError( "SmilFunctionParser::parseSmilFunction(): string not fully parseable" ); 625cdf0e10cSrcweir 626cdf0e10cSrcweir // parser's state stack now must contain exactly _one_ ExpressionNode, 627cdf0e10cSrcweir // which represents our formula. 628cdf0e10cSrcweir if( pContext->maOperandStack.size() != 1 ) 629cdf0e10cSrcweir throw ParseError( "SmilFunctionParser::parseSmilFunction(): incomplete or empty expression" ); 630cdf0e10cSrcweir 631cdf0e10cSrcweir return pContext->maOperandStack.top(); 632cdf0e10cSrcweir } 633cdf0e10cSrcweir } 634cdf0e10cSrcweir } 635