LibreOffice Module oox (master) 1
WpsContext.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10#include "WpsContext.hxx"
11#include "WpgContext.hxx"
27#include <oox/token/namespaces.hxx>
28#include <oox/token/tokens.hxx>
29#include <svx/svdoashp.hxx>
30
31#include <com/sun/star/beans/PropertyAttribute.hpp>
32#include <com/sun/star/beans/XPropertySet.hpp>
33#include <com/sun/star/beans/XPropertySetInfo.hpp>
34#include <com/sun/star/beans/XPropertyState.hpp>
35#include <com/sun/star/container/XEnumerationAccess.hpp>
36#include <com/sun/star/drawing/FillStyle.hpp>
37#include <com/sun/star/drawing/HomogenMatrix3.hpp>
38#include <com/sun/star/drawing/LineStyle.hpp>
39#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
40#include <com/sun/star/geometry/IntegerRectangle2D.hpp>
41#include <com/sun/star/lang/XServiceInfo.hpp>
42#include <com/sun/star/text/XText.hpp>
43#include <com/sun/star/text/XTextCursor.hpp>
44#include <com/sun/star/text/WritingMode.hpp>
45#include <com/sun/star/text/WritingMode2.hpp>
46
47#include <optional>
48
49using namespace com::sun::star;
50
51namespace
52{
53bool lcl_getTextPropsFromFrameText(const uno::Reference<text::XText>& xText,
54 std::vector<beans::PropertyValue>& rTextPropVec)
55{
56 if (!xText.is())
57 return false;
58 uno::Reference<text::XTextCursor> xTextCursor = xText->createTextCursor();
59 xTextCursor->gotoStart(false);
60 xTextCursor->gotoEnd(true);
61 uno::Reference<container::XEnumerationAccess> paraEnumAccess(xText, uno::UNO_QUERY);
62 if (!paraEnumAccess.is())
63 return false;
64 uno::Reference<container::XEnumeration> paraEnum(paraEnumAccess->createEnumeration());
65 while (paraEnum->hasMoreElements())
66 {
67 uno::Reference<text::XTextRange> xParagraph(paraEnum->nextElement(), uno::UNO_QUERY);
68 uno::Reference<container::XEnumerationAccess> runEnumAccess(xParagraph, uno::UNO_QUERY);
69 if (!runEnumAccess.is())
70 continue;
71 uno::Reference<container::XEnumeration> runEnum = runEnumAccess->createEnumeration();
72 while (runEnum->hasMoreElements())
73 {
74 uno::Reference<text::XTextRange> xRun(runEnum->nextElement(), uno::UNO_QUERY);
75 if (xRun->getString().isEmpty())
76 continue;
77 uno::Reference<beans::XPropertySet> xRunPropSet(xRun, uno::UNO_QUERY);
78 if (!xRunPropSet.is())
79 continue;
80 auto xRunPropSetInfo = xRunPropSet->getPropertySetInfo();
81 if (!xRunPropSetInfo.is())
82 continue;
83
84 // We have found a non-empty run. Collect its properties.
85 auto aRunPropInfoSequence = xRunPropSetInfo->getProperties();
86 for (const beans::Property& aProp : aRunPropInfoSequence)
87 {
88 rTextPropVec.push_back(comphelper::makePropertyValue(
89 aProp.Name, xRunPropSet->getPropertyValue(aProp.Name)));
90 }
91 return true;
92 }
93 }
94 return false;
95}
96
97// CharInteropGrabBag puts all attributes of an element into a property with Name="attributes" and
98// Value being a sequence of the attributes. This methods finds the value of an individual rName
99// attribute and puts it into rValue parameter. If it does not find it, rValue is unchanged and
100// the method returns false, otherwise it returns true.
101bool lcl_getAttributeAsString(const uno::Sequence<beans::PropertyValue>& aPropertyValueAsSeq,
102 const OUString& rName, OUString& rValue)
103{
104 comphelper::SequenceAsHashMap aPropertyValueAsMap(aPropertyValueAsSeq);
105 uno::Sequence<beans::PropertyValue> aAttributesSeq;
106 if (!((aPropertyValueAsMap.getValue("attributes") >>= aAttributesSeq)
107 && aAttributesSeq.hasElements()))
108 return false;
109 comphelper::SequenceAsHashMap aAttributesMap(aAttributesSeq);
110 OUString sRet;
111 if (!(aAttributesMap.getValue(rName) >>= sRet))
112 return false;
113 rValue = sRet;
114 return true;
115}
116
117// Same as above for a number as attribute value
118bool lcl_getAttributeAsNumber(const uno::Sequence<beans::PropertyValue>& rPropertyValueAsSeq,
119 const OUString& rName, sal_Int32& rValue)
120{
121 comphelper::SequenceAsHashMap aPropertyValueAsMap(rPropertyValueAsSeq);
122 uno::Sequence<beans::PropertyValue> aAttributesSeq;
123 if (!((aPropertyValueAsMap.getValue("attributes") >>= aAttributesSeq)
124 && aAttributesSeq.hasElements()))
125 return false;
126 comphelper::SequenceAsHashMap aAttributesMap(aAttributesSeq);
127 sal_Int32 nRet;
128 if (!(aAttributesMap.getValue(rName) >>= nRet))
129 return false;
130 rValue = nRet;
131 return true;
132}
133
134void lcl_getColorTransformationsFromPropSeq(const uno::Sequence<beans::PropertyValue>& rPropSeq,
135 oox::drawingml::Color& rColor)
136{
137 auto isValidPropName = [](const OUString& rName) -> bool {
138 return rName == u"tint" || rName == u"shade" || rName == u"alpha" || rName == u"hueMod"
139 || rName == u"sat" || rName == u"satOff" || rName == u"satMod" || rName == u"lum"
140 || rName == u"lumOff" || rName == u"lumMod";
141 };
142 for (auto it = rPropSeq.begin(); it < rPropSeq.end(); ++it)
143 {
144 if (isValidPropName((*it).Name))
145 {
146 uno::Sequence<beans::PropertyValue> aValueSeq;
147 sal_Int32 nNumber(0); // dummy value to make compiler happy, "val" should exist
148 if (((*it).Value >>= aValueSeq) && lcl_getAttributeAsNumber(aValueSeq, u"val", nNumber))
149 {
150 // char w14:alpha contains transparency, whereas shape fill a:alpha contains opacity.
151 if ((*it).Name == u"alpha")
152 rColor.addTransformation(
153 oox::NMSP_dml | oox::AttributeConversion::decodeToken((*it).Name),
155 else
156 rColor.addTransformation(
157 oox::NMSP_w14 | oox::AttributeConversion::decodeToken((*it).Name), nNumber);
158 }
159 }
160 }
161}
162
163// Expected: rPropSeq contains a property "schemeClr" or a property "srgbClr".
164bool lcl_getColorFromPropSeq(const uno::Sequence<beans::PropertyValue>& rPropSeq,
165 oox::drawingml::Color& rColor)
166{
167 bool bColorFound = false;
168 comphelper::SequenceAsHashMap aPropMap(rPropSeq);
169 uno::Sequence<beans::PropertyValue> aColorDetailSeq;
170 if (aPropMap.getValue(u"schemeClr") >>= aColorDetailSeq)
171 {
172 OUString sColorString;
173 bColorFound = lcl_getAttributeAsString(aColorDetailSeq, u"val", sColorString);
174 if (bColorFound)
175 {
176 sal_Int32 nColorToken = oox::AttributeConversion::decodeToken(sColorString);
177 rColor.setSchemeClr(nColorToken);
178 rColor.setSchemeName(sColorString);
179 }
180 }
181 if (!bColorFound && (aPropMap.getValue(u"srgbClr") >>= aColorDetailSeq))
182 {
183 OUString sColorString;
184 bColorFound = lcl_getAttributeAsString(aColorDetailSeq, u"val", sColorString);
185 if (bColorFound)
186 {
187 sal_Int32 nColor = oox::AttributeConversion::decodeIntegerHex(sColorString);
188 rColor.setSrgbClr(nColor);
189 }
190 }
191 // Without color, color transformations are pointless.
192 if (bColorFound)
193 lcl_getColorTransformationsFromPropSeq(aColorDetailSeq, rColor);
194 return bColorFound;
195}
196
197void lcl_getFillDetailsFromPropSeq(const uno::Sequence<beans::PropertyValue>& rTextFillSeq,
198 oox::drawingml::FillProperties& rFillProperties)
199{
200 // rTextFillSeq should have an item containing either "noFill" or "solidFill" or "gradFill"
201 // property.
202 if (!rTextFillSeq.hasElements())
203 return;
204 comphelper::SequenceAsHashMap aTextFillMap(rTextFillSeq);
205 if (aTextFillMap.find(u"noFill") != aTextFillMap.end())
206 {
207 rFillProperties.moFillType = oox::XML_noFill;
208 return;
209 }
210
211 uno::Sequence<beans::PropertyValue> aPropSeq;
212 if ((aTextFillMap.getValue(u"solidFill") >>= aPropSeq) && aPropSeq.hasElements())
213 {
214 rFillProperties.moFillType = oox::XML_solidFill;
215 lcl_getColorFromPropSeq(aPropSeq, rFillProperties.maFillColor);
216 return;
217 }
218
219 if ((aTextFillMap.getValue(u"gradFill") >>= aPropSeq) && aPropSeq.hasElements())
220 {
221 rFillProperties.moFillType = oox::XML_gradFill;
222 // aPropSeq should have two items. One is "gsLst" for the stop colors, the other is
223 // either "lin" or "path" for the kind of gradient.
224 // First get stop colors
225 comphelper::SequenceAsHashMap aPropMap(aPropSeq);
226 uno::Sequence<beans::PropertyValue> aGsLstSeq;
227 if (aPropMap.getValue("gsLst") >>= aGsLstSeq)
228 {
229 for (auto it = aGsLstSeq.begin(); it < aGsLstSeq.end(); ++it)
230 {
231 // (*it) is a bean::PropertyValue with Name="gs". Its Value is a property sequence.
232 uno::Sequence<beans::PropertyValue> aColorStopSeq;
233 if ((*it).Value >>= aColorStopSeq)
234 {
235 // aColorStopSeq should have an item for the color and an item for the position
236 sal_Int32 nPos;
238 if (lcl_getAttributeAsNumber(aColorStopSeq, u"pos", nPos)
239 && lcl_getColorFromPropSeq(aColorStopSeq, aColor))
240 {
241 // The position in maGradientStops is relative, thus in range [0.0;1.0].
242 double fPos = nPos / 100000.0;
243 rFillProperties.maGradientProps.maGradientStops.insert({ fPos, aColor });
244 }
245 }
246 }
247 }
248 // Now determine kind of gradient.
249 uno::Sequence<beans::PropertyValue> aKindSeq;
250 if (aPropMap.getValue("lin") >>= aKindSeq)
251 {
252 // aKindSeq contains the attributes "ang" and "scaled"
253 sal_Int32 nAngle; // in 1/60000 deg
254 if (lcl_getAttributeAsNumber(aKindSeq, "ang", nAngle))
255 rFillProperties.maGradientProps.moShadeAngle = nAngle;
256 OUString sScaledString;
257 if (lcl_getAttributeAsString(aKindSeq, "scaled", sScaledString))
258 rFillProperties.maGradientProps.moShadeScaled
259 = sScaledString == u"1" || sScaledString == u"true";
260 return;
261 }
262 if (aPropMap.getValue("path") >>= aKindSeq)
263 {
264 // aKindSeq contains the attribute "path" for the kind of path and a property "fillToRect"
265 // which defines the center rectangle of the gradient. The property "a:tileRect" known from
266 // fill of shapes does not exist in w14 namespace.
267 OUString sKind;
268 if (lcl_getAttributeAsString(aKindSeq, "path", sKind))
269 rFillProperties.maGradientProps.moGradientPath
271 comphelper::SequenceAsHashMap aKindMap(aKindSeq);
272 uno::Sequence<beans::PropertyValue> aFillToRectSeq;
273 if (aKindMap.getValue("fillToRect") >>= aFillToRectSeq)
274 {
275 // The values l, t, r and b are not coordinates, but determine an offset from the
276 // edge of the bounding box of the shape. This unusual meaning of X1, Y1, X2 and
277 // Y2 is needed for method pushToPropMap() of FillProperties.
278 geometry::IntegerRectangle2D aRect;
279 if (!lcl_getAttributeAsNumber(aFillToRectSeq, u"l", aRect.X1))
280 aRect.X1 = 0;
281 if (!lcl_getAttributeAsNumber(aFillToRectSeq, u"t", aRect.Y1))
282 aRect.Y1 = 0;
283 if (!lcl_getAttributeAsNumber(aFillToRectSeq, u"r", aRect.X2))
284 aRect.X2 = 0;
285 if (!lcl_getAttributeAsNumber(aFillToRectSeq, u"b", aRect.Y2))
286 aRect.Y2 = 0;
287 rFillProperties.maGradientProps.moFillToRect = aRect;
288 }
289 }
290 return;
291 }
292}
293
294void lcl_getLineDetailsFromPropSeq(const uno::Sequence<beans::PropertyValue>& rTextOutlineSeq,
295 oox::drawingml::LineProperties& rLineProperties)
296{
297 if (!rTextOutlineSeq.hasElements())
298 {
299 rLineProperties.maLineFill.moFillType = oox::XML_noFill; // MS Office default
300 return;
301 }
302 // aTextOulineSeq contains e.g. "attributes" {w, cap, cmpd, ctr}, either
303 // "solidFill" or "gradFill or "noFill", and "prstDash" and "lineJoint" properties.
304
305 // Fill
306 lcl_getFillDetailsFromPropSeq(rTextOutlineSeq, rLineProperties.maLineFill);
307
308 // LineJoint
309 comphelper::SequenceAsHashMap aTextOutlineMap(rTextOutlineSeq);
310 if (aTextOutlineMap.find(u"bevel") != aTextOutlineMap.end())
311 rLineProperties.moLineJoint = oox::XML_bevel;
312 else if (aTextOutlineMap.find(u"round") != aTextOutlineMap.end())
313 rLineProperties.moLineJoint = oox::XML_round;
314 else if (aTextOutlineMap.find(u"miter") != aTextOutlineMap.end())
315 {
316 // LineProperties has no member to store a miter limit. Therefore some heuristic is
317 // added here. 0 is default for attribute "lim" in MS Office. It is rendered same as bevel.
318 sal_Int32 nMiterLimit = aTextOutlineMap.getUnpackedValueOrDefault("lim", sal_Int32(0));
319 if (nMiterLimit == 0)
320 rLineProperties.moLineJoint = oox::XML_bevel;
321 else
322 rLineProperties.moLineJoint = oox::XML_miter;
323 }
324
325 // Dash
326 uno::Sequence<beans::PropertyValue> aDashSeq;
327 if (aTextOutlineMap.getValue(u"prstDash") >>= aDashSeq)
328 {
329 // aDashSeq contains the attribute "val" with the kind of dash, e.g. "sysDot"
330 OUString sDashKind;
331 if (lcl_getAttributeAsString(aDashSeq, u"val", sDashKind))
332 rLineProperties.moPresetDash = oox::AttributeConversion::decodeToken(sDashKind);
333 }
334 OUString sCapKind;
335 if (lcl_getAttributeAsString(rTextOutlineSeq, u"cap", sCapKind))
336 rLineProperties.moLineCap = oox::AttributeConversion::decodeToken(sCapKind);
337
338 // Width
339 sal_Int32 nWidth; // EMU
340 if (lcl_getAttributeAsNumber(rTextOutlineSeq, u"w", nWidth))
341 rLineProperties.moLineWidth = nWidth;
342
343 // Compound. LineProperties has a member for it, however Fontwork can currently only render "sng".
344 OUString sCompoundKind;
345 if (lcl_getAttributeAsString(rTextOutlineSeq, u"cmpd", sCompoundKind))
346 rLineProperties.moLineCompound = oox::AttributeConversion::decodeToken(sCompoundKind);
347
348 // Align. LineProperties has no member for attribute "algn".
349
350 return;
351}
352
354lcl_generateLinePropertiesFromTextProps(const comphelper::SequenceAsHashMap& aTextPropMap)
355{
356 oox::drawingml::LineProperties aLineProperties;
357 aLineProperties.maLineFill.moFillType = oox::XML_noFill; // default
358
359 // Get property "textOutline" from aTextPropMap
360 uno::Sequence<beans::PropertyValue> aCharInteropGrabBagSeq;
361 if (!(aTextPropMap.getValue(u"CharInteropGrabBag") >>= aCharInteropGrabBagSeq))
362 return aLineProperties;
363 if (!aCharInteropGrabBagSeq.hasElements())
364 return aLineProperties;
365 comphelper::SequenceAsHashMap aCharInteropGrabBagMap(aCharInteropGrabBagSeq);
366 beans::PropertyValue aProp;
367 if (!(aCharInteropGrabBagMap.getValue(u"CharTextOutlineTextEffect") >>= aProp))
368 return aLineProperties;
369 uno::Sequence<beans::PropertyValue> aTextOutlineSeq;
370 if (!(aProp.Name == "textOutline" && (aProp.Value >>= aTextOutlineSeq)
371 && aTextOutlineSeq.hasElements()))
372 return aLineProperties;
373
374 // Copy line properties from aTextOutlineSeq to aLineProperties
375 lcl_getLineDetailsFromPropSeq(aTextOutlineSeq, aLineProperties);
376 return aLineProperties;
377}
378
380lcl_generateFillPropertiesFromTextProps(const comphelper::SequenceAsHashMap& rTextPropMap)
381{
382 oox::drawingml::FillProperties aFillProperties;
383 aFillProperties.moFillType = oox::XML_solidFill; // default
384 // Theme color supersedes direct color. textFill supersedes theme color. Theme color and textFill
385 // are in CharInteropGrabBag.
386 uno::Sequence<beans::PropertyValue> aCharInteropGrabBagSeq;
387 if ((rTextPropMap.getValue(u"CharInteropGrabBag") >>= aCharInteropGrabBagSeq)
388 && aCharInteropGrabBagSeq.hasElements())
389 {
390 // Handle case textFill
391 comphelper::SequenceAsHashMap aCharInteropGrabBagMap(aCharInteropGrabBagSeq);
392 beans::PropertyValue aProp;
393 if (aCharInteropGrabBagMap.getValue(u"CharTextFillTextEffect") >>= aProp)
394 {
395 uno::Sequence<beans::PropertyValue> aTextFillSeq;
396 if (aProp.Name == "textFill" && (aProp.Value >>= aTextFillSeq)
397 && aTextFillSeq.hasElements())
398 {
399 // Copy fill properties from aTextFillSeq to aFillProperties
400 lcl_getFillDetailsFromPropSeq(aTextFillSeq, aFillProperties);
401 return aFillProperties;
402 }
403 }
404
405 // no textFill, look for theme color, tint and shade
406 bool bColorFound(false);
407 OUString sColorString;
408 if (aCharInteropGrabBagMap.getValue("CharThemeOriginalColor") >>= sColorString)
409 {
410 sal_Int32 nThemeOrigColor = oox::AttributeConversion::decodeIntegerHex(sColorString);
411 aFillProperties.maFillColor.setSrgbClr(nThemeOrigColor);
412 bColorFound = true;
413 }
414 if (aCharInteropGrabBagMap.getValue("CharThemeColor") >>= sColorString)
415 {
416 sal_Int32 nColorToken = oox::AttributeConversion::decodeToken(sColorString);
417 aFillProperties.maFillColor.setSchemeClr(nColorToken);
418 aFillProperties.maFillColor.setSchemeName(sColorString);
419 bColorFound = true;
420 // A character color has shade or tint, a shape color has lumMod and lumOff.
421 OUString sTransformString;
422 if (aCharInteropGrabBagMap.getValue("CharThemeColorTint") >>= sTransformString)
423 {
424 double fTint = oox::AttributeConversion::decodeIntegerHex(sTransformString);
425 fTint = fTint / 255.0 * oox::drawingml::MAX_PERCENT;
426 aFillProperties.maFillColor.addTransformation(OOX_TOKEN(w14, lumMod),
427 static_cast<sal_Int32>(fTint + 0.5));
428 double fOff = oox::drawingml::MAX_PERCENT - fTint;
429 aFillProperties.maFillColor.addTransformation(OOX_TOKEN(w14, lumOff),
430 static_cast<sal_Int32>(fOff + 0.5));
431 }
432 else if (aCharInteropGrabBagMap.getValue("CharThemeColorShade") >>= sTransformString)
433 {
434 double fShade = oox::AttributeConversion::decodeIntegerHex(sTransformString);
435 fShade = fShade / 255.0 * oox::drawingml::MAX_PERCENT;
436 aFillProperties.maFillColor.addTransformation(OOX_TOKEN(w14, lumMod),
437 static_cast<sal_Int32>(fShade + 0.5));
438 }
439 }
440 if (bColorFound)
441 return aFillProperties;
442 }
443
444 // Neither textFill nor theme color. Look for direct color.
445 sal_Int32 aCharColor = 0;
446 if (rTextPropMap.getValue(u"CharColor") >>= aCharColor)
447 aFillProperties.maFillColor.setSrgbClr(aCharColor);
448 else
449 aFillProperties.maFillColor.setUnused();
450 return aFillProperties;
451}
452
453void lcl_applyShapePropsToShape(const uno::Reference<beans::XPropertySet>& xShapePropertySet,
454 const oox::drawingml::ShapePropertyMap& rShapeProps)
455{
456 for (const auto& rProp : rShapeProps.makePropertyValueSequence())
457 {
458 xShapePropertySet->setPropertyValue(rProp.Name, rProp.Value);
459 }
460}
461
462void lcl_setTextAnchorFromTextProps(const uno::Reference<beans::XPropertySet>& xShapePropertySet,
463 const comphelper::SequenceAsHashMap& aTextPropMap)
464{
465 // Fontwork does not evaluate paragraph alignment but uses text anchor instead
466 auto eHorzAdjust(drawing::TextHorizontalAdjust_CENTER);
467 sal_Int16 nParaAlign = sal_Int16(drawing::TextHorizontalAdjust_CENTER);
468 aTextPropMap.getValue("ParaAdjust") >>= nParaAlign;
469 switch (nParaAlign)
470 {
471 case sal_Int16(style::ParagraphAdjust_LEFT):
472 eHorzAdjust = drawing::TextHorizontalAdjust_LEFT;
473 break;
474 case sal_Int16(style::ParagraphAdjust_RIGHT):
475 eHorzAdjust = drawing::TextHorizontalAdjust_RIGHT;
476 break;
477 default:
478 eHorzAdjust = drawing::TextHorizontalAdjust_CENTER;
479 }
480 xShapePropertySet->setPropertyValue("TextHorizontalAdjust", uno::Any(eHorzAdjust));
481 xShapePropertySet->setPropertyValue("TextVerticalAdjust",
482 uno::Any(drawing::TextVerticalAdjust_TOP));
483}
484
485void lcl_setTextPropsToShape(const uno::Reference<beans::XPropertySet>& xShapePropertySet,
486 std::vector<beans::PropertyValue>& aTextPropVec)
487{
488 auto xShapePropertySetInfo = xShapePropertySet->getPropertySetInfo();
489 if (!xShapePropertySetInfo.is())
490 return;
491 for (size_t i = 0; i < aTextPropVec.size(); ++i)
492 {
493 if (xShapePropertySetInfo->hasPropertyByName(aTextPropVec[i].Name)
494 && !(xShapePropertySetInfo->getPropertyByName(aTextPropVec[i].Name).Attributes
495 & beans::PropertyAttribute::READONLY)
496 && aTextPropVec[i].Name != u"CharInteropGrabBag")
497 {
498 xShapePropertySet->setPropertyValue(aTextPropVec[i].Name, aTextPropVec[i].Value);
499 }
500 }
501}
502
503void lcl_applyUsedTextPropsToAllTextRuns(uno::Reference<text::XText>& xText,
504 const std::vector<beans::PropertyValue>& aTextPropVec)
505{
506 if (!xText.is())
507 return;
508 uno::Reference<text::XTextCursor> xTextCursor = xText->createTextCursor();
509 xTextCursor->gotoStart(false);
510 xTextCursor->gotoEnd(true);
511 uno::Reference<container::XEnumerationAccess> paraEnumAccess(xText, uno::UNO_QUERY);
512 if (!paraEnumAccess.is())
513 return;
514 uno::Reference<container::XEnumeration> paraEnum(paraEnumAccess->createEnumeration());
515 while (paraEnum->hasMoreElements())
516 {
517 uno::Reference<text::XTextRange> xParagraph(paraEnum->nextElement(), uno::UNO_QUERY);
518 uno::Reference<container::XEnumerationAccess> runEnumAccess(xParagraph, uno::UNO_QUERY);
519 if (!runEnumAccess.is())
520 continue;
521 uno::Reference<container::XEnumeration> runEnum = runEnumAccess->createEnumeration();
522 while (runEnum->hasMoreElements())
523 {
524 uno::Reference<text::XTextRange> xRun(runEnum->nextElement(), uno::UNO_QUERY);
525 if (xRun->getString().isEmpty())
526 continue;
527 uno::Reference<beans::XPropertySet> xRunPropSet(xRun, uno::UNO_QUERY);
528 if (!xRunPropSet.is())
529 continue;
530 auto xRunPropSetInfo = xRunPropSet->getPropertySetInfo();
531 if (!xRunPropSetInfo.is())
532 continue;
533
534 for (size_t i = 0; i < aTextPropVec.size(); ++i)
535 {
536 if (xRunPropSetInfo->hasPropertyByName(aTextPropVec[i].Name)
537 && !(xRunPropSetInfo->getPropertyByName(aTextPropVec[i].Name).Attributes
538 & beans::PropertyAttribute::READONLY))
539 xRunPropSet->setPropertyValue(aTextPropVec[i].Name, aTextPropVec[i].Value);
540 }
541 }
542 }
543}
544} // anonymous namespace
545
546namespace oox::shape
547{
548WpsContext::WpsContext(ContextHandler2Helper const& rParent, uno::Reference<drawing::XShape> xShape,
549 const drawingml::ShapePtr& pMasterShapePtr,
550 const drawingml::ShapePtr& pShapePtr)
551 : ShapeContext(rParent, pMasterShapePtr, pShapePtr)
552 , mxShape(std::move(xShape))
553{
554 if (mpShapePtr)
555 mpShapePtr->setWps(true);
556
557 if (const auto pParent = dynamic_cast<const WpgContext*>(&rParent))
558 m_bHasWPGParent = pParent->isFullWPGSupport();
559 else
560 m_bHasWPGParent = false;
561}
562
563WpsContext::~WpsContext() = default;
564
566 const oox::AttributeList& rAttribs)
567{
568 switch (getBaseToken(nElementToken))
569 {
570 case XML_wsp:
571 case XML_cNvCnPr:
572 break;
573 case XML_bodyPr:
574 if (mxShape.is())
575 {
576 // no evaluation of attribute XML_rot, because Word ignores it, as of 2022-07.
577
578 uno::Reference<lang::XServiceInfo> xServiceInfo(mxShape, uno::UNO_QUERY);
579 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
580 sal_Int32 nVert = rAttribs.getToken(XML_vert, XML_horz);
581 // Values 'wordArtVert' and 'wordArtVertRtl' are not implemented.
582 // Map them to other vert values.
583 if (nVert == XML_eaVert || nVert == XML_wordArtVertRtl)
584 {
585 xPropertySet->setPropertyValue("TextWritingMode",
586 uno::Any(text::WritingMode_TB_RL));
587 xPropertySet->setPropertyValue("WritingMode",
588 uno::Any(text::WritingMode2::TB_RL));
589 }
590 else if (nVert == XML_mongolianVert || nVert == XML_wordArtVert)
591 {
592 xPropertySet->setPropertyValue("WritingMode",
593 uno::Any(text::WritingMode2::TB_LR));
594 }
595 else if (nVert != XML_horz) // cases XML_vert and XML_vert270
596 {
597 // Hack to get same rendering as after the fix for tdf#87924. If shape rotation
598 // plus text direction results in upright text, use horizontal text direction.
599 // Remove hack when frame is able to rotate.
600
601 // Need transformation matrix since RotateAngle does not contain flip.
602 drawing::HomogenMatrix3 aMatrix;
603 xPropertySet->getPropertyValue("Transformation") >>= aMatrix;
604 basegfx::B2DHomMatrix aTransformation;
605 aTransformation.set(0, 0, aMatrix.Line1.Column1);
606 aTransformation.set(0, 1, aMatrix.Line1.Column2);
607 aTransformation.set(0, 2, aMatrix.Line1.Column3);
608 aTransformation.set(1, 0, aMatrix.Line2.Column1);
609 aTransformation.set(1, 1, aMatrix.Line2.Column2);
610 aTransformation.set(1, 2, aMatrix.Line2.Column3);
611 aTransformation.set(2, 0, aMatrix.Line3.Column1);
612 aTransformation.set(2, 1, aMatrix.Line3.Column2);
613 aTransformation.set(2, 2, aMatrix.Line3.Column3);
614 basegfx::B2DTuple aScale;
615 basegfx::B2DTuple aTranslate;
616 double fRotate = 0;
617 double fShearX = 0;
618 aTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
619 auto nRotate(static_cast<sal_uInt16>(NormAngle360(basegfx::rad2deg(fRotate))));
620 if ((nVert == XML_vert && nRotate == 270)
621 || (nVert == XML_vert270 && nRotate == 90))
622 {
623 xPropertySet->setPropertyValue("WritingMode",
624 uno::Any(text::WritingMode2::LR_TB));
625 // ToDo: Remember original vert value and remove hack on export.
626 }
627 else if (nVert == XML_vert)
628 xPropertySet->setPropertyValue("WritingMode",
629 uno::Any(text::WritingMode2::TB_RL90));
630 else // nVert == XML_vert270
631 xPropertySet->setPropertyValue("WritingMode",
632 uno::Any(text::WritingMode2::BT_LR));
633 }
634
635 if (bool bUpright = rAttribs.getBool(XML_upright, false))
636 {
637 uno::Sequence<beans::PropertyValue> aGrabBag;
638 xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
639 sal_Int32 length = aGrabBag.getLength();
640 aGrabBag.realloc(length + 1);
641 auto pGrabBag = aGrabBag.getArray();
642 pGrabBag[length].Name = "Upright";
643 pGrabBag[length].Value <<= bUpright;
644 xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag));
645 }
646
647 if (xServiceInfo.is())
648 {
649 // Handle inset attributes for Writer textframes.
650 sal_Int32 aInsets[] = { XML_lIns, XML_tIns, XML_rIns, XML_bIns };
651 std::optional<sal_Int32> oInsets[4];
652 for (std::size_t i = 0; i < SAL_N_ELEMENTS(aInsets); ++i)
653 {
654 std::optional<OUString> oValue = rAttribs.getString(aInsets[i]);
655 if (oValue.has_value())
656 oInsets[i] = oox::drawingml::GetCoordinate(oValue.value());
657 else
658 // Defaults from the spec: left/right: 91440 EMU, top/bottom: 45720 EMU
659 oInsets[i]
660 = (aInsets[i] == XML_lIns || aInsets[i] == XML_rIns) ? 254 : 127;
661 }
662 const OUString aShapeProps[]
663 = { OUString("TextLeftDistance"), OUString("TextUpperDistance"),
664 OUString("TextRightDistance"), OUString("TextLowerDistance") };
665 for (std::size_t i = 0; i < SAL_N_ELEMENTS(aShapeProps); ++i)
666 if (oInsets[i])
667 xPropertySet->setPropertyValue(aShapeProps[i], uno::Any(*oInsets[i]));
668 }
669
670 // Handle text vertical adjustment inside a text frame
671 if (rAttribs.hasAttribute(XML_anchor))
672 {
673 drawing::TextVerticalAdjust eAdjust
674 = drawingml::GetTextVerticalAdjust(rAttribs.getToken(XML_anchor, XML_t));
675 xPropertySet->setPropertyValue("TextVerticalAdjust", uno::Any(eAdjust));
676 }
677
678 // Apply character color of the shape to the shape's textbox.
679 uno::Reference<text::XText> xText(mxShape, uno::UNO_QUERY);
680 uno::Any xCharColor = xPropertySet->getPropertyValue("CharColor");
681 Color aColor = COL_AUTO;
682 if ((xCharColor >>= aColor) && aColor != COL_AUTO)
683 {
684 // tdf#135923 Apply character color of the shape to the textrun
685 // when the character color of the textrun is default.
686 // tdf#153791 But only if the run has no background color (shd element in OOXML)
687 if (uno::Reference<container::XEnumerationAccess> paraEnumAccess{
688 xText, uno::UNO_QUERY })
689 {
690 uno::Reference<container::XEnumeration> paraEnum(
691 paraEnumAccess->createEnumeration());
692
693 while (paraEnum->hasMoreElements())
694 {
695 uno::Reference<text::XTextRange> xParagraph(paraEnum->nextElement(),
696 uno::UNO_QUERY);
697 uno::Reference<container::XEnumerationAccess> runEnumAccess(
698 xParagraph, uno::UNO_QUERY);
699 if (!runEnumAccess.is())
700 continue;
701 if (uno::Reference<beans::XPropertySet> xParaPropSet{ xParagraph,
702 uno::UNO_QUERY })
703 if ((xParaPropSet->getPropertyValue("ParaBackColor") >>= aColor)
704 && aColor != COL_AUTO)
705 continue;
706
707 uno::Reference<container::XEnumeration> runEnum
708 = runEnumAccess->createEnumeration();
709
710 while (runEnum->hasMoreElements())
711 {
712 uno::Reference<text::XTextRange> xRun(runEnum->nextElement(),
713 uno::UNO_QUERY);
714 const uno::Reference<beans::XPropertyState> xRunState(
715 xRun, uno::UNO_QUERY);
716 if (!xRunState
717 || xRunState->getPropertyState("CharColor")
718 == beans::PropertyState_DEFAULT_VALUE)
719 {
720 uno::Reference<beans::XPropertySet> xRunPropSet(xRun,
721 uno::UNO_QUERY);
722 if (!xRunPropSet)
723 continue;
724 if ((xRunPropSet->getPropertyValue("CharBackColor") >>= aColor)
725 && aColor != COL_AUTO)
726 continue;
727 if (!(xRunPropSet->getPropertyValue("CharColor") >>= aColor)
728 || aColor == COL_AUTO)
729 xRunPropSet->setPropertyValue("CharColor", xCharColor);
730 }
731 }
732 }
733 }
734 }
735
736 auto nWrappingType = rAttribs.getToken(XML_wrap, XML_square);
737 xPropertySet->setPropertyValue("TextWordWrap",
738 uno::Any(nWrappingType == XML_square));
739
740 return this;
741 }
742 else if (m_bHasWPGParent && mpShapePtr)
743 {
744 // this WPS context has to be inside a WPG shape, so the <BodyPr> element
745 // cannot be applied to mxShape member, use mpShape instead, and after the
746 // the parent shape finished, apply it for its children.
747 mpShapePtr->setWPGChild(true);
749 pTextBody.reset(new oox::drawingml::TextBody());
750
751 if (rAttribs.hasAttribute(XML_anchor))
752 {
753 drawing::TextVerticalAdjust eAdjust
754 = drawingml::GetTextVerticalAdjust(rAttribs.getToken(XML_anchor, XML_t));
755 pTextBody->getTextProperties().meVA = eAdjust;
756 }
757
758 sal_Int32 aInsets[] = { XML_lIns, XML_tIns, XML_rIns, XML_bIns };
759 for (int i = 0; i < 4; ++i)
760 {
761 if (rAttribs.hasAttribute(XML_lIns))
762 {
763 std::optional<OUString> oValue = rAttribs.getString(aInsets[i]);
764 if (oValue.has_value())
765 pTextBody->getTextProperties().moInsets[i]
766 = oox::drawingml::GetCoordinate(oValue.value());
767 else
768 // Defaults from the spec: left/right: 91440 EMU, top/bottom: 45720 EMU
769 pTextBody->getTextProperties().moInsets[i]
770 = (aInsets[i] == XML_lIns || aInsets[i] == XML_rIns) ? 254 : 127;
771 }
772 }
773
774 mpShapePtr->setTextBody(pTextBody);
775 }
776 break;
777 case XML_noAutofit:
778 case XML_spAutoFit:
779 {
780 uno::Reference<lang::XServiceInfo> xServiceInfo(mxShape, uno::UNO_QUERY);
781 // We can't use oox::drawingml::TextBodyPropertiesContext here, as this
782 // is a child context of bodyPr, so the shape is already sent: we need
783 // to alter the XShape directly.
784 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
785 if (xPropertySet.is())
786 {
787 if (xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
788 xPropertySet->setPropertyValue(
789 "FrameIsAutomaticHeight",
790 uno::Any(getBaseToken(nElementToken) == XML_spAutoFit));
791 else
792 xPropertySet->setPropertyValue(
793 "TextAutoGrowHeight",
794 uno::Any(getBaseToken(nElementToken) == XML_spAutoFit));
795 }
796 }
797 break;
798 case XML_prstTxWarp:
799 if (rAttribs.hasAttribute(XML_prst))
800 {
801 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
802 if (xPropertySet.is())
803 {
804 std::optional<OUString> presetShapeName = rAttribs.getString(XML_prst);
805 const OUString& preset = presetShapeName.value();
806 comphelper::SequenceAsHashMap aCustomShapeGeometry(
807 xPropertySet->getPropertyValue("CustomShapeGeometry"));
808 aCustomShapeGeometry["PresetTextWarp"] <<= preset;
809 xPropertySet->setPropertyValue(
810 "CustomShapeGeometry",
811 uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList()));
812 }
813 }
815 *this, rAttribs, *(getShape()->getCustomShapeProperties()));
816 case XML_txbx:
817 {
818 mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
819 mpShapePtr->setTextBox(true);
820 //in case if the textbox is linked, save the attributes
821 //for further processing.
822 if (rAttribs.hasAttribute(XML_id))
823 {
824 std::optional<OUString> id = rAttribs.getString(XML_id);
825 if (id.has_value())
826 {
827 oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr;
828 linkedTxtBoxAttr.id = id.value().toInt32();
829 mpShapePtr->setTxbxHasLinkedTxtBox(true);
830 mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr);
831 }
832 }
833 return this;
834 }
835 break;
836 case XML_linkedTxbx:
837 {
838 //in case if the textbox is linked, save the attributes
839 //for further processing.
840 mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
841 mpShapePtr->setTextBox(true);
842 std::optional<OUString> id = rAttribs.getString(XML_id);
843 std::optional<OUString> seq = rAttribs.getString(XML_seq);
844 if (id.has_value() && seq.has_value())
845 {
846 oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr;
847 linkedTxtBoxAttr.id = id.value().toInt32();
848 linkedTxtBoxAttr.seq = seq.value().toInt32();
849 mpShapePtr->setTxbxHasLinkedTxtBox(true);
850 mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr);
851 }
852 }
853 break;
854 default:
855 return ShapeContext::onCreateContext(nElementToken, rAttribs);
856 }
857 return nullptr;
858}
859
861{
862 // Convert shape to Fontwork shape if necessary and meaningful.
863 // Only at end of bodyPr all needed info is available.
864
865 if (getBaseToken(getCurrentElement()) != XML_bodyPr)
866 return;
867
868 // Make sure all needed parts are available
869 auto* pCustomShape
871 if (!pCustomShape || !mpShapePtr || !mxShape.is())
872 return;
873 uno::Reference<beans::XPropertySet> xShapePropertySet(mxShape, uno::UNO_QUERY);
874 if (!xShapePropertySet.is())
875 return;
876 // This is the text in the frame, associated with the shape
877 uno::Reference<text::XText> xText(mxShape, uno::UNO_QUERY);
878 if (!xText.is())
879 return;
880
881 OUString sMSPresetType;
882 comphelper::SequenceAsHashMap aCustomShapeGeometry(
883 xShapePropertySet->getPropertyValue("CustomShapeGeometry"));
884 aCustomShapeGeometry["PresetTextWarp"] >>= sMSPresetType;
885 if (sMSPresetType.isEmpty() || sMSPresetType == u"textNoShape")
886 return;
887
888 // Word can combine its "abc Transform" with a lot of shape types. LibreOffice can only render
889 // the old kind WordArt, which is based on a rectangle. In case of non rectangular shape we keep
890 // the shape and do not convert the text to Fontwork.
891 OUString sType;
892 aCustomShapeGeometry["Type"] >>= sType;
893 if (sType != u"ooxml-rect")
894 return;
895
896 // Copy properties from frame text to have them available after the frame is removed.
897 std::vector<beans::PropertyValue> aTextPropVec;
898 if (!lcl_getTextPropsFromFrameText(xText, aTextPropVec))
899 return;
901
902 // Copy text content from frame to shape. Since Fontwork uses simple text anyway, we can use
903 // a string.
904 OUString sFrameContent(xText->getString());
905 pCustomShape->NbcSetText(sFrameContent);
906
907 // Setting the property "TextBox" to false includes removing the attached frame from the shape.
908 xShapePropertySet->setPropertyValue("TextBox", uno::Any(false));
909
910 // Set the shape into text path mode, so that the text is drawn as Fontwork. Word renders a legacy
911 // "text on path" without the legacy stretching, therefore use false for bFromWordArt.
912 mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
914 sMSPresetType, /*bFromWordArt*/ false);
915
916 // Apply the text props to the fontwork shape
917 lcl_setTextPropsToShape(xShapePropertySet, aTextPropVec); // includes e.g. FontName
918 lcl_setTextAnchorFromTextProps(xShapePropertySet, aTextPropMap);
919
920 // Fontwork in LO uses fill and stroke of the shape and cannot style text portions individually.
921 // "abc Transform" in Word uses fill and outline of the characters.
922 // We need to copy the properties from a run to the shape.
923 oox::drawingml::ShapePropertyMap aStrokeShapeProps(getFilter().getModelObjectHelper());
924 oox::drawingml::LineProperties aCreatedLineProperties
925 = lcl_generateLinePropertiesFromTextProps(aTextPropMap);
926 aCreatedLineProperties.pushToPropMap(aStrokeShapeProps, getFilter().getGraphicHelper());
927 lcl_applyShapePropsToShape(xShapePropertySet, aStrokeShapeProps);
928
929 oox::drawingml::ShapePropertyMap aFillShapeProps(getFilter().getModelObjectHelper());
930 oox::drawingml::FillProperties aCreatedFillProperties
931 = lcl_generateFillPropertiesFromTextProps(aTextPropMap);
932 aCreatedFillProperties.pushToPropMap(aFillShapeProps, getFilter().getGraphicHelper(),
933 /*nShapeRotation*/ 0,
934 /*nPhClr*/ API_RGB_TRANSPARENT, /*nPhClrTheme*/ -1,
935 pCustomShape->IsMirroredX(), pCustomShape->IsMirroredY(),
936 /*bIsCustomShape*/ true);
937 lcl_applyShapePropsToShape(xShapePropertySet, aFillShapeProps);
938
939 // Copying the text content from frame to shape as string has lost the styles. Apply the used text
940 // properties back to all runs in the text.
941 uno::Reference<text::XText> xNewText(pCustomShape->getUnoShape(), uno::UNO_QUERY);
942 if (xNewText.is())
943 lcl_applyUsedTextPropsToAllTextRuns(xNewText, aTextPropVec);
944
945 // Fontwork stretches the text to the given path. So adapt shape size to text is nonsensical.
946 xShapePropertySet->setPropertyValue("TextAutoGrowHeight", uno::Any(false));
947 xShapePropertySet->setPropertyValue("TextAutoGrowWidth", uno::Any(false));
948}
949}
950
951/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
css::uno::Any getValue(const OUString &sKey) const
css::uno::Sequence< css::beans::PropertyValue > getAsConstPropertyValueList() const
static sal_Int32 decodeIntegerHex(std::u16string_view rValue)
Returns the 32-bit signed integer value from the passed string (hexadecimal).
static sal_Int32 decodeToken(std::u16string_view rValue)
Returns the XML token identifier from the passed string.
Provides access to attribute values of an element.
bool hasAttribute(sal_Int32 nAttrToken) const
Returns true, if the specified attribute is present.
std::optional< OUString > getString(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute.
std::optional< bool > getBool(sal_Int32 nAttrToken) const
Returns the boolean value of the specified attribute.
std::optional< sal_Int32 > getToken(sal_Int32 nAttrToken) const
Returns the token identifier of the value of the specified attribute.
css::uno::Sequence< css::beans::PropertyValue > makePropertyValueSequence() const
Returns a sequence of property values, filled with all contained properties.
XmlFilterBase & getFilter() const
Returns the filter instance.
void addTransformation(sal_Int32 nElement, sal_Int32 nValue=-1)
Inserts the passed color transformation.
Definition: color.cxx:327
void setSchemeClr(sal_Int32 nToken)
Sets a scheme color from the a:schemeClr element.
Definition: color.cxx:305
void setUnused()
Sets the color to unused state.
Definition: color.cxx:250
void setSchemeName(const OUString &sSchemeName)
Sets the scheme name from the a:schemeClr element for interoperability purposes.
Definition: color.hxx:66
void setSrgbClr(sal_Int32 nRgb)
Sets an RGB value (hexadecimal RRGGBB) from the a:srgbClr element.
Definition: color.cxx:260
virtual ::oox::core::ContextHandlerRef onCreateContext(::sal_Int32 Element, const ::oox::AttributeList &rAttribs) override
const ShapePtr & getShape() const
Wpg is the drawingML equivalent of v:group.
Definition: WpgContext.hxx:20
oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElementToken, const oox::AttributeList &rAttribs) override
Definition: WpsContext.cxx:565
WpsContext(oox::core::ContextHandler2Helper const &rParent, css::uno::Reference< css::drawing::XShape > xShape, oox::drawingml::ShapePtr const &pMasterShapePtr, oox::drawingml::ShapePtr const &pShapePtr)
Definition: WpsContext.cxx:548
virtual void onEndElement() override
Definition: WpsContext.cxx:860
css::uno::Reference< css::drawing::XShape > mxShape
Definition: WpsContext.hxx:39
constexpr ::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
float u
T NormAngle360(T angle)
sal_uInt16 nPos
#define SAL_N_ELEMENTS(arr)
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...
constexpr double rad2deg(double v)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
TextVerticalAdjust GetTextVerticalAdjust(sal_Int32 nToken)
sal_Int32 GetCoordinate(sal_Int32 nValue)
converts EMUs into 1/100th mmm
std::shared_ptr< Shape > ShapePtr
const sal_Int32 MAX_PERCENT
std::shared_ptr< TextBody > TextBodyPtr
const ::Color API_RGB_TRANSPARENT(ColorTransparency, 0xffffffff)
Transparent color for API calls.
uno::Reference< drawing::XShape > const mxShape
void pushToPropMap(ShapePropertyMap &rPropMap, const GraphicHelper &rGraphicHelper, sal_Int32 nShapeRotation=0, ::Color nPhClr=API_RGB_TRANSPARENT, sal_Int16 nPhClrTheme=-1, bool bFlipH=false, bool bFlipV=false, bool bIsCustomShape=false) const
Writes the properties to the passed property map.
GradientFillProperties maGradientProps
Whether the background is used as fill type.
Color maFillColor
Fill type (OOXML token).
std::optional< sal_Int32 > moFillType
std::optional< css::geometry::IntegerRectangle2D > moFillToRect
Gradient stops (colors/transparence).
std::optional< sal_Int32 > moGradientPath
std::optional< bool > moShadeScaled
Flip mode of gradient, if not stretched to shape.
std::optional< sal_Int32 > moShadeAngle
If set, gradient follows rectangle, circle, or shape.
FillProperties maLineFill
End line arrow style.
std::optional< sal_Int32 > moLineCompound
Preset dash (OOXML token).
std::optional< sal_Int32 > moLineCap
Line compound type (OOXML token).
std::optional< sal_Int32 > moLineWidth
User-defined line dash style.
void pushToPropMap(ShapePropertyMap &rPropMap, const GraphicHelper &rGraphicHelper, ::Color nPhClr=API_RGB_TRANSPARENT, sal_Int16 nPhClrTheme=-1) const
Writes the properties to the passed property map.
std::optional< sal_Int32 > moLineJoint
Line cap (OOXML token).
std::optional< sal_Int32 > moPresetDash
Line width (EMUs).
Attributes for a linked textbox.
Definition: shape.hxx:101