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