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