LCOV - code coverage report
Current view: top level - slideshow/source/engine - smilfunctionparser.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 178 0.6 %
Date: 2014-11-03 Functions: 2 56 3.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10