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
);
153 auto aGeomPropSeq
= xSet
->getPropertyValue(u
"CustomShapeGeometry"_ustr
)
154 .get
<uno::Sequence
<beans::PropertyValue
>>();
156 = comphelper::sequenceToContainer
<std::vector
<beans::PropertyValue
>>(aGeomPropSeq
);
158 // Reset old properties
159 static constexpr OUString
sTextPath(u
"TextPath"_ustr
);
160 static constexpr OUString
sAdjustmentValues(u
"AdjustmentValues"_ustr
);
161 static constexpr OUString
sPresetTextWarp(u
"PresetTextWarp"_ustr
);
163 resetPropertyValueInVec(aGeomPropVec
, u
"CoordinateSize"_ustr
);
164 resetPropertyValueInVec(aGeomPropVec
, u
"Equations"_ustr
);
165 resetPropertyValueInVec(aGeomPropVec
, u
"Path"_ustr
);
166 resetPropertyValueInVec(aGeomPropVec
, sAdjustmentValues
);
167 resetPropertyValueInVec(aGeomPropVec
, u
"ViewBox"_ustr
);
168 resetPropertyValueInVec(aGeomPropVec
, u
"Handles"_ustr
);
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"_ustr
, uno::Any(drawing::EnhancedCustomShapeTextPathMode_PATH
) },
184 { u
"ScaleX"_ustr
, 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"_ustr
,
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"_ustr
, u
"CharLumMod"_ustr
, u
"CharLumOff"_ustr
,
857 u
"CharColorTheme"_ustr
, u
"CharComplexColor"_ustr
, u
"CharTransparence"_ustr
};
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"_ustr
)
935 && (rXPropSet
->getPropertyValue(u
"FillColor"_ustr
) >>= nColorRGB
))
937 ::Color
aColor(ColorTransparency
, nColorRGB
);
938 sal_Int16 nTransPercent
= 0;
939 if (xPropSetInfo
->hasPropertyByName(u
"FillTransparence"_ustr
)
940 && (rXPropSet
->getPropertyValue(u
"FillTransparence"_ustr
) >>= 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"_ustr
, 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)
987 rsPrstDash
= u
"dot"_ustr
;
988 else if (nDotLen
== 400 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 300)
989 rsPrstDash
= u
"dash"_ustr
;
990 else if (nDotLen
== 400 && rLineDash
.Dashes
== 1 && nDashLen
== 100 && nDistance
== 300)
991 rsPrstDash
= u
"dashDot"_ustr
;
992 else if (nDotLen
== 800 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 300)
993 rsPrstDash
= u
"lgDash"_ustr
;
994 else if (nDotLen
== 800 && rLineDash
.Dashes
== 1 && nDashLen
== 100 && nDistance
== 300)
995 rsPrstDash
= u
"lgDashDot"_ustr
;
996 else if (nDotLen
== 800 && rLineDash
.Dashes
== 2 && nDashLen
== 100 && nDistance
== 300)
997 rsPrstDash
= u
"lgDashDotDot"_ustr
;
998 else if (nDotLen
== 100 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 100)
999 rsPrstDash
= u
"sysDot"_ustr
;
1000 else if (nDotLen
== 300 && rLineDash
.Dashes
== 0 && nDashLen
== 0 && nDistance
== 100)
1001 rsPrstDash
= u
"sysDash"_ustr
;
1002 else if (nDotLen
== 300 && rLineDash
.Dashes
== 1 && nDashLen
== 100 && nDistance
== 100)
1003 rsPrstDash
= u
"sysDashDot"_ustr
;
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 return rComplexColor
.isValidThemeType();
1031 // Contains information about one gradient stop. Each gradient has at least 2 of these.
1032 struct GradientStopColor
1034 // RGBColor contains no transformations. In case TTColor has other type than
1035 // ThemeColorType::Unknown, it has precedence. The color transformations in TTColor are used
1036 // for RGBColor as well.
1037 model::ComplexColor TTColor
; // ThemeColorType and color transformations
1042 // 'first' contains the position in the range 0 (=0%) to 100000 (=100%) in the gradient as needed for
1043 // the 'pos' attribute in <w14:gs> element in oox, 'second' contains color and color transformations
1044 // at this position. The map contains all information needed for a <w14:gsLst> element in oox.
1045 typedef std::multimap
<sal_Int32
, GradientStopColor
> ColorMapType
;
1049 constexpr const std::array
<std::u16string_view
, 12> W14ColorNames
{
1050 u
"tx1", u
"bg1", u
"tx2", u
"bg2", u
"accent1", u
"accent2",
1051 u
"accent3", u
"accent4", u
"accent5", u
"accent6", u
"hlink", u
"folHlink"
1054 constexpr const std::array
<std::u16string_view
, 12> WColorNames
{
1055 u
"text1", u
"background1", u
"text2", u
"background2", u
"accent1", u
"accent2",
1056 u
"accent3", u
"accent4", u
"accent5", u
"accent6", u
"hyperlink", u
"followedHyperlink"
1059 // Returns the string to be used in w14:schemeClr in case of w14:textOutline or w14:textFill
1060 OUString
lcl_getW14MarkupStringForThemeColor(const model::ComplexColor
& rComplexColor
)
1062 const sal_uInt8 nClrNameIndex
= std::clamp
<sal_uInt8
>(
1063 sal_Int32(rComplexColor
.getThemeColorType()), sal_Int32(model::ThemeColorType::Dark1
),
1064 sal_Int32(model::ThemeColorType::FollowedHyperlink
));
1065 return OUString(W14ColorNames
[nClrNameIndex
]);
1068 // Returns the string to be used in w:themeColor. It is exported via CharThemeColor.
1069 OUString
lcl_getWMarkupStringForThemeColor(const model::ComplexColor
& rComplexColor
)
1071 const sal_uInt8 nClrNameIndex
= std::clamp
<sal_uInt8
>(
1072 sal_Int32(rComplexColor
.getThemeColorType()), sal_Int32(model::ThemeColorType::Dark1
),
1073 sal_Int32(model::ThemeColorType::FollowedHyperlink
));
1074 return OUString(WColorNames
[nClrNameIndex
]);
1077 // Puts the value of the first occurrence of rType in rComplexColor into rValue and returns true.
1078 // If such does not exist, rValue is unchanged and the method returns false.
1079 bool lcl_getThemeColorTransformationValue(const model::ComplexColor
& rComplexColor
,
1080 const model::TransformationType
& rType
, sal_Int16
& rValue
)
1082 const std::vector
<model::Transformation
>& aTransVec(rComplexColor
.getTransformations());
1084 = [rType
](const model::Transformation
& rTrans
) { return rType
== rTrans
.meType
; };
1085 auto pIt
= std::find_if(aTransVec
.begin(), aTransVec
.end(), bItemFound
);
1086 if (pIt
== aTransVec
.end())
1088 rValue
= (*pIt
).mnValue
;
1092 // Adds the child elements 'lumMod' and 'lumOff' to 'schemeClr' maCurrentElement of pGrabStack,
1093 // if such exist in rComplexColor. 'alpha' is contained in the maTransformations of rComplexColor
1094 // in case of gradient fill.
1095 void lcl_addColorTransformationToGrabBagStack(const model::ComplexColor
& rComplexColor
,
1096 std::unique_ptr
<oox::GrabBagStack
>& pGrabBagStack
)
1098 if (pGrabBagStack
== nullptr)
1100 for (auto const& rColorTransform
: rComplexColor
.getTransformations())
1102 switch (rColorTransform
.meType
)
1104 case model::TransformationType::LumMod
:
1105 pGrabBagStack
->push(u
"lumMod"_ustr
);
1106 pGrabBagStack
->push(u
"attributes"_ustr
);
1107 pGrabBagStack
->addInt32(u
"val"_ustr
, rColorTransform
.mnValue
* 10);
1108 pGrabBagStack
->pop();
1109 pGrabBagStack
->pop();
1111 case model::TransformationType::LumOff
:
1112 pGrabBagStack
->push(u
"lumOff"_ustr
);
1113 pGrabBagStack
->push(u
"attributes"_ustr
);
1114 pGrabBagStack
->addInt32(u
"val"_ustr
, rColorTransform
.mnValue
* 10);
1115 pGrabBagStack
->pop();
1116 pGrabBagStack
->pop();
1118 case model::TransformationType::Alpha
:
1119 pGrabBagStack
->push(u
"alpha"_ustr
);
1120 pGrabBagStack
->push(u
"attributes"_ustr
);
1121 // model::TransformationType::Alpha is designed to be used with a:alpha, which has
1122 // opacity. But w14:alpha uses transparency. So convert it here.
1123 pGrabBagStack
->addInt32(u
"val"_ustr
,
1124 oox::drawingml::MAX_PERCENT
- rColorTransform
.mnValue
* 10);
1125 pGrabBagStack
->pop();
1126 pGrabBagStack
->pop();
1128 default: // other child elements can be added later if needed for Fontwork
1134 void lcl_getGradientsFromShape(const uno::Reference
<beans::XPropertySet
>& rXPropSet
,
1135 const uno::Reference
<beans::XPropertySetInfo
>& rXPropSetInfo
,
1136 awt::Gradient2
& rColorGradient
, bool& rbHasColorGradient
,
1137 awt::Gradient2
& rTransparenceGradient
,
1138 bool& rbHasTransparenceGradient
)
1140 OUString sColorGradientName
;
1142 = rXPropSetInfo
->hasPropertyByName(u
"FillGradientName"_ustr
)
1143 && (rXPropSet
->getPropertyValue(u
"FillGradientName"_ustr
) >>= sColorGradientName
)
1144 && !sColorGradientName
.isEmpty() && rXPropSetInfo
->hasPropertyByName(u
"FillGradient"_ustr
)
1145 && (rXPropSet
->getPropertyValue(u
"FillGradient"_ustr
) >>= rColorGradient
);
1147 OUString sTransparenceGradientName
;
1148 rbHasTransparenceGradient
1149 = rXPropSetInfo
->hasPropertyByName(u
"FillTransparenceGradientName"_ustr
)
1150 && (rXPropSet
->getPropertyValue(u
"FillTransparenceGradientName"_ustr
)
1151 >>= sTransparenceGradientName
)
1152 && !sTransparenceGradientName
.isEmpty()
1153 && rXPropSetInfo
->hasPropertyByName(u
"FillTransparenceGradient"_ustr
)
1154 && (rXPropSet
->getPropertyValue(u
"FillTransparenceGradient"_ustr
)
1155 >>= rTransparenceGradient
);
1158 ColorMapType
lcl_createColorMapFromShapeProps(
1159 const uno::Reference
<beans::XPropertySet
>& rXPropSet
,
1160 const uno::Reference
<beans::XPropertySetInfo
>& rXPropSetInfo
,
1161 const awt::Gradient2
& rColorGradient
, const bool& rbHasColorGradient
,
1162 const awt::Gradient2
& rTransparenceGradient
, const bool& rbHasTransparenceGradient
)
1164 // LibreOffice can use color gradients and transparency gradients with different geometries.
1165 // That is not possible in OOXML, so a fill might look different in Word. But a round-trip
1166 // with gradients imported from Word, should work well.
1168 // Word has transparency not as separate gradient but as color transformation in a color
1169 // gradient. Thus we synchronize the gradients. Then they have same offsets and count.
1170 basegfx::BColor aSingleColor
;
1171 basegfx::BGradient aColorBGradient
;
1172 basegfx::BColorStops aColorStops
;
1173 if (rbHasColorGradient
)
1175 aColorBGradient
= model::gradient::getFromUnoGradient2(rColorGradient
);
1176 aColorBGradient
.tryToApplyStartEndIntensity();
1177 aColorBGradient
.tryToApplyBorder();
1178 aColorBGradient
.tryToApplyAxial();
1179 basegfx::utils::prepareColorStops(aColorBGradient
, aColorStops
, aSingleColor
);
1180 // All gradient styles but LINEAR and AXIAL (which is already converted to LINEAR) need the
1181 // stops sequence reverse.
1182 if (awt::GradientStyle_LINEAR
!= aColorBGradient
.GetGradientStyle())
1183 aColorStops
.reverseColorStops();
1187 sal_Int32
nFillColor(0);
1188 if (rXPropSetInfo
->hasPropertyByName(u
"FillColor"_ustr
))
1189 rXPropSet
->getPropertyValue(u
"FillColor"_ustr
) >>= nFillColor
;
1190 aSingleColor
= ::Color(ColorTransparency
, nFillColor
).getBColor().clamp();
1193 basegfx::BColor aSingleTrans
;
1194 basegfx::BGradient aTransBGradient
;
1195 basegfx::BColorStops aTransStops
;
1196 if (rbHasTransparenceGradient
)
1198 aTransBGradient
= model::gradient::getFromUnoGradient2(rTransparenceGradient
);
1199 aTransBGradient
.tryToApplyStartEndIntensity(); // usually 100%, but might be set by macro
1200 aTransBGradient
.tryToApplyBorder();
1201 aTransBGradient
.tryToApplyAxial();
1202 basegfx::utils::prepareColorStops(aTransBGradient
, aTransStops
, aSingleTrans
);
1203 // All gradient styles but LINEAR and AXIAL (which is already converted to LINEAR) need the
1204 // stops sequence reverse.
1205 if (awt::GradientStyle_LINEAR
!= aTransBGradient
.GetGradientStyle())
1206 aTransStops
.reverseColorStops();
1210 sal_Int16
nAPITrans(0);
1211 if (rXPropSetInfo
->hasPropertyByName(u
"FillTransparence"_ustr
))
1212 rXPropSet
->getPropertyValue(u
"FillTransparence"_ustr
) >>= nAPITrans
;
1213 // API transparency is in range 0..100, BColor in range [0.0, 1.0].
1214 aSingleTrans
= basegfx::BColor(nAPITrans
* 0.01).clamp();
1217 basegfx::utils::synchronizeColorStops(aColorStops
, aTransStops
, aSingleColor
, aSingleTrans
);
1219 ColorMapType aColorMap
;
1221 // If we have no color gradient, the fix fill color might be a theme color. In that case we use
1222 // it instead of the color from the color stop.
1223 GradientStopColor aFixColor
;
1224 bool bUseThemeColor(!rbHasColorGradient
1225 && FontworkHelpers::getThemeColorFromShape(u
"FillComplexColor"_ustr
,
1226 rXPropSet
, aFixColor
.TTColor
));
1228 for (auto itC
= aColorStops
.begin(), itT
= aTransStops
.begin();
1229 itC
!= aColorStops
.end() && itT
!= aTransStops
.end(); ++itC
, ++itT
)
1231 GradientStopColor aNextStopColor
= aFixColor
;
1232 if (!bUseThemeColor
)
1234 aNextStopColor
.TTColor
= model::ComplexColor();
1235 aNextStopColor
.RGBColor
= ::Color((*itC
).getStopColor());
1237 // model::TransformationType::Alpha is opacity in range 0..10000,
1238 // BColor is transparency in range [0.0, 1.0]
1239 sal_Int16 nAlpha
= std::clamp
<sal_Int16
>(
1240 10000 - std::lround((*itT
).getStopColor().luminance() * 10000.0), 0, 10000);
1242 aNextStopColor
.TTColor
.addTransformation({ model::TransformationType::Alpha
, nAlpha
});
1244 = static_cast<sal_Int32
>(std::lround((*itC
).getStopOffset() * 100000.0));
1245 aColorMap
.insert(std::pair
{ nPosition
, aNextStopColor
});
1248 // If a gradient has only two stops, MS Office renders it with a non-linear method which looks
1249 // different than gradient in LibreOffice (see tdf#128795). For more than two stops rendering is
1250 // the same as in LibreOffice, even if two stops are identical.
1251 if (aColorMap
.size() == 2)
1253 auto it
= aColorMap
.begin();
1254 aColorMap
.insert(std::pair
{ 0, (*it
).second
});
1260 void FontworkHelpers::createCharInteropGrabBagUpdatesFromShapeProps(
1261 const uno::Reference
<beans::XPropertySet
>& rXPropSet
,
1262 std::vector
<beans::PropertyValue
>& rUpdatePropVec
)
1264 auto xPropSetInfo
= rXPropSet
->getPropertySetInfo();
1265 if (!xPropSetInfo
.is())
1268 // GrabBagStack is a special tool for handling the hierarchy in a GrabBag
1269 std::unique_ptr
<oox::GrabBagStack
> pGrabBagStack
;
1271 // CharTextFillTextEffect
1272 pGrabBagStack
.reset(new oox::GrabBagStack(u
"textFill"_ustr
));
1273 drawing::FillStyle eFillStyle
= drawing::FillStyle_SOLID
;
1274 if (xPropSetInfo
->hasPropertyByName(u
"FillStyle"_ustr
))
1275 rXPropSet
->getPropertyValue(u
"FillStyle"_ustr
) >>= eFillStyle
;
1277 // We might have a solid fill but a transparency gradient. That needs to be exported as gradFill
1278 // too, because Word has transparency not separated but in the color stops in a color gradient.
1279 // A gradient exists, if the GradientName is not empty.
1280 OUString sTransparenceGradientName
;
1281 if (eFillStyle
== drawing::FillStyle_SOLID
1282 && xPropSetInfo
->hasPropertyByName(u
"FillTransparenceGradientName"_ustr
)
1283 && (rXPropSet
->getPropertyValue(u
"FillTransparenceGradientName"_ustr
)
1284 >>= sTransparenceGradientName
)
1285 && !sTransparenceGradientName
.isEmpty())
1286 eFillStyle
= drawing::FillStyle_GRADIENT
;
1290 case drawing::FillStyle_NONE
:
1292 pGrabBagStack
->appendElement(u
"noFill"_ustr
, uno::Any());
1295 case drawing::FillStyle_GRADIENT
:
1297 awt::Gradient2 aColorGradient
;
1298 bool bHasColorGradient(false);
1299 awt::Gradient2 aTransparenceGradient
;
1300 bool bHasTransparenceGradient(false);
1301 lcl_getGradientsFromShape(rXPropSet
, xPropSetInfo
, aColorGradient
, bHasColorGradient
,
1302 aTransparenceGradient
, bHasTransparenceGradient
);
1303 // aColorMap contains the color stops suitable to generate gsLst
1304 ColorMapType aColorMap
= lcl_createColorMapFromShapeProps(
1305 rXPropSet
, xPropSetInfo
, aColorGradient
, bHasColorGradient
, aTransparenceGradient
,
1306 bHasTransparenceGradient
);
1307 pGrabBagStack
->push(u
"gradFill"_ustr
);
1308 pGrabBagStack
->push(u
"gsLst"_ustr
);
1309 for (auto it
= aColorMap
.begin(); it
!= aColorMap
.end(); ++it
)
1311 pGrabBagStack
->push(u
"gs"_ustr
);
1312 pGrabBagStack
->push(u
"attributes"_ustr
);
1313 pGrabBagStack
->addInt32(u
"pos"_ustr
, (*it
).first
);
1314 pGrabBagStack
->pop();
1315 if ((*it
).second
.TTColor
.getThemeColorType() == model::ThemeColorType::Unknown
)
1317 pGrabBagStack
->push(u
"srgbClr"_ustr
);
1318 pGrabBagStack
->push(u
"attributes"_ustr
);
1319 pGrabBagStack
->addString(u
"val"_ustr
, (*it
).second
.RGBColor
.AsRGBHexString());
1320 pGrabBagStack
->pop(); // maCurrentElement:'srgbClr', maPropertyList:'attributes'
1324 pGrabBagStack
->push(u
"schemeClr"_ustr
);
1325 pGrabBagStack
->push(u
"attributes"_ustr
);
1326 pGrabBagStack
->addString(
1327 u
"val"_ustr
, lcl_getW14MarkupStringForThemeColor((*it
).second
.TTColor
));
1328 pGrabBagStack
->pop();
1329 // maCurrentElement:'schemeClr', maPropertyList:'attributes'
1332 lcl_addColorTransformationToGrabBagStack((*it
).second
.TTColor
, pGrabBagStack
);
1333 pGrabBagStack
->pop();
1334 // maCurrentElement:'gs', maPropertyList:'attributes', 'srgbClr' or 'schemeClr'
1335 pGrabBagStack
->pop(); // maCurrentElement:'gsLst', maPropertyList: at least two 'gs'
1337 pGrabBagStack
->pop(); // maCurrentElement:'gradFill', maPropertyList: gsLst
1340 awt::GradientStyle eGradientStyle
= awt::GradientStyle_LINEAR
;
1341 if (bHasColorGradient
)
1342 eGradientStyle
= aColorGradient
.Style
;
1343 else if (bHasTransparenceGradient
)
1344 eGradientStyle
= aTransparenceGradient
.Style
;
1345 // write 'lin' or 'path'. LibreOffice has nothing which corresponds to 'shape'.
1346 if (eGradientStyle
== awt::GradientStyle_LINEAR
1347 || eGradientStyle
== awt::GradientStyle_AXIAL
)
1349 // API angle is in 1/10th deg and describes counter-clockwise rotation of line of
1350 // equal color. OOX angle is in 1/60000th deg and describes clockwise rotation of
1351 // color transition direction.
1352 sal_Int32 nAngleOOX
= 0;
1353 if (bHasColorGradient
)
1354 nAngleOOX
= ((3600 - aColorGradient
.Angle
+ 900) % 3600) * 6000;
1355 else if (bHasTransparenceGradient
)
1356 nAngleOOX
= ((3600 - aTransparenceGradient
.Angle
+ 900) % 3600) * 6000;
1357 pGrabBagStack
->push(u
"lin"_ustr
);
1358 pGrabBagStack
->push(u
"attributes"_ustr
);
1359 pGrabBagStack
->addInt32(u
"ang"_ustr
, nAngleOOX
);
1360 // LibreOffice cannot scale a gradient to the shape size.
1361 pGrabBagStack
->addString(u
"scaled"_ustr
, u
"0"_ustr
);
1365 // Same rendering as in LibreOffice is not possible:
1366 // (1) The gradient type 'path' in Word has no rotation.
1367 // (2) To get the same size of gradient area, the element 'tileRect' is needed, but
1368 // that is not available for <w14:textFill> element.
1369 // So we can only set a reasonably suitable focus point.
1370 pGrabBagStack
->push(u
"path"_ustr
);
1371 pGrabBagStack
->push(u
"attributes"_ustr
);
1372 if (eGradientStyle
== awt::GradientStyle_RADIAL
1373 || eGradientStyle
== awt::GradientStyle_ELLIPTICAL
)
1374 pGrabBagStack
->addString(u
"path"_ustr
, u
"circle"_ustr
);
1376 pGrabBagStack
->addString(u
"path"_ustr
, u
"rect"_ustr
);
1377 pGrabBagStack
->pop();
1378 pGrabBagStack
->push(u
"fillToRect"_ustr
);
1379 pGrabBagStack
->push(u
"attributes"_ustr
);
1380 sal_Int32 nLeftPercent
1381 = bHasColorGradient
? aColorGradient
.XOffset
: aTransparenceGradient
.XOffset
;
1382 sal_Int32 nTopPercent
1383 = bHasColorGradient
? aColorGradient
.YOffset
: aTransparenceGradient
.YOffset
;
1384 pGrabBagStack
->addInt32(u
"l"_ustr
, nLeftPercent
* 1000);
1385 pGrabBagStack
->addInt32(u
"t"_ustr
, nTopPercent
* 1000);
1386 pGrabBagStack
->addInt32(u
"r"_ustr
, (100 - nLeftPercent
) * 1000);
1387 pGrabBagStack
->addInt32(u
"b"_ustr
, (100 - nTopPercent
) * 1000);
1389 // all remaining pop() calls are in the final getRootProperty() method
1392 case drawing::FillStyle_SOLID
:
1394 pGrabBagStack
->push(u
"solidFill"_ustr
);
1395 model::ComplexColor aComplexColor
;
1396 // It is either "schemeClr" or "srgbClr".
1397 if (FontworkHelpers::getThemeColorFromShape(u
"FillComplexColor"_ustr
, rXPropSet
,
1400 pGrabBagStack
->push(u
"schemeClr"_ustr
);
1401 pGrabBagStack
->push(u
"attributes"_ustr
);
1402 pGrabBagStack
->addString(u
"val"_ustr
,
1403 lcl_getW14MarkupStringForThemeColor(aComplexColor
));
1404 pGrabBagStack
->pop(); // maCurrentElement:'schemeClr', maPropertyList:'attributes'
1405 lcl_addColorTransformationToGrabBagStack(aComplexColor
, pGrabBagStack
);
1406 // maCurrentElement:'schemeClr', maPropertyList:'attributes', maybe 'lumMod' and
1411 pGrabBagStack
->push(u
"srgbClr"_ustr
);
1412 sal_Int32
nFillColor(0);
1413 if (xPropSetInfo
->hasPropertyByName(u
"FillColor"_ustr
))
1414 rXPropSet
->getPropertyValue(u
"FillColor"_ustr
) >>= nFillColor
;
1415 pGrabBagStack
->push(u
"attributes"_ustr
);
1416 ::Color
aColor(ColorTransparency
, nFillColor
);
1417 pGrabBagStack
->addString(u
"val"_ustr
, aColor
.AsRGBHexString());
1418 pGrabBagStack
->pop();
1419 // maCurrentElement:'srgbClr', maPropertyList:'attributes'
1422 sal_Int16
nFillTransparence(0);
1423 if (xPropSetInfo
->hasPropertyByName(u
"FillTransparence"_ustr
))
1424 rXPropSet
->getPropertyValue(u
"FillTransparence"_ustr
) >>= nFillTransparence
;
1425 if (nFillTransparence
!= 0)
1427 pGrabBagStack
->push(u
"alpha"_ustr
);
1428 pGrabBagStack
->push(u
"attributes"_ustr
);
1429 pGrabBagStack
->addInt32(u
"val"_ustr
, nFillTransparence
* 1000);
1431 // all remaining pop() calls are in the final getRootProperty() method
1434 default: // BITMAP is VML only export and does not arrive here. HATCH has to be VML only
1435 // export too, but is not yet implemented.
1438 // resolve the stack and put resulting PropertyValue into the update vector
1439 beans::PropertyValue aCharTextFillTextEffect
;
1440 aCharTextFillTextEffect
.Name
= "CharTextFillTextEffect";
1441 aCharTextFillTextEffect
.Value
<<= pGrabBagStack
->getRootProperty();
1442 rUpdatePropVec
.push_back(aCharTextFillTextEffect
);
1444 // CharTextOutlineTextEffect
1445 pGrabBagStack
.reset(new oox::GrabBagStack(u
"textOutline"_ustr
));
1448 pGrabBagStack
->push(u
"attributes"_ustr
);
1450 sal_Int32
nLineWidth(0);
1451 if (xPropSetInfo
->hasPropertyByName(u
"LineWidth"_ustr
))
1452 rXPropSet
->getPropertyValue(u
"LineWidth"_ustr
) >>= nLineWidth
;
1453 pGrabBagStack
->addInt32(u
"w"_ustr
, nLineWidth
* 360);
1455 drawing::LineCap eLineCap
= drawing::LineCap_BUTT
;
1456 if (xPropSetInfo
->hasPropertyByName(u
"LineCap"_ustr
))
1457 rXPropSet
->getPropertyValue(u
"LineCap"_ustr
) >>= eLineCap
;
1458 OUString sCap
= u
"flat"_ustr
;
1459 if (eLineCap
== drawing::LineCap_ROUND
)
1461 else if (eLineCap
== drawing::LineCap_SQUARE
)
1463 pGrabBagStack
->addString(u
"cap"_ustr
, sCap
);
1464 // LO has no compound lines and always centers the lines
1465 pGrabBagStack
->addString(u
"cmpd"_ustr
, u
"sng"_ustr
);
1466 pGrabBagStack
->addString(u
"alng"_ustr
, u
"ctr"_ustr
);
1467 pGrabBagStack
->pop();
1468 // maCurrentElement:'textOutline', maPropertyList:'attributes'
1471 drawing::LineStyle eLineStyle
= drawing::LineStyle_NONE
;
1472 if (xPropSetInfo
->hasPropertyByName(u
"LineStyle"_ustr
))
1473 rXPropSet
->getPropertyValue(u
"LineStyle"_ustr
) >>= eLineStyle
;
1474 // 'dashed' is not a separate style in Word. Word has a style 'gradFill', but that is not yet
1475 // implemented in LO. So only 'noFill' and 'solidFill'.
1476 if (eLineStyle
== drawing::LineStyle_NONE
)
1478 pGrabBagStack
->appendElement(u
"noFill"_ustr
, uno::Any());
1482 pGrabBagStack
->push(u
"solidFill"_ustr
);
1483 // It is either "schemeClr" or "srgbClr".
1484 model::ComplexColor aComplexColor
;
1485 if (FontworkHelpers::getThemeColorFromShape(u
"LineComplexColor"_ustr
, rXPropSet
,
1488 pGrabBagStack
->push(u
"schemeClr"_ustr
);
1489 pGrabBagStack
->push(u
"attributes"_ustr
);
1490 pGrabBagStack
->addString(u
"val"_ustr
,
1491 lcl_getW14MarkupStringForThemeColor(aComplexColor
));
1492 pGrabBagStack
->pop();
1493 lcl_addColorTransformationToGrabBagStack(aComplexColor
, pGrabBagStack
);
1494 // maCurrentElement:'schemeClr', maPropertylist:'attributes'
1496 else // not a theme color
1498 pGrabBagStack
->push(u
"srgbClr"_ustr
);
1499 pGrabBagStack
->push(u
"attributes"_ustr
);
1500 sal_Int32
nLineColor(0);
1501 if (xPropSetInfo
->hasPropertyByName(u
"LineColor"_ustr
))
1502 rXPropSet
->getPropertyValue(u
"LineColor"_ustr
) >>= nLineColor
;
1503 ::Color
aColor(ColorTransparency
, nLineColor
);
1504 pGrabBagStack
->addString(u
"val"_ustr
, aColor
.AsRGBHexString());
1505 pGrabBagStack
->pop();
1506 // maCurrentElement:'srgbClr', maPropertylist:'attributes'
1509 sal_Int16
nLineTransparence(0);
1510 if (xPropSetInfo
->hasPropertyByName(u
"LineTransparence"_ustr
))
1511 rXPropSet
->getPropertyValue(u
"LineTransparence"_ustr
) >>= nLineTransparence
;
1512 if (nLineTransparence
!= 0)
1514 pGrabBagStack
->push(u
"alpha"_ustr
);
1515 pGrabBagStack
->push(u
"attributes"_ustr
);
1516 pGrabBagStack
->addInt32(u
"val"_ustr
, nLineTransparence
* 1000);
1517 pGrabBagStack
->pop(); // maCurrentElement: 'alpha'
1518 pGrabBagStack
->pop(); // maCurrentElement: 'srgbClr' or 'schemeClr'
1520 pGrabBagStack
->pop();
1521 // maCurrentElement:'solidFill', maPropertyList:either 'srgbClr' or 'schemeClr
1522 pGrabBagStack
->pop();
1524 // maCurrentElement:'textOutline', maPropertyList:'attributes' and either 'noFill' or 'solidFill'
1527 if (eLineStyle
== drawing::LineStyle_DASH
)
1529 pGrabBagStack
->push(u
"prstDash"_ustr
);
1530 OUString sPrstDash
= u
"sysDot"_ustr
;
1531 drawing::LineDash aLineDash
;
1532 if (xPropSetInfo
->hasPropertyByName(u
"LineDash"_ustr
)
1533 && (rXPropSet
->getPropertyValue(u
"LineDash"_ustr
) >>= aLineDash
))
1535 // The outline of abc-transform in Word is not able to use custDash. But we know the line
1536 // is dashed. We keep "sysDot" as fallback in case no prstDash is detected.
1537 FontworkHelpers::createPrstDashFromLineDash(aLineDash
, eLineCap
, sPrstDash
);
1541 // ToDo: There may be a named dash style, but that is unlikely for Fontwork shapes. So
1542 // I skip it for now and use the "sysDot" fallback.
1544 pGrabBagStack
->push(u
"attributes"_ustr
);
1545 pGrabBagStack
->addString(u
"val"_ustr
, sPrstDash
);
1546 pGrabBagStack
->pop(); // maCurrentElement:'prstDash'
1547 pGrabBagStack
->pop(); // maCurrentElement:'textOutline'
1549 // maCurrentElement:'textOutline', maPropertyList:'attributes', either 'noFill' or 'solidFill',
1550 // and maybe 'prstDash'.
1552 // LineJoint, can be 'round', 'bevel' or 'miter' in Word
1553 drawing::LineJoint eLineJoint
= drawing::LineJoint_NONE
;
1554 if (xPropSetInfo
->hasPropertyByName(u
"LineJoint"_ustr
))
1555 rXPropSet
->getPropertyValue(u
"LineJoint"_ustr
) >>= eLineJoint
;
1556 if (eLineJoint
== drawing::LineJoint_NONE
|| eLineJoint
== drawing::LineJoint_BEVEL
)
1557 pGrabBagStack
->appendElement(u
"bevel"_ustr
, uno::Any());
1558 else if (eLineJoint
== drawing::LineJoint_ROUND
)
1559 pGrabBagStack
->appendElement(u
"round"_ustr
, uno::Any());
1560 else // MITER or deprecated MIDDLE
1562 pGrabBagStack
->push(u
"miter"_ustr
);
1563 pGrabBagStack
->push(u
"attributes"_ustr
);
1564 pGrabBagStack
->addInt32(u
"lim"_ustr
, 0); // As of Feb. 2023 LO cannot render other values.
1565 pGrabBagStack
->pop(); // maCurrentElement:'attributes'
1566 pGrabBagStack
->pop(); // maCurrentElement:'miter'
1568 // maCurrentElement:'textOutline', maPropertyList:'attributes', either 'noFill' or
1569 // 'solidFill', maybe 'prstDash', and either 'bevel', 'round' or 'miter'.
1571 // resolve the stack and put resulting PropertyValue into the update vector
1572 beans::PropertyValue aCharTextOutlineTextEffect
;
1573 aCharTextOutlineTextEffect
.Name
= "CharTextOutlineTextEffect";
1574 aCharTextOutlineTextEffect
.Value
<<= pGrabBagStack
->getRootProperty();
1575 rUpdatePropVec
.push_back(aCharTextOutlineTextEffect
);
1577 // CharThemeOriginalColor, CharThemeColor, and CharThemeColorShade or CharThemeColorTint will be
1578 // used for <w:color> element. That is evaluated by applications, which do not understand w14
1579 // namespace, or if w14:textFill is omitted.
1580 model::ComplexColor aComplexColor
;
1581 if (FontworkHelpers::getThemeColorFromShape(u
"FillComplexColor"_ustr
, rXPropSet
, aComplexColor
))
1584 beans::PropertyValue aCharThemeColor
;
1585 aCharThemeColor
.Name
= u
"CharThemeColor"_ustr
;
1586 aCharThemeColor
.Value
<<= lcl_getWMarkupStringForThemeColor(aComplexColor
);
1587 rUpdatePropVec
.push_back(aCharThemeColor
);
1589 // CharThemeColorShade or CharThemeColorTint
1590 // MS Office uses themeTint and themeShade on the luminance in a HSL color space, see 2.1.72
1591 // in [MS-OI29500]. That is different from OOXML specification.
1592 // We made two assumption here: (1) If LumOff exists and is not zero, it is a 'tint'.
1593 // (2) LumMod + LumOff == 10000;
1595 if (lcl_getThemeColorTransformationValue(aComplexColor
, model::TransformationType::LumMod
,
1599 bool bIsTint
= lcl_getThemeColorTransformationValue(
1600 aComplexColor
, model::TransformationType::LumOff
, nLumOff
)
1603 = std::clamp
<sal_uInt8
>(lround(double(nLumMod
) * 255.0 / 10000.0), 0, 255);
1604 OUString sValue
= OUString::number(nValue
, 16);
1606 beans::PropertyValue aCharThemeTintOrShade
;
1607 aCharThemeTintOrShade
.Name
= bIsTint
? u
"CharThemeColorTint" : u
"CharThemeColorShade";
1608 aCharThemeTintOrShade
.Value
<<= sValue
;
1609 rUpdatePropVec
.push_back(aCharThemeTintOrShade
);
1612 // ToDo: Are FillColorLumMod, FillColorLumOff and FillColorTheme possible without
1613 // FillComplexColor? If yes, we need an 'else' part here.
1615 // CharThemeOriginalColor.
1616 beans::PropertyValue aCharThemeOriginalColor
;
1617 sal_Int32
nFillColor(0);
1618 if (xPropSetInfo
->hasPropertyByName(u
"FillColor"_ustr
))
1619 rXPropSet
->getPropertyValue(u
"FillColor"_ustr
) >>= nFillColor
;
1620 aCharThemeOriginalColor
.Name
= u
"CharThemeOriginalColor"_ustr
;
1621 ::Color
aColor(ColorTransparency
, nFillColor
);
1622 aCharThemeOriginalColor
.Value
<<= aColor
.AsRGBHEXString();
1623 rUpdatePropVec
.push_back(aCharThemeOriginalColor
);
1626 void FontworkHelpers::applyUpdatesToCharInteropGrabBag(
1627 const std::vector
<beans::PropertyValue
>& rUpdatePropVec
, uno::Reference
<text::XText
>& rXText
)
1631 uno::Reference
<text::XTextCursor
> rXTextCursor
= rXText
->createTextCursor();
1632 rXTextCursor
->gotoStart(false);
1633 rXTextCursor
->gotoEnd(true);
1634 uno::Reference
<container::XEnumerationAccess
> paraEnumAccess(rXText
, uno::UNO_QUERY
);
1635 if (!paraEnumAccess
.is())
1637 uno::Reference
<container::XEnumeration
> paraEnum(paraEnumAccess
->createEnumeration());
1638 while (paraEnum
->hasMoreElements())
1640 uno::Reference
<text::XTextRange
> xParagraph(paraEnum
->nextElement(), uno::UNO_QUERY
);
1641 uno::Reference
<container::XEnumerationAccess
> runEnumAccess(xParagraph
, uno::UNO_QUERY
);
1642 if (!runEnumAccess
.is())
1644 uno::Reference
<container::XEnumeration
> runEnum
= runEnumAccess
->createEnumeration();
1645 while (runEnum
->hasMoreElements())
1647 uno::Reference
<text::XTextRange
> xRun(runEnum
->nextElement(), uno::UNO_QUERY
);
1648 if (xRun
->getString().isEmpty())
1650 uno::Reference
<beans::XPropertySet
> xRunPropSet(xRun
, uno::UNO_QUERY
);
1651 if (!xRunPropSet
.is())
1653 auto xRunPropSetInfo
= xRunPropSet
->getPropertySetInfo();
1654 if (!xRunPropSetInfo
.is())
1657 // Now apply the updates to the CharInteropGrabBag of this run
1658 uno::Sequence
<beans::PropertyValue
> aCharInteropGrabBagSeq
;
1659 if (xRunPropSetInfo
->hasPropertyByName(u
"CharInteropGrabBag"_ustr
))
1660 xRunPropSet
->getPropertyValue(u
"CharInteropGrabBag"_ustr
)
1661 >>= aCharInteropGrabBagSeq
;
1662 comphelper::SequenceAsHashMap
aGrabBagMap(aCharInteropGrabBagSeq
);
1663 for (const auto& rProp
: rUpdatePropVec
)
1665 aGrabBagMap
[rProp
.Name
] = rProp
.Value
; // [] inserts if not exists
1667 xRunPropSet
->setPropertyValue(u
"CharInteropGrabBag"_ustr
,
1668 uno::Any(aGrabBagMap
.getAsConstPropertyValueList()));
1673 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */