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 : #include "svx/EnhancedCustomShape2d.hxx"
21 : #include <rtl/ustring.hxx>
22 : #include <tools/fract.hxx>
23 :
24 : // Makes parser a static resource,
25 : // we're synchronized externally.
26 : // But watch out, the parser might have
27 : // state not visible to this code!
28 :
29 : #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
30 : #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
31 : #include <typeinfo>
32 : #define BOOST_SPIRIT_DEBUG
33 : #endif
34 : #include <boost/spirit/include/classic_core.hpp>
35 :
36 : #if (OSL_DEBUG_LEVEL > 0)
37 : #include <iostream>
38 : #endif
39 : #include <functional>
40 : #include <algorithm>
41 : #include <stack>
42 :
43 : #include <math.h> // fabs, sqrt, sin, cos, tan, atan, atan2
44 : using namespace EnhancedCustomShape;
45 : using namespace com::sun::star;
46 : using namespace com::sun::star::drawing;
47 :
48 0 : void EnhancedCustomShape::FillEquationParameter( const EnhancedCustomShapeParameter& rSource, const sal_Int32 nDestPara, EnhancedCustomShapeEquation& rDest )
49 : {
50 0 : sal_Int32 nValue = 0;
51 0 : if ( rSource.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
52 : {
53 0 : double fValue(0.0);
54 0 : if ( rSource.Value >>= fValue )
55 0 : nValue = (sal_Int32)fValue;
56 : }
57 : else
58 0 : rSource.Value >>= nValue;
59 :
60 0 : switch( rSource.Type )
61 : {
62 : case com::sun::star::drawing::EnhancedCustomShapeParameterType::EQUATION :
63 : {
64 0 : if ( nValue & 0x40000000 )
65 : {
66 0 : nValue ^= 0x40000000;
67 0 : rDest.nOperation |= 0x20000000 << nDestPara; // the bit is indicating that this value has to be adjusted later
68 : }
69 0 : nValue |= 0x400;
70 : }
71 0 : break;
72 0 : case com::sun::star::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT : nValue += DFF_Prop_adjustValue; break;
73 0 : case com::sun::star::drawing::EnhancedCustomShapeParameterType::BOTTOM : nValue = DFF_Prop_geoBottom; break;
74 0 : case com::sun::star::drawing::EnhancedCustomShapeParameterType::RIGHT : nValue = DFF_Prop_geoRight; break;
75 0 : case com::sun::star::drawing::EnhancedCustomShapeParameterType::TOP : nValue = DFF_Prop_geoTop; break;
76 0 : case com::sun::star::drawing::EnhancedCustomShapeParameterType::LEFT : nValue = DFF_Prop_geoLeft; break;
77 : }
78 0 : if ( rSource.Type != com::sun::star::drawing::EnhancedCustomShapeParameterType::NORMAL )
79 0 : rDest.nOperation |= ( 0x2000 << nDestPara );
80 0 : rDest.nPara[ nDestPara ] = nValue;
81 0 : }
82 :
83 3127 : ExpressionNode::~ExpressionNode()
84 3127 : {}
85 :
86 : namespace
87 : {
88 :
89 : //////////////////////
90 : //////////////////////
91 : // EXPRESSION NODES
92 : //////////////////////
93 : //////////////////////
94 1730 : class ConstantValueExpression : public ExpressionNode
95 : {
96 : double maValue;
97 :
98 : public:
99 :
100 865 : ConstantValueExpression( double rValue ) :
101 865 : maValue( rValue )
102 : {
103 865 : }
104 232 : virtual double operator()() const
105 : {
106 232 : return maValue;
107 : }
108 637 : virtual bool isConstant() const
109 : {
110 637 : return true;
111 : }
112 0 : virtual ExpressionFunct getType() const
113 : {
114 0 : return FUNC_CONST;
115 : }
116 0 : virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
117 : {
118 0 : EnhancedCustomShapeParameter aRet;
119 0 : Fraction aFract( maValue );
120 0 : if ( aFract.GetDenominator() == 1 )
121 : {
122 0 : aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
123 0 : aRet.Value <<= (sal_Int32)aFract.GetNumerator();
124 : }
125 : else
126 : {
127 0 : EnhancedCustomShapeEquation aEquation;
128 0 : aEquation.nOperation = 1;
129 0 : aEquation.nPara[ 0 ] = 1;
130 0 : aEquation.nPara[ 1 ] = (sal_Int16)aFract.GetNumerator();
131 0 : aEquation.nPara[ 2 ] = (sal_Int16)aFract.GetDenominator();
132 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
133 0 : aRet.Value <<= (sal_Int32)rEquations.size();
134 0 : rEquations.push_back( aEquation );
135 : }
136 0 : return aRet;
137 : }
138 : };
139 :
140 480 : class AdjustmentExpression : public ExpressionNode
141 : {
142 : sal_Int32 mnIndex;
143 : const EnhancedCustomShape2d& mrCustoShape;
144 :
145 : public:
146 :
147 240 : AdjustmentExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex )
148 : : mnIndex ( nIndex )
149 240 : , mrCustoShape( rCustoShape )
150 :
151 : {
152 240 : }
153 45 : virtual double operator()() const
154 : {
155 : OSL_TRACE(" $%d --> %f (angle: %f)", mnIndex, mrCustoShape.GetAdjustValueAsDouble( mnIndex ), 180.0*mrCustoShape.GetAdjustValueAsDouble( mnIndex )/10800000.0);
156 45 : return mrCustoShape.GetAdjustValueAsDouble( mnIndex );
157 : }
158 106 : virtual bool isConstant() const
159 : {
160 106 : return false;
161 : }
162 0 : virtual ExpressionFunct getType() const
163 : {
164 0 : return ENUM_FUNC_ADJUSTMENT;
165 : }
166 0 : virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ )
167 : {
168 0 : EnhancedCustomShapeParameter aRet;
169 0 : aRet.Type = EnhancedCustomShapeParameterType::ADJUSTMENT;
170 0 : aRet.Value <<= mnIndex;
171 0 : return aRet;
172 : }
173 : };
174 :
175 1228 : class EquationExpression : public ExpressionNode
176 : {
177 : sal_Int32 mnIndex;
178 : const EnhancedCustomShape2d& mrCustoShape;
179 :
180 : public:
181 :
182 614 : EquationExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex )
183 : : mnIndex ( nIndex )
184 614 : , mrCustoShape( rCustoShape )
185 : {
186 614 : }
187 80 : virtual double operator()() const
188 : {
189 80 : return mrCustoShape.GetEquationValueAsDouble( mnIndex );
190 : }
191 540 : virtual bool isConstant() const
192 : {
193 540 : return false;
194 : }
195 0 : virtual ExpressionFunct getType() const
196 : {
197 0 : return ENUM_FUNC_EQUATION;
198 : }
199 0 : virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ )
200 : {
201 0 : EnhancedCustomShapeParameter aRet;
202 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
203 0 : aRet.Value <<= mnIndex | 0x40000000; // the bit is indicating that this equation needs to be adjusted later
204 0 : return aRet;
205 : }
206 : };
207 :
208 338 : class EnumValueExpression : public ExpressionNode
209 : {
210 : const ExpressionFunct meFunct;
211 : const EnhancedCustomShape2d& mrCustoShape;
212 :
213 : public:
214 :
215 169 : EnumValueExpression( const EnhancedCustomShape2d& rCustoShape, const ExpressionFunct eFunct )
216 : : meFunct ( eFunct )
217 169 : , mrCustoShape ( rCustoShape )
218 : {
219 169 : }
220 34 : static double getValue( const EnhancedCustomShape2d& rCustoShape, const ExpressionFunct eFunc )
221 : {
222 : EnhancedCustomShape2d::EnumFunc eF;
223 34 : switch( eFunc )
224 : {
225 8 : case ENUM_FUNC_PI : eF = EnhancedCustomShape2d::ENUM_FUNC_PI; break;
226 5 : case ENUM_FUNC_LEFT : eF = EnhancedCustomShape2d::ENUM_FUNC_LEFT; break;
227 5 : case ENUM_FUNC_TOP : eF = EnhancedCustomShape2d::ENUM_FUNC_TOP; break;
228 8 : case ENUM_FUNC_RIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_RIGHT; break;
229 8 : case ENUM_FUNC_BOTTOM : eF = EnhancedCustomShape2d::ENUM_FUNC_BOTTOM; break;
230 0 : case ENUM_FUNC_XSTRETCH : eF = EnhancedCustomShape2d::ENUM_FUNC_XSTRETCH; break;
231 0 : case ENUM_FUNC_YSTRETCH : eF = EnhancedCustomShape2d::ENUM_FUNC_YSTRETCH; break;
232 0 : case ENUM_FUNC_HASSTROKE : eF = EnhancedCustomShape2d::ENUM_FUNC_HASSTROKE; break;
233 0 : case ENUM_FUNC_HASFILL : eF = EnhancedCustomShape2d::ENUM_FUNC_HASFILL; break;
234 0 : case ENUM_FUNC_WIDTH : eF = EnhancedCustomShape2d::ENUM_FUNC_WIDTH; break;
235 0 : case ENUM_FUNC_HEIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_HEIGHT; break;
236 0 : case ENUM_FUNC_LOGWIDTH : eF = EnhancedCustomShape2d::ENUM_FUNC_LOGWIDTH; break;
237 0 : case ENUM_FUNC_LOGHEIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_LOGHEIGHT; break;
238 :
239 : default :
240 0 : return 0.0;
241 : }
242 34 : return rCustoShape.GetEnumFunc( eF );
243 : }
244 34 : virtual double operator()() const
245 : {
246 : #if OSL_DEBUG_LEVEL > 1
247 : const char *funcName;
248 :
249 : switch (meFunct) {
250 : case ENUM_FUNC_PI : funcName = "pi"; break;
251 : case ENUM_FUNC_LEFT : funcName = "left"; break;
252 : case ENUM_FUNC_TOP : funcName = "top"; break;
253 : case ENUM_FUNC_RIGHT : funcName = "right"; break;
254 : case ENUM_FUNC_BOTTOM : funcName = "bottom"; break;
255 : case ENUM_FUNC_XSTRETCH : funcName = "xstretch"; break;
256 : case ENUM_FUNC_YSTRETCH : funcName = "ystretch"; break;
257 : case ENUM_FUNC_HASSTROKE : funcName = "hasstroke"; break;
258 : case ENUM_FUNC_HASFILL : funcName = "hasfill"; break;
259 : case ENUM_FUNC_WIDTH : funcName = "width"; break;
260 : case ENUM_FUNC_HEIGHT : funcName = "height"; break;
261 : case ENUM_FUNC_LOGWIDTH : funcName = "logwidth"; break;
262 : case ENUM_FUNC_LOGHEIGHT : funcName = "logheight"; break;
263 : default: funcName = "???"; break;
264 : }
265 :
266 : OSL_TRACE(" %s --> %f (angle: %f)", funcName, getValue( mrCustoShape, meFunct ), 180.0*getValue( mrCustoShape, meFunct )/10800000.0);
267 : #endif
268 :
269 34 : return getValue( mrCustoShape, meFunct );
270 : }
271 542 : virtual bool isConstant() const
272 : {
273 542 : return false;
274 : }
275 0 : virtual ExpressionFunct getType() const
276 : {
277 0 : return meFunct;
278 : }
279 0 : virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags )
280 : {
281 0 : EnhancedCustomShapeParameter aRet;
282 :
283 0 : sal_Int32 nDummy = 1;
284 0 : aRet.Value <<= nDummy;
285 :
286 0 : switch( meFunct )
287 : {
288 : case ENUM_FUNC_WIDTH : // TODO: do not use this as constant value
289 : case ENUM_FUNC_HEIGHT :
290 : case ENUM_FUNC_LOGWIDTH :
291 : case ENUM_FUNC_LOGHEIGHT :
292 : case ENUM_FUNC_PI :
293 : {
294 0 : ConstantValueExpression aConstantValue( getValue( mrCustoShape, meFunct ) );
295 0 : aRet = aConstantValue.fillNode( rEquations, NULL, nFlags );
296 : }
297 0 : break;
298 0 : case ENUM_FUNC_LEFT : aRet.Type = EnhancedCustomShapeParameterType::LEFT; break;
299 0 : case ENUM_FUNC_TOP : aRet.Type = EnhancedCustomShapeParameterType::TOP; break;
300 0 : case ENUM_FUNC_RIGHT : aRet.Type = EnhancedCustomShapeParameterType::RIGHT; break;
301 0 : case ENUM_FUNC_BOTTOM : aRet.Type = EnhancedCustomShapeParameterType::BOTTOM; break;
302 :
303 : // not implemented so far
304 : case ENUM_FUNC_XSTRETCH :
305 : case ENUM_FUNC_YSTRETCH :
306 : case ENUM_FUNC_HASSTROKE :
307 0 : case ENUM_FUNC_HASFILL : aRet.Type = EnhancedCustomShapeParameterType::NORMAL; break;
308 :
309 : default:
310 0 : break;
311 : }
312 0 : return aRet;
313 : }
314 : };
315 :
316 : /** ExpressionNode implementation for unary
317 : function over one ExpressionNode
318 : */
319 310 : class UnaryFunctionExpression : public ExpressionNode
320 : {
321 : const ExpressionFunct meFunct;
322 : ExpressionNodeSharedPtr mpArg;
323 :
324 : public:
325 155 : UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
326 : meFunct( eFunct ),
327 155 : mpArg( rArg )
328 : {
329 155 : }
330 56 : static double getValue( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg )
331 : {
332 56 : double fRet = 0;
333 56 : switch( eFunct )
334 : {
335 0 : case UNARY_FUNC_ABS : fRet = fabs( (*rArg)() ); break;
336 0 : case UNARY_FUNC_SQRT: fRet = sqrt( (*rArg)() ); break;
337 6 : case UNARY_FUNC_SIN : fRet = sin( (*rArg)() ); break;
338 2 : case UNARY_FUNC_COS : fRet = cos( (*rArg)() ); break;
339 0 : case UNARY_FUNC_TAN : fRet = tan( (*rArg)() ); break;
340 0 : case UNARY_FUNC_ATAN: fRet = atan( (*rArg)() ); break;
341 48 : case UNARY_FUNC_NEG : fRet = ::std::negate<double>()( (*rArg)() ); break;
342 : default:
343 0 : break;
344 : }
345 56 : return fRet;
346 : }
347 8 : virtual double operator()() const
348 : {
349 8 : return getValue( meFunct, mpArg );
350 : }
351 245 : virtual bool isConstant() const
352 : {
353 245 : return mpArg->isConstant();
354 : }
355 0 : virtual ExpressionFunct getType() const
356 : {
357 0 : return meFunct;
358 : }
359 0 : virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* pOptionalArg, sal_uInt32 nFlags )
360 : {
361 0 : EnhancedCustomShapeParameter aRet;
362 0 : switch( meFunct )
363 : {
364 : case UNARY_FUNC_ABS :
365 : {
366 0 : EnhancedCustomShapeEquation aEquation;
367 0 : aEquation.nOperation |= 3;
368 0 : FillEquationParameter( mpArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
369 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
370 0 : aRet.Value <<= (sal_Int32)rEquations.size();
371 0 : rEquations.push_back( aEquation );
372 : }
373 0 : break;
374 : case UNARY_FUNC_SQRT:
375 : {
376 0 : EnhancedCustomShapeEquation aEquation;
377 0 : aEquation.nOperation |= 13;
378 0 : FillEquationParameter( mpArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
379 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
380 0 : aRet.Value <<= (sal_Int32)rEquations.size();
381 0 : rEquations.push_back( aEquation );
382 : }
383 0 : break;
384 : case UNARY_FUNC_SIN :
385 : {
386 0 : EnhancedCustomShapeEquation aEquation;
387 0 : aEquation.nOperation |= 9;
388 0 : if ( pOptionalArg )
389 0 : FillEquationParameter( pOptionalArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
390 : else
391 0 : aEquation.nPara[ 0 ] = 1;
392 :
393 0 : EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, NULL, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
394 0 : if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
395 : { // sumangle needed :-(
396 0 : EnhancedCustomShapeEquation _aEquation;
397 0 : _aEquation.nOperation |= 0xe; // sumangle
398 0 : FillEquationParameter( aSource, 1, _aEquation );
399 0 : aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
400 0 : aSource.Value <<= (sal_Int32)rEquations.size();
401 0 : rEquations.push_back( _aEquation );
402 : }
403 0 : FillEquationParameter( aSource, 1, aEquation );
404 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
405 0 : aRet.Value <<= (sal_Int32)rEquations.size();
406 0 : rEquations.push_back( aEquation );
407 : }
408 0 : break;
409 : case UNARY_FUNC_COS :
410 : {
411 0 : EnhancedCustomShapeEquation aEquation;
412 0 : aEquation.nOperation |= 10;
413 0 : if ( pOptionalArg )
414 0 : FillEquationParameter( pOptionalArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
415 : else
416 0 : aEquation.nPara[ 0 ] = 1;
417 :
418 0 : EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, NULL, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
419 0 : if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
420 : { // sumangle needed :-(
421 0 : EnhancedCustomShapeEquation aTmpEquation;
422 0 : aTmpEquation.nOperation |= 0xe; // sumangle
423 0 : FillEquationParameter( aSource, 1, aTmpEquation );
424 0 : aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
425 0 : aSource.Value <<= (sal_Int32)rEquations.size();
426 0 : rEquations.push_back( aTmpEquation );
427 : }
428 0 : FillEquationParameter( aSource, 1, aEquation );
429 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
430 0 : aRet.Value <<= (sal_Int32)rEquations.size();
431 0 : rEquations.push_back( aEquation );
432 : }
433 0 : break;
434 : case UNARY_FUNC_TAN :
435 : {
436 0 : EnhancedCustomShapeEquation aEquation;
437 0 : aEquation.nOperation |= 16;
438 0 : if ( pOptionalArg )
439 0 : FillEquationParameter( pOptionalArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
440 : else
441 0 : aEquation.nPara[ 0 ] = 1;
442 :
443 0 : EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, NULL, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
444 0 : if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
445 : { // sumangle needed :-(
446 0 : EnhancedCustomShapeEquation aTmpEquation;
447 0 : aTmpEquation.nOperation |= 0xe; // sumangle
448 0 : FillEquationParameter( aSource, 1, aTmpEquation );
449 0 : aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
450 0 : aSource.Value <<= (sal_Int32)rEquations.size();
451 0 : rEquations.push_back( aTmpEquation );
452 : }
453 0 : FillEquationParameter( aSource, 1, aEquation );
454 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
455 0 : aRet.Value <<= (sal_Int32)rEquations.size();
456 0 : rEquations.push_back( aEquation );
457 : }
458 0 : break;
459 : case UNARY_FUNC_ATAN:
460 : {
461 : // TODO:
462 0 : aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
463 : }
464 0 : break;
465 : case UNARY_FUNC_NEG:
466 : {
467 0 : EnhancedCustomShapeEquation aEquation;
468 0 : aEquation.nOperation |= 1;
469 0 : aEquation.nPara[ 1 ] = -1;
470 0 : aEquation.nPara[ 2 ] = 1;
471 0 : FillEquationParameter( mpArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
472 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
473 0 : aRet.Value <<= (sal_Int32)rEquations.size();
474 0 : rEquations.push_back( aEquation );
475 : }
476 0 : break;
477 : default:
478 0 : break;
479 : }
480 0 : return aRet;
481 : }
482 : };
483 :
484 : /** ExpressionNode implementation for unary
485 : function over two ExpressionNodes
486 : */
487 1964 : class BinaryFunctionExpression : public ExpressionNode
488 : {
489 : const ExpressionFunct meFunct;
490 : ExpressionNodeSharedPtr mpFirstArg;
491 : ExpressionNodeSharedPtr mpSecondArg;
492 :
493 : public:
494 :
495 982 : BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) :
496 : meFunct( eFunct ),
497 : mpFirstArg( rFirstArg ),
498 982 : mpSecondArg( rSecondArg )
499 : {
500 982 : }
501 179 : static double getValue( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg )
502 : {
503 179 : double fRet = 0;
504 179 : switch( eFunct )
505 : {
506 23 : case BINARY_FUNC_PLUS : fRet = (*rFirstArg)() + (*rSecondArg)(); break;
507 73 : case BINARY_FUNC_MINUS: fRet = (*rFirstArg)() - (*rSecondArg)(); break;
508 47 : case BINARY_FUNC_MUL : fRet = (*rFirstArg)() * (*rSecondArg)(); break;
509 36 : case BINARY_FUNC_DIV : fRet = (*rFirstArg)() / (*rSecondArg)(); break;
510 0 : case BINARY_FUNC_MIN : fRet = ::std::min( (*rFirstArg)(), (*rSecondArg)() ); break;
511 0 : case BINARY_FUNC_MAX : fRet = ::std::max( (*rFirstArg)(), (*rSecondArg)() ); break;
512 0 : case BINARY_FUNC_ATAN2: fRet = atan2( (*rFirstArg)(), (*rSecondArg)() ); break;
513 : default:
514 0 : break;
515 : }
516 179 : return fRet;
517 : }
518 179 : virtual double operator()() const
519 : {
520 179 : return getValue( meFunct, mpFirstArg, mpSecondArg );
521 : }
522 1027 : virtual bool isConstant() const
523 : {
524 1027 : return mpFirstArg->isConstant() && mpSecondArg->isConstant();
525 : }
526 0 : virtual ExpressionFunct getType() const
527 : {
528 0 : return meFunct;
529 : }
530 0 : virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags )
531 : {
532 0 : EnhancedCustomShapeParameter aRet;
533 0 : switch( meFunct )
534 : {
535 : case BINARY_FUNC_PLUS :
536 : {
537 0 : if ( nFlags & EXPRESSION_FLAG_SUMANGLE_MODE )
538 : {
539 0 : if ( mpFirstArg->getType() == ENUM_FUNC_ADJUSTMENT )
540 : {
541 0 : EnhancedCustomShapeEquation aEquation;
542 0 : aEquation.nOperation |= 0xe; // sumangle
543 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
544 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation );
545 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
546 0 : aRet.Value <<= (sal_Int32)rEquations.size();
547 0 : rEquations.push_back( aEquation );
548 : }
549 0 : else if ( mpSecondArg->getType() == ENUM_FUNC_ADJUSTMENT )
550 : {
551 0 : EnhancedCustomShapeEquation aEquation;
552 0 : aEquation.nOperation |= 0xe; // sumangle
553 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
554 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation );
555 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
556 0 : aRet.Value <<= (sal_Int32)rEquations.size();
557 0 : rEquations.push_back( aEquation );
558 : }
559 : else
560 : {
561 0 : EnhancedCustomShapeEquation aSumangle1;
562 0 : aSumangle1.nOperation |= 0xe; // sumangle
563 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags &~EXPRESSION_FLAG_SUMANGLE_MODE ), 1, aSumangle1 );
564 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
565 0 : aRet.Value <<= (sal_Int32)rEquations.size();
566 0 : rEquations.push_back( aSumangle1 );
567 :
568 0 : EnhancedCustomShapeEquation aSumangle2;
569 0 : aSumangle2.nOperation |= 0xe; // sumangle
570 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags &~EXPRESSION_FLAG_SUMANGLE_MODE ), 1, aSumangle2 );
571 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
572 0 : aRet.Value <<= (sal_Int32)rEquations.size();
573 0 : rEquations.push_back( aSumangle2 );
574 :
575 0 : EnhancedCustomShapeEquation aEquation;
576 0 : aEquation.nOperation |= 0;
577 0 : aEquation.nPara[ 0 ] = ( rEquations.size() - 2 ) | 0x400;
578 0 : aEquation.nPara[ 1 ] = ( rEquations.size() - 1 ) | 0x400;
579 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
580 0 : aRet.Value <<= (sal_Int32)rEquations.size();
581 0 : rEquations.push_back( aEquation );
582 : }
583 : }
584 : else
585 : {
586 0 : sal_Bool bFirstIsEmpty = mpFirstArg->isConstant() && ( (*mpFirstArg)() == 0 );
587 0 : sal_Bool bSecondIsEmpty = mpSecondArg->isConstant() && ( (*mpSecondArg)() == 0 );
588 :
589 0 : if ( bFirstIsEmpty )
590 0 : aRet = mpSecondArg->fillNode( rEquations, NULL, nFlags );
591 0 : else if ( bSecondIsEmpty )
592 0 : aRet = mpFirstArg->fillNode( rEquations, NULL, nFlags );
593 : else
594 : {
595 0 : EnhancedCustomShapeEquation aEquation;
596 0 : aEquation.nOperation |= 0;
597 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
598 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation );
599 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
600 0 : aRet.Value <<= (sal_Int32)rEquations.size();
601 0 : rEquations.push_back( aEquation );
602 : }
603 : }
604 : }
605 0 : break;
606 : case BINARY_FUNC_MINUS:
607 : {
608 0 : EnhancedCustomShapeEquation aEquation;
609 0 : aEquation.nOperation |= 0;
610 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
611 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 2, aEquation );
612 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
613 0 : aRet.Value <<= (sal_Int32)rEquations.size();
614 0 : rEquations.push_back( aEquation );
615 : }
616 0 : break;
617 : case BINARY_FUNC_MUL :
618 : {
619 : // in the dest. format the cos function is using integer as result :-(
620 : // so we can't use the generic algorithm
621 0 : if ( ( mpFirstArg->getType() == UNARY_FUNC_SIN ) || ( mpFirstArg->getType() == UNARY_FUNC_COS ) || ( mpFirstArg->getType() == UNARY_FUNC_TAN ) )
622 0 : aRet = mpFirstArg->fillNode( rEquations, mpSecondArg.get(), nFlags );
623 0 : else if ( ( mpSecondArg->getType() == UNARY_FUNC_SIN ) || ( mpSecondArg->getType() == UNARY_FUNC_COS ) || ( mpSecondArg->getType() == UNARY_FUNC_TAN ) )
624 0 : aRet = mpSecondArg->fillNode( rEquations, mpFirstArg.get(), nFlags );
625 : else
626 : {
627 0 : if ( mpFirstArg->isConstant() && (*mpFirstArg)() == 1 )
628 0 : aRet = mpSecondArg->fillNode( rEquations, NULL, nFlags );
629 0 : else if ( mpSecondArg->isConstant() && (*mpSecondArg)() == 1 )
630 0 : aRet = mpFirstArg->fillNode( rEquations, NULL, nFlags );
631 0 : else if ( ( mpFirstArg->getType() == BINARY_FUNC_DIV ) // don't care of (pi/180)
632 0 : && ( ((BinaryFunctionExpression*)((BinaryFunctionExpression*)mpFirstArg.get())->mpFirstArg.get())->getType() == ENUM_FUNC_PI )
633 0 : && ( ((BinaryFunctionExpression*)((BinaryFunctionExpression*)mpFirstArg.get())->mpSecondArg.get())->getType() == FUNC_CONST ) )
634 : {
635 0 : aRet = mpSecondArg->fillNode( rEquations, NULL, nFlags );
636 : }
637 0 : else if ( ( mpSecondArg->getType() == BINARY_FUNC_DIV ) // don't care of (pi/180)
638 0 : && ( ((BinaryFunctionExpression*)((BinaryFunctionExpression*)mpSecondArg.get())->mpFirstArg.get())->getType() == ENUM_FUNC_PI )
639 0 : && ( ((BinaryFunctionExpression*)((BinaryFunctionExpression*)mpSecondArg.get())->mpSecondArg.get())->getType() == FUNC_CONST ) )
640 : {
641 0 : aRet = mpFirstArg->fillNode( rEquations, NULL, nFlags );
642 : }
643 : else
644 : {
645 0 : EnhancedCustomShapeEquation aEquation;
646 0 : aEquation.nOperation |= 1;
647 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
648 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation );
649 0 : aEquation.nPara[ 2 ] = 1;
650 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
651 0 : aRet.Value <<= (sal_Int32)rEquations.size();
652 0 : rEquations.push_back( aEquation );
653 : }
654 : }
655 : }
656 0 : break;
657 : case BINARY_FUNC_DIV :
658 : {
659 0 : EnhancedCustomShapeEquation aEquation;
660 0 : aEquation.nOperation |= 1;
661 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
662 0 : aEquation.nPara[ 1 ] = 1;
663 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 2, aEquation );
664 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
665 0 : aRet.Value <<= (sal_Int32)rEquations.size();
666 0 : rEquations.push_back( aEquation );
667 : }
668 0 : break;
669 : case BINARY_FUNC_MIN :
670 : {
671 0 : EnhancedCustomShapeEquation aEquation;
672 0 : aEquation.nOperation |= 4;
673 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
674 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation );
675 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
676 0 : aRet.Value <<= (sal_Int32)rEquations.size();
677 0 : rEquations.push_back( aEquation );
678 : }
679 0 : break;
680 : case BINARY_FUNC_MAX :
681 : {
682 0 : EnhancedCustomShapeEquation aEquation;
683 0 : aEquation.nOperation |= 5;
684 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
685 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation );
686 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
687 0 : aRet.Value <<= (sal_Int32)rEquations.size();
688 0 : rEquations.push_back( aEquation );
689 : }
690 0 : break;
691 : case BINARY_FUNC_ATAN2:
692 : {
693 0 : EnhancedCustomShapeEquation aEquation;
694 0 : aEquation.nOperation |= 8;
695 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
696 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation );
697 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
698 0 : aRet.Value <<= (sal_Int32)rEquations.size();
699 0 : rEquations.push_back( aEquation );
700 : }
701 0 : break;
702 : default:
703 0 : break;
704 : }
705 0 : return aRet;
706 : }
707 : };
708 :
709 204 : class IfExpression : public ExpressionNode
710 : {
711 : ExpressionNodeSharedPtr mpFirstArg;
712 : ExpressionNodeSharedPtr mpSecondArg;
713 : ExpressionNodeSharedPtr mpThirdArg;
714 :
715 : public:
716 :
717 102 : IfExpression( const ExpressionNodeSharedPtr& rFirstArg,
718 : const ExpressionNodeSharedPtr& rSecondArg,
719 : const ExpressionNodeSharedPtr& rThirdArg ) :
720 : mpFirstArg( rFirstArg ),
721 : mpSecondArg( rSecondArg ),
722 102 : mpThirdArg( rThirdArg )
723 : {
724 102 : }
725 0 : virtual bool isConstant() const
726 : {
727 : return
728 0 : mpFirstArg->isConstant() &&
729 0 : mpSecondArg->isConstant() &&
730 0 : mpThirdArg->isConstant();
731 : }
732 0 : virtual double operator()() const
733 : {
734 0 : return (*mpFirstArg)() > 0 ? (*mpSecondArg)() : (*mpThirdArg)();
735 : }
736 0 : virtual ExpressionFunct getType() const
737 : {
738 0 : return TERNARY_FUNC_IF;
739 : }
740 0 : virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags )
741 : {
742 0 : EnhancedCustomShapeParameter aRet;
743 0 : aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
744 0 : aRet.Value <<= (sal_Int32)rEquations.size();
745 : {
746 0 : EnhancedCustomShapeEquation aEquation;
747 0 : aEquation.nOperation |= 6;
748 0 : FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation );
749 0 : FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation );
750 0 : FillEquationParameter( mpThirdArg->fillNode( rEquations, NULL, nFlags ), 2, aEquation );
751 0 : rEquations.push_back( aEquation );
752 : }
753 0 : return aRet;
754 : }
755 : };
756 :
757 : ////////////////////////
758 : ////////////////////////
759 : // FUNCTION PARSER
760 : ////////////////////////
761 : ////////////////////////
762 :
763 : typedef const sal_Char* StringIteratorT;
764 :
765 6 : struct ParserContext
766 : {
767 : typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack;
768 :
769 : // stores a stack of not-yet-evaluated operands. This is used
770 : // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
771 : // arguments from. If all arguments to an operator are constant,
772 : // the operator pushes a precalculated result on the stack, and
773 : // a composite ExpressionNode otherwise.
774 : OperandStack maOperandStack;
775 :
776 : const EnhancedCustomShape2d* mpCustoShape;
777 :
778 : };
779 :
780 : typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr;
781 :
782 : /** Generate apriori constant value
783 : */
784 :
785 : class ConstantFunctor
786 : {
787 : const double mnValue;
788 : ParserContextSharedPtr mpContext;
789 :
790 : public:
791 :
792 : ConstantFunctor( double rValue, const ParserContextSharedPtr& rContext ) :
793 : mnValue( rValue ),
794 : mpContext( rContext )
795 : {
796 : }
797 : void operator()( StringIteratorT /*rFirst*/, StringIteratorT /*rSecond*/ ) const
798 : {
799 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( mnValue ) ) );
800 : }
801 : };
802 :
803 : /** Generate parse-dependent-but-then-constant value
804 : */
805 57 : class DoubleConstantFunctor
806 : {
807 : ParserContextSharedPtr mpContext;
808 :
809 : public:
810 3 : DoubleConstantFunctor( const ParserContextSharedPtr& rContext ) :
811 3 : mpContext( rContext )
812 : {
813 3 : }
814 766 : void operator()( double n ) const
815 : {
816 766 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( n ) ) );
817 766 : }
818 : };
819 :
820 765 : class EnumFunctor
821 : {
822 : const ExpressionFunct meFunct;
823 : double mnValue;
824 : ParserContextSharedPtr mpContext;
825 :
826 : public:
827 :
828 45 : EnumFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext )
829 : : meFunct( eFunct )
830 : , mnValue( 0 )
831 45 : , mpContext( rContext )
832 : {
833 45 : }
834 1023 : void operator()( StringIteratorT rFirst, StringIteratorT rSecond ) const
835 : {
836 : /*double nVal = mnValue;*/
837 1023 : switch( meFunct )
838 : {
839 : case ENUM_FUNC_ADJUSTMENT :
840 : {
841 240 : rtl::OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
842 240 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new AdjustmentExpression( *mpContext->mpCustoShape, aVal.toInt32() ) ) );
843 : }
844 240 : break;
845 : case ENUM_FUNC_EQUATION :
846 : {
847 614 : rtl::OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
848 614 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new EquationExpression( *mpContext->mpCustoShape, aVal.toInt32() ) ) );
849 : }
850 614 : break;
851 : default:
852 169 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new EnumValueExpression( *mpContext->mpCustoShape, meFunct ) ) );
853 : }
854 1023 : }
855 : };
856 :
857 231 : class UnaryFunctionFunctor
858 : {
859 : const ExpressionFunct meFunct;
860 : ParserContextSharedPtr mpContext;
861 :
862 : public :
863 :
864 21 : UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
865 : meFunct( eFunct ),
866 21 : mpContext( rContext )
867 : {
868 21 : }
869 203 : void operator()( StringIteratorT, StringIteratorT ) const
870 : {
871 203 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
872 :
873 203 : if( rNodeStack.size() < 1 )
874 0 : throw ParseError( "Not enough arguments for unary operator" );
875 :
876 : // retrieve arguments
877 203 : ExpressionNodeSharedPtr pArg( rNodeStack.top() );
878 203 : rNodeStack.pop();
879 :
880 203 : if( pArg->isConstant() ) // check for constness
881 48 : rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( UnaryFunctionExpression::getValue( meFunct, pArg ) ) ) );
882 : else // push complex node, that calcs the value on demand
883 155 : rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
884 203 : }
885 : };
886 :
887 : /** Implements a binary function over two ExpressionNodes
888 :
889 : @tpl Generator
890 : Generator functor, to generate an ExpressionNode of
891 : appropriate type
892 :
893 : */
894 207 : class BinaryFunctionFunctor
895 : {
896 : const ExpressionFunct meFunct;
897 : ParserContextSharedPtr mpContext;
898 :
899 : public:
900 :
901 21 : BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
902 : meFunct( eFunct ),
903 21 : mpContext( rContext )
904 : {
905 21 : }
906 :
907 982 : void operator()( StringIteratorT, StringIteratorT ) const
908 : {
909 982 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
910 :
911 982 : if( rNodeStack.size() < 2 )
912 0 : throw ParseError( "Not enough arguments for binary operator" );
913 :
914 : // retrieve arguments
915 982 : ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
916 982 : rNodeStack.pop();
917 982 : ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
918 982 : rNodeStack.pop();
919 :
920 : // create combined ExpressionNode
921 982 : ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
922 : // check for constness
923 982 : if( pFirstArg->isConstant() && pSecondArg->isConstant() ) // call the operator() at pNode, store result in constant value ExpressionNode.
924 51 : rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( (*pNode)() ) ) );
925 : else // push complex node, that calcs the value on demand
926 931 : rNodeStack.push( pNode );
927 982 : }
928 : };
929 :
930 15 : class IfFunctor
931 : {
932 : ParserContextSharedPtr mpContext;
933 :
934 : public :
935 :
936 3 : IfFunctor( const ParserContextSharedPtr& rContext ) :
937 3 : mpContext( rContext )
938 : {
939 3 : }
940 102 : void operator()( StringIteratorT, StringIteratorT ) const
941 : {
942 102 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
943 :
944 102 : if( rNodeStack.size() < 3 )
945 0 : throw ParseError( "Not enough arguments for ternary operator" );
946 :
947 : // retrieve arguments
948 102 : ExpressionNodeSharedPtr pThirdArg( rNodeStack.top() );
949 102 : rNodeStack.pop();
950 102 : ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
951 102 : rNodeStack.pop();
952 102 : ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
953 102 : rNodeStack.pop();
954 :
955 : // create combined ExpressionNode
956 102 : ExpressionNodeSharedPtr pNode( new IfExpression( pFirstArg, pSecondArg, pThirdArg ) );
957 : // check for constness
958 102 : if( pFirstArg->isConstant() && pSecondArg->isConstant() && pThirdArg->isConstant() )
959 0 : rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( (*pNode)() ) ) ); // call the operator() at pNode, store result in constant value ExpressionNode.
960 : else
961 102 : rNodeStack.push( pNode ); // push complex node, that calcs the value on demand
962 102 : }
963 : };
964 :
965 : // Workaround for MSVC compiler anomaly (stack trashing)
966 : //
967 : // The default ureal_parser_policies implementation of parse_exp
968 : // triggers a really weird error in MSVC7 (Version 13.00.9466), in
969 : // that the real_parser_impl::parse_main() call of parse_exp()
970 : // overwrites the frame pointer _on the stack_ (EBP of the calling
971 : // function gets overwritten while lying on the stack).
972 : //
973 : // For the time being, our parser thus can only read the 1.0E10
974 : // notation, not the 1.0e10 one.
975 : //
976 : // TODO(F1): Also handle the 1.0e10 case here.
977 : template< typename T > struct custom_real_parser_policies : public ::boost::spirit::ureal_parser_policies<T>
978 : {
979 : template< typename ScannerT >
980 : static typename ::boost::spirit::parser_result< ::boost::spirit::chlit<>, ScannerT >::type
981 766 : parse_exp(ScannerT& scan)
982 : {
983 : // as_lower_d somehow breaks MSVC7
984 766 : return ::boost::spirit::ch_p('E').parse(scan);
985 : }
986 : };
987 :
988 : /* This class implements the following grammar (more or
989 : less literally written down below, only slightly
990 : obfuscated by the parser actions):
991 :
992 : identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height'
993 :
994 : function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log'
995 :
996 : basic_expression =
997 : number |
998 : identifier |
999 : function '(' additive_expression ')' |
1000 : '(' additive_expression ')'
1001 :
1002 : unary_expression =
1003 : '-' basic_expression |
1004 : basic_expression
1005 :
1006 : multiplicative_expression =
1007 : unary_expression ( ( '*' unary_expression )* |
1008 : ( '/' unary_expression )* )
1009 :
1010 : additive_expression =
1011 : multiplicative_expression ( ( '+' multiplicative_expression )* |
1012 : ( '-' multiplicative_expression )* )
1013 :
1014 : */
1015 :
1016 603 : class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
1017 : {
1018 : public:
1019 : /** Create an arithmetic expression grammar
1020 :
1021 : @param rParserContext
1022 : Contains context info for the parser
1023 : */
1024 603 : ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
1025 603 : mpParserContext( rParserContext )
1026 : {
1027 603 : }
1028 :
1029 3 : template< typename ScannerT > class definition
1030 : {
1031 : public:
1032 : // grammar definition
1033 3 : definition( const ExpressionGrammar& self )
1034 3 : {
1035 : using ::boost::spirit::str_p;
1036 : using ::boost::spirit::range_p;
1037 : using ::boost::spirit::lexeme_d;
1038 : using ::boost::spirit::real_parser;
1039 : using ::boost::spirit::chseq_p;
1040 :
1041 3 : identifier =
1042 : str_p( "pi" )[ EnumFunctor(ENUM_FUNC_PI, self.getContext() ) ]
1043 : | str_p( "left" )[ EnumFunctor(ENUM_FUNC_LEFT, self.getContext() ) ]
1044 : | str_p( "top" )[ EnumFunctor(ENUM_FUNC_TOP, self.getContext() ) ]
1045 : | str_p( "right" )[ EnumFunctor(ENUM_FUNC_RIGHT, self.getContext() ) ]
1046 : | str_p( "bottom" )[ EnumFunctor(ENUM_FUNC_BOTTOM, self.getContext() ) ]
1047 : | str_p( "xstretch" )[ EnumFunctor(ENUM_FUNC_XSTRETCH, self.getContext() ) ]
1048 : | str_p( "ystretch" )[ EnumFunctor(ENUM_FUNC_YSTRETCH, self.getContext() ) ]
1049 : | str_p( "hasstroke" )[ EnumFunctor(ENUM_FUNC_HASSTROKE, self.getContext() ) ]
1050 : | str_p( "hasfill" )[ EnumFunctor(ENUM_FUNC_HASFILL, self.getContext() ) ]
1051 : | str_p( "width" )[ EnumFunctor(ENUM_FUNC_WIDTH, self.getContext() ) ]
1052 : | str_p( "height" )[ EnumFunctor(ENUM_FUNC_HEIGHT, self.getContext() ) ]
1053 : | str_p( "logwidth" )[ EnumFunctor(ENUM_FUNC_LOGWIDTH, self.getContext() ) ]
1054 : | str_p( "logheight" )[ EnumFunctor(ENUM_FUNC_LOGHEIGHT, self.getContext() ) ]
1055 : ;
1056 :
1057 3 : unaryFunction =
1058 : (str_p( "abs" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_ABS, self.getContext()) ]
1059 : | (str_p( "sqrt" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_SQRT, self.getContext()) ]
1060 : | (str_p( "sin" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_SIN, self.getContext()) ]
1061 : | (str_p( "cos" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_COS, self.getContext()) ]
1062 : | (str_p( "tan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_TAN, self.getContext()) ]
1063 : | (str_p( "atan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_ATAN, self.getContext()) ]
1064 : ;
1065 :
1066 3 : binaryFunction =
1067 : (str_p( "min" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_MIN, self.getContext()) ]
1068 : | (str_p( "max" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_MAX, self.getContext()) ]
1069 : | (str_p( "atan2") >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_ATAN2,self.getContext()) ]
1070 : ;
1071 :
1072 3 : ternaryFunction =
1073 : (str_p( "if" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ IfFunctor( self.getContext() ) ]
1074 : ;
1075 :
1076 3 : funcRef_decl =
1077 : lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ];
1078 :
1079 3 : functionReference =
1080 : (str_p( "?" ) >> funcRef_decl )[ EnumFunctor( ENUM_FUNC_EQUATION, self.getContext() ) ];
1081 :
1082 3 : modRef_decl =
1083 : lexeme_d[ +( range_p('0','9') ) ];
1084 :
1085 3 : modifierReference =
1086 : (str_p( "$" ) >> modRef_decl )[ EnumFunctor( ENUM_FUNC_ADJUSTMENT, self.getContext() ) ];
1087 :
1088 3 : basicExpression =
1089 : real_parser<double, custom_real_parser_policies<double> >()[ DoubleConstantFunctor(self.getContext()) ]
1090 : | identifier
1091 : | functionReference
1092 : | modifierReference
1093 : | unaryFunction
1094 : | binaryFunction
1095 : | ternaryFunction
1096 : | '(' >> additiveExpression >> ')'
1097 : ;
1098 :
1099 3 : unaryExpression =
1100 : ('-' >> basicExpression)[ UnaryFunctionFunctor( UNARY_FUNC_NEG, self.getContext()) ]
1101 : | basicExpression
1102 : ;
1103 :
1104 3 : multiplicativeExpression =
1105 : unaryExpression
1106 : >> *( ('*' >> unaryExpression)[ BinaryFunctionFunctor( BINARY_FUNC_MUL, self.getContext()) ]
1107 : | ('/' >> unaryExpression)[ BinaryFunctionFunctor( BINARY_FUNC_DIV, self.getContext()) ]
1108 : )
1109 : ;
1110 :
1111 3 : additiveExpression =
1112 : multiplicativeExpression
1113 : >> *( ('+' >> multiplicativeExpression)[ BinaryFunctionFunctor( BINARY_FUNC_PLUS, self.getContext()) ]
1114 : | ('-' >> multiplicativeExpression)[ BinaryFunctionFunctor( BINARY_FUNC_MINUS, self.getContext()) ]
1115 : )
1116 : ;
1117 :
1118 : BOOST_SPIRIT_DEBUG_RULE(additiveExpression);
1119 : BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression);
1120 : BOOST_SPIRIT_DEBUG_RULE(unaryExpression);
1121 : BOOST_SPIRIT_DEBUG_RULE(basicExpression);
1122 : BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
1123 : BOOST_SPIRIT_DEBUG_RULE(binaryFunction);
1124 : BOOST_SPIRIT_DEBUG_RULE(ternaryFunction);
1125 : BOOST_SPIRIT_DEBUG_RULE(identifier);
1126 3 : }
1127 :
1128 603 : const ::boost::spirit::rule< ScannerT >& start() const
1129 : {
1130 603 : return additiveExpression;
1131 : }
1132 :
1133 : private:
1134 : // the constituents of the Spirit arithmetic expression grammar.
1135 : // For the sake of readability, without 'ma' prefix.
1136 : ::boost::spirit::rule< ScannerT > additiveExpression;
1137 : ::boost::spirit::rule< ScannerT > multiplicativeExpression;
1138 : ::boost::spirit::rule< ScannerT > unaryExpression;
1139 : ::boost::spirit::rule< ScannerT > basicExpression;
1140 : ::boost::spirit::rule< ScannerT > unaryFunction;
1141 : ::boost::spirit::rule< ScannerT > binaryFunction;
1142 : ::boost::spirit::rule< ScannerT > ternaryFunction;
1143 : ::boost::spirit::rule< ScannerT > funcRef_decl;
1144 : ::boost::spirit::rule< ScannerT > functionReference;
1145 : ::boost::spirit::rule< ScannerT > modRef_decl;
1146 : ::boost::spirit::rule< ScannerT > modifierReference;
1147 : ::boost::spirit::rule< ScannerT > identifier;
1148 : };
1149 :
1150 93 : const ParserContextSharedPtr& getContext() const
1151 : {
1152 93 : return mpParserContext;
1153 : }
1154 :
1155 : private:
1156 : ParserContextSharedPtr mpParserContext; // might get modified during parsing
1157 : };
1158 :
1159 : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
1160 603 : const ParserContextSharedPtr& getParserContext()
1161 : {
1162 603 : static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
1163 :
1164 : // clear node stack (since we reuse the static object, that's
1165 : // the whole point here)
1166 1806 : while( !lcl_parserContext->maOperandStack.empty() )
1167 600 : lcl_parserContext->maOperandStack.pop();
1168 :
1169 603 : return lcl_parserContext;
1170 : }
1171 : #endif
1172 :
1173 : }
1174 :
1175 : namespace EnhancedCustomShape {
1176 :
1177 :
1178 :
1179 603 : ExpressionNodeSharedPtr FunctionParser::parseFunction( const ::rtl::OUString& rFunction, const EnhancedCustomShape2d& rCustoShape )
1180 : {
1181 : // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
1182 : // gives better conversion robustness here (we might want to map space
1183 : // etc. to ASCII space here)
1184 : const ::rtl::OString& rAsciiFunction(
1185 603 : rtl::OUStringToOString( rFunction, RTL_TEXTENCODING_ASCII_US ) );
1186 :
1187 603 : StringIteratorT aStart( rAsciiFunction.getStr() );
1188 603 : StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
1189 :
1190 603 : ParserContextSharedPtr pContext;
1191 :
1192 : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
1193 : // static parser context, because the actual
1194 : // Spirit parser is also a static object
1195 603 : pContext = getParserContext();
1196 : #else
1197 : pContext.reset( new ParserContext() );
1198 : #endif
1199 603 : pContext->mpCustoShape = &rCustoShape;
1200 :
1201 603 : ExpressionGrammar aExpressionGrammer( pContext );
1202 : const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
1203 : ::boost::spirit::parse( aStart,
1204 : aEnd,
1205 : aExpressionGrammer >> ::boost::spirit::end_p,
1206 603 : ::boost::spirit::space_p ) );
1207 : OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
1208 :
1209 :
1210 :
1211 : // input fully congested by the parser?
1212 603 : if( !aParseInfo.full )
1213 0 : throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): string not fully parseable" );
1214 :
1215 : // parser's state stack now must contain exactly _one_ ExpressionNode,
1216 : // which represents our formula.
1217 603 : if( pContext->maOperandStack.size() != 1 )
1218 0 : throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): incomplete or empty expression" );
1219 :
1220 :
1221 603 : return pContext->maOperandStack.top();
1222 : }
1223 :
1224 :
1225 63 : }
1226 :
1227 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|