1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawingml/fontworkhelpers.hxx>
22 #include <basegfx/utils/bgradient.hxx>
23 #include <basegfx/utils/gradienttools.hxx>
24 #include <comphelper/propertysequence.hxx>
25 #include <comphelper/propertyvalue.hxx>
26 #include <comphelper/sequence.hxx>
27 #include <comphelper/sequenceashashmap.hxx>
28 #include <docmodel/uno/UnoComplexColor.hxx>
29 #include <docmodel/uno/UnoGradientTools.hxx>
30 #include <drawingml/customshapeproperties.hxx>
31 #include <drawingml/presetgeometrynames.hxx>
32 #include <oox/drawingml/drawingmltypes.hxx>
33 #include <oox/helper/grabbagstack.hxx>
34 #include <sal/log.hxx>
35 #include <svx/msdffdef.hxx>
36 #include <tools/color.hxx>
37 #include <tools/helpers.hxx>
39 #include <com/sun/star/awt/Gradient2.hpp>
40 #include <com/sun/star/beans/PropertyAttribute.hpp>
41 #include <com/sun/star/beans/PropertyValue.hpp>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/container/XEnumeration.hpp>
44 #include <com/sun/star/container/XEnumerationAccess.hpp>
45 #include <com/sun/star/drawing/DashStyle.hpp>
46 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
47 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
48 #include <com/sun/star/drawing/FillStyle.hpp>
49 #include <com/sun/star/drawing/LineCap.hpp>
50 #include <com/sun/star/drawing/LineDash.hpp>
51 #include <com/sun/star/drawing/LineJoint.hpp>
52 #include <com/sun/star/drawing/LineStyle.hpp>
53 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
54 #include <com/sun/star/drawing/XShape.hpp>
55 #include <com/sun/star/text/XText.hpp>
56 #include <com/sun/star/text/XTextRange.hpp>
57 #include <com/sun/star/util/XComplexColor.hpp>
62 using namespace com::sun::star
;
64 void FontworkHelpers::resetPropertyValueInVec(std::vector
<beans::PropertyValue
>& rPropVec
,
65 const OUString
& rName
)
67 auto aIterator
= std::find_if(
68 rPropVec
.begin(), rPropVec
.end(),
69 [rName
](const beans::PropertyValue
& rValue
) { return rValue
.Name
== rName
; });
71 if (aIterator
!= rPropVec
.end())
72 rPropVec
.erase(aIterator
);
75 void FontworkHelpers::putCustomShapeIntoTextPathMode(
76 const css::uno::Reference
<drawing::XShape
>& xShape
,
77 const oox::drawingml::CustomShapePropertiesPtr
& pCustomShapePropertiesPtr
,
78 const OUString
& sMSPresetType
, const bool bFromWordArt
)
80 if (!xShape
.is() || !pCustomShapePropertiesPtr
|| sMSPresetType
== u
"textNoShape")
83 uno::Reference
<drawing::XEnhancedCustomShapeDefaulter
> xDefaulter(xShape
, uno::UNO_QUERY
);
87 uno::Reference
<beans::XPropertySet
> xSet(xShape
, uno::UNO_QUERY
);
91 // The DrawingML shapes from the presetTextWarpDefinitions are mapped to the definitions
92 // in svx/../EnhancedCustomShapeGeometry.cxx, which are used for WordArt shapes from
93 // binary MS Office. Therefore all adjustment values need to be adapted.
94 const OUString sFontworkType
= PresetGeometryTypeNames::GetFontworkType(sMSPresetType
);
95 auto aAdjGdList
= pCustomShapePropertiesPtr
->getAdjustmentGuideList();
96 uno::Sequence
<drawing::EnhancedCustomShapeAdjustmentValue
> aAdjustment(
97 !aAdjGdList
.empty() ? aAdjGdList
.size() : 1);
98 auto pAdjustment
= aAdjustment
.getArray();
100 for (const auto& aEntry
: aAdjGdList
)
102 double fValue
= aEntry
.maFormula
.toDouble();
103 // then: polar-handle, else: XY-handle
104 // There exist only 8 polar-handles at all in presetTextWarp.
105 if ((sFontworkType
== "fontwork-arch-down-curve")
106 || (sFontworkType
== "fontwork-arch-down-pour" && aEntry
.maName
== "adj1")
107 || (sFontworkType
== "fontwork-arch-up-curve")
108 || (sFontworkType
== "fontwork-arch-up-pour" && aEntry
.maName
== "adj1")
109 || (sFontworkType
== "fontwork-open-circle-curve")
110 || (sFontworkType
== "fontwork-open-circle-pour" && aEntry
.maName
== "adj1")
111 || (sFontworkType
== "fontwork-circle-curve")
112 || (sFontworkType
== "fontwork-circle-pour" && aEntry
.maName
== "adj1"))
114 // DrawingML has 1/60000 degree unit, but WordArt simple degree. Range [0..360[
115 // or range ]-180..180] doesn't matter, because only cos(angle) and
116 // sin(angle) are used.
117 fValue
= NormAngle360(fValue
/ 60000.0);
121 // DrawingML writes adjustment guides as relative value with 100% = 100000,
122 // but WordArt definitions use values absolute in viewBox 0 0 21600 21600,
123 // so scale with 21600/100000 = 0.216, with two exceptions:
124 // X-handles of waves describe increase/decrease relative to horizontal center.
125 // The gdRefR of pour-shapes is not relative to viewBox but to radius.
126 if ((sFontworkType
== "mso-spt158" && aEntry
.maName
== "adj2") // textDoubleWave1
127 || (sFontworkType
== "fontwork-wave" && aEntry
.maName
== "adj2") // textWave1
128 || (sFontworkType
== "mso-spt157" && aEntry
.maName
== "adj2") // textWave2
129 || (sFontworkType
== "mso-spt159" && aEntry
.maName
== "adj2")) // textWave4
131 fValue
= (fValue
+ 50000.0) * 0.216;
133 else if ((sFontworkType
== "fontwork-arch-down-pour" && aEntry
.maName
== "adj2")
134 || (sFontworkType
== "fontwork-arch-up-pour" && aEntry
.maName
== "adj2")
135 || (sFontworkType
== "fontwork-open-circle-pour" && aEntry
.maName
== "adj2")
136 || (sFontworkType
== "fontwork-circle-pour" && aEntry
.maName
== "adj2"))
146 pAdjustment
[nIndex
].Value
<<= fValue
;
147 pAdjustment
[nIndex
++].State
= css::beans::PropertyState_DIRECT_VALUE
;
150 // Set attributes in CustomShapeGeometry
151 xDefaulter
->createCustomShapeDefaults(sFontworkType
);
154 = xSet
->getPropertyValue("CustomShapeGeometry").get
<uno::Sequence
<beans::PropertyValue
>>();
156 = comphelper::sequenceToContainer
<std::vector
<beans::PropertyValue
>>(aGeomPropSeq
);
158 // Reset old properties
159 static const OUStringLiteral
sTextPath(u
"TextPath");
160 static const OUStringLiteral
sAdjustmentValues(u
"AdjustmentValues");
161 static const OUStringLiteral
sPresetTextWarp(u
"PresetTextWarp");
163 resetPropertyValueInVec(aGeomPropVec
, u
"CoordinateSize");
164 resetPropertyValueInVec(aGeomPropVec
, u
"Equations");
165 resetPropertyValueInVec(aGeomPropVec
, u
"Path");
166 resetPropertyValueInVec(aGeomPropVec
, sAdjustmentValues
);
167 resetPropertyValueInVec(aGeomPropVec
, u
"ViewBox");
168 resetPropertyValueInVec(aGeomPropVec
, u
"Handles");
169 resetPropertyValueInVec(aGeomPropVec
, sTextPath
);
170 resetPropertyValueInVec(aGeomPropVec
, sPresetTextWarp
);
174 && (sMSPresetType
== u
"textArchDown" || sMSPresetType
== u
"textArchUp"
175 || sMSPresetType
== u
"textCircle" || sMSPresetType
== u
"textButton"))
180 // Apply new properties
181 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
182 { { sTextPath
, uno::Any(true) },
183 { u
"TextPathMode", uno::Any(drawing::EnhancedCustomShapeTextPathMode_PATH
) },
184 { u
"ScaleX", uno::Any(bScaleX
) } }));
185 aGeomPropVec
.push_back(comphelper::makePropertyValue(sTextPath
, aPropertyValues
));
187 aGeomPropVec
.push_back(comphelper::makePropertyValue(sPresetTextWarp
, sMSPresetType
));
189 if (!aAdjGdList
.empty())
191 aGeomPropVec
.push_back(comphelper::makePropertyValue(sAdjustmentValues
, aAdjustment
));
194 xSet
->setPropertyValue(u
"CustomShapeGeometry",
195 uno::Any(comphelper::containerToSequence(aGeomPropVec
)));
198 OString
FontworkHelpers::GetVMLFontworkShapetypeMarkup(const MSO_SPT eShapeType
)
200 // The markup is taken from VML in DOCX documents. Using the generated 'vml-shape-types' file
203 static const std::map
<MSO_SPT
, OString
> aTypeToMarkupMap
{
205 "<v:shapetype id=\"_x0000_t24\" coordsize=\"21600,21600\" o:spt=\"24\" adj=\"10800\" "
206 "path=\"m@7,l@8,m@5,21600l@6,21600e\"><v:formulas><v:f eqn=\"sum #0 0 10800\"/><v:f "
207 "eqn=\"prod #0 2 1\"/><v:f eqn=\"sum 21600 0 @1\"/><v:f eqn=\"sum 0 0 @2\"/><v:f "
208 "eqn=\"sum 21600 0 @3\"/><v:f eqn=\"if @0 @3 0\"/><v:f eqn=\"if @0 21600 @1\"/><v:f "
209 "eqn=\"if @0 0 @2\"/><v:f eqn=\"if @0 @4 21600\"/><v:f eqn=\"mid @5 @6\"/><v:f eqn=\"mid "
210 "@8 @5\"/><v:f eqn=\"mid @7 @8\"/><v:f eqn=\"mid @6 @7\"/><v:f eqn=\"sum @6 0 "
211 "@5\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
212 "o:connectlocs=\"@9,0;@10,10800;@11,21600;@12,10800\" "
213 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
214 "position=\"#0,bottomRight\" xrange=\"6629,14971\"/></v:handles><o:lock v:ext=\"edit\" "
215 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
216 { mso_sptTextOctagon
,
217 "<v:shapetype id=\"_x0000_t25\" coordsize=\"21600,21600\" o:spt=\"25\" adj=\"4800\" "
218 "path=\"m0@0l7200,r7200,l21600@0m0@1l7200,21600r7200,l21600@1e\"><v:formulas><v:f "
219 "eqn=\"val #0\"/><v:f eqn=\"sum 21600 0 @0\"/></v:formulas><v:path textpathok=\"t\" "
220 "o:connecttype=\"rect\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
221 "position=\"topLeft,#0\" yrange=\"3086,10800\"/></v:handles><o:lock v:ext=\"edit\" "
222 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
223 { mso_sptTextHexagon
,
224 "<v:shapetype id=\"_x0000_t26\" coordsize=\"21600,21600\" o:spt=\"26\" adj=\"10800\" "
225 "path=\"m0@0l10800,,21600@0m,21600r10800,l21600,21600e\"><v:formulas><v:f eqn=\"val "
226 "#0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum @1 10800 0\"/><v:f eqn=\"sum 21600 0 "
227 "@1\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
228 "o:connectlocs=\"10800,0;5400,@1;10800,21600;16200,@1\" "
229 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
230 "position=\"topLeft,#0\" yrange=\"0,21600\"/></v:handles><o:lock v:ext=\"edit\" "
231 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
233 "<v:shapetype id=\"_x0000_t27\" coordsize=\"21600,21600\" o:spt=\"27\" adj=\"3086\" "
234 "path=\"m,qy10800@0,21600,m0@1qy10800,21600,21600@1e\"><v:formulas><v:f eqn=\"val "
235 "#0\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"prod @1 1 2\"/><v:f eqn=\"sum @2 10800 "
236 "0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
237 "o:connectlocs=\"10800,@0;0,@2;10800,21600;21600,@2\" "
238 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
239 "position=\"center,#0\" yrange=\"0,7200\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
240 "shapetype=\"t\"/></v:shapetype>" },
242 "<v:shapetype id=\"_x0000_t28\" coordsize=\"21600,21600\" o:spt=\"28\" "
243 "adj=\"2809,10800\" "
244 "path=\"m@25@0c@26@3@27@1@28@0m@21@4c@22@5@23@6@24@4e\"><v:formulas><v:f eqn=\"val "
245 "#0\"/><v:f eqn=\"prod @0 41 9\"/><v:f eqn=\"prod @0 23 9\"/><v:f eqn=\"sum 0 0 "
246 "@2\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"sum 21600 0 @1\"/><v:f eqn=\"sum 21600 0 "
247 "@3\"/><v:f eqn=\"sum #1 0 10800\"/><v:f eqn=\"sum 21600 0 #1\"/><v:f eqn=\"prod @8 2 "
248 "3\"/><v:f eqn=\"prod @8 4 3\"/><v:f eqn=\"prod @8 2 1\"/><v:f eqn=\"sum 21600 0 "
249 "@9\"/><v:f eqn=\"sum 21600 0 @10\"/><v:f eqn=\"sum 21600 0 @11\"/><v:f eqn=\"prod #1 2 "
250 "3\"/><v:f eqn=\"prod #1 4 3\"/><v:f eqn=\"prod #1 2 1\"/><v:f eqn=\"sum 21600 0 "
251 "@15\"/><v:f eqn=\"sum 21600 0 @16\"/><v:f eqn=\"sum 21600 0 @17\"/><v:f eqn=\"if @7 @14 "
252 "0\"/><v:f eqn=\"if @7 @13 @15\"/><v:f eqn=\"if @7 @12 @16\"/><v:f eqn=\"if @7 21600 "
253 "@17\"/><v:f eqn=\"if @7 0 @20\"/><v:f eqn=\"if @7 @9 @19\"/><v:f eqn=\"if @7 @10 "
254 "@18\"/><v:f eqn=\"if @7 @11 21600\"/><v:f eqn=\"sum @24 0 @21\"/><v:f eqn=\"sum @4 0 "
255 "@0\"/><v:f eqn=\"max @21 @25\"/><v:f eqn=\"min @24 @28\"/><v:f eqn=\"prod @0 2 "
256 "1\"/><v:f eqn=\"sum 21600 0 @33\"/><v:f eqn=\"mid @26 @27\"/><v:f eqn=\"mid @24 "
257 "@28\"/><v:f eqn=\"mid @22 @23\"/><v:f eqn=\"mid @21 @25\"/></v:formulas><v:path "
258 "textpathok=\"t\" o:connecttype=\"custom\" "
259 "o:connectlocs=\"@35,@0;@38,10800;@37,@4;@36,10800\" "
260 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
261 "xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" yrange=\"0,4459\"/><v:h "
262 "position=\"#1,bottomRight\" xrange=\"8640,12960\"/></v:handles><o:lock v:ext=\"edit\" "
263 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
265 "<v:shapetype id=\"_x0000_t29\" coordsize=\"21600,21600\" o:spt=\"29\" "
266 "adj=\"11796480,5400\" "
267 "path=\"al10800,10800,10800,10800@2@14al10800,10800@0@0@2@14e\"><v:formulas><v:f "
268 "eqn=\"val #1\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"sumangle #0 0 "
269 "180\"/><v:f eqn=\"sumangle #0 0 90\"/><v:f eqn=\"prod @4 2 1\"/><v:f eqn=\"sumangle #0 "
270 "90 0\"/><v:f eqn=\"prod @6 2 1\"/><v:f eqn=\"abs #0\"/><v:f eqn=\"sumangle @8 0 "
271 "90\"/><v:f eqn=\"if @9 @7 @5\"/><v:f eqn=\"sumangle @10 0 360\"/><v:f eqn=\"if @10 @11 "
272 "@10\"/><v:f eqn=\"sumangle @12 0 360\"/><v:f eqn=\"if @12 @13 @12\"/><v:f eqn=\"sum 0 0 "
273 "@14\"/><v:f eqn=\"val 10800\"/><v:f eqn=\"sum 10800 0 #1\"/><v:f eqn=\"prod #1 1 "
274 "2\"/><v:f eqn=\"sum @18 5400 0\"/><v:f eqn=\"cos @19 #0\"/><v:f eqn=\"sin @19 "
275 "#0\"/><v:f eqn=\"sum @20 10800 0\"/><v:f eqn=\"sum @21 10800 0\"/><v:f eqn=\"sum 10800 "
276 "0 @20\"/><v:f eqn=\"sum #1 10800 0\"/><v:f eqn=\"if @9 @17 @25\"/><v:f eqn=\"if @9 0 "
277 "21600\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
278 "o:connectlocs=\"10800,@27;@22,@23;10800,@26;@24,@23\"/><v:textpath on=\"t\" "
279 "fitshape=\"t\"/><v:handles><v:h position=\"#1,#0\" polar=\"10800,10800\" "
280 "radiusrange=\"0,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
281 "shapetype=\"t\"/></v:shapetype>" },
282 { mso_sptTextOnCurve
,
283 "<v:shapetype id=\"_x0000_t30\" coordsize=\"21600,21600\" o:spt=\"30\" adj=\"3086\" "
284 "path=\"m,qy10800@0,21600,m0@1qy10800,21600,21600@1e\"><v:formulas><v:f eqn=\"val "
285 "#0\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"prod @1 1 2\"/><v:f eqn=\"sum @2 10800 "
286 "0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
287 "o:connectlocs=\"10800,@0;0,@2;10800,21600;21600,@2\" "
288 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
289 "position=\"center,#0\" yrange=\"0,7200\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
290 "shapetype=\"t\"/></v:shapetype>" },
292 "<v:shapetype id=\"_x0000_t31\" coordsize=\"21600,21600\" o:spt=\"31\" adj=\"11796480\" "
293 "path=\"al10800,10800,10800,10800@2@14e\"><v:formulas><v:f eqn=\"val #1\"/><v:f "
294 "eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"sumangle #0 0 180\"/><v:f "
295 "eqn=\"sumangle #0 0 90\"/><v:f eqn=\"prod @4 2 1\"/><v:f eqn=\"sumangle #0 90 0\"/><v:f "
296 "eqn=\"prod @6 2 1\"/><v:f eqn=\"abs #0\"/><v:f eqn=\"sumangle @8 0 90\"/><v:f eqn=\"if "
297 "@9 @7 @5\"/><v:f eqn=\"sumangle @10 0 360\"/><v:f eqn=\"if @10 @11 @10\"/><v:f "
298 "eqn=\"sumangle @12 0 360\"/><v:f eqn=\"if @12 @13 @12\"/><v:f eqn=\"sum 0 0 @14\"/><v:f "
299 "eqn=\"val 10800\"/><v:f eqn=\"cos 10800 #0\"/><v:f eqn=\"sin 10800 #0\"/><v:f eqn=\"sum "
300 "@17 10800 0\"/><v:f eqn=\"sum @18 10800 0\"/><v:f eqn=\"sum 10800 0 @17\"/><v:f "
301 "eqn=\"if @9 0 21600\"/><v:f eqn=\"sum 10800 0 @18\"/></v:formulas><v:path "
302 "textpathok=\"t\" o:connecttype=\"custom\" "
303 "o:connectlocs=\"10800,@22;@19,@20;@21,@20\"/><v:textpath on=\"t\" "
304 "style=\"v-text-kern:t\" fitpath=\"t\"/><v:handles><v:h position=\"@16,#0\" "
305 "polar=\"10800,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
306 "shapetype=\"t\"/></v:shapetype>" },
307 { mso_sptTextPlainText
,
308 "<v:shapetype id=\"_x0000_t136\" coordsize=\"21600,21600\" o:spt=\"136\" adj=\"10800\" "
309 "path=\"m@7,l@8,m@5,21600l@6,21600e\"><v:formulas><v:f eqn=\"sum #0 0 10800\"/><v:f "
310 "eqn=\"prod #0 2 1\"/><v:f eqn=\"sum 21600 0 @1\"/><v:f eqn=\"sum 0 0 @2\"/><v:f "
311 "eqn=\"sum 21600 0 @3\"/><v:f eqn=\"if @0 @3 0\"/><v:f eqn=\"if @0 21600 @1\"/><v:f "
312 "eqn=\"if @0 0 @2\"/><v:f eqn=\"if @0 @4 21600\"/><v:f eqn=\"mid @5 @6\"/><v:f eqn=\"mid "
313 "@8 @5\"/><v:f eqn=\"mid @7 @8\"/><v:f eqn=\"mid @6 @7\"/><v:f eqn=\"sum @6 0 "
314 "@5\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
315 "o:connectlocs=\"@9,0;@10,10800;@11,21600;@12,10800\" "
316 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
317 "position=\"#0,bottomRight\" xrange=\"6629,14971\"/></v:handles><o:lock v:ext=\"edit\" "
318 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
320 "<v:shapetype id=\"_x0000_t137\" coordsize=\"21600,21600\" o:spt=\"137\" adj=\"4800\" "
321 "path=\"m0@0l7200,r7200,l21600@0m0@1l7200,21600r7200,l21600@1e\"><v:formulas><v:f "
322 "eqn=\"val #0\"/><v:f eqn=\"sum 21600 0 @0\"/></v:formulas><v:path textpathok=\"t\" "
323 "o:connecttype=\"rect\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
324 "position=\"topLeft,#0\" yrange=\"3086,10800\"/></v:handles><o:lock v:ext=\"edit\" "
325 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
326 { mso_sptTextTriangle
,
327 "<v:shapetype id=\"_x0000_t138\" coordsize=\"21600,21600\" o:spt=\"138\" adj=\"10800\" "
328 "path=\"m0@0l10800,,21600@0m,21600r10800,l21600,21600e\"><v:formulas><v:f eqn=\"val "
329 "#0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum @1 10800 0\"/><v:f eqn=\"sum 21600 0 "
330 "@1\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
331 "o:connectlocs=\"10800,0;5400,@1;10800,21600;16200,@1\" "
332 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
333 "position=\"topLeft,#0\" yrange=\"0,21600\"/></v:handles><o:lock v:ext=\"edit\" "
334 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
335 { mso_sptTextTriangleInverted
,
336 "<v:shapetype id=\"_x0000_t139\" coordsize=\"21600,21600\" o:spt=\"139\" adj=\"10800\" "
337 "path=\"m,l10800,,21600,m0@0l10800,21600,21600@0e\"><v:formulas><v:f eqn=\"val "
338 "#0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum @1 10800 0\"/><v:f eqn=\"sum 21600 0 "
339 "@1\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
340 "o:connectlocs=\"10800,0;5400,@2;10800,21600;16200,@2\" "
341 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
342 "position=\"topLeft,#0\" yrange=\"0,21600\"/></v:handles><o:lock v:ext=\"edit\" "
343 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
344 { mso_sptTextChevron
,
345 "<v:shapetype id=\"_x0000_t140\" coordsize=\"21600,21600\" o:spt=\"140\" adj=\"5400\" "
346 "path=\"m0@0l10800,,21600@0m,21600l10800@1,21600,21600e\"><v:formulas><v:f eqn=\"val "
347 "#0\"/><v:f eqn=\"sum 21600 0 @0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum @2 10800 "
348 "0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
349 "o:connectlocs=\"10800,0;0,@3;10800,@1;21600,@3\" "
350 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
351 "position=\"topLeft,#0\" yrange=\"0,10800\"/></v:handles><o:lock v:ext=\"edit\" "
352 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
353 { mso_sptTextChevronInverted
,
354 "<v:shapetype id=\"_x0000_t141\" coordsize=\"21600,21600\" o:spt=\"141\" adj=\"16200\" "
355 "path=\"m,l10800@1,21600,m0@0l10800,21600,21600@0e\"><v:formulas><v:f eqn=\"val "
356 "#0\"/><v:f eqn=\"sum 21600 0 @0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum @2 10800 "
357 "0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
358 "o:connectlocs=\"10800,@1;0,@2;10800,21600;21600,@2\" "
359 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
360 "position=\"topLeft,#0\" yrange=\"10800,21600\"/></v:handles><o:lock v:ext=\"edit\" "
361 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
362 { mso_sptTextRingInside
,
363 "<v:shapetype id=\"_x0000_t142\" coordsize=\"21600,21600\" o:spt=\"142\" adj=\"13500\" "
364 "path=\"m0@1qy10800,,21600@1,10800@0,0@1m0@2qy10800@3,21600@2,10800,21600,0@2e\"><v:"
365 "formulas><v:f eqn=\"val #0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum height 0 "
366 "@1\"/><v:f eqn=\"sum height 0 #0\"/><v:f eqn=\"sum @2 0 @1\"/></v:formulas><v:path "
367 "textpathok=\"t\" o:connecttype=\"custom\" "
368 "o:connectlocs=\"10800,0;10800,@0;0,10800;10800,21600;10800,@3;21600,10800\" "
369 "o:connectangles=\"270,270,180,90,90,0\"/><v:textpath on=\"t\" "
370 "fitshape=\"t\"/><v:handles><v:h position=\"center,#0\" "
371 "yrange=\"10800,21600\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
372 "shapetype=\"t\"/></v:shapetype>" },
373 { mso_sptTextRingOutside
,
374 "<v:shapetype id=\"_x0000_t143\" coordsize=\"21600,21600\" o:spt=\"143\" adj=\"13500\" "
375 "path=\"m0@1qy10800@0,21600@1,10800,,0@1m0@2qy10800,21600,21600@2,10800@3,0@2e\"><v:"
376 "formulas><v:f eqn=\"val #0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum height 0 "
377 "@1\"/><v:f eqn=\"sum height 0 #0\"/><v:f eqn=\"sum @2 0 @1\"/></v:formulas><v:path "
378 "textpathok=\"t\" o:connecttype=\"custom\" "
379 "o:connectlocs=\"10800,0;10800,@0;0,10800;10800,21600;10800,@3;21600,10800\" "
380 "o:connectangles=\"270,270,180,90,90,0\"/><v:textpath on=\"t\" "
381 "fitshape=\"t\"/><v:handles><v:h position=\"center,#0\" "
382 "yrange=\"10800,21600\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
383 "shapetype=\"t\"/></v:shapetype>" },
384 { mso_sptTextArchUpCurve
,
385 "<v:shapetype id=\"_x0000_t144\" coordsize=\"21600,21600\" o:spt=\"144\" "
386 "adj=\"11796480\" path=\"al10800,10800,10800,10800@2@14e\"><v:formulas><v:f eqn=\"val "
387 "#1\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"sumangle #0 0 "
388 "180\"/><v:f eqn=\"sumangle #0 0 90\"/><v:f eqn=\"prod @4 2 1\"/><v:f eqn=\"sumangle #0 "
389 "90 0\"/><v:f eqn=\"prod @6 2 1\"/><v:f eqn=\"abs #0\"/><v:f eqn=\"sumangle @8 0 "
390 "90\"/><v:f eqn=\"if @9 @7 @5\"/><v:f eqn=\"sumangle @10 0 360\"/><v:f eqn=\"if @10 @11 "
391 "@10\"/><v:f eqn=\"sumangle @12 0 360\"/><v:f eqn=\"if @12 @13 @12\"/><v:f eqn=\"sum 0 0 "
392 "@14\"/><v:f eqn=\"val 10800\"/><v:f eqn=\"cos 10800 #0\"/><v:f eqn=\"sin 10800 "
393 "#0\"/><v:f eqn=\"sum @17 10800 0\"/><v:f eqn=\"sum @18 10800 0\"/><v:f eqn=\"sum 10800 "
394 "0 @17\"/><v:f eqn=\"if @9 0 21600\"/><v:f eqn=\"sum 10800 0 @18\"/></v:formulas><v:path "
395 "textpathok=\"t\" o:connecttype=\"custom\" "
396 "o:connectlocs=\"10800,@22;@19,@20;@21,@20\"/><v:textpath on=\"t\" "
397 "style=\"v-text-kern:t\" fitpath=\"t\"/><v:handles><v:h position=\"@16,#0\" "
398 "polar=\"10800,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
399 "shapetype=\"t\"/></v:shapetype>" },
400 { mso_sptTextArchDownCurve
,
401 "<v:shapetype id=\"_x0000_t145\" coordsize=\"21600,21600\" o:spt=\"145\" "
402 "path=\"al10800,10800,10800,10800@3@15e\"><v:formulas><v:f eqn=\"val #1\"/><v:f "
403 "eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"sumangle #0 0 180\"/><v:f "
404 "eqn=\"sumangle #0 0 90\"/><v:f eqn=\"prod @4 2 1\"/><v:f eqn=\"sumangle #0 90 0\"/><v:f "
405 "eqn=\"prod @6 2 1\"/><v:f eqn=\"abs #0\"/><v:f eqn=\"sumangle @8 0 90\"/><v:f eqn=\"if "
406 "@9 @7 @5\"/><v:f eqn=\"sumangle @10 0 360\"/><v:f eqn=\"if @10 @11 @10\"/><v:f "
407 "eqn=\"sumangle @12 0 360\"/><v:f eqn=\"if @12 @13 @12\"/><v:f eqn=\"sum 0 0 @14\"/><v:f "
408 "eqn=\"val 10800\"/><v:f eqn=\"cos 10800 #0\"/><v:f eqn=\"sin 10800 #0\"/><v:f eqn=\"sum "
409 "@17 10800 0\"/><v:f eqn=\"sum @18 10800 0\"/><v:f eqn=\"sum 10800 0 @17\"/><v:f "
410 "eqn=\"if @9 0 21600\"/><v:f eqn=\"sum 10800 0 @18\"/></v:formulas><v:path "
411 "textpathok=\"t\" o:connecttype=\"custom\" "
412 "o:connectlocs=\"10800,@22;@19,@20;@21,@20\"/><v:textpath on=\"t\" "
413 "style=\"v-text-kern:t\" fitpath=\"t\"/><v:handles><v:h position=\"@16,#0\" "
414 "polar=\"10800,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
415 "shapetype=\"t\"/></v:shapetype>" },
416 { mso_sptTextCircleCurve
,
417 "<v:shapetype id=\"_x0000_t146\" coordsize=\"21600,21600\" o:spt=\"146\" "
418 "adj=\"-11730944\" path=\"al10800,10800,10800,10800@2@5e\"><v:formulas><v:f eqn=\"val "
419 "#1\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"prod #0 2 1\"/><v:f "
420 "eqn=\"sumangle @3 0 360\"/><v:f eqn=\"if @3 @4 @3\"/><v:f eqn=\"val 10800\"/><v:f "
421 "eqn=\"cos 10800 #0\"/><v:f eqn=\"sin 10800 #0\"/><v:f eqn=\"sum @7 10800 0\"/><v:f "
422 "eqn=\"sum @8 10800 0\"/><v:f eqn=\"sum 10800 0 @8\"/><v:f eqn=\"if #0 0 "
423 "21600\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
424 "o:connectlocs=\"@12,10800;@9,@10;@9,@11\"/><v:textpath on=\"t\" style=\"v-text-kern:t\" "
425 "fitpath=\"t\"/><v:handles><v:h position=\"@6,#0\" "
426 "polar=\"10800,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
427 "shapetype=\"t\"/></v:shapetype>" },
428 { mso_sptTextButtonCurve
,
429 "<v:shapetype id=\"_x0000_t147\" coordsize=\"21600,21600\" o:spt=\"147\" "
431 "path=\"al10800,10800,10800,10800@2@14m,10800r21600,al10800,10800,10800,10800@1@15e\"><v:"
432 "formulas><v:f eqn=\"val #1\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f "
433 "eqn=\"sumangle #0 0 180\"/><v:f eqn=\"sumangle #0 0 90\"/><v:f eqn=\"prod @4 2 "
434 "1\"/><v:f eqn=\"sumangle #0 90 0\"/><v:f eqn=\"prod @6 2 1\"/><v:f eqn=\"abs #0\"/><v:f "
435 "eqn=\"sumangle @8 0 90\"/><v:f eqn=\"if @9 @7 @5\"/><v:f eqn=\"sumangle @10 0 "
436 "360\"/><v:f eqn=\"if @10 @11 @10\"/><v:f eqn=\"sumangle @12 0 360\"/><v:f eqn=\"if @12 "
437 "@13 @12\"/><v:f eqn=\"sum 0 0 @14\"/><v:f eqn=\"val 10800\"/><v:f eqn=\"cos 10800 "
438 "#0\"/><v:f eqn=\"sin 10800 #0\"/><v:f eqn=\"sum @17 10800 0\"/><v:f eqn=\"sum @18 10800 "
439 "0\"/><v:f eqn=\"sum 10800 0 @17\"/><v:f eqn=\"if @9 0 21600\"/><v:f eqn=\"sum 10800 0 "
440 "@18\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
441 "o:connectlocs=\"10800,0;@19,@20;@21,@20;10800,10800;0,10800;21600,10800;10800,21600;@19,"
442 "@23;@21,@23\"/><v:textpath on=\"t\" style=\"v-text-kern:t\" "
443 "fitpath=\"t\"/><v:handles><v:h position=\"@16,#0\" "
444 "polar=\"10800,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
445 "shapetype=\"t\"/></v:shapetype>" },
446 { mso_sptTextArchUpPour
,
447 "<v:shapetype id=\"_x0000_t148\" coordsize=\"21600,21600\" o:spt=\"148\" "
448 "adj=\"11796480,5400\" "
449 "path=\"al10800,10800,10800,10800@2@14al10800,10800@0@0@2@14e\"><v:formulas><v:f "
450 "eqn=\"val #1\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"sumangle #0 0 "
451 "180\"/><v:f eqn=\"sumangle #0 0 90\"/><v:f eqn=\"prod @4 2 1\"/><v:f eqn=\"sumangle #0 "
452 "90 0\"/><v:f eqn=\"prod @6 2 1\"/><v:f eqn=\"abs #0\"/><v:f eqn=\"sumangle @8 0 "
453 "90\"/><v:f eqn=\"if @9 @7 @5\"/><v:f eqn=\"sumangle @10 0 360\"/><v:f eqn=\"if @10 @11 "
454 "@10\"/><v:f eqn=\"sumangle @12 0 360\"/><v:f eqn=\"if @12 @13 @12\"/><v:f eqn=\"sum 0 0 "
455 "@14\"/><v:f eqn=\"val 10800\"/><v:f eqn=\"sum 10800 0 #1\"/><v:f eqn=\"prod #1 1 "
456 "2\"/><v:f eqn=\"sum @18 5400 0\"/><v:f eqn=\"cos @19 #0\"/><v:f eqn=\"sin @19 "
457 "#0\"/><v:f eqn=\"sum @20 10800 0\"/><v:f eqn=\"sum @21 10800 0\"/><v:f eqn=\"sum 10800 "
458 "0 @20\"/><v:f eqn=\"sum #1 10800 0\"/><v:f eqn=\"if @9 @17 @25\"/><v:f eqn=\"if @9 0 "
459 "21600\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
460 "o:connectlocs=\"10800,@27;@22,@23;10800,@26;@24,@23\"/><v:textpath on=\"t\" "
461 "fitshape=\"t\"/><v:handles><v:h position=\"#1,#0\" polar=\"10800,10800\" "
462 "radiusrange=\"0,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
463 "shapetype=\"t\"/></v:shapetype>" },
464 { mso_sptTextArchDownPour
,
465 "<v:shapetype id=\"_x0000_t149\" coordsize=\"21600,21600\" o:spt=\"149\" adj=\",5400\" "
466 "path=\"al10800,10800@0@0@3@15al10800,10800,10800,10800@3@15e\"><v:formulas><v:f "
467 "eqn=\"val #1\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"sumangle #0 0 "
468 "180\"/><v:f eqn=\"sumangle #0 0 90\"/><v:f eqn=\"prod @4 2 1\"/><v:f eqn=\"sumangle #0 "
469 "90 0\"/><v:f eqn=\"prod @6 2 1\"/><v:f eqn=\"abs #0\"/><v:f eqn=\"sumangle @8 0 "
470 "90\"/><v:f eqn=\"if @9 @7 @5\"/><v:f eqn=\"sumangle @10 0 360\"/><v:f eqn=\"if @10 @11 "
471 "@10\"/><v:f eqn=\"sumangle @12 0 360\"/><v:f eqn=\"if @12 @13 @12\"/><v:f eqn=\"sum 0 0 "
472 "@14\"/><v:f eqn=\"val 10800\"/><v:f eqn=\"sum 10800 0 #1\"/><v:f eqn=\"prod #1 1 "
473 "2\"/><v:f eqn=\"sum @18 5400 0\"/><v:f eqn=\"cos @19 #0\"/><v:f eqn=\"sin @19 "
474 "#0\"/><v:f eqn=\"sum @20 10800 0\"/><v:f eqn=\"sum @21 10800 0\"/><v:f eqn=\"sum 10800 "
475 "0 @20\"/><v:f eqn=\"sum #1 10800 0\"/><v:f eqn=\"if @9 @17 @25\"/><v:f eqn=\"if @9 0 "
476 "21600\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
477 "o:connectlocs=\"10800,@27;@22,@23;10800,@26;@24,@23\"/><v:textpath on=\"t\" "
478 "fitshape=\"t\"/><v:handles><v:h position=\"#1,#0\" polar=\"10800,10800\" "
479 "radiusrange=\"0,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
480 "shapetype=\"t\"/></v:shapetype>" },
481 { mso_sptTextCirclePour
,
482 "<v:shapetype id=\"_x0000_t150\" coordsize=\"21600,21600\" o:spt=\"150\" "
483 "adj=\"-11730944,5400\" "
484 "path=\"al10800,10800,10800,10800@2@5al10800,10800@0@0@2@5e\"><v:formulas><v:f eqn=\"val "
485 "#1\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"prod #0 2 1\"/><v:f "
486 "eqn=\"sumangle @3 0 360\"/><v:f eqn=\"if @3 @4 @3\"/><v:f eqn=\"val 10800\"/><v:f "
487 "eqn=\"sum 10800 0 #1\"/><v:f eqn=\"prod #1 1 2\"/><v:f eqn=\"sum @8 5400 0\"/><v:f "
488 "eqn=\"cos @9 #0\"/><v:f eqn=\"sin @9 #0\"/><v:f eqn=\"sum @10 10800 0\"/><v:f eqn=\"sum "
489 "@11 10800 0\"/><v:f eqn=\"sum 10800 0 @11\"/><v:f eqn=\"sum #1 10800 0\"/><v:f eqn=\"if "
490 "#0 @7 @15\"/><v:f eqn=\"if #0 0 21600\"/></v:formulas><v:path textpathok=\"t\" "
491 "o:connecttype=\"custom\" "
492 "o:connectlocs=\"@17,10800;@12,@13;@16,10800;@12,@14\"/><v:textpath on=\"t\" "
493 "fitshape=\"t\"/><v:handles><v:h position=\"#1,#0\" polar=\"10800,10800\" "
494 "radiusrange=\"0,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
495 "shapetype=\"t\"/></v:shapetype>" },
496 { mso_sptTextButtonPour
,
497 "<v:shapetype id=\"_x0000_t151\" coordsize=\"21600,21600\" o:spt=\"151\" "
498 "adj=\"11796480,5400\" "
499 "path=\"al10800,10800,10800,10800@2@14al10800,10800@0@0@2@14m@25@17l@26@17m@25@18l@26@"
500 "18al10800,10800@0@0@1@15al10800,10800,10800,10800@1@15e\"><v:formulas><v:f eqn=\"val "
501 "#1\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum 0 0 #0\"/><v:f eqn=\"sumangle #0 0 "
502 "180\"/><v:f eqn=\"sumangle #0 0 90\"/><v:f eqn=\"prod @4 2 1\"/><v:f eqn=\"sumangle #0 "
503 "90 0\"/><v:f eqn=\"prod @6 2 1\"/><v:f eqn=\"abs #0\"/><v:f eqn=\"sumangle @8 0 "
504 "90\"/><v:f eqn=\"if @9 @7 @5\"/><v:f eqn=\"sumangle @10 0 360\"/><v:f eqn=\"if @10 @11 "
505 "@10\"/><v:f eqn=\"sumangle @12 0 360\"/><v:f eqn=\"if @12 @13 @12\"/><v:f eqn=\"sum 0 0 "
506 "@14\"/><v:f eqn=\"sum #1 10800 0\"/><v:f eqn=\"prod @16 1 2\"/><v:f eqn=\"sum 21600 0 "
507 "@17\"/><v:f eqn=\"sum 10800 0 #1\"/><v:f eqn=\"prod @19 1 2\"/><v:f eqn=\"prod @20 @20 "
508 "1\"/><v:f eqn=\"prod #1 #1 1\"/><v:f eqn=\"sum @22 0 @21\"/><v:f eqn=\"sqrt @23\"/><v:f "
509 "eqn=\"sum 10800 0 @24\"/><v:f eqn=\"sum @24 10800 0\"/><v:f eqn=\"val 10800\"/><v:f "
510 "eqn=\"cos @17 #0\"/><v:f eqn=\"sin @17 #0\"/><v:f eqn=\"sum @28 10800 0\"/><v:f "
511 "eqn=\"sum @29 10800 0\"/><v:f eqn=\"sum 10800 0 @28\"/><v:f eqn=\"sum 10800 0 "
512 "@29\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
513 "o:connectlocs=\"10800,0;@30,@31;10800,@19;@32,@31;10800,@17;@25,10800;10800,@18;@26,"
514 "10800;10800,@16;@30,@33;10800,21600;@32,@33\"/><v:textpath on=\"t\" "
515 "fitshape=\"t\"/><v:handles><v:h position=\"#1,#0\" polar=\"10800,10800\" "
516 "radiusrange=\"4320,10800\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
517 "shapetype=\"t\"/></v:shapetype>" },
518 { mso_sptTextCurveUp
,
519 "<v:shapetype id=\"_x0000_t152\" coordsize=\"21600,21600\" o:spt=\"152\" adj=\"9931\" "
520 "path=\"m0@0c7200@2,14400@1,21600,m0@5c7200@6,14400@6,21600@5e\"><v:formulas><v:f "
521 "eqn=\"val #0\"/><v:f eqn=\"prod #0 3 4\"/><v:f eqn=\"prod #0 5 4\"/><v:f eqn=\"prod #0 "
522 "3 8\"/><v:f eqn=\"prod #0 1 8\"/><v:f eqn=\"sum 21600 0 @3\"/><v:f eqn=\"sum @4 21600 "
523 "0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"prod @5 1 2\"/><v:f eqn=\"sum @7 @8 0\"/><v:f "
524 "eqn=\"prod #0 7 8\"/><v:f eqn=\"prod @5 1 3\"/><v:f eqn=\"sum @1 @2 0\"/><v:f eqn=\"sum "
525 "@12 @0 0\"/><v:f eqn=\"prod @13 1 4\"/><v:f eqn=\"sum @11 14400 "
526 "@14\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
527 "o:connectlocs=\"10800,@10;0,@9;10800,21600;21600,@8\" "
528 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
529 "xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" "
530 "yrange=\"0,12169\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
531 "shapetype=\"t\"/></v:shapetype>" },
532 { mso_sptTextCurveDown
,
533 "<v:shapetype id=\"_x0000_t153\" coordsize=\"21600,21600\" o:spt=\"153\" adj=\"9391\" "
534 "path=\"m,c7200@1,14400@2,21600@0m0@5c7200@6,14400@6,21600@5e\"><v:formulas><v:f "
535 "eqn=\"val #0\"/><v:f eqn=\"prod #0 3 4\"/><v:f eqn=\"prod #0 5 4\"/><v:f eqn=\"prod #0 "
536 "3 8\"/><v:f eqn=\"prod #0 1 8\"/><v:f eqn=\"sum 21600 0 @3\"/><v:f eqn=\"sum @4 21600 "
537 "0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"prod @5 1 2\"/><v:f eqn=\"sum @7 @8 0\"/><v:f "
538 "eqn=\"prod #0 7 8\"/><v:f eqn=\"prod @5 1 3\"/><v:f eqn=\"sum @1 @2 0\"/><v:f eqn=\"sum "
539 "@12 @0 0\"/><v:f eqn=\"prod @13 1 4\"/><v:f eqn=\"sum @11 14400 "
540 "@14\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
541 "o:connectlocs=\"10800,@10;0,@8;10800,21600;21600,@9\" "
542 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
543 "xscale=\"t\"/><v:handles><v:h position=\"bottomRight,#0\" "
544 "yrange=\"0,11368\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
545 "shapetype=\"t\"/></v:shapetype>" },
546 { mso_sptTextCascadeUp
,
547 "<v:shapetype id=\"_x0000_t154\" coordsize=\"21600,21600\" o:spt=\"154\" adj=\"9600\" "
548 "path=\"m0@2l21600,m,21600l21600@0e\"><v:formulas><v:f eqn=\"val #0\"/><v:f eqn=\"sum "
549 "21600 0 #0\"/><v:f eqn=\"prod @1 1 4\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"prod @2 1 "
550 "2\"/><v:f eqn=\"sum @3 10800 0\"/><v:f eqn=\"sum @4 10800 0\"/><v:f eqn=\"sum @0 21600 "
551 "@2\"/><v:f eqn=\"prod @7 1 2\"/></v:formulas><v:path textpathok=\"t\" "
552 "o:connecttype=\"custom\" o:connectlocs=\"10800,@4;0,@6;10800,@5;21600,@3\" "
553 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
554 "position=\"bottomRight,#0\" yrange=\"6171,21600\"/></v:handles><o:lock v:ext=\"edit\" "
555 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
556 { mso_sptTextCascadeDown
,
557 "<v:shapetype id=\"_x0000_t155\" coordsize=\"21600,21600\" o:spt=\"155\" adj=\"9600\" "
558 "path=\"m,l21600@2m0@0l21600,21600e\"><v:formulas><v:f eqn=\"val #0\"/><v:f eqn=\"sum "
559 "21600 0 #0\"/><v:f eqn=\"prod @1 1 4\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"prod @2 1 "
560 "2\"/><v:f eqn=\"sum @3 10800 0\"/><v:f eqn=\"sum @4 10800 0\"/><v:f eqn=\"sum @0 21600 "
561 "@2\"/><v:f eqn=\"prod @7 1 2\"/></v:formulas><v:path textpathok=\"t\" "
562 "o:connecttype=\"custom\" o:connectlocs=\"10800,@4;0,@3;10800,@5;21600,@6\" "
563 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
564 "position=\"topLeft,#0\" yrange=\"6171,21600\"/></v:handles><o:lock v:ext=\"edit\" "
565 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
567 "<v:shapetype id=\"_x0000_t156\" coordsize=\"21600,21600\" o:spt=\"156\" "
568 "adj=\"2809,10800\" "
569 "path=\"m@25@0c@26@3@27@1@28@0m@21@4c@22@5@23@6@24@4e\"><v:formulas><v:f eqn=\"val "
570 "#0\"/><v:f eqn=\"prod @0 41 9\"/><v:f eqn=\"prod @0 23 9\"/><v:f eqn=\"sum 0 0 "
571 "@2\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"sum 21600 0 @1\"/><v:f eqn=\"sum 21600 0 "
572 "@3\"/><v:f eqn=\"sum #1 0 10800\"/><v:f eqn=\"sum 21600 0 #1\"/><v:f eqn=\"prod @8 2 "
573 "3\"/><v:f eqn=\"prod @8 4 3\"/><v:f eqn=\"prod @8 2 1\"/><v:f eqn=\"sum 21600 0 "
574 "@9\"/><v:f eqn=\"sum 21600 0 @10\"/><v:f eqn=\"sum 21600 0 @11\"/><v:f eqn=\"prod #1 2 "
575 "3\"/><v:f eqn=\"prod #1 4 3\"/><v:f eqn=\"prod #1 2 1\"/><v:f eqn=\"sum 21600 0 "
576 "@15\"/><v:f eqn=\"sum 21600 0 @16\"/><v:f eqn=\"sum 21600 0 @17\"/><v:f eqn=\"if @7 @14 "
577 "0\"/><v:f eqn=\"if @7 @13 @15\"/><v:f eqn=\"if @7 @12 @16\"/><v:f eqn=\"if @7 21600 "
578 "@17\"/><v:f eqn=\"if @7 0 @20\"/><v:f eqn=\"if @7 @9 @19\"/><v:f eqn=\"if @7 @10 "
579 "@18\"/><v:f eqn=\"if @7 @11 21600\"/><v:f eqn=\"sum @24 0 @21\"/><v:f eqn=\"sum @4 0 "
580 "@0\"/><v:f eqn=\"max @21 @25\"/><v:f eqn=\"min @24 @28\"/><v:f eqn=\"prod @0 2 "
581 "1\"/><v:f eqn=\"sum 21600 0 @33\"/><v:f eqn=\"mid @26 @27\"/><v:f eqn=\"mid @24 "
582 "@28\"/><v:f eqn=\"mid @22 @23\"/><v:f eqn=\"mid @21 @25\"/></v:formulas><v:path "
583 "textpathok=\"t\" o:connecttype=\"custom\" "
584 "o:connectlocs=\"@35,@0;@38,10800;@37,@4;@36,10800\" "
585 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
586 "xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" yrange=\"0,4459\"/><v:h "
587 "position=\"#1,bottomRight\" xrange=\"8640,12960\"/></v:handles><o:lock v:ext=\"edit\" "
588 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
590 "<v:shapetype id=\"_x0000_t157\" coordsize=\"21600,21600\" o:spt=\"157\" "
591 "adj=\"2809,10800\" "
592 "path=\"m@25@0c@26@1@27@3@28@0m@21@4c@22@6@23@5@24@4e\"><v:formulas><v:f eqn=\"val "
593 "#0\"/><v:f eqn=\"prod @0 41 9\"/><v:f eqn=\"prod @0 23 9\"/><v:f eqn=\"sum 0 0 "
594 "@2\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"sum 21600 0 @1\"/><v:f eqn=\"sum 21600 0 "
595 "@3\"/><v:f eqn=\"sum #1 0 10800\"/><v:f eqn=\"sum 21600 0 #1\"/><v:f eqn=\"prod @8 2 "
596 "3\"/><v:f eqn=\"prod @8 4 3\"/><v:f eqn=\"prod @8 2 1\"/><v:f eqn=\"sum 21600 0 "
597 "@9\"/><v:f eqn=\"sum 21600 0 @10\"/><v:f eqn=\"sum 21600 0 @11\"/><v:f eqn=\"prod #1 2 "
598 "3\"/><v:f eqn=\"prod #1 4 3\"/><v:f eqn=\"prod #1 2 1\"/><v:f eqn=\"sum 21600 0 "
599 "@15\"/><v:f eqn=\"sum 21600 0 @16\"/><v:f eqn=\"sum 21600 0 @17\"/><v:f eqn=\"if @7 @14 "
600 "0\"/><v:f eqn=\"if @7 @13 @15\"/><v:f eqn=\"if @7 @12 @16\"/><v:f eqn=\"if @7 21600 "
601 "@17\"/><v:f eqn=\"if @7 0 @20\"/><v:f eqn=\"if @7 @9 @19\"/><v:f eqn=\"if @7 @10 "
602 "@18\"/><v:f eqn=\"if @7 @11 21600\"/><v:f eqn=\"sum @24 0 @21\"/><v:f eqn=\"sum @4 0 "
603 "@0\"/><v:f eqn=\"max @21 @25\"/><v:f eqn=\"min @24 @28\"/><v:f eqn=\"prod @0 2 "
604 "1\"/><v:f eqn=\"sum 21600 0 @33\"/><v:f eqn=\"mid @26 @27\"/><v:f eqn=\"mid @24 "
605 "@28\"/><v:f eqn=\"mid @22 @23\"/><v:f eqn=\"mid @21 @25\"/></v:formulas><v:path "
606 "textpathok=\"t\" o:connecttype=\"custom\" "
607 "o:connectlocs=\"@35,@0;@38,10800;@37,@4;@36,10800\" "
608 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
609 "xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" yrange=\"0,4459\"/><v:h "
610 "position=\"#1,bottomRight\" xrange=\"8640,12960\"/></v:handles><o:lock v:ext=\"edit\" "
611 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
613 "<v:shapetype id=\"_x0000_t158\" coordsize=\"21600,21600\" o:spt=\"158\" "
614 "adj=\"1404,10800\" "
615 "path=\"m@37@0c@38@3@39@1@40@0@41@3@42@1@43@0m@30@4c@31@5@32@6@33@4@34@5@35@6@36@4e\"><v:"
616 "formulas><v:f eqn=\"val #0\"/><v:f eqn=\"prod @0 41 9\"/><v:f eqn=\"prod @0 23 "
617 "9\"/><v:f eqn=\"sum 0 0 @2\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"sum 21600 0 "
618 "@1\"/><v:f eqn=\"sum 21600 0 @3\"/><v:f eqn=\"sum #1 0 10800\"/><v:f eqn=\"sum 21600 0 "
619 "#1\"/><v:f eqn=\"prod @8 1 3\"/><v:f eqn=\"prod @8 2 3\"/><v:f eqn=\"prod @8 4 "
620 "3\"/><v:f eqn=\"prod @8 5 3\"/><v:f eqn=\"prod @8 2 1\"/><v:f eqn=\"sum 21600 0 "
621 "@9\"/><v:f eqn=\"sum 21600 0 @10\"/><v:f eqn=\"sum 21600 0 @8\"/><v:f eqn=\"sum 21600 0 "
622 "@11\"/><v:f eqn=\"sum 21600 0 @12\"/><v:f eqn=\"sum 21600 0 @13\"/><v:f eqn=\"prod #1 1 "
623 "3\"/><v:f eqn=\"prod #1 2 3\"/><v:f eqn=\"prod #1 4 3\"/><v:f eqn=\"prod #1 5 3\"/><v:f "
624 "eqn=\"prod #1 2 1\"/><v:f eqn=\"sum 21600 0 @20\"/><v:f eqn=\"sum 21600 0 @21\"/><v:f "
625 "eqn=\"sum 21600 0 @22\"/><v:f eqn=\"sum 21600 0 @23\"/><v:f eqn=\"sum 21600 0 "
626 "@24\"/><v:f eqn=\"if @7 @19 0\"/><v:f eqn=\"if @7 @18 @20\"/><v:f eqn=\"if @7 @17 "
627 "@21\"/><v:f eqn=\"if @7 @16 #1\"/><v:f eqn=\"if @7 @15 @22\"/><v:f eqn=\"if @7 @14 "
628 "@23\"/><v:f eqn=\"if @7 21600 @24\"/><v:f eqn=\"if @7 0 @29\"/><v:f eqn=\"if @7 @9 "
629 "@28\"/><v:f eqn=\"if @7 @10 @27\"/><v:f eqn=\"if @7 @8 @8\"/><v:f eqn=\"if @7 @11 "
630 "@26\"/><v:f eqn=\"if @7 @12 @25\"/><v:f eqn=\"if @7 @13 21600\"/><v:f eqn=\"sum @36 0 "
631 "@30\"/><v:f eqn=\"sum @4 0 @0\"/><v:f eqn=\"max @30 @37\"/><v:f eqn=\"min @36 "
632 "@43\"/><v:f eqn=\"prod @0 2 1\"/><v:f eqn=\"sum 21600 0 @48\"/><v:f eqn=\"mid @36 "
633 "@43\"/><v:f eqn=\"mid @30 @37\"/></v:formulas><v:path textpathok=\"t\" "
634 "o:connecttype=\"custom\" o:connectlocs=\"@40,@0;@51,10800;@33,@4;@50,10800\" "
635 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
636 "xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" yrange=\"0,2229\"/><v:h "
637 "position=\"#1,bottomRight\" xrange=\"8640,12960\"/></v:handles><o:lock v:ext=\"edit\" "
638 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
640 "<v:shapetype id=\"_x0000_t159\" coordsize=\"21600,21600\" o:spt=\"159\" "
641 "adj=\"1404,10800\" "
642 "path=\"m@37@0c@38@1@39@3@40@0@41@1@42@3@43@0m@30@4c@31@6@32@5@33@4@34@6@35@5@36@4e\"><v:"
643 "formulas><v:f eqn=\"val #0\"/><v:f eqn=\"prod @0 41 9\"/><v:f eqn=\"prod @0 23 "
644 "9\"/><v:f eqn=\"sum 0 0 @2\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"sum 21600 0 "
645 "@1\"/><v:f eqn=\"sum 21600 0 @3\"/><v:f eqn=\"sum #1 0 10800\"/><v:f eqn=\"sum 21600 0 "
646 "#1\"/><v:f eqn=\"prod @8 1 3\"/><v:f eqn=\"prod @8 2 3\"/><v:f eqn=\"prod @8 4 "
647 "3\"/><v:f eqn=\"prod @8 5 3\"/><v:f eqn=\"prod @8 2 1\"/><v:f eqn=\"sum 21600 0 "
648 "@9\"/><v:f eqn=\"sum 21600 0 @10\"/><v:f eqn=\"sum 21600 0 @8\"/><v:f eqn=\"sum 21600 0 "
649 "@11\"/><v:f eqn=\"sum 21600 0 @12\"/><v:f eqn=\"sum 21600 0 @13\"/><v:f eqn=\"prod #1 1 "
650 "3\"/><v:f eqn=\"prod #1 2 3\"/><v:f eqn=\"prod #1 4 3\"/><v:f eqn=\"prod #1 5 3\"/><v:f "
651 "eqn=\"prod #1 2 1\"/><v:f eqn=\"sum 21600 0 @20\"/><v:f eqn=\"sum 21600 0 @21\"/><v:f "
652 "eqn=\"sum 21600 0 @22\"/><v:f eqn=\"sum 21600 0 @23\"/><v:f eqn=\"sum 21600 0 "
653 "@24\"/><v:f eqn=\"if @7 @19 0\"/><v:f eqn=\"if @7 @18 @20\"/><v:f eqn=\"if @7 @17 "
654 "@21\"/><v:f eqn=\"if @7 @16 #1\"/><v:f eqn=\"if @7 @15 @22\"/><v:f eqn=\"if @7 @14 "
655 "@23\"/><v:f eqn=\"if @7 21600 @24\"/><v:f eqn=\"if @7 0 @29\"/><v:f eqn=\"if @7 @9 "
656 "@28\"/><v:f eqn=\"if @7 @10 @27\"/><v:f eqn=\"if @7 @8 @8\"/><v:f eqn=\"if @7 @11 "
657 "@26\"/><v:f eqn=\"if @7 @12 @25\"/><v:f eqn=\"if @7 @13 21600\"/><v:f eqn=\"sum @36 0 "
658 "@30\"/><v:f eqn=\"sum @4 0 @0\"/><v:f eqn=\"max @30 @37\"/><v:f eqn=\"min @36 "
659 "@43\"/><v:f eqn=\"prod @0 2 1\"/><v:f eqn=\"sum 21600 0 @48\"/><v:f eqn=\"mid @36 "
660 "@43\"/><v:f eqn=\"mid @30 @37\"/></v:formulas><v:path textpathok=\"t\" "
661 "o:connecttype=\"custom\" o:connectlocs=\"@40,@0;@51,10800;@33,@4;@50,10800\" "
662 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
663 "xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" yrange=\"0,2229\"/><v:h "
664 "position=\"#1,bottomRight\" xrange=\"8640,12960\"/></v:handles><o:lock v:ext=\"edit\" "
665 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
666 { mso_sptTextInflate
,
667 "<v:shapetype id=\"_x0000_t160\" coordsize=\"21600,21600\" o:spt=\"160\" adj=\"2945\" "
668 "path=\"m0@0c7200@2,14400@2,21600@0m0@3c7200@4,14400@4,21600@3e\"><v:formulas><v:f "
669 "eqn=\"val #0\"/><v:f eqn=\"prod #0 1 3\"/><v:f eqn=\"sum 0 0 @1\"/><v:f eqn=\"sum 21600 "
670 "0 #0\"/><v:f eqn=\"sum 21600 0 @2\"/><v:f eqn=\"prod #0 2 3\"/><v:f eqn=\"sum 21600 0 "
671 "@5\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"rect\"/><v:textpath "
672 "on=\"t\" fitshape=\"t\" xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" "
673 "yrange=\"0,4629\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
674 "shapetype=\"t\"/></v:shapetype>" },
675 { mso_sptTextDeflate
,
676 "<v:shapetype id=\"_x0000_t161\" coordsize=\"21600,21600\" o:spt=\"161\" adj=\"4050\" "
677 "path=\"m,c7200@0,14400@0,21600,m,21600c7200@1,14400@1,21600,21600e\"><v:formulas><v:f "
678 "eqn=\"prod #0 4 3\"/><v:f eqn=\"sum 21600 0 @0\"/><v:f eqn=\"val #0\"/><v:f eqn=\"sum "
679 "21600 0 #0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
680 "o:connectlocs=\"10800,@2;0,10800;10800,@3;21600,10800\" "
681 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
682 "xscale=\"t\"/><v:handles><v:h position=\"center,#0\" "
683 "yrange=\"0,8100\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
684 "shapetype=\"t\"/></v:shapetype>" },
685 { mso_sptTextInflateBottom
,
686 "<v:shapetype id=\"_x0000_t162\" coordsize=\"21600,21600\" o:spt=\"162\" adj=\"14706\" "
687 "path=\"m,l21600,m0@0c7200@2,14400@2,21600@0e\"><v:formulas><v:f eqn=\"val #0\"/><v:f "
688 "eqn=\"prod #0 1 3\"/><v:f eqn=\"sum 28800 0 @1\"/><v:f eqn=\"prod #0 1 2\"/><v:f "
689 "eqn=\"sum @1 7200 0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
690 "o:connectlocs=\"10800,0;0,@3;10800,21600;21600,@3\" "
691 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
692 "xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" "
693 "yrange=\"11148,21600\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
694 "shapetype=\"t\"/></v:shapetype>" },
695 { mso_sptTextDeflateBottom
,
696 "<v:shapetype id=\"_x0000_t163\" coordsize=\"21600,21600\" o:spt=\"163\" adj=\"11475\" "
697 "path=\"m,l21600,m,21600c7200@1,14400@1,21600,21600e\"><v:formulas><v:f eqn=\"prod #0 4 "
698 "3\"/><v:f eqn=\"sum @0 0 7200\"/><v:f eqn=\"val #0\"/><v:f eqn=\"prod #0 2 3\"/><v:f "
699 "eqn=\"sum @3 7200 0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
700 "o:connectlocs=\"10800,0;0,10800;10800,@2;21600,10800\" "
701 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
702 "xscale=\"t\"/><v:handles><v:h position=\"center,#0\" "
703 "yrange=\"1350,21600\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
704 "shapetype=\"t\"/></v:shapetype>" },
705 { mso_sptTextInflateTop
,
706 "<v:shapetype id=\"_x0000_t164\" coordsize=\"21600,21600\" o:spt=\"164\" adj=\"6894\" "
707 "path=\"m0@0c7200@2,14400@2,21600@0m,21600r21600,e\"><v:formulas><v:f eqn=\"val "
708 "#0\"/><v:f eqn=\"prod #0 1 3\"/><v:f eqn=\"sum 0 0 @1\"/><v:f eqn=\"prod #0 1 2\"/><v:f "
709 "eqn=\"sum @3 10800 0\"/><v:f eqn=\"sum 21600 0 @1\"/></v:formulas><v:path "
710 "textpathok=\"t\" o:connecttype=\"custom\" "
711 "o:connectlocs=\"10800,0;0,@4;10800,21600;21600,@4\" "
712 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
713 "xscale=\"t\"/><v:handles><v:h position=\"topLeft,#0\" "
714 "yrange=\"0,10452\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
715 "shapetype=\"t\"/></v:shapetype>" },
716 { mso_sptTextDeflateTop
,
717 "<v:shapetype id=\"_x0000_t165\" coordsize=\"21600,21600\" o:spt=\"165\" adj=\"10125\" "
718 "path=\"m,c7200@0,14400@0,21600,m,21600r21600,e\"><v:formulas><v:f eqn=\"prod #0 4 "
719 "3\"/><v:f eqn=\"val #0\"/><v:f eqn=\"prod #0 2 3\"/><v:f eqn=\"sum 21600 0 "
720 "@2\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
721 "o:connectlocs=\"10800,@1;0,10800;10800,21600;21600,10800\" "
722 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\" "
723 "xscale=\"t\"/><v:handles><v:h position=\"center,#0\" "
724 "yrange=\"0,20250\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
725 "shapetype=\"t\"/></v:shapetype>" },
726 { mso_sptTextDeflateInflate
,
727 "<v:shapetype id=\"_x0000_t166\" coordsize=\"21600,21600\" o:spt=\"166\" adj=\"6054\" "
728 "path=\"m,l21600,m,10125c7200@1,14400@1,21600,10125m,11475c7200@2,14400@2,21600,11475m,"
729 "21600r21600,e\"><v:formulas><v:f eqn=\"prod #0 4 3\"/><v:f eqn=\"sum @0 0 4275\"/><v:f "
730 "eqn=\"sum @0 0 2925\"/></v:formulas><v:path textpathok=\"t\" "
731 "o:connecttype=\"rect\"/><v:textpath on=\"t\" fitshape=\"t\" "
732 "xscale=\"t\"/><v:handles><v:h position=\"center,#0\" "
733 "yrange=\"1308,20292\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
734 "shapetype=\"t\"/></v:shapetype>" },
735 { mso_sptTextDeflateInflateDeflate
,
736 "<v:shapetype id=\"_x0000_t167\" coordsize=\"21600,21600\" o:spt=\"167\" adj=\"6054\" "
737 "path=\"m,l21600,m,6609c7200@1,14400@1,21600,6609m,7491c7200@2,14400@2,21600,7491m,"
738 "14109c7200@4,14400@4,21600,14109m,14991c7200@3,14400@3,21600,14991m,21600r21600,e\"><v:"
739 "formulas><v:f eqn=\"prod #0 4 3\"/><v:f eqn=\"sum @0 0 2791\"/><v:f eqn=\"sum @0 0 "
740 "1909\"/><v:f eqn=\"sum 21600 0 @1\"/><v:f eqn=\"sum 21600 0 @2\"/></v:formulas><v:path "
741 "textpathok=\"t\" o:connecttype=\"rect\"/><v:textpath on=\"t\" fitshape=\"t\" "
742 "xscale=\"t\"/><v:handles><v:h position=\"center,#0\" "
743 "yrange=\"854,9525\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
744 "shapetype=\"t\"/></v:shapetype>" },
745 { mso_sptTextFadeRight
,
746 "<v:shapetype id=\"_x0000_t168\" coordsize=\"21600,21600\" o:spt=\"168\" adj=\"7200\" "
747 "path=\"m,l21600@0m,21600l21600@1e\"><v:formulas><v:f eqn=\"val #0\"/><v:f eqn=\"sum "
748 "21600 0 @0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum 21600 0 @2\"/><v:f eqn=\"sum @1 "
749 "21600 @0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
750 "o:connectlocs=\"10800,@2;0,10800;10800,@3;21600,10800\" "
751 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
752 "position=\"bottomRight,#0\" yrange=\"0,10800\"/></v:handles><o:lock v:ext=\"edit\" "
753 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
754 { mso_sptTextFadeLeft
,
755 "<v:shapetype id=\"_x0000_t169\" coordsize=\"21600,21600\" o:spt=\"169\" adj=\"7200\" "
756 "path=\"m0@0l21600,m0@1l21600,21600e\"><v:formulas><v:f eqn=\"val #0\"/><v:f eqn=\"sum "
757 "21600 0 @0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum 21600 0 @2\"/><v:f eqn=\"sum @1 "
758 "21600 @0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
759 "o:connectlocs=\"10800,@2;0,10800;10800,@3;21600,10800\" "
760 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
761 "position=\"topLeft,#0\" yrange=\"0,10800\"/></v:handles><o:lock v:ext=\"edit\" "
762 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
764 "<v:shapetype id=\"_x0000_t170\" coordsize=\"21600,21600\" o:spt=\"170\" adj=\"7200\" "
765 "path=\"m@0,l@1,m,21600r21600,e\"><v:formulas><v:f eqn=\"val #0\"/><v:f eqn=\"sum 21600 "
766 "0 @0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum 21600 0 @2\"/><v:f eqn=\"sum @1 21600 "
767 "@0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
768 "o:connectlocs=\"10800,0;@2,10800;10800,21600;@3,10800\" "
769 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
770 "position=\"#0,topLeft\" xrange=\"0,10792\"/></v:handles><o:lock v:ext=\"edit\" "
771 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
772 { mso_sptTextFadeDown
,
773 "<v:shapetype id=\"_x0000_t171\" coordsize=\"21600,21600\" o:spt=\"171\" adj=\"7200\" "
774 "path=\"m,l21600,m@0,21600l@1,21600e\"><v:formulas><v:f eqn=\"val #0\"/><v:f eqn=\"sum "
775 "21600 0 @0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum 21600 0 @2\"/><v:f eqn=\"sum @1 "
776 "21600 @0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
777 "o:connectlocs=\"10800,0;@2,10800;10800,21600;@3,10800\" "
778 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
779 "position=\"#0,bottomRight\" xrange=\"0,10792\"/></v:handles><o:lock v:ext=\"edit\" "
780 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
781 { mso_sptTextSlantUp
,
782 "<v:shapetype id=\"_x0000_t172\" coordsize=\"21600,21600\" o:spt=\"172\" adj=\"12000\" "
783 "path=\"m0@0l21600,m,21600l21600@1e\"><v:formulas><v:f eqn=\"val #0\"/><v:f eqn=\"sum "
784 "21600 0 @0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum @2 10800 0\"/><v:f eqn=\"prod @1 "
785 "1 2\"/><v:f eqn=\"sum @4 10800 0\"/></v:formulas><v:path textpathok=\"t\" "
786 "o:connecttype=\"custom\" o:connectlocs=\"10800,@2;0,@3;10800,@5;21600,@4\" "
787 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
788 "position=\"topLeft,#0\" yrange=\"0,15429\"/></v:handles><o:lock v:ext=\"edit\" "
789 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
790 { mso_sptTextSlantDown
,
791 "<v:shapetype id=\"_x0000_t173\" coordsize=\"21600,21600\" o:spt=\"173\" adj=\"9600\" "
792 "path=\"m,l21600@1m0@0l21600,21600e\"><v:formulas><v:f eqn=\"val #0\"/><v:f eqn=\"sum "
793 "21600 0 @0\"/><v:f eqn=\"prod #0 1 2\"/><v:f eqn=\"sum @2 10800 0\"/><v:f eqn=\"prod @1 "
794 "1 2\"/><v:f eqn=\"sum @4 10800 0\"/></v:formulas><v:path textpathok=\"t\" "
795 "o:connecttype=\"custom\" o:connectlocs=\"10800,@4;0,@2;10800,@3;21600,@5\" "
796 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
797 "position=\"topLeft,#0\" yrange=\"6171,21600\"/></v:handles><o:lock v:ext=\"edit\" "
798 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
800 "<v:shapetype id=\"_x0000_t174\" coordsize=\"21600,21600\" o:spt=\"174\" adj=\"18514\" "
801 "path=\"m0@1qy10800,,21600@1m,21600qy10800@0,21600,21600e\"><v:formulas><v:f eqn=\"val "
802 "#0\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"prod @1 1 2\"/><v:f eqn=\"sum @2 10800 "
803 "0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
804 "o:connectlocs=\"10800,0;0,@3;10800,@0;21600,@3\" "
805 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
806 "position=\"center,#0\" yrange=\"14400,21600\"/></v:handles><o:lock v:ext=\"edit\" "
807 "text=\"t\" shapetype=\"t\"/></v:shapetype>" },
808 { mso_sptTextCanDown
,
809 "<v:shapetype id=\"_x0000_t175\" coordsize=\"21600,21600\" o:spt=\"175\" adj=\"3086\" "
810 "path=\"m,qy10800@0,21600,m0@1qy10800,21600,21600@1e\"><v:formulas><v:f eqn=\"val "
811 "#0\"/><v:f eqn=\"sum 21600 0 #0\"/><v:f eqn=\"prod @1 1 2\"/><v:f eqn=\"sum @2 10800 "
812 "0\"/></v:formulas><v:path textpathok=\"t\" o:connecttype=\"custom\" "
813 "o:connectlocs=\"10800,@0;0,@2;10800,21600;21600,@2\" "
814 "o:connectangles=\"270,180,90,0\"/><v:textpath on=\"t\" fitshape=\"t\"/><v:handles><v:h "
815 "position=\"center,#0\" yrange=\"0,7200\"/></v:handles><o:lock v:ext=\"edit\" text=\"t\" "
816 "shapetype=\"t\"/></v:shapetype>" }
819 auto i(aTypeToMarkupMap
.find(eShapeType
));
820 return i
== aTypeToMarkupMap
.end() ? OString() : i
->second
;
823 void FontworkHelpers::collectCharColorProps(const uno::Reference
<text::XText
>& rXText
,
824 std::vector
<beans::PropertyValue
>& rCharPropVec
)
828 uno::Reference
<text::XTextCursor
> rXTextCursor
= rXText
->createTextCursor();
829 rXTextCursor
->gotoStart(false);
830 rXTextCursor
->gotoEnd(true);
831 uno::Reference
<container::XEnumerationAccess
> paraEnumAccess(rXText
, uno::UNO_QUERY
);
832 if (!paraEnumAccess
.is())
834 uno::Reference
<container::XEnumeration
> paraEnum(paraEnumAccess
->createEnumeration());
835 while (paraEnum
->hasMoreElements())
837 uno::Reference
<text::XTextRange
> xParagraph(paraEnum
->nextElement(), uno::UNO_QUERY
);
838 uno::Reference
<container::XEnumerationAccess
> runEnumAccess(xParagraph
, uno::UNO_QUERY
);
839 if (!runEnumAccess
.is())
841 uno::Reference
<container::XEnumeration
> runEnum
= runEnumAccess
->createEnumeration();
842 while (runEnum
->hasMoreElements())
844 uno::Reference
<text::XTextRange
> xRun(runEnum
->nextElement(), uno::UNO_QUERY
);
845 if (xRun
->getString().isEmpty())
847 uno::Reference
<beans::XPropertySet
> xRunPropSet(xRun
, uno::UNO_QUERY
);
848 if (!xRunPropSet
.is())
850 auto xRunPropSetInfo
= xRunPropSet
->getPropertySetInfo();
851 if (!xRunPropSetInfo
.is())
854 // We have found a non-empty run. Collect its simple color properties.
855 const std::array
<OUString
, 6> aNamesArray
856 = { u
"CharColor", u
"CharLumMod", u
"CharLumOff",
857 u
"CharColorTheme", u
"CharComplexColor", u
"CharTransparence" };
858 for (const auto& propName
: aNamesArray
)
860 if (xRunPropSetInfo
->hasPropertyByName(propName
))
861 rCharPropVec
.push_back(comphelper::makePropertyValue(
862 propName
, xRunPropSet
->getPropertyValue(propName
)));
869 void FontworkHelpers::applyPropsToRuns(const std::vector
<beans::PropertyValue
>& rTextPropVec
,
870 uno::Reference
<text::XText
>& rXText
)
874 uno::Reference
<text::XTextCursor
> xTextCursor
= rXText
->createTextCursor();
875 xTextCursor
->gotoStart(false);
876 xTextCursor
->gotoEnd(true);
877 uno::Reference
<container::XEnumerationAccess
> paraEnumAccess(rXText
, uno::UNO_QUERY
);
878 if (!paraEnumAccess
.is())
880 uno::Reference
<container::XEnumeration
> paraEnum(paraEnumAccess
->createEnumeration());
881 while (paraEnum
->hasMoreElements())
883 uno::Reference
<text::XTextRange
> xParagraph(paraEnum
->nextElement(), uno::UNO_QUERY
);
884 uno::Reference
<container::XEnumerationAccess
> runEnumAccess(xParagraph
, uno::UNO_QUERY
);
885 if (!runEnumAccess
.is())
887 uno::Reference
<container::XEnumeration
> runEnum
= runEnumAccess
->createEnumeration();
888 while (runEnum
->hasMoreElements())
890 uno::Reference
<text::XTextRange
> xRun(runEnum
->nextElement(), uno::UNO_QUERY
);
891 uno::Reference
<beans::XPropertySet
> xRunPropSet(xRun
, uno::UNO_QUERY
);
892 if (!xRunPropSet
.is())
894 auto xRunPropSetInfo
= xRunPropSet
->getPropertySetInfo();
895 if (!xRunPropSetInfo
.is())
898 for (const beans::PropertyValue
& rProp
: rTextPropVec
)
900 if (xRunPropSetInfo
->hasPropertyByName(rProp
.Name
)
901 && !(xRunPropSetInfo
->getPropertyByName(rProp
.Name
).Attributes
902 & beans::PropertyAttribute::READONLY
)
903 && rProp
.Name
!= u
"CharInteropGrabBag")
905 xRunPropSet
->setPropertyValue(rProp
.Name
, rProp
.Value
);
913 constexpr const std::array
<std::u16string_view
, 5> aCharPropNames
{
914 u
"CharColorLumMod", u
"CharColorLumOff", u
"CharColorTheme", u
"CharComplexColor",
918 constexpr const std::array
<std::u16string_view
, 5> aShapePropNames
{
919 u
"FillColorLumMod", u
"FillColorLumOff", u
"FillColorTheme", u
"FillComplexColor",
924 void FontworkHelpers::createCharFillPropsFromShape(
925 const uno::Reference
<beans::XPropertySet
>& rXPropSet
,
926 std::vector
<beans::PropertyValue
>& rCharPropVec
)
928 auto xPropSetInfo
= rXPropSet
->getPropertySetInfo();
929 if (!xPropSetInfo
.is())
931 // CharColor contains the color including all color transformations
932 // FillColor contains darken and lighten but not transparency
933 sal_Int32 nColorRGB
= 0;
934 if (xPropSetInfo
->hasPropertyByName(u
"FillColor")
935 && (rXPropSet
->getPropertyValue(u
"FillColor") >>= nColorRGB
))
937 ::Color
aColor(ColorTransparency
, nColorRGB
);
938 sal_Int16 nTransPercent
= 0;
939 if (xPropSetInfo
->hasPropertyByName(u
"FillTransparence")
940 && (rXPropSet
->getPropertyValue(u
"FillTransparence") >>= nTransPercent
))
942 sal_uInt8 nAlpha
= 255 - sal_uInt8(std::lround(double(nTransPercent
) * 2.55));
943 aColor
.SetAlpha(nAlpha
);
945 rCharPropVec
.push_back(comphelper::makePropertyValue(u
"CharColor", sal_Int32(aColor
)));
948 for (size_t i
= 0; i
< 5; i
++)
950 OUString
aPropertyName(aShapePropNames
[i
]);
951 if (xPropSetInfo
->hasPropertyByName(aPropertyName
))
952 rCharPropVec
.push_back(comphelper::makePropertyValue(
953 OUString(aCharPropNames
[i
]), rXPropSet
->getPropertyValue(aPropertyName
)));
957 bool FontworkHelpers::createPrstDashFromLineDash(const drawing::LineDash
& rLineDash
,
958 const drawing::LineCap
& rLineCap
,
959 OUString
& rsPrstDash
)
961 bool bIsConverted
= false;
963 bool bIsRelative(rLineDash
.Style
== drawing::DashStyle_RECTRELATIVE
964 || rLineDash
.Style
== drawing::DashStyle_ROUNDRELATIVE
);
965 if (bIsRelative
&& rLineDash
.Dots
== 1)
966 { // The length were tweaked on import in case of prstDash. Revert it here.
967 sal_uInt32 nDotLen
= rLineDash
.DotLen
;
968 sal_uInt32 nDashLen
= rLineDash
.DashLen
;
969 sal_uInt32 nDistance
= rLineDash
.Distance
;
970 if (rLineCap
!= drawing::LineCap_BUTT
&& nDistance
>= 99)
978 // LO uses length 0 for 100%, if the attribute is missing in ODF.
979 // Other applications might write 100%. Make is unique for the conditions.
982 if (nDashLen
== 0 && rLineDash
.Dashes
> 0)
986 if (nDotLen
== 100 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 300)
988 else if (nDotLen
== 400 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 300)
989 rsPrstDash
= u
"dash";
990 else if (nDotLen
== 400 && rLineDash
.Dashes
== 1 && nDashLen
== 100 && nDistance
== 300)
991 rsPrstDash
= u
"dashDot";
992 else if (nDotLen
== 800 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 300)
993 rsPrstDash
= u
"lgDash";
994 else if (nDotLen
== 800 && rLineDash
.Dashes
== 1 && nDashLen
== 100 && nDistance
== 300)
995 rsPrstDash
= u
"lgDashDot";
996 else if (nDotLen
== 800 && rLineDash
.Dashes
== 2 && nDashLen
== 100 && nDistance
== 300)
997 rsPrstDash
= u
"lgDashDotDot";
998 else if (nDotLen
== 100 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 100)
999 rsPrstDash
= u
"sysDot";
1000 else if (nDotLen
== 300 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 100)
1001 rsPrstDash
= u
"sysDash";
1002 else if (nDotLen
== 300 && rLineDash
.Dashes
== 1 && nDashLen
== 100 && nDistance
== 100)
1003 rsPrstDash
= u
"sysDashDot";
1004 else if (nDotLen
== 300 && rLineDash
.Dashes
== 2 && nDashLen
== 100 && nDistance
== 100)
1005 rsPrstDash
= "sysDashDotDot";
1007 bIsConverted
= false;
1009 return bIsConverted
;
1012 bool FontworkHelpers::getThemeColorFromShape(
1013 OUString
const& rPropertyName
, const uno::Reference
<beans::XPropertySet
>& xPropertySet
,
1014 model::ComplexColor
& rComplexColor
)
1016 auto xPropSetInfo
= xPropertySet
->getPropertySetInfo();
1017 if (!xPropSetInfo
.is())
1019 uno::Reference
<util::XComplexColor
> xComplexColor
;
1020 if (xPropSetInfo
->hasPropertyByName(rPropertyName
)
1021 && (xPropertySet
->getPropertyValue(rPropertyName
) >>= xComplexColor
) && xComplexColor
.is())
1023 rComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
1024 if (rComplexColor
.getSchemeType() == model::ThemeColorType::Unknown
)
1034 // Contains information about one gradient stop. Each gradient has at least 2 of these.
1035 struct GradientStopColor
1037 // RGBColor contains no transformations. In case TTColor has other type than
1038 // ThemeColorType::Unknown, it has precedence. The color transformations in TTColor are used
1039 // for RGBColor as well.
1040 model::ComplexColor TTColor
; // ThemeColorType and color transformations
1045 // 'first' contains the position in the range 0 (=0%) to 100000 (=100%) in the gradient as needed for
1046 // the 'pos' attribute in <w14:gs> element in oox, 'second' contains color and color transformations
1047 // at this position. The map contains all information needed for a <w14:gsLst> element in oox.
1048 typedef std::multimap
<sal_Int32
, GradientStopColor
> ColorMapType
;
1052 constexpr const std::array
<std::u16string_view
, 12> W14ColorNames
{
1053 u
"tx1", u
"bg1", u
"tx2", u
"bg2", u
"accent1", u
"accent2",
1054 u
"accent3", u
"accent4", u
"accent5", u
"accent6", u
"hlink", u
"folHlink"
1057 constexpr const std::array
<std::u16string_view
, 12> WColorNames
{
1058 u
"text1", u
"background1", u
"text2", u
"background2", u
"accent1", u
"accent2",
1059 u
"accent3", u
"accent4", u
"accent5", u
"accent6", u
"hyperlink", u
"followedHyperlink"
1062 // Returns the string to be used in w14:schemeClr in case of w14:textOutline or w14:textFill
1063 OUString
lcl_getW14MarkupStringForThemeColor(const model::ComplexColor
& rComplexColor
)
1065 const sal_uInt8 nClrNameIndex
= std::clamp
<sal_uInt8
>(
1066 sal_Int32(rComplexColor
.getSchemeType()), sal_Int32(model::ThemeColorType::Dark1
),
1067 sal_Int32(model::ThemeColorType::FollowedHyperlink
));
1068 return OUString(W14ColorNames
[nClrNameIndex
]);
1071 // Returns the string to be used in w:themeColor. It is exported via CharThemeColor.
1072 OUString
lcl_getWMarkupStringForThemeColor(const model::ComplexColor
& rComplexColor
)
1074 const sal_uInt8 nClrNameIndex
= std::clamp
<sal_uInt8
>(
1075 sal_Int32(rComplexColor
.getSchemeType()), sal_Int32(model::ThemeColorType::Dark1
),
1076 sal_Int32(model::ThemeColorType::FollowedHyperlink
));
1077 return OUString(WColorNames
[nClrNameIndex
]);
1080 // Puts the value of the first occurrence of rType in rComplexColor into rValue and returns true.
1081 // If such does not exist, rValue is unchanged and the method returns false.
1082 bool lcl_getThemeColorTransformationValue(const model::ComplexColor
& rComplexColor
,
1083 const model::TransformationType
& rType
, sal_Int16
& rValue
)
1085 const std::vector
<model::Transformation
> aTransVec(rComplexColor
.getTransformations());
1087 = [rType
](const model::Transformation
& rTrans
) { return rType
== rTrans
.meType
; };
1088 auto pIt
= std::find_if(aTransVec
.begin(), aTransVec
.end(), bItemFound
);
1089 if (pIt
== aTransVec
.end())
1091 rValue
= (*pIt
).mnValue
;
1095 // Adds the child elements 'lumMod' and 'lumOff' to 'schemeClr' maCurrentElement of pGrabStack,
1096 // if such exist in rComplexColor. 'alpha' is contained in the maTransformations of rComplexColor
1097 // in case of gradient fill.
1098 void lcl_addColorTransformationToGrabBagStack(const model::ComplexColor
& rComplexColor
,
1099 std::unique_ptr
<oox::GrabBagStack
>& pGrabBagStack
)
1101 if (pGrabBagStack
== nullptr)
1103 for (auto const& rColorTransform
: rComplexColor
.getTransformations())
1105 switch (rColorTransform
.meType
)
1107 case model::TransformationType::LumMod
:
1108 pGrabBagStack
->push("lumMod");
1109 pGrabBagStack
->push("attributes");
1110 pGrabBagStack
->addInt32("val", rColorTransform
.mnValue
* 10);
1111 pGrabBagStack
->pop();
1112 pGrabBagStack
->pop();
1114 case model::TransformationType::LumOff
:
1115 pGrabBagStack
->push("lumOff");
1116 pGrabBagStack
->push("attributes");
1117 pGrabBagStack
->addInt32("val", rColorTransform
.mnValue
* 10);
1118 pGrabBagStack
->pop();
1119 pGrabBagStack
->pop();
1121 case model::TransformationType::Alpha
:
1122 pGrabBagStack
->push("alpha");
1123 pGrabBagStack
->push("attributes");
1124 // model::TransformationType::Alpha is designed to be used with a:alpha, which has
1125 // opacity. But w14:alpha uses transparency. So convert it here.
1126 pGrabBagStack
->addInt32("val",
1127 oox::drawingml::MAX_PERCENT
- rColorTransform
.mnValue
* 10);
1128 pGrabBagStack
->pop();
1129 pGrabBagStack
->pop();
1131 default: // other child elements can be added later if needed for Fontwork
1137 void lcl_getGradientsFromShape(const uno::Reference
<beans::XPropertySet
>& rXPropSet
,
1138 const uno::Reference
<beans::XPropertySetInfo
>& rXPropSetInfo
,
1139 awt::Gradient2
& rColorGradient
, bool& rbHasColorGradient
,
1140 awt::Gradient2
& rTransparenceGradient
,
1141 bool& rbHasTransparenceGradient
)
1143 OUString sColorGradientName
;
1145 = rXPropSetInfo
->hasPropertyByName(u
"FillGradientName")
1146 && (rXPropSet
->getPropertyValue(u
"FillGradientName") >>= sColorGradientName
)
1147 && !sColorGradientName
.isEmpty() && rXPropSetInfo
->hasPropertyByName(u
"FillGradient")
1148 && (rXPropSet
->getPropertyValue(u
"FillGradient") >>= rColorGradient
);
1150 OUString sTransparenceGradientName
;
1151 rbHasTransparenceGradient
1152 = rXPropSetInfo
->hasPropertyByName(u
"FillTransparenceGradientName")
1153 && (rXPropSet
->getPropertyValue(u
"FillTransparenceGradientName")
1154 >>= sTransparenceGradientName
)
1155 && !sTransparenceGradientName
.isEmpty()
1156 && rXPropSetInfo
->hasPropertyByName(u
"FillTransparenceGradient")
1157 && (rXPropSet
->getPropertyValue(u
"FillTransparenceGradient") >>= rTransparenceGradient
);
1160 ColorMapType
lcl_createColorMapFromShapeProps(
1161 const uno::Reference
<beans::XPropertySet
>& rXPropSet
,
1162 const uno::Reference
<beans::XPropertySetInfo
>& rXPropSetInfo
,
1163 const awt::Gradient2
& rColorGradient
, const bool& rbHasColorGradient
,
1164 const awt::Gradient2
& rTransparenceGradient
, const bool& rbHasTransparenceGradient
)
1166 // LibreOffice can use color gradients and transparency gradients with different geometries.
1167 // That is not possible in OOXML, so a fill might look different in Word. But a round-trip
1168 // with gradients imported from Word, should work well.
1170 // Word has transparency not as separate gradient but as color transformation in a color
1171 // gradient. Thus we synchronize the gradients. Then they have same offsets and count.
1172 basegfx::BColor aSingleColor
;
1173 basegfx::BGradient aColorBGradient
;
1174 basegfx::BColorStops aColorStops
;
1175 if (rbHasColorGradient
)
1177 aColorBGradient
= model::gradient::getFromUnoGradient2(rColorGradient
);
1178 aColorBGradient
.tryToApplyStartEndIntensity();
1179 aColorBGradient
.tryToApplyBorder();
1180 aColorBGradient
.tryToApplyAxial();
1181 basegfx::utils::prepareColorStops(aColorBGradient
, aColorStops
, aSingleColor
);
1182 // All gradient styles but LINEAR and AXIAL (which is already converted to LINEAR) need the
1183 // stops sequence reverse.
1184 if (awt::GradientStyle_LINEAR
!= aColorBGradient
.GetGradientStyle())
1185 aColorStops
.reverseColorStops();
1189 sal_Int32
nFillColor(0);
1190 if (rXPropSetInfo
->hasPropertyByName("FillColor"))
1191 rXPropSet
->getPropertyValue(u
"FillColor") >>= nFillColor
;
1192 aSingleColor
= ::Color(ColorTransparency
, nFillColor
).getBColor().clamp();
1195 basegfx::BColor aSingleTrans
;
1196 basegfx::BGradient aTransBGradient
;
1197 basegfx::BColorStops aTransStops
;
1198 if (rbHasTransparenceGradient
)
1200 aTransBGradient
= model::gradient::getFromUnoGradient2(rTransparenceGradient
);
1201 aTransBGradient
.tryToApplyStartEndIntensity(); // usually 100%, but might be set by macro
1202 aTransBGradient
.tryToApplyBorder();
1203 aTransBGradient
.tryToApplyAxial();
1204 basegfx::utils::prepareColorStops(aTransBGradient
, aTransStops
, aSingleTrans
);
1205 // All gradient styles but LINEAR and AXIAL (which is already converted to LINEAR) need the
1206 // stops sequence reverse.
1207 if (awt::GradientStyle_LINEAR
!= aTransBGradient
.GetGradientStyle())
1208 aTransStops
.reverseColorStops();
1212 sal_Int16
nAPITrans(0);
1213 if (rXPropSetInfo
->hasPropertyByName(u
"FillTransparence"))
1214 rXPropSet
->getPropertyValue(u
"FillTransparence") >>= nAPITrans
;
1215 // API transparency is in range 0..100, BColor in range [0.0, 1.0].
1216 aSingleTrans
= basegfx::BColor(nAPITrans
* 0.01).clamp();
1219 basegfx::utils::synchronizeColorStops(aColorStops
, aTransStops
, aSingleColor
, aSingleTrans
);
1221 ColorMapType aColorMap
;
1223 // If we have no color gradient, the fix fill color might be a theme color. In that case we use
1224 // it instead of the color from the color stop.
1225 GradientStopColor aFixColor
;
1226 bool bUseThemeColor(!rbHasColorGradient
1227 && FontworkHelpers::getThemeColorFromShape("FillComplexColor", rXPropSet
,
1228 aFixColor
.TTColor
));
1230 for (auto itC
= aColorStops
.begin(), itT
= aTransStops
.begin();
1231 itC
!= aColorStops
.end() && itT
!= aTransStops
.end(); ++itC
, ++itT
)
1233 GradientStopColor aNextStopColor
= aFixColor
;
1234 if (!bUseThemeColor
)
1236 aNextStopColor
.TTColor
= model::ComplexColor();
1237 aNextStopColor
.RGBColor
= ::Color((*itC
).getStopColor());
1239 // model::TransformationType::Alpha is opacity in range 0..10000,
1240 // BColor is transparency in range [0.0, 1.0]
1241 sal_Int16 nAlpha
= std::clamp
<sal_Int16
>(
1242 10000 - std::lround((*itT
).getStopColor().luminance() * 10000.0), 0, 10000);
1244 aNextStopColor
.TTColor
.addTransformation({ model::TransformationType::Alpha
, nAlpha
});
1246 = static_cast<sal_Int32
>(std::lround((*itC
).getStopOffset() * 100000.0));
1247 aColorMap
.insert(std::pair
{ nPosition
, aNextStopColor
});
1250 // If a gradient has only two stops, MS Office renders it with a non-linear method which looks
1251 // different than gradient in LibreOffice (see tdf#128795). For more than two stops rendering is
1252 // the same as in LibreOffice, even if two stops are identical.
1253 if (aColorMap
.size() == 2)
1255 auto it
= aColorMap
.begin();
1256 aColorMap
.insert(std::pair
{ 0, (*it
).second
});
1262 void FontworkHelpers::createCharInteropGrabBagUpdatesFromShapeProps(
1263 const uno::Reference
<beans::XPropertySet
>& rXPropSet
,
1264 std::vector
<beans::PropertyValue
>& rUpdatePropVec
)
1266 auto xPropSetInfo
= rXPropSet
->getPropertySetInfo();
1267 if (!xPropSetInfo
.is())
1270 // GrabBagStack is a special tool for handling the hierarchy in a GrabBag
1271 std::unique_ptr
<oox::GrabBagStack
> pGrabBagStack
;
1273 // CharTextFillTextEffect
1274 pGrabBagStack
.reset(new oox::GrabBagStack("textFill"));
1275 drawing::FillStyle eFillStyle
= drawing::FillStyle_SOLID
;
1276 if (xPropSetInfo
->hasPropertyByName(u
"FillStyle"))
1277 rXPropSet
->getPropertyValue(u
"FillStyle") >>= eFillStyle
;
1279 // We might have a solid fill but a transparency gradient. That needs to be exported as gradFill
1280 // too, because Word has transparency not separated but in the color stops in a color gradient.
1281 // A gradient exists, if the GradientName is not empty.
1282 OUString sTransparenceGradientName
;
1283 if (eFillStyle
== drawing::FillStyle_SOLID
1284 && xPropSetInfo
->hasPropertyByName(u
"FillTransparenceGradientName")
1285 && (rXPropSet
->getPropertyValue(u
"FillTransparenceGradientName")
1286 >>= sTransparenceGradientName
)
1287 && !sTransparenceGradientName
.isEmpty())
1288 eFillStyle
= drawing::FillStyle_GRADIENT
;
1292 case drawing::FillStyle_NONE
:
1294 pGrabBagStack
->appendElement("noFill", uno::Any());
1297 case drawing::FillStyle_GRADIENT
:
1299 awt::Gradient2 aColorGradient
;
1300 bool bHasColorGradient(false);
1301 awt::Gradient2 aTransparenceGradient
;
1302 bool bHasTransparenceGradient(false);
1303 lcl_getGradientsFromShape(rXPropSet
, xPropSetInfo
, aColorGradient
, bHasColorGradient
,
1304 aTransparenceGradient
, bHasTransparenceGradient
);
1305 // aColorMap contains the color stops suitable to generate gsLst
1306 ColorMapType aColorMap
= lcl_createColorMapFromShapeProps(
1307 rXPropSet
, xPropSetInfo
, aColorGradient
, bHasColorGradient
, aTransparenceGradient
,
1308 bHasTransparenceGradient
);
1309 pGrabBagStack
->push("gradFill");
1310 pGrabBagStack
->push("gsLst");
1311 for (auto it
= aColorMap
.begin(); it
!= aColorMap
.end(); ++it
)
1313 pGrabBagStack
->push("gs");
1314 pGrabBagStack
->push("attributes");
1315 pGrabBagStack
->addInt32("pos", (*it
).first
);
1316 pGrabBagStack
->pop();
1317 if ((*it
).second
.TTColor
.getSchemeType() == model::ThemeColorType::Unknown
)
1319 pGrabBagStack
->push("srgbClr");
1320 pGrabBagStack
->push("attributes");
1321 pGrabBagStack
->addString("val", (*it
).second
.RGBColor
.AsRGBHexString());
1322 pGrabBagStack
->pop(); // maCurrentElement:'srgbClr', maPropertyList:'attributes'
1326 pGrabBagStack
->push("schemeClr");
1327 pGrabBagStack
->push("attributes");
1328 pGrabBagStack
->addString(
1329 "val", lcl_getW14MarkupStringForThemeColor((*it
).second
.TTColor
));
1330 pGrabBagStack
->pop();
1331 // maCurrentElement:'schemeClr', maPropertyList:'attributes'
1334 lcl_addColorTransformationToGrabBagStack((*it
).second
.TTColor
, pGrabBagStack
);
1335 pGrabBagStack
->pop();
1336 // maCurrentElement:'gs', maPropertyList:'attributes', 'srgbClr' or 'schemeClr'
1337 pGrabBagStack
->pop(); // maCurrentElement:'gsLst', maPropertyList: at least two 'gs'
1339 pGrabBagStack
->pop(); // maCurrentElement:'gradFill', maPropertyList: gsLst
1342 awt::GradientStyle eGradientStyle
= awt::GradientStyle_LINEAR
;
1343 if (bHasColorGradient
)
1344 eGradientStyle
= aColorGradient
.Style
;
1345 else if (bHasTransparenceGradient
)
1346 eGradientStyle
= aTransparenceGradient
.Style
;
1347 // write 'lin' or 'path'. LibreOffice has nothing which corresponds to 'shape'.
1348 if (eGradientStyle
== awt::GradientStyle_LINEAR
1349 || eGradientStyle
== awt::GradientStyle_AXIAL
)
1351 // API angle is in 1/10th deg and describes counter-clockwise rotation of line of
1352 // equal color. OOX angle is in 1/60000th deg and describes clockwise rotation of
1353 // color transition direction.
1354 sal_Int32 nAngleOOX
= 0;
1355 if (bHasColorGradient
)
1356 nAngleOOX
= ((3600 - aColorGradient
.Angle
+ 900) % 3600) * 6000;
1357 else if (bHasTransparenceGradient
)
1358 nAngleOOX
= ((3600 - aTransparenceGradient
.Angle
+ 900) % 3600) * 6000;
1359 pGrabBagStack
->push("lin");
1360 pGrabBagStack
->push("attributes");
1361 pGrabBagStack
->addInt32("ang", nAngleOOX
);
1362 // LibreOffice cannot scale a gradient to the shape size.
1363 pGrabBagStack
->addString("scaled", "0");
1367 // Same rendering as in LibreOffice is not possible:
1368 // (1) The gradient type 'path' in Word has no rotation.
1369 // (2) To get the same size of gradient area, the element 'tileRect' is needed, but
1370 // that is not available for <w14:textFill> element.
1371 // So we can only set a reasonably suitable focus point.
1372 pGrabBagStack
->push("path");
1373 pGrabBagStack
->push("attributes");
1374 if (eGradientStyle
== awt::GradientStyle_RADIAL
1375 || eGradientStyle
== awt::GradientStyle_ELLIPTICAL
)
1376 pGrabBagStack
->addString("path", "circle");
1378 pGrabBagStack
->addString("path", "rect");
1379 pGrabBagStack
->pop();
1380 pGrabBagStack
->push("fillToRect");
1381 pGrabBagStack
->push("attributes");
1382 sal_Int32 nLeftPercent
1383 = bHasColorGradient
? aColorGradient
.XOffset
: aTransparenceGradient
.XOffset
;
1384 sal_Int32 nTopPercent
1385 = bHasColorGradient
? aColorGradient
.YOffset
: aTransparenceGradient
.YOffset
;
1386 pGrabBagStack
->addInt32("l", nLeftPercent
* 1000);
1387 pGrabBagStack
->addInt32("t", nTopPercent
* 1000);
1388 pGrabBagStack
->addInt32("r", (100 - nLeftPercent
) * 1000);
1389 pGrabBagStack
->addInt32("b", (100 - nTopPercent
) * 1000);
1391 // all remaining pop() calls are in the final getRootProperty() method
1394 case drawing::FillStyle_SOLID
:
1396 pGrabBagStack
->push("solidFill");
1397 model::ComplexColor aComplexColor
;
1398 // It is either "schemeClr" or "srgbClr".
1399 if (FontworkHelpers::getThemeColorFromShape("FillComplexColor", rXPropSet
,
1402 pGrabBagStack
->push("schemeClr");
1403 pGrabBagStack
->push("attributes");
1404 pGrabBagStack
->addString("val", lcl_getW14MarkupStringForThemeColor(aComplexColor
));
1405 pGrabBagStack
->pop(); // maCurrentElement:'schemeClr', maPropertyList:'attributes'
1406 lcl_addColorTransformationToGrabBagStack(aComplexColor
, pGrabBagStack
);
1407 // maCurrentElement:'schemeClr', maPropertyList:'attributes', maybe 'lumMod' and
1412 pGrabBagStack
->push("srgbClr");
1413 sal_Int32
nFillColor(0);
1414 if (xPropSetInfo
->hasPropertyByName(u
"FillColor"))
1415 rXPropSet
->getPropertyValue(u
"FillColor") >>= nFillColor
;
1416 pGrabBagStack
->push("attributes");
1417 ::Color
aColor(ColorTransparency
, nFillColor
);
1418 pGrabBagStack
->addString("val", aColor
.AsRGBHexString());
1419 pGrabBagStack
->pop();
1420 // maCurrentElement:'srgbClr', maPropertyList:'attributes'
1423 sal_Int16
nFillTransparence(0);
1424 if (xPropSetInfo
->hasPropertyByName(u
"FillTransparence"))
1425 rXPropSet
->getPropertyValue(u
"FillTransparence") >>= nFillTransparence
;
1426 if (nFillTransparence
!= 0)
1428 pGrabBagStack
->push("alpha");
1429 pGrabBagStack
->push("attributes");
1430 pGrabBagStack
->addInt32("val", nFillTransparence
* 1000);
1432 // all remaining pop() calls are in the final getRootProperty() method
1435 default: // BITMAP is VML only export and does not arrive here. HATCH has to be VML only
1436 // export too, but is not yet implemented.
1439 // resolve the stack and put resulting PropertyValue into the update vector
1440 beans::PropertyValue aCharTextFillTextEffect
;
1441 aCharTextFillTextEffect
.Name
= "CharTextFillTextEffect";
1442 aCharTextFillTextEffect
.Value
<<= pGrabBagStack
->getRootProperty();
1443 rUpdatePropVec
.push_back(aCharTextFillTextEffect
);
1445 // CharTextOutlineTextEffect
1446 pGrabBagStack
.reset(new oox::GrabBagStack("textOutline"));
1449 pGrabBagStack
->push("attributes");
1451 sal_Int32
nLineWidth(0);
1452 if (xPropSetInfo
->hasPropertyByName(u
"LineWidth"))
1453 rXPropSet
->getPropertyValue(u
"LineWidth") >>= nLineWidth
;
1454 pGrabBagStack
->addInt32("w", nLineWidth
* 360);
1456 drawing::LineCap eLineCap
= drawing::LineCap_BUTT
;
1457 if (xPropSetInfo
->hasPropertyByName(u
"LineCap"))
1458 rXPropSet
->getPropertyValue(u
"LineCap") >>= eLineCap
;
1459 OUString sCap
= u
"flat";
1460 if (eLineCap
== drawing::LineCap_ROUND
)
1462 else if (eLineCap
== drawing::LineCap_SQUARE
)
1464 pGrabBagStack
->addString("cap", sCap
);
1465 // LO has no compound lines and always centers the lines
1466 pGrabBagStack
->addString("cmpd", u
"sng");
1467 pGrabBagStack
->addString("alng", u
"ctr");
1468 pGrabBagStack
->pop();
1469 // maCurrentElement:'textOutline', maPropertyList:'attributes'
1472 drawing::LineStyle eLineStyle
= drawing::LineStyle_NONE
;
1473 if (xPropSetInfo
->hasPropertyByName(u
"LineStyle"))
1474 rXPropSet
->getPropertyValue(u
"LineStyle") >>= eLineStyle
;
1475 // 'dashed' is not a separate style in Word. Word has a style 'gradFill', but that is not yet
1476 // implemented in LO. So only 'noFill' and 'solidFill'.
1477 if (eLineStyle
== drawing::LineStyle_NONE
)
1479 pGrabBagStack
->appendElement("noFill", uno::Any());
1483 pGrabBagStack
->push("solidFill");
1484 // It is either "schemeClr" or "srgbClr".
1485 model::ComplexColor aComplexColor
;
1486 if (FontworkHelpers::getThemeColorFromShape("LineComplexColor", rXPropSet
, aComplexColor
))
1488 pGrabBagStack
->push("schemeClr");
1489 pGrabBagStack
->push("attributes");
1490 pGrabBagStack
->addString("val", lcl_getW14MarkupStringForThemeColor(aComplexColor
));
1491 pGrabBagStack
->pop();
1492 lcl_addColorTransformationToGrabBagStack(aComplexColor
, pGrabBagStack
);
1493 // maCurrentElement:'schemeClr', maPropertylist:'attributes'
1495 else // not a theme color
1497 pGrabBagStack
->push("srgbClr");
1498 pGrabBagStack
->push("attributes");
1499 sal_Int32
nLineColor(0);
1500 if (xPropSetInfo
->hasPropertyByName(u
"LineColor"))
1501 rXPropSet
->getPropertyValue(u
"LineColor") >>= nLineColor
;
1502 ::Color
aColor(ColorTransparency
, nLineColor
);
1503 pGrabBagStack
->addString("val", aColor
.AsRGBHexString());
1504 pGrabBagStack
->pop();
1505 // maCurrentElement:'srgbClr', maPropertylist:'attributes'
1508 sal_Int16
nLineTransparence(0);
1509 if (xPropSetInfo
->hasPropertyByName(u
"LineTransparence"))
1510 rXPropSet
->getPropertyValue(u
"LineTransparence") >>= nLineTransparence
;
1511 if (nLineTransparence
!= 0)
1513 pGrabBagStack
->push("alpha");
1514 pGrabBagStack
->push("attributes");
1515 pGrabBagStack
->addInt32("val", nLineTransparence
* 1000);
1516 pGrabBagStack
->pop(); // maCurrentElement: 'alpha'
1517 pGrabBagStack
->pop(); // maCurrentElement: 'srgbClr' or 'schemeClr'
1519 pGrabBagStack
->pop();
1520 // maCurrentElement:'solidFill', maPropertyList:either 'srgbClr' or 'schemeClr
1521 pGrabBagStack
->pop();
1523 // maCurrentElement:'textOutline', maPropertyList:'attributes' and either 'noFill' or 'solidFill'
1526 if (eLineStyle
== drawing::LineStyle_DASH
)
1528 pGrabBagStack
->push("prstDash");
1529 OUString sPrstDash
= u
"sysDot";
1530 drawing::LineDash aLineDash
;
1531 if (xPropSetInfo
->hasPropertyByName(u
"LineDash")
1532 && (rXPropSet
->getPropertyValue(u
"LineDash") >>= aLineDash
))
1534 // The outline of abc-transform in Word is not able to use custDash. But we know the line
1535 // is dashed. We keep "sysDot" as fallback in case no prstDash is detected.
1536 FontworkHelpers::createPrstDashFromLineDash(aLineDash
, eLineCap
, sPrstDash
);
1540 // ToDo: There may be a named dash style, but that is unlikely for Fontwork shapes. So
1541 // I skip it for now and use the "sysDot" fallback.
1543 pGrabBagStack
->push("attributes");
1544 pGrabBagStack
->addString("val", sPrstDash
);
1545 pGrabBagStack
->pop(); // maCurrentElement:'prstDash'
1546 pGrabBagStack
->pop(); // maCurrentElement:'textOutline'
1548 // maCurrentElement:'textOutline', maPropertyList:'attributes', either 'noFill' or 'solidFill',
1549 // and maybe 'prstDash'.
1551 // LineJoint, can be 'round', 'bevel' or 'miter' in Word
1552 drawing::LineJoint eLineJoint
= drawing::LineJoint_NONE
;
1553 if (xPropSetInfo
->hasPropertyByName(u
"LineJoint"))
1554 rXPropSet
->getPropertyValue(u
"LineJoint") >>= eLineJoint
;
1555 if (eLineJoint
== drawing::LineJoint_NONE
|| eLineJoint
== drawing::LineJoint_BEVEL
)
1556 pGrabBagStack
->appendElement("bevel", uno::Any());
1557 else if (eLineJoint
== drawing::LineJoint_ROUND
)
1558 pGrabBagStack
->appendElement("round", uno::Any());
1559 else // MITER or deprecated MIDDLE
1561 pGrabBagStack
->push("miter");
1562 pGrabBagStack
->push("attributes");
1563 pGrabBagStack
->addInt32("lim", 0); // As of Feb. 2023 LO cannot render other values.
1564 pGrabBagStack
->pop(); // maCurrentElement:'attributes'
1565 pGrabBagStack
->pop(); // maCurrentElement:'miter'
1567 // maCurrentElement:'textOutline', maPropertyList:'attributes', either 'noFill' or
1568 // 'solidFill', maybe 'prstDash', and either 'bevel', 'round' or 'miter'.
1570 // resolve the stack and put resulting PropertyValue into the update vector
1571 beans::PropertyValue aCharTextOutlineTextEffect
;
1572 aCharTextOutlineTextEffect
.Name
= "CharTextOutlineTextEffect";
1573 aCharTextOutlineTextEffect
.Value
<<= pGrabBagStack
->getRootProperty();
1574 rUpdatePropVec
.push_back(aCharTextOutlineTextEffect
);
1576 // CharThemeOriginalColor, CharThemeColor, and CharThemeColorShade or CharThemeColorTint will be
1577 // used for <w:color> element. That is evaluated by applications, which do not understand w14
1578 // namespace, or if w14:textFill is omitted.
1579 model::ComplexColor aComplexColor
;
1580 if (FontworkHelpers::getThemeColorFromShape("FillComplexColor", rXPropSet
, aComplexColor
))
1583 beans::PropertyValue aCharThemeColor
;
1584 aCharThemeColor
.Name
= u
"CharThemeColor";
1585 aCharThemeColor
.Value
<<= lcl_getWMarkupStringForThemeColor(aComplexColor
);
1586 rUpdatePropVec
.push_back(aCharThemeColor
);
1588 // CharThemeColorShade or CharThemeColorTint
1589 // MS Office uses themeTint and themeShade on the luminance in a HSL color space, see 2.1.72
1590 // in [MS-OI29500]. That is different from OOXML specification.
1591 // We made two assumption here: (1) If LumOff exists and is not zero, it is a 'tint'.
1592 // (2) LumMod + LumOff == 10000;
1594 if (lcl_getThemeColorTransformationValue(aComplexColor
, model::TransformationType::LumMod
,
1598 bool bIsTint
= lcl_getThemeColorTransformationValue(
1599 aComplexColor
, model::TransformationType::LumOff
, nLumOff
)
1602 = std::clamp
<sal_uInt8
>(lround(double(nLumMod
) * 255.0 / 10000.0), 0, 255);
1603 OUString sValue
= OUString::number(nValue
, 16);
1605 beans::PropertyValue aCharThemeTintOrShade
;
1606 aCharThemeTintOrShade
.Name
= bIsTint
? u
"CharThemeColorTint" : u
"CharThemeColorShade";
1607 aCharThemeTintOrShade
.Value
<<= sValue
;
1608 rUpdatePropVec
.push_back(aCharThemeTintOrShade
);
1611 // ToDo: Are FillColorLumMod, FillColorLumOff and FillColorTheme possible without
1612 // FillComplexColor? If yes, we need an 'else' part here.
1614 // CharThemeOriginalColor.
1615 beans::PropertyValue aCharThemeOriginalColor
;
1616 sal_Int32
nFillColor(0);
1617 if (xPropSetInfo
->hasPropertyByName(u
"FillColor"))
1618 rXPropSet
->getPropertyValue(u
"FillColor") >>= nFillColor
;
1619 aCharThemeOriginalColor
.Name
= u
"CharThemeOriginalColor";
1620 ::Color
aColor(ColorTransparency
, nFillColor
);
1621 aCharThemeOriginalColor
.Value
<<= aColor
.AsRGBHEXString();
1622 rUpdatePropVec
.push_back(aCharThemeOriginalColor
);
1625 void FontworkHelpers::applyUpdatesToCharInteropGrabBag(
1626 const std::vector
<beans::PropertyValue
>& rUpdatePropVec
, uno::Reference
<text::XText
>& rXText
)
1630 uno::Reference
<text::XTextCursor
> rXTextCursor
= rXText
->createTextCursor();
1631 rXTextCursor
->gotoStart(false);
1632 rXTextCursor
->gotoEnd(true);
1633 uno::Reference
<container::XEnumerationAccess
> paraEnumAccess(rXText
, uno::UNO_QUERY
);
1634 if (!paraEnumAccess
.is())
1636 uno::Reference
<container::XEnumeration
> paraEnum(paraEnumAccess
->createEnumeration());
1637 while (paraEnum
->hasMoreElements())
1639 uno::Reference
<text::XTextRange
> xParagraph(paraEnum
->nextElement(), uno::UNO_QUERY
);
1640 uno::Reference
<container::XEnumerationAccess
> runEnumAccess(xParagraph
, uno::UNO_QUERY
);
1641 if (!runEnumAccess
.is())
1643 uno::Reference
<container::XEnumeration
> runEnum
= runEnumAccess
->createEnumeration();
1644 while (runEnum
->hasMoreElements())
1646 uno::Reference
<text::XTextRange
> xRun(runEnum
->nextElement(), uno::UNO_QUERY
);
1647 if (xRun
->getString().isEmpty())
1649 uno::Reference
<beans::XPropertySet
> xRunPropSet(xRun
, uno::UNO_QUERY
);
1650 if (!xRunPropSet
.is())
1652 auto xRunPropSetInfo
= xRunPropSet
->getPropertySetInfo();
1653 if (!xRunPropSetInfo
.is())
1656 // Now apply the updates to the CharInteropGrabBag of this run
1657 uno::Sequence
<beans::PropertyValue
> aCharInteropGrabBagSeq
;
1658 if (xRunPropSetInfo
->hasPropertyByName("CharInteropGrabBag"))
1659 xRunPropSet
->getPropertyValue("CharInteropGrabBag") >>= aCharInteropGrabBagSeq
;
1660 comphelper::SequenceAsHashMap
aGrabBagMap(aCharInteropGrabBagSeq
);
1661 for (const auto& rProp
: rUpdatePropVec
)
1663 aGrabBagMap
[rProp
.Name
] = rProp
.Value
; // [] inserts if not exists
1665 xRunPropSet
->setPropertyValue("CharInteropGrabBag",
1666 uno::Any(aGrabBagMap
.getAsConstPropertyValueList()));
1671 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */