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