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