tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / oox / source / drawingml / fontworkhelpers.cxx
blob565f6b6c7b889fc8d93b7acb0be0433944035d72
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
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>
59 #include <array>
60 #include <map>
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")
81 return;
83 uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY);
84 if (!xDefaulter.is())
85 return;
87 uno::Reference<beans::XPropertySet> xSet(xShape, uno::UNO_QUERY);
88 if (!xSet.is())
89 return;
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();
99 int nIndex = 0;
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);
119 else
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"))
138 fValue *= 0.108;
140 else
142 fValue *= 0.216;
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>>();
155 auto aGeomPropVec
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);
172 bool bScaleX(false);
173 if (!bFromWordArt
174 && (sMSPresetType == u"textArchDown" || sMSPresetType == u"textArchUp"
175 || sMSPresetType == u"textCircle" || sMSPresetType == u"textButton"))
177 bScaleX = true;
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
201 // does not work.
203 static const std::map<MSO_SPT, OString> aTypeToMarkupMap{
204 { mso_sptTextSimple,
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>" },
232 { mso_sptTextCurve,
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>" },
241 { mso_sptTextWave,
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>" },
264 { mso_sptTextRing,
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>" },
291 { mso_sptTextOnRing,
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>" },
319 { mso_sptTextStop,
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\" "
430 "adj=\"11796480\" "
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>" },
566 { mso_sptTextWave1,
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>" },
589 { mso_sptTextWave2,
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>" },
612 { mso_sptTextWave3,
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>" },
639 { mso_sptTextWave4,
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>" },
763 { mso_sptTextFadeUp,
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>" },
799 { mso_sptTextCanUp,
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)
826 if (!rXText.is())
827 return;
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())
833 return;
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())
840 continue;
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())
846 continue;
847 uno::Reference<beans::XPropertySet> xRunPropSet(xRun, uno::UNO_QUERY);
848 if (!xRunPropSet.is())
849 continue;
850 auto xRunPropSetInfo = xRunPropSet->getPropertySetInfo();
851 if (!xRunPropSetInfo.is())
852 continue;
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)));
864 return;
869 void FontworkHelpers::applyPropsToRuns(const std::vector<beans::PropertyValue>& rTextPropVec,
870 uno::Reference<text::XText>& rXText)
872 if (!rXText.is())
873 return;
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())
879 return;
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())
886 continue;
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())
893 continue;
894 auto xRunPropSetInfo = xRunPropSet->getPropertySetInfo();
895 if (!xRunPropSetInfo.is())
896 continue;
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);
911 namespace
913 constexpr const std::array<std::u16string_view, 5> aCharPropNames{
914 u"CharColorLumMod", u"CharColorLumOff", u"CharColorTheme", u"CharComplexColor",
915 u"CharTransparence"
918 constexpr const std::array<std::u16string_view, 5> aShapePropNames{
919 u"FillColorLumMod", u"FillColorLumOff", u"FillColorTheme", u"FillComplexColor",
920 u"FillTransparence"
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())
930 return;
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)
972 nDistance -= 99;
973 nDotLen += 99;
974 if (nDashLen > 0)
975 nDashLen += 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.
980 if (nDotLen == 0)
981 nDotLen = 100;
982 if (nDashLen == 0 && rLineDash.Dashes > 0)
983 nDashLen = 100;
985 bIsConverted = true;
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";
1006 else
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())
1018 return false;
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();
1026 return false;
1029 namespace
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
1038 ::Color RGBColor;
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;
1047 namespace
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());
1083 auto bItemFound
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())
1087 return false;
1088 rValue = (*pIt).mnValue;
1089 return true;
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)
1099 return;
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();
1110 break;
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();
1117 break;
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();
1127 break;
1128 default: // other child elements can be added later if needed for Fontwork
1129 break;
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;
1141 rbHasColorGradient
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();
1185 else
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();
1208 else
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);
1241 if (nAlpha < 10000)
1242 aNextStopColor.TTColor.addTransformation({ model::TransformationType::Alpha, nAlpha });
1243 sal_Int32 nPosition
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 });
1256 return aColorMap;
1258 } // end namespace
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())
1266 return;
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;
1288 switch (eFillStyle)
1290 case drawing::FillStyle_NONE:
1292 pGrabBagStack->appendElement(u"noFill"_ustr, uno::Any());
1293 break;
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'
1322 else
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
1339 // Kind of gradient
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);
1363 else
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);
1375 else
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
1390 break;
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,
1398 aComplexColor))
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
1407 // maybe 'lumOff'
1409 else
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
1432 break;
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.
1436 break;
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));
1447 // attributes
1448 pGrabBagStack->push(u"attributes"_ustr);
1449 // line width
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);
1454 // cap for dashes
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)
1460 sCap = u"rnd"_ustr;
1461 else if (eLineCap == drawing::LineCap_SQUARE)
1462 sCap = u"sq"_ustr;
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'
1470 // style
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());
1480 else
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,
1486 aComplexColor))
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'
1526 // prstDash
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);
1539 else
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))
1583 // CharThemeColor
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;
1594 sal_Int16 nLumMod;
1595 if (lcl_getThemeColorTransformationValue(aComplexColor, model::TransformationType::LumMod,
1596 nLumMod))
1598 sal_Int16 nLumOff;
1599 bool bIsTint = lcl_getThemeColorTransformationValue(
1600 aComplexColor, model::TransformationType::LumOff, nLumOff)
1601 && nLumOff != 0;
1602 sal_uInt8 nValue
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)
1629 if (!rXText.is())
1630 return;
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())
1636 return;
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())
1643 continue;
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())
1649 continue;
1650 uno::Reference<beans::XPropertySet> xRunPropSet(xRun, uno::UNO_QUERY);
1651 if (!xRunPropSet.is())
1652 continue;
1653 auto xRunPropSetInfo = xRunPropSet->getPropertySetInfo();
1654 if (!xRunPropSetInfo.is())
1655 continue;
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: */