Coverage Report

Created: 2025-07-07 10:01

/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: */