Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/oox/source/drawingml/customshapegeometry.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 <drawingml/customshapegeometry.hxx>
21
#include <drawingml/customshapeproperties.hxx>
22
23
#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
24
#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
25
#include <com/sun/star/xml/sax/FastToken.hpp>
26
#include <osl/diagnose.h>
27
#include <sal/log.hxx>
28
#include <o3tl/string_view.hxx>
29
#include <oox/helper/helper.hxx>
30
#include <oox/helper/attributelist.hxx>
31
#include <oox/token/namespaces.hxx>
32
#include <oox/token/tokens.hxx>
33
#include <unordered_map>
34
35
using namespace ::oox::core;
36
using namespace ::com::sun::star::uno;
37
using namespace ::com::sun::star::drawing;
38
using namespace ::com::sun::star::xml::sax;
39
40
namespace oox::drawingml {
41
42
namespace {
43
44
enum FormulaCommand
45
{
46
    FC_MULDIV = 0,
47
    FC_PLUSMINUS,
48
    FC_PLUSDIV,
49
    FC_IFELSE,
50
    FC_IFELSE1,
51
    FC_ABS,
52
    FC_AT2,
53
    FC_CAT2,
54
    FC_COS,
55
    FC_MAX,
56
    FC_MIN,
57
    FC_MOD,
58
    FC_PIN,
59
    FC_SAT2,
60
    FC_SIN,
61
    FC_SQRT,
62
    FC_TAN,
63
    FC_VAL
64
};
65
66
struct FormulaCommandNameTable
67
{
68
    const char*     pS;
69
    FormulaCommand pE;
70
};
71
72
}
73
74
const FormulaCommandNameTable pFormulaCommandNameTable[] =
75
{
76
    { "*/",     FC_MULDIV },
77
    { "+-",     FC_PLUSMINUS },
78
    { "+/",     FC_PLUSDIV },
79
    { "ifelse", FC_IFELSE },
80
    { "?:",     FC_IFELSE1 },
81
    { "abs",    FC_ABS },
82
    { "at2",    FC_AT2 },
83
    { "cat2",   FC_CAT2 },
84
    { "cos",    FC_COS },
85
    { "max",    FC_MAX },
86
    { "min",    FC_MIN },
87
    { "mod",    FC_MOD },
88
    { "pin",    FC_PIN },
89
    { "sat2",   FC_SAT2 },
90
    { "sin",    FC_SIN },
91
    { "sqrt",   FC_SQRT },
92
    { "tan",    FC_TAN },
93
    { "val",    FC_VAL }
94
95
};
96
typedef std::unordered_map< OUString, FormulaCommand > FormulaCommandHMap;
97
98
static const FormulaCommandHMap* pCommandHashMap;
99
100
static OUString GetFormulaParameter( const EnhancedCustomShapeParameter& rParameter )
101
5.51k
{
102
5.51k
    OUString aRet;
103
5.51k
    switch( rParameter.Type )
104
5.51k
    {
105
3.27k
        case EnhancedCustomShapeParameterType::NORMAL :
106
3.27k
        {
107
3.27k
            if ( rParameter.Value.getValueTypeClass() == TypeClass_DOUBLE )
108
0
            {
109
0
                double fValue = 0.0;
110
0
                if ( rParameter.Value >>= fValue )
111
0
                    aRet = OUString::number( fValue );
112
0
            }
113
3.27k
            else
114
3.27k
            {
115
3.27k
                sal_Int32 nValue = 0;
116
3.27k
                if ( rParameter.Value >>= nValue )
117
3.27k
                    aRet = OUString::number( nValue );
118
3.27k
            }
119
3.27k
        }
120
3.27k
        break;
121
2.06k
        case EnhancedCustomShapeParameterType::EQUATION :
122
2.06k
        {
123
2.06k
            if ( rParameter.Value.getValueTypeClass() == TypeClass_LONG )
124
2.06k
            {
125
2.06k
                sal_Int32 nFormulaIndex;
126
2.06k
                if ( rParameter.Value >>= nFormulaIndex )
127
2.06k
                {
128
2.06k
                    aRet = "?"
129
2.06k
                        + OUString::number( nFormulaIndex )
130
2.06k
                            + " ";
131
2.06k
                }
132
2.06k
            }
133
0
            else
134
0
            {
135
                // ups... we should have an index here and not the formula name
136
0
            }
137
2.06k
        }
138
2.06k
        break;
139
0
        case EnhancedCustomShapeParameterType::ADJUSTMENT :
140
0
        {
141
0
            if ( rParameter.Value.getValueTypeClass() == TypeClass_LONG )
142
0
            {
143
0
                sal_Int32 nAdjustmentIndex;
144
0
                if ( rParameter.Value >>= nAdjustmentIndex )
145
0
                {
146
0
                    aRet = "$"
147
0
                        + OUString::number( nAdjustmentIndex )
148
0
                            + " ";
149
0
                }
150
0
            }
151
0
            else
152
0
            {
153
                // ups... we should have an index here and not the formula name
154
0
            }
155
0
        }
156
0
        break;
157
0
        case EnhancedCustomShapeParameterType::LEFT :
158
0
            aRet = "left";
159
0
        break;
160
0
        case EnhancedCustomShapeParameterType::TOP :
161
0
            aRet = "top";
162
0
        break;
163
0
        case EnhancedCustomShapeParameterType::RIGHT :
164
0
            aRet = "right";
165
0
        break;
166
0
        case EnhancedCustomShapeParameterType::BOTTOM :
167
0
            aRet = "bottom";
168
0
        break;
169
0
        case EnhancedCustomShapeParameterType::XSTRETCH :
170
0
            aRet = "xstretch";
171
0
        break;
172
0
        case EnhancedCustomShapeParameterType::YSTRETCH :
173
0
            aRet = "ystretch";
174
0
        break;
175
0
        case EnhancedCustomShapeParameterType::HASSTROKE :
176
0
            aRet = "hasstroke";
177
0
        break;
178
0
        case EnhancedCustomShapeParameterType::HASFILL :
179
0
            aRet = "hasfill";
180
0
        break;
181
0
        case EnhancedCustomShapeParameterType::WIDTH :
182
0
            aRet = "width";
183
0
        break;
184
0
        case EnhancedCustomShapeParameterType::HEIGHT :
185
0
            aRet = "height";
186
0
        break;
187
89
        case EnhancedCustomShapeParameterType::LOGWIDTH :
188
89
            aRet = "logwidth";
189
89
        break;
190
89
        case EnhancedCustomShapeParameterType::LOGHEIGHT :
191
89
            aRet = "logheight";
192
89
        break;
193
5.51k
    }
194
5.51k
    return aRet;
195
5.51k
}
196
197
static EnhancedCustomShapeParameter GetAdjCoordinate( CustomShapeProperties& rCustomShapeProperties, const OUString& rValue, bool bNoSymbols = true )
198
14.7k
{
199
14.7k
    css::drawing::EnhancedCustomShapeParameter aRet;
200
14.7k
    if ( !rValue.isEmpty() )
201
14.7k
    {
202
14.7k
        bool        bConstant = true;
203
14.7k
        sal_Int32   nConstant = -1;
204
14.7k
        sal_Int32   nIntVal = 0;
205
206
        // first check if it's a constant value
207
14.7k
        switch( AttributeConversion::decodeToken( rValue ) )
208
14.7k
        {
209
35
            case XML_3cd4 : nConstant = 270 * 60000; break;
210
0
            case XML_3cd8 : nConstant = 135 * 60000; break;
211
0
            case XML_5cd8 : nConstant = 225 * 60000; break;
212
0
            case XML_7cd8 : nConstant = 315 * 60000; break;
213
35
            case XML_cd2  : nConstant = 180 * 60000; break;
214
0
            case XML_cd3  : nConstant = 120 * 60000; break;
215
35
            case XML_cd4  : nConstant =  90 * 60000; break;
216
0
            case XML_cd8  : nConstant =  45 * 60000; break;
217
218
302
            case XML_b :    // variable height of the shape defined in spPr
219
391
            case XML_h :
220
391
            {
221
391
                if ( bNoSymbols )
222
302
                {
223
302
                    CustomShapeGuide aGuide;
224
302
                    aGuide.maName = rValue;
225
302
                    aGuide.maFormula = "logheight" ;
226
227
302
                    aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );
228
302
                    aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
229
302
                }
230
89
                else
231
89
                    aRet.Type = EnhancedCustomShapeParameterType::LOGHEIGHT;   // TODO: HEIGHT needs to be implemented
232
391
            }
233
391
            break;
234
235
0
            case XML_hd10 :
236
0
                nIntVal += 2; // */ h 1.0 10.0
237
0
                [[fallthrough]];
238
0
            case XML_hd8 :    // */ h 1.0 8.0
239
0
                nIntVal += 2;
240
0
                [[fallthrough]];
241
0
            case XML_hd6 :    // */ h 1.0 6.0
242
0
                nIntVal++;
243
0
                [[fallthrough]];
244
0
            case XML_hd5 :    // */ h 1.0 5.0
245
0
                nIntVal++;
246
0
                [[fallthrough]];
247
0
            case XML_hd4 :    // */ h 1.0 4.0
248
0
                nIntVal++;
249
0
                [[fallthrough]];
250
0
            case XML_hd3 :    // */ h 1.0 3.0
251
0
                nIntVal++;
252
0
                [[fallthrough]];
253
0
            case XML_hd2 :    // */ h 1.0 2.0
254
70
            case XML_vc :     // */ h 1.0 2.0
255
70
            {
256
70
                nIntVal += 2;
257
258
70
                CustomShapeGuide aGuide;
259
70
                aGuide.maName = rValue;
260
70
                aGuide.maFormula = "logheight/" + OUString::number( nIntVal );
261
262
70
                aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );
263
70
                aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
264
70
            }
265
70
            break;
266
267
64
            case XML_t :
268
128
            case XML_l :
269
128
            {
270
128
                nConstant = 0;
271
128
                aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
272
128
            }
273
128
            break;
274
275
0
            case XML_ls :   // longest side: max w h
276
0
            {
277
0
                CustomShapeGuide aGuide;
278
0
                aGuide.maName = rValue;
279
0
                aGuide.maFormula = "max(logwidth,logheight)";
280
281
0
                aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );
282
0
                aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
283
0
            }
284
0
            break;
285
0
            case XML_ss :   // shortest side: min w h
286
0
            {
287
0
                CustomShapeGuide aGuide;
288
0
                aGuide.maName = rValue;
289
0
                aGuide.maFormula = "min(logwidth,logheight)";
290
291
0
                aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );
292
0
                aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
293
0
            }
294
0
            break;
295
0
            case XML_ssd32 : // */ ss 1.0 32.0
296
0
                nIntVal += 16;
297
0
                [[fallthrough]];
298
0
            case XML_ssd16 : // */ ss 1.0 16.0
299
0
                nIntVal += 8;
300
0
                [[fallthrough]];
301
0
            case XML_ssd8 :  // */ ss 1.0 8.0
302
0
                nIntVal += 2;
303
0
                [[fallthrough]];
304
0
            case XML_ssd6 :  // */ ss 1.0 6.0
305
0
                nIntVal += 2;
306
0
                [[fallthrough]];
307
0
            case XML_ssd4 :  // */ ss 1.0 4.0
308
0
                nIntVal += 2;
309
0
                [[fallthrough]];
310
0
            case XML_ssd2 :  // */ ss 1.0 2.0
311
0
            {
312
0
                nIntVal += 2;
313
314
0
                CustomShapeGuide aGuide;
315
0
                aGuide.maName = rValue;
316
0
                aGuide.maFormula = "min(logwidth,logheight)/" + OUString::number( nIntVal );
317
318
0
                aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );
319
0
                aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
320
0
            }
321
0
            break;
322
323
302
            case XML_r :    // variable width of the shape defined in spPr
324
391
            case XML_w :
325
391
            {
326
391
                if ( bNoSymbols )
327
302
                {
328
302
                    CustomShapeGuide aGuide;
329
302
                    aGuide.maName = rValue;
330
302
                    aGuide.maFormula = "logwidth" ;
331
332
302
                    aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );
333
302
                    aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
334
302
                }
335
89
                else
336
89
                    aRet.Type = EnhancedCustomShapeParameterType::LOGWIDTH;
337
391
            }
338
391
            break;
339
340
0
            case XML_wd32 : // */ w 1.0 32.0
341
0
                nIntVal += 20;
342
0
                [[fallthrough]];
343
0
            case XML_wd12 : // */ w 1.0 12.0
344
0
                nIntVal += 2;
345
0
                [[fallthrough]];
346
0
            case XML_wd10 : // */ w 1.0 10.0
347
0
                nIntVal += 2;
348
0
                [[fallthrough]];
349
0
            case XML_wd8 :  // */ w 1.0 8.0
350
0
                nIntVal += 2;
351
0
                [[fallthrough]];
352
0
            case XML_wd6 :  // */ w 1.0 6.0
353
0
                nIntVal++;
354
0
                [[fallthrough]];
355
0
            case XML_wd5 :  // */ w 1.0 5.0
356
0
                nIntVal++;
357
0
                [[fallthrough]];
358
0
            case XML_wd4 :  // */ w 1.0 4.0
359
0
                nIntVal++;
360
0
                [[fallthrough]];
361
0
            case XML_wd3 :  // */ w 1.0 3.0
362
0
                nIntVal++;
363
0
                [[fallthrough]];
364
70
            case XML_hc :   // */ w 1.0 2.0
365
70
            case XML_wd2 :  // */ w 1.0 2.0
366
70
            {
367
70
                nIntVal += 2;
368
369
70
                CustomShapeGuide aGuide;
370
70
                aGuide.maName = rValue;
371
70
                aGuide.maFormula = "logwidth/" + OUString::number( nIntVal );
372
373
70
                aRet.Value <<= rCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );;
374
70
                aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
375
70
            }
376
70
            break;
377
378
13.5k
            default:
379
13.5k
                bConstant = false;
380
13.5k
            break;
381
14.7k
        }
382
14.7k
        if ( bConstant )
383
1.15k
        {
384
1.15k
            if (nConstant != -1) {
385
233
                aRet.Value <<= nConstant;
386
233
                aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
387
233
            }
388
1.15k
        }
389
13.5k
        else
390
13.5k
        {
391
            // Check if rValue is a number
392
13.5k
            sal_Unicode n = rValue[ 0 ];
393
13.5k
            bool bHasSign =  ( n == '+' ) || ( n == '-' );
394
            // "+" or "-" is formally allowed as guide name and works in app 'SoftMaker Office NX'.
395
13.5k
            bool bIsNumber = !(bHasSign && (rValue.getLength() == 1));
396
36.1k
            for (sal_Int32 i = bHasSign ? 1 : 0; i < rValue.getLength(); ++i)
397
25.9k
            {
398
25.9k
                if (!isdigit(rValue[i]))
399
3.29k
                {
400
3.29k
                    bIsNumber = false;
401
3.29k
                    break;
402
3.29k
                }
403
25.9k
            }
404
13.5k
            if (bIsNumber)
405
10.2k
            {   // seems to be a ST_Coordinate
406
10.2k
                aRet.Value <<= rValue.toInt32();
407
10.2k
                aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
408
10.2k
            }
409
3.29k
            else
410
3.29k
            {
411
3.29k
                sal_Int32 nGuideIndex = rCustomShapeProperties.getAdjustmentGuideList().GetCustomShapeGuideValue( rValue );
412
3.29k
                if ( nGuideIndex >= 0 )
413
0
                {
414
0
                    aRet.Value <<= nGuideIndex;
415
0
                    aRet.Type = EnhancedCustomShapeParameterType::ADJUSTMENT;
416
0
                }
417
3.29k
                else
418
3.29k
                {
419
3.29k
                    nGuideIndex = rCustomShapeProperties.getGuideList().GetCustomShapeGuideValue( rValue );
420
3.29k
                    if ( nGuideIndex >= 0 )
421
3.29k
                    {
422
3.29k
                        aRet.Value <<= nGuideIndex;
423
3.29k
                        aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
424
3.29k
                    }
425
0
                    else
426
0
                    {
427
0
                        SAL_WARN("oox", "error: unhandled value " << rValue);
428
0
                        aRet.Value <<= rValue;
429
0
                    }
430
3.29k
                }
431
3.29k
            }
432
13.5k
        }
433
14.7k
    }
434
14.7k
    return aRet;
435
14.7k
}
436
437
namespace {
438
439
// CT_GeomGuideList
440
class GeomGuideListContext : public ContextHandler2
441
{
442
public:
443
    GeomGuideListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, CustomShapeGuideContainer& rGuideList );
444
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
445
446
protected:
447
    CustomShapeGuideContainer&    mrGuideList;
448
    CustomShapeProperties&        mrCustomShapeProperties;
449
};
450
451
}
452
453
GeomGuideListContext::GeomGuideListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, CustomShapeGuideContainer& rGuideList )
454
94.0k
: ContextHandler2( rParent )
455
94.0k
, mrGuideList( rGuideList )
456
94.0k
, mrCustomShapeProperties( rCustomShapeProperties )
457
94.0k
{
458
94.0k
}
459
460
static OUString convertToOOEquation( CustomShapeProperties& rCustomShapeProperties, std::u16string_view rSource )
461
2.23k
{
462
2.23k
    if ( !pCommandHashMap )
463
3
    {
464
3
        FormulaCommandHMap* pHM = new FormulaCommandHMap;
465
3
        for(const FormulaCommandNameTable& i : pFormulaCommandNameTable)
466
54
            (*pHM)[ OUString::createFromAscii( i.pS ) ] =  i.pE;
467
3
        pCommandHashMap = pHM;
468
3
    }
469
470
2.23k
    std::vector< OUString > aTokens;
471
2.23k
    sal_Int32 nIndex = 0;
472
2.23k
    do
473
7.62k
    {
474
7.62k
        OUString aToken( o3tl::getToken(rSource, 0, ' ', nIndex ) );
475
7.62k
        if ( !aToken.isEmpty() )
476
7.62k
            aTokens.push_back( aToken );
477
7.62k
    }
478
7.62k
    while ( nIndex >= 0 );
479
480
2.23k
    OUString aEquation;
481
2.23k
    if ( !aTokens.empty() )
482
2.23k
    {
483
2.23k
        sal_Int32 i, nParameters = aTokens.size() - 1;
484
2.23k
        if ( nParameters > 3 )
485
0
            nParameters = 3;
486
487
2.23k
        OUString sParameters[ 3 ];
488
489
7.62k
        for ( i = 0; i < nParameters; i++ )
490
5.38k
            sParameters[ i ] = GetFormulaParameter( GetAdjCoordinate( rCustomShapeProperties, aTokens[ i + 1 ], false ) );
491
492
2.23k
        const FormulaCommandHMap::const_iterator aIter( pCommandHashMap->find( aTokens[ 0 ] ) );
493
2.23k
        if ( aIter != pCommandHashMap->end() )
494
2.23k
        {
495
2.23k
            switch( aIter->second )
496
2.23k
            {
497
1.12k
                case FC_MULDIV :
498
1.12k
                {
499
1.12k
                    if ( nParameters == 3 )
500
1.12k
                        aEquation = sParameters[ 0 ] + "*" + sParameters[ 1 ]
501
1.12k
                            + "/" + sParameters[ 2 ];
502
1.12k
                }
503
1.12k
                break;
504
420
                case FC_PLUSMINUS :
505
420
                {
506
420
                    if ( nParameters == 3 )
507
420
                        aEquation = sParameters[ 0 ] + "+" + sParameters[ 1 ]
508
420
                            + "-" + sParameters[ 2 ];
509
420
                }
510
420
                break;
511
0
                case FC_PLUSDIV :
512
0
                {
513
0
                    if ( nParameters == 3 )
514
0
                        aEquation = "(" + sParameters[ 0 ] + "+"
515
0
                            + sParameters[ 1 ] + ")/" + sParameters[ 2 ];
516
0
                }
517
0
                break;
518
0
                case FC_IFELSE :
519
0
                case FC_IFELSE1 :
520
0
                {
521
0
                    if ( nParameters == 3 )
522
0
                        aEquation = "if(" + sParameters[ 0 ] + ","
523
0
                            + sParameters[ 1 ] + "," + sParameters[ 2 ] + ")";
524
0
                }
525
0
                break;
526
0
                case FC_ABS :
527
0
                {
528
0
                    if ( nParameters == 1 )
529
0
                        aEquation = "abs(" + sParameters[ 0 ] + ")";
530
0
                }
531
0
                break;
532
0
                case FC_AT2 :
533
0
                {
534
0
                    if ( nParameters == 2 )
535
0
                        aEquation = "(10800000*atan2(" + sParameters[ 1 ] + ","
536
0
                        + sParameters[ 0 ] + "))/pi";
537
0
                }
538
0
                break;
539
0
                case FC_CAT2 :
540
0
                {
541
0
                    if ( nParameters == 3 )
542
0
                        aEquation = sParameters[ 0 ] + "*(cos(atan2(" +
543
0
                            sParameters[ 2 ] + "," + sParameters[ 1 ] + ")))";
544
0
                }
545
0
                break;
546
35
                case FC_COS :
547
35
                {
548
35
                    if ( nParameters == 2 )
549
35
                        aEquation = sParameters[ 0 ] + "*cos(pi*(" +
550
35
                        sParameters[ 1 ] + ")/10800000)";
551
35
                }
552
35
                break;
553
0
                case FC_MAX :
554
0
                {
555
0
                    if ( nParameters == 2 )
556
0
                        aEquation = "max(" + sParameters[ 0 ] + "," +
557
0
                            sParameters[ 1 ] + ")";
558
0
                }
559
0
                break;
560
0
                case FC_MIN :
561
0
                {
562
0
                    if ( nParameters == 2 )
563
0
                        aEquation = "min(" + sParameters[ 0 ] + "," +
564
0
                            sParameters[ 1 ] + ")";
565
0
                }
566
0
                break;
567
0
                case FC_MOD :
568
0
                {
569
0
                    if ( nParameters == 3 )
570
0
                        aEquation = "sqrt("
571
0
                            + sParameters[ 0 ] + "*" + sParameters[ 0 ] + "+"
572
0
                            + sParameters[ 1 ] + "*" + sParameters[ 1 ] + "+"
573
0
                            + sParameters[ 2 ] + "*" + sParameters[ 2 ] + ")";
574
0
                }
575
0
                break;
576
0
                case FC_PIN :
577
0
                {
578
0
                    if ( nParameters == 3 ) // if(x-y,x,if(y-z,z,y))
579
0
                        aEquation = "if(" + sParameters[ 0 ] + "-" + sParameters[ 1 ]
580
0
                            + "," + sParameters[ 0 ] + ",if(" + sParameters[ 2 ]
581
0
                            + "-" + sParameters[ 1 ] + "," + sParameters[ 1 ]
582
0
                            + "," + sParameters[ 2 ] + "))";
583
0
                }
584
0
                break;
585
0
                case FC_SAT2 :
586
0
                {
587
0
                    if ( nParameters == 3 )
588
0
                        aEquation = sParameters[ 0 ] + "*(sin(atan2(" +
589
0
                            sParameters[ 2 ] + "," + sParameters[ 1 ] + ")))";
590
0
                }
591
0
                break;
592
35
                case FC_SIN :
593
35
                {
594
35
                    if ( nParameters == 2 )
595
35
                        aEquation = sParameters[ 0 ] + "*sin(pi*(" +
596
35
                        sParameters[ 1 ] + ")/10800000)";
597
35
                }
598
35
                break;
599
35
                case FC_SQRT :
600
35
                {
601
35
                    if ( nParameters == 1 )
602
35
                        aEquation = "sqrt(" + sParameters[ 0 ] + ")";
603
35
                }
604
35
                break;
605
0
                case FC_TAN :
606
0
                {
607
0
                    if ( nParameters == 2 )
608
0
                        aEquation = sParameters[ 0 ] + "*tan(pi*(" +
609
0
                        sParameters[ 1 ] + ")/10800000)";
610
0
                }
611
0
                break;
612
584
                case FC_VAL :
613
584
                {
614
584
                    if ( nParameters == 1 )
615
584
                        aEquation = sParameters[ 0 ];
616
584
                }
617
584
                break;
618
0
                default :
619
0
                    break;
620
2.23k
            }
621
2.23k
        }
622
2.23k
    }
623
2.23k
    return aEquation;
624
2.23k
}
625
626
ContextHandlerRef GeomGuideListContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
627
2.23k
{
628
2.23k
    if ( aElementToken == A_TOKEN( gd ) )   // CT_GeomGuide
629
2.23k
    {
630
2.23k
        CustomShapeGuide aGuide;
631
2.23k
        aGuide.maName = rAttribs.getStringDefaulted( XML_name );
632
2.23k
        aGuide.maFormula = convertToOOEquation( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_fmla ) );
633
2.23k
        mrGuideList.push_back( aGuide );
634
2.23k
    }
635
2.23k
    return this;
636
2.23k
}
637
638
static const OUString& GetGeomGuideName( const OUString& rValue )
639
0
{
640
0
    return rValue;
641
0
}
642
643
namespace {
644
645
// CT_AdjPoint2D
646
class AdjPoint2DContext : public ContextHandler2
647
{
648
public:
649
    AdjPoint2DContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, EnhancedCustomShapeParameterPair& rAdjPoint2D );
650
};
651
652
}
653
654
AdjPoint2DContext::AdjPoint2DContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, EnhancedCustomShapeParameterPair& rAdjPoint2D )
655
2.47k
: ContextHandler2( rParent )
656
2.47k
{
657
2.47k
    rAdjPoint2D.First = GetAdjCoordinate( rCustomShapeProperties, rAttribs.getStringDefaulted( XML_x ) );
658
2.47k
    rAdjPoint2D.Second = GetAdjCoordinate( rCustomShapeProperties, rAttribs.getStringDefaulted( XML_y ) );
659
2.47k
}
660
661
namespace {
662
663
// CT_XYAdjustHandle
664
class XYAdjustHandleContext : public ContextHandler2
665
{
666
public:
667
    XYAdjustHandleContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, AdjustHandle& rAdjustHandle );
668
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
669
670
protected:
671
    AdjustHandle& mrAdjustHandle;
672
    CustomShapeProperties& mrCustomShapeProperties;
673
};
674
675
}
676
677
XYAdjustHandleContext::XYAdjustHandleContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, AdjustHandle& rAdjustHandle )
678
0
: ContextHandler2( rParent )
679
0
, mrAdjustHandle( rAdjustHandle )
680
0
, mrCustomShapeProperties( rCustomShapeProperties )
681
0
{
682
0
    if ( rAttribs.hasAttribute( XML_gdRefX ) )
683
0
    {
684
0
        mrAdjustHandle.gdRef1 = GetGeomGuideName( rAttribs.getStringDefaulted( XML_gdRefX) );
685
0
    }
686
0
    if ( rAttribs.hasAttribute( XML_minX ) )
687
0
    {
688
0
        mrAdjustHandle.min1 = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_minX) );
689
0
    }
690
0
    if ( rAttribs.hasAttribute( XML_maxX ) )
691
0
    {
692
0
        mrAdjustHandle.max1 = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_maxX) );
693
0
    }
694
0
    if ( rAttribs.hasAttribute( XML_gdRefY ) )
695
0
    {
696
0
        mrAdjustHandle.gdRef2 = GetGeomGuideName( rAttribs.getStringDefaulted( XML_gdRefY) );
697
0
    }
698
0
    if ( rAttribs.hasAttribute( XML_minY ) )
699
0
    {
700
0
        mrAdjustHandle.min2 = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_minY) );
701
0
    }
702
0
    if ( rAttribs.hasAttribute( XML_maxY ) )
703
0
    {
704
0
        mrAdjustHandle.max2 = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_maxY) );
705
0
    }
706
0
}
707
708
ContextHandlerRef XYAdjustHandleContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
709
0
{
710
0
    if ( aElementToken == A_TOKEN( pos ) )
711
0
        return new AdjPoint2DContext( *this, rAttribs, mrCustomShapeProperties, mrAdjustHandle.pos );   // CT_AdjPoint2D
712
0
    return nullptr;
713
0
}
714
715
namespace {
716
717
// CT_PolarAdjustHandle
718
class PolarAdjustHandleContext : public ContextHandler2
719
{
720
public:
721
    PolarAdjustHandleContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, AdjustHandle& rAdjustHandle );
722
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
723
724
protected:
725
    AdjustHandle& mrAdjustHandle;
726
    CustomShapeProperties& mrCustomShapeProperties;
727
};
728
729
}
730
731
PolarAdjustHandleContext::PolarAdjustHandleContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, AdjustHandle& rAdjustHandle )
732
0
: ContextHandler2( rParent )
733
0
, mrAdjustHandle( rAdjustHandle )
734
0
, mrCustomShapeProperties( rCustomShapeProperties )
735
0
{
736
0
    if ( rAttribs.hasAttribute( XML_gdRefR ) )
737
0
    {
738
0
        mrAdjustHandle.polar = true ;
739
0
        mrAdjustHandle.gdRef1 = GetGeomGuideName( rAttribs.getStringDefaulted( XML_gdRefR) );
740
0
    }
741
0
    if ( rAttribs.hasAttribute( XML_minR ) )
742
0
    {
743
0
        mrAdjustHandle.min1 = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_minR) );
744
0
    }
745
0
    if ( rAttribs.hasAttribute( XML_maxR ) )
746
0
    {
747
0
        mrAdjustHandle.max1 = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_maxR) );
748
0
    }
749
0
    if ( rAttribs.hasAttribute( XML_gdRefAng ) )
750
0
    {
751
0
        mrAdjustHandle.polar = true ;
752
0
        mrAdjustHandle.gdRef2 = GetGeomGuideName( rAttribs.getStringDefaulted( XML_gdRefAng) );
753
0
    }
754
0
    if ( rAttribs.hasAttribute( XML_minAng ) )
755
0
    {
756
0
        mrAdjustHandle.min2 = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_minAng) );
757
0
    }
758
0
    if ( rAttribs.hasAttribute( XML_maxAng ) )
759
0
    {
760
0
        mrAdjustHandle.max2 = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_maxAng) );
761
0
    }
762
0
}
763
764
ContextHandlerRef PolarAdjustHandleContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
765
0
{
766
    // mrAdjustHandle.pos uses planar coordinates.
767
0
    if ( aElementToken == A_TOKEN( pos ) )
768
0
        return new AdjPoint2DContext( *this, rAttribs, mrCustomShapeProperties, mrAdjustHandle.pos );   // CT_AdjPoint2D
769
0
    return nullptr;
770
0
}
771
772
namespace {
773
774
// CT_AdjustHandleList
775
class AdjustHandleListContext : public ContextHandler2
776
{
777
public:
778
    AdjustHandleListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, std::vector< AdjustHandle >& rAdjustHandleList );
779
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
780
781
protected:
782
    std::vector< AdjustHandle >& mrAdjustHandleList;
783
    CustomShapeProperties& mrCustomShapeProperties;
784
};
785
786
}
787
788
AdjustHandleListContext::AdjustHandleListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, std::vector< AdjustHandle >& rAdjustHandleList )
789
750
: ContextHandler2( rParent )
790
750
, mrAdjustHandleList( rAdjustHandleList )
791
750
, mrCustomShapeProperties( rCustomShapeProperties )
792
750
{
793
750
}
794
795
ContextHandlerRef AdjustHandleListContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
796
0
{
797
0
    if ( aElementToken == A_TOKEN( ahXY ) )         // CT_XYAdjustHandle
798
0
    {
799
0
        AdjustHandle aAdjustHandle( false );
800
0
        mrAdjustHandleList.push_back( aAdjustHandle );
801
0
        return new XYAdjustHandleContext( *this, rAttribs, mrCustomShapeProperties, mrAdjustHandleList.back() );
802
0
    }
803
0
    else if ( aElementToken == A_TOKEN( ahPolar ) ) // CT_PolarAdjustHandle
804
0
    {
805
0
        AdjustHandle aAdjustHandle( true );
806
0
        mrAdjustHandleList.push_back( aAdjustHandle );
807
0
        return new PolarAdjustHandleContext( *this, rAttribs, mrCustomShapeProperties, mrAdjustHandleList.back() );
808
0
    }
809
0
    return nullptr;
810
0
}
811
812
namespace {
813
814
// CT_ConnectionSite
815
class ConnectionSiteContext : public ContextHandler2
816
{
817
public:
818
    ConnectionSiteContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, ConnectionSite& rConnectionSite );
819
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
820
821
protected:
822
    ConnectionSite& mrConnectionSite;
823
    CustomShapeProperties& mrCustomShapeProperties;
824
};
825
826
}
827
828
ConnectionSiteContext::ConnectionSiteContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, ConnectionSite& rConnectionSite )
829
1.12k
: ContextHandler2( rParent )
830
1.12k
, mrConnectionSite( rConnectionSite )
831
1.12k
, mrCustomShapeProperties( rCustomShapeProperties )
832
1.12k
{
833
1.12k
    mrConnectionSite.ang = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_ang ) );
834
1.12k
}
835
836
ContextHandlerRef ConnectionSiteContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
837
1.12k
{
838
1.12k
    if ( aElementToken == A_TOKEN( pos ) )
839
1.12k
        return new AdjPoint2DContext( *this, rAttribs, mrCustomShapeProperties, mrConnectionSite.pos ); // CT_AdjPoint2D
840
0
    return nullptr;
841
1.12k
}
842
843
namespace {
844
845
// CT_Path2DMoveTo
846
class Path2DMoveToContext : public ContextHandler2
847
{
848
public:
849
    Path2DMoveToContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, EnhancedCustomShapeParameterPair& rAdjPoint2D );
850
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
851
852
protected:
853
    EnhancedCustomShapeParameterPair& mrAdjPoint2D;
854
    CustomShapeProperties& mrCustomShapeProperties;
855
};
856
857
}
858
859
Path2DMoveToContext::Path2DMoveToContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, EnhancedCustomShapeParameterPair& rAdjPoint2D )
860
366
: ContextHandler2( rParent )
861
366
, mrAdjPoint2D( rAdjPoint2D )
862
366
, mrCustomShapeProperties( rCustomShapeProperties )
863
366
{
864
366
}
865
866
ContextHandlerRef Path2DMoveToContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
867
366
{
868
366
    if ( aElementToken == A_TOKEN( pt ) )
869
366
        return new AdjPoint2DContext( *this, rAttribs, mrCustomShapeProperties, mrAdjPoint2D );     // CT_AdjPoint2D
870
0
    return nullptr;
871
366
}
872
873
namespace {
874
875
// CT_Path2DLineTo
876
class Path2DLineToContext : public ContextHandler2
877
{
878
public:
879
    Path2DLineToContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, EnhancedCustomShapeParameterPair& rAdjPoint2D );
880
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
881
882
protected:
883
    EnhancedCustomShapeParameterPair& mrAdjPoint2D;
884
    CustomShapeProperties& mrCustomShapeProperties;
885
};
886
887
}
888
889
Path2DLineToContext::Path2DLineToContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, EnhancedCustomShapeParameterPair& rAdjPoint2D )
890
839
: ContextHandler2( rParent )
891
839
, mrAdjPoint2D( rAdjPoint2D )
892
839
, mrCustomShapeProperties( rCustomShapeProperties )
893
839
{
894
839
}
895
896
ContextHandlerRef Path2DLineToContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
897
839
{
898
839
    if ( aElementToken == A_TOKEN( pt ) )
899
839
        return new AdjPoint2DContext( *this, rAttribs, mrCustomShapeProperties, mrAdjPoint2D );     // CT_AdjPoint2D
900
0
    return nullptr;
901
839
}
902
903
namespace {
904
905
// CT_Path2DQuadBezierTo
906
class Path2DQuadBezierToContext : public ContextHandler2
907
{
908
public:
909
    Path2DQuadBezierToContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, EnhancedCustomShapeParameterPair& rPt1, EnhancedCustomShapeParameterPair& rPt2 );
910
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
911
912
protected:
913
    EnhancedCustomShapeParameterPair& mrPt1;
914
    EnhancedCustomShapeParameterPair& mrPt2;
915
    int nCount;
916
    CustomShapeProperties& mrCustomShapeProperties;
917
};
918
919
}
920
921
Path2DQuadBezierToContext::Path2DQuadBezierToContext( ContextHandler2Helper const & rParent,
922
    CustomShapeProperties& rCustomShapeProperties,
923
        EnhancedCustomShapeParameterPair& rPt1,
924
            EnhancedCustomShapeParameterPair& rPt2 )
925
0
: ContextHandler2( rParent )
926
0
, mrPt1( rPt1 )
927
0
, mrPt2( rPt2 )
928
0
, nCount( 0 )
929
0
, mrCustomShapeProperties( rCustomShapeProperties )
930
0
{
931
0
}
932
933
ContextHandlerRef Path2DQuadBezierToContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
934
0
{
935
0
    if ( aElementToken == A_TOKEN( pt ) )
936
0
        return new AdjPoint2DContext( *this, rAttribs, mrCustomShapeProperties, nCount++ ? mrPt2 : mrPt1 ); // CT_AdjPoint2D
937
0
    return nullptr;
938
0
}
939
940
namespace {
941
942
// CT_Path2DCubicBezierTo
943
class Path2DCubicBezierToContext : public ContextHandler2
944
{
945
public:
946
    Path2DCubicBezierToContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties,
947
        EnhancedCustomShapeParameterPair&, EnhancedCustomShapeParameterPair&, EnhancedCustomShapeParameterPair& );
948
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
949
950
protected:
951
    CustomShapeProperties& mrCustomShapeProperties;
952
    EnhancedCustomShapeParameterPair& mrControlPt1;
953
    EnhancedCustomShapeParameterPair& mrControlPt2;
954
    EnhancedCustomShapeParameterPair& mrEndPt;
955
    int nCount;
956
};
957
958
}
959
960
Path2DCubicBezierToContext::Path2DCubicBezierToContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties,
961
    EnhancedCustomShapeParameterPair& rControlPt1,
962
        EnhancedCustomShapeParameterPair& rControlPt2,
963
            EnhancedCustomShapeParameterPair& rEndPt )
964
48
: ContextHandler2( rParent )
965
48
, mrCustomShapeProperties( rCustomShapeProperties )
966
48
, mrControlPt1( rControlPt1 )
967
48
, mrControlPt2( rControlPt2 )
968
48
, mrEndPt( rEndPt )
969
48
, nCount( 0 )
970
48
{
971
48
}
972
973
ContextHandlerRef Path2DCubicBezierToContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
974
144
{
975
144
    if ( aElementToken == A_TOKEN( pt ) )
976
144
        return new AdjPoint2DContext( *this, rAttribs, mrCustomShapeProperties,
977
144
            nCount++ ? nCount == 2 ? mrControlPt2 : mrEndPt : mrControlPt1 );   // CT_AdjPoint2D
978
0
    return nullptr;
979
144
}
980
981
namespace {
982
983
// CT_Path2DContext
984
class Path2DContext : public ContextHandler2
985
{
986
public:
987
    Path2DContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, std::vector< css::drawing::EnhancedCustomShapeSegment >& rSegments, Path2D& rPath2D );
988
    virtual void onEndElement() override;
989
    virtual ::oox::core::ContextHandlerRef
990
        onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
991
992
protected:
993
    Path2D& mrPath2D;
994
    std::vector< css::drawing::EnhancedCustomShapeSegment >& mrSegments;
995
    CustomShapeProperties& mrCustomShapeProperties;
996
};
997
998
}
999
1000
Path2DContext::Path2DContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties, std::vector< css::drawing::EnhancedCustomShapeSegment >& rSegments, Path2D& rPath2D )
1001
366
: ContextHandler2( rParent )
1002
366
, mrPath2D( rPath2D )
1003
366
, mrSegments( rSegments )
1004
366
, mrCustomShapeProperties( rCustomShapeProperties )
1005
366
{
1006
366
    rPath2D.w = rAttribs.getHyper( XML_w, 0 );
1007
366
    rPath2D.h = rAttribs.getHyper( XML_h, 0 );
1008
366
    rPath2D.fill = rAttribs.getToken( XML_fill, XML_norm );
1009
366
    rPath2D.stroke = rAttribs.getBool( XML_stroke, true );
1010
366
    rPath2D.extrusionOk = rAttribs.getBool( XML_extrusionOk, true );
1011
366
}
1012
1013
void Path2DContext::onEndElement()
1014
366
{
1015
366
    EnhancedCustomShapeSegment aNewSegment;
1016
366
    switch ( mrPath2D.fill )
1017
366
    {
1018
0
        case XML_none:
1019
0
            aNewSegment.Command = EnhancedCustomShapeSegmentCommand::NOFILL;
1020
0
            break;
1021
0
        case XML_darken:
1022
0
            aNewSegment.Command = EnhancedCustomShapeSegmentCommand::DARKEN;
1023
0
            break;
1024
0
        case XML_darkenLess:
1025
0
            aNewSegment.Command = EnhancedCustomShapeSegmentCommand::DARKENLESS;
1026
0
            break;
1027
0
        case XML_lighten:
1028
0
            aNewSegment.Command = EnhancedCustomShapeSegmentCommand::LIGHTEN;
1029
0
            break;
1030
0
        case XML_lightenLess:
1031
0
            aNewSegment.Command = EnhancedCustomShapeSegmentCommand::LIGHTENLESS;
1032
0
            break;
1033
366
    }
1034
366
    if (mrPath2D.fill != XML_norm) {
1035
0
        aNewSegment.Count = 0;
1036
0
        mrSegments.push_back( aNewSegment );
1037
0
    }
1038
366
    if ( !mrPath2D.stroke )
1039
0
    {
1040
0
        aNewSegment.Command = EnhancedCustomShapeSegmentCommand::NOSTROKE;
1041
0
        aNewSegment.Count = 0;
1042
0
        mrSegments.push_back( aNewSegment );
1043
0
    }
1044
366
    aNewSegment.Command = EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
1045
366
    aNewSegment.Count = 0;
1046
366
    mrSegments.push_back( aNewSegment );
1047
366
}
1048
1049
1050
ContextHandlerRef Path2DContext::onCreateContext( sal_Int32 aElementToken,
1051
    const AttributeList& rAttribs )
1052
1.37k
{
1053
1.37k
    switch( aElementToken )
1054
1.37k
    {
1055
52
        case A_TOKEN( close ) :
1056
52
        {
1057
            // ignore close after move to (ppt does seems to do the same, see accentCallout2 preset for example)
1058
52
            if ( mrSegments.empty() || ( mrSegments.back().Command != EnhancedCustomShapeSegmentCommand::MOVETO ) ) {
1059
52
                EnhancedCustomShapeSegment aNewSegment;
1060
52
                aNewSegment.Command = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
1061
52
                aNewSegment.Count = 0;
1062
52
                mrSegments.push_back( aNewSegment );
1063
52
            }
1064
52
        }
1065
52
        break;
1066
366
        case A_TOKEN( moveTo ) :
1067
366
        {
1068
366
            EnhancedCustomShapeSegment aNewSegment;
1069
366
            aNewSegment.Command = EnhancedCustomShapeSegmentCommand::MOVETO;
1070
366
            aNewSegment.Count = 1;
1071
366
            mrSegments.push_back( aNewSegment );
1072
1073
366
            EnhancedCustomShapeParameterPair aAdjPoint2D;
1074
366
            mrPath2D.parameter.push_back( aAdjPoint2D );
1075
366
            return new Path2DMoveToContext( *this, mrCustomShapeProperties, mrPath2D.parameter.back() );
1076
0
        }
1077
0
        break;
1078
839
        case A_TOKEN( lnTo ) :
1079
839
        {
1080
839
            if ( !mrSegments.empty() && ( mrSegments.back().Command == EnhancedCustomShapeSegmentCommand::LINETO ) )
1081
553
                mrSegments.back().Count++;
1082
286
            else
1083
286
            {
1084
286
                EnhancedCustomShapeSegment aSegment;
1085
286
                aSegment.Command = EnhancedCustomShapeSegmentCommand::LINETO;
1086
286
                aSegment.Count = 1;
1087
286
                mrSegments.push_back( aSegment );
1088
286
            }
1089
839
            EnhancedCustomShapeParameterPair aAdjPoint2D;
1090
839
            mrPath2D.parameter.push_back( aAdjPoint2D );
1091
839
            return new Path2DLineToContext( *this, mrCustomShapeProperties, mrPath2D.parameter.back() );
1092
0
        }
1093
0
        break;
1094
65
        case A_TOKEN( arcTo ) : // CT_Path2DArcTo
1095
65
        {
1096
65
            if ( !mrSegments.empty() && ( mrSegments.back().Command == EnhancedCustomShapeSegmentCommand::ARCANGLETO ) )
1097
0
                mrSegments.back().Count++;
1098
65
            else
1099
65
            {
1100
65
                EnhancedCustomShapeSegment aSegment;
1101
65
                aSegment.Command = EnhancedCustomShapeSegmentCommand::ARCANGLETO;
1102
65
                aSegment.Count = 1;
1103
65
                mrSegments.push_back( aSegment );
1104
65
            }
1105
1106
65
            EnhancedCustomShapeParameterPair aScale;
1107
65
            EnhancedCustomShapeParameterPair aAngles;
1108
1109
65
            aScale.First = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_wR ) );
1110
65
            aScale.Second = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_hR ) );
1111
1112
65
            CustomShapeGuide aGuide;
1113
65
            sal_Int32 nArcNum = mrCustomShapeProperties.getArcNum();
1114
1115
            // start angle
1116
65
            aGuide.maName = "arctosa" + OUString::number( nArcNum );
1117
65
            aGuide.maFormula = "("
1118
65
                + GetFormulaParameter( GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_stAng ) ) )
1119
65
                + ")/60000.0";
1120
65
            aAngles.First.Value <<= mrCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );
1121
65
            aAngles.First.Type = EnhancedCustomShapeParameterType::EQUATION;
1122
1123
            // swing angle
1124
65
            aGuide.maName = "arctosw" + OUString::number( nArcNum );
1125
65
            aGuide.maFormula = "("
1126
65
                + GetFormulaParameter( GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_swAng ) ) )
1127
65
                + ")/60000.0";
1128
65
            aAngles.Second.Value <<= mrCustomShapeProperties.getGuideList().SetCustomShapeGuideValue( aGuide );
1129
65
            aAngles.Second.Type = EnhancedCustomShapeParameterType::EQUATION;
1130
1131
65
            mrPath2D.parameter.push_back( aScale );
1132
65
            mrPath2D.parameter.push_back( aAngles );
1133
65
        }
1134
65
        break;
1135
0
        case A_TOKEN( quadBezTo ) :
1136
0
        {
1137
0
            if ( !mrSegments.empty() && ( mrSegments.back().Command == EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO ) )
1138
0
                mrSegments.back().Count++;
1139
0
            else
1140
0
            {
1141
0
                EnhancedCustomShapeSegment aSegment;
1142
0
                aSegment.Command = EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO;
1143
0
                aSegment.Count = 1;
1144
0
                mrSegments.push_back( aSegment );
1145
0
            }
1146
0
            EnhancedCustomShapeParameterPair aPt1;
1147
0
            EnhancedCustomShapeParameterPair aPt2;
1148
0
            mrPath2D.parameter.push_back( aPt1 );
1149
0
            mrPath2D.parameter.push_back( aPt2 );
1150
0
            return new Path2DQuadBezierToContext( *this, mrCustomShapeProperties,
1151
0
                            mrPath2D.parameter[ mrPath2D.parameter.size() - 2 ],
1152
0
                                mrPath2D.parameter.back() );
1153
0
        }
1154
0
        break;
1155
48
        case A_TOKEN( cubicBezTo ) :
1156
48
        {
1157
48
            if ( !mrSegments.empty() && ( mrSegments.back().Command == EnhancedCustomShapeSegmentCommand::CURVETO ) )
1158
21
                mrSegments.back().Count++;
1159
27
            else
1160
27
            {
1161
27
                EnhancedCustomShapeSegment aSegment;
1162
27
                aSegment.Command = EnhancedCustomShapeSegmentCommand::CURVETO;
1163
27
                aSegment.Count = 1;
1164
27
                mrSegments.push_back( aSegment );
1165
27
            }
1166
48
            EnhancedCustomShapeParameterPair aControlPt1;
1167
48
            EnhancedCustomShapeParameterPair aControlPt2;
1168
48
            EnhancedCustomShapeParameterPair aEndPt;
1169
48
            mrPath2D.parameter.push_back( aControlPt1 );
1170
48
            mrPath2D.parameter.push_back( aControlPt2 );
1171
48
            mrPath2D.parameter.push_back( aEndPt );
1172
48
            return new Path2DCubicBezierToContext( *this, mrCustomShapeProperties,
1173
48
                            mrPath2D.parameter[ mrPath2D.parameter.size() - 3 ],
1174
48
                                mrPath2D.parameter[ mrPath2D.parameter.size() - 2 ],
1175
48
                                    mrPath2D.parameter.back() );
1176
0
        }
1177
0
        break;
1178
1.37k
    }
1179
117
    return nullptr;
1180
1.37k
}
1181
1182
namespace {
1183
1184
// CT_Path2DList
1185
class Path2DListContext : public ContextHandler2
1186
{
1187
public:
1188
    Path2DListContext( ContextHandler2Helper const & rParent, CustomShapeProperties & rCustomShapeProperties, std::vector< EnhancedCustomShapeSegment >& rSegments,
1189
        std::vector< Path2D >& rPath2DList );
1190
1191
    virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const ::oox::AttributeList& rAttribs ) override;
1192
1193
protected:
1194
1195
    CustomShapeProperties& mrCustomShapeProperties;
1196
    std::vector< css::drawing::EnhancedCustomShapeSegment >& mrSegments;
1197
    std::vector< Path2D >& mrPath2DList;
1198
};
1199
1200
}
1201
1202
Path2DListContext:: Path2DListContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties, std::vector< EnhancedCustomShapeSegment >& rSegments,
1203
                                        std::vector< Path2D >& rPath2DList )
1204
756
: ContextHandler2( rParent )
1205
756
, mrCustomShapeProperties( rCustomShapeProperties )
1206
756
, mrSegments( rSegments )
1207
756
, mrPath2DList( rPath2DList )
1208
756
{
1209
756
}
1210
1211
ContextHandlerRef Path2DListContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
1212
366
{
1213
366
    if ( aElementToken == A_TOKEN( path ) )
1214
366
    {
1215
366
        Path2D aPath2D;
1216
366
        mrPath2DList.push_back( aPath2D );
1217
366
        return new Path2DContext( *this, rAttribs, mrCustomShapeProperties,  mrSegments, mrPath2DList.back() );
1218
366
    }
1219
0
    return nullptr;
1220
366
}
1221
1222
// CT_CustomGeometry2D
1223
CustomShapeGeometryContext::CustomShapeGeometryContext( ContextHandler2Helper const & rParent, CustomShapeProperties& rCustomShapeProperties )
1224
756
: ContextHandler2( rParent )
1225
756
, mrCustomShapeProperties( rCustomShapeProperties )
1226
756
{
1227
756
}
1228
1229
ContextHandlerRef CustomShapeGeometryContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
1230
5.54k
{
1231
5.54k
    switch( aElementToken )
1232
5.54k
    {
1233
750
        case A_TOKEN( avLst ):          // CT_GeomGuideList adjust value list
1234
750
            return new GeomGuideListContext( *this, mrCustomShapeProperties, mrCustomShapeProperties.getAdjustmentGuideList() );
1235
750
        case A_TOKEN( gdLst ):          // CT_GeomGuideList guide list
1236
750
            return new GeomGuideListContext( *this, mrCustomShapeProperties, mrCustomShapeProperties.getGuideList() );
1237
750
        case A_TOKEN( ahLst ):          // CT_AdjustHandleList adjust handle list
1238
750
            return new AdjustHandleListContext( *this, mrCustomShapeProperties, mrCustomShapeProperties.getAdjustHandleList() );
1239
663
        case A_TOKEN( cxnLst ):         // CT_ConnectionSiteList connection site list
1240
663
            return this;
1241
750
        case A_TOKEN( rect ):           // CT_GeomRectList geometry rect list
1242
750
        {
1243
750
            GeomRect aGeomRect;
1244
750
            aGeomRect.l = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_l ) );
1245
750
            aGeomRect.t = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_t ) );
1246
750
            aGeomRect.r = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_r ) );
1247
750
            aGeomRect.b = GetAdjCoordinate( mrCustomShapeProperties, rAttribs.getStringDefaulted( XML_b ) );
1248
750
            mrCustomShapeProperties.getTextRect() = aGeomRect;
1249
750
        }
1250
750
        break;
1251
756
        case A_TOKEN( pathLst ):        // CT_Path2DList 2d path list
1252
756
            return new Path2DListContext( *this, mrCustomShapeProperties, mrCustomShapeProperties.getSegments(), mrCustomShapeProperties.getPath2DList() );
1253
1254
        // from cxnLst:
1255
1.12k
        case A_TOKEN( cxn ):                // CT_ConnectionSite
1256
1.12k
        {
1257
1.12k
            ConnectionSite aConnectionSite;
1258
1.12k
            mrCustomShapeProperties.getConnectionSiteList().push_back( aConnectionSite );
1259
1.12k
            return new ConnectionSiteContext( *this, rAttribs, mrCustomShapeProperties, mrCustomShapeProperties.getConnectionSiteList().back() );
1260
0
        }
1261
5.54k
    }
1262
750
    return nullptr;
1263
5.54k
}
1264
1265
// CT_PresetGeometry2D
1266
PresetShapeGeometryContext::PresetShapeGeometryContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties )
1267
92.6k
: ContextHandler2( rParent )
1268
92.6k
, mrCustomShapeProperties( rCustomShapeProperties )
1269
92.6k
{
1270
92.6k
    sal_Int32 nShapeType = rAttribs.getToken( XML_prst, FastToken::DONTKNOW );
1271
92.6k
    OSL_ENSURE( nShapeType != FastToken::DONTKNOW, "oox::drawingml::CustomShapeCustomGeometryContext::CustomShapeCustomGeometryContext(), unknown shape type" );
1272
92.6k
    mrCustomShapeProperties.setShapePresetType( nShapeType );
1273
92.6k
}
1274
1275
ContextHandlerRef PresetShapeGeometryContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& )
1276
92.5k
{
1277
92.5k
    if ( aElementToken == A_TOKEN( avLst ) )
1278
92.5k
        return new GeomGuideListContext( *this, mrCustomShapeProperties, mrCustomShapeProperties.getAdjustmentGuideList() );
1279
0
    else
1280
0
        return this;
1281
92.5k
}
1282
1283
// CT_PresetTextShape
1284
PresetTextShapeContext::PresetTextShapeContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, CustomShapeProperties& rCustomShapeProperties )
1285
18
: ContextHandler2( rParent )
1286
18
, mrCustomShapeProperties( rCustomShapeProperties )
1287
18
{
1288
18
    sal_Int32 nShapeType = rAttribs.getToken( XML_prst, FastToken::DONTKNOW );
1289
18
    OSL_ENSURE( nShapeType != FastToken::DONTKNOW, "oox::drawingml::CustomShapeCustomGeometryContext::CustomShapeCustomGeometryContext(), unknown shape type" );
1290
18
    mrCustomShapeProperties.setShapePresetType( nShapeType );
1291
18
}
1292
1293
ContextHandlerRef PresetTextShapeContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& )
1294
18
{
1295
18
    if ( aElementToken == A_TOKEN( avLst ) )
1296
18
        return new GeomGuideListContext( *this, mrCustomShapeProperties, mrCustomShapeProperties.getAdjustmentGuideList() );
1297
0
    else
1298
0
        return this;
1299
18
}
1300
1301
}
1302
1303
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */