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