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"
15 #include <com/sun/star/beans/XPropertySet.hpp>
16 #include <com/sun/star/beans/XPropertyState.hpp>
17 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
18 #include <com/sun/star/lang/XServiceInfo.hpp>
19 #include <com/sun/star/text/XText.hpp>
20 #include <com/sun/star/text/XTextCursor.hpp>
21 #include <com/sun/star/text/WritingMode.hpp>
22 #include <svx/svdtrans.hxx>
24 #include <oox/token/namespaces.hxx>
25 #include <oox/token/tokens.hxx>
26 #include <oox/drawingml/shape.hxx>
27 
28 #include <optional>
29 
30 using namespace com::sun::star;
31 
32 namespace oox::shape
33 {
34 WpsContext::WpsContext(ContextHandler2Helper const& rParent, uno::Reference<drawing::XShape> xShape,
35  const drawingml::ShapePtr& pMasterShapePtr,
36  const drawingml::ShapePtr& pShapePtr)
37  : ShapeContext(rParent, pMasterShapePtr, pShapePtr)
38  , mxShape(std::move(xShape))
39 {
40  if (mpShapePtr)
41  mpShapePtr->setWps(true);
42 }
43 
44 WpsContext::~WpsContext() = default;
45 
47  const oox::AttributeList& rAttribs)
48 {
49  switch (getBaseToken(nElementToken))
50  {
51  case XML_wsp:
52  case XML_cNvCnPr:
53  break;
54  case XML_bodyPr:
55  if (mxShape.is())
56  {
57  uno::Reference<lang::XServiceInfo> xServiceInfo(mxShape, uno::UNO_QUERY);
58  uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
59  sal_Int32 nVert = rAttribs.getToken(XML_vert, XML_horz);
60  if (nVert == XML_eaVert)
61  {
62  xPropertySet->setPropertyValue("TextWritingMode",
63  uno::makeAny(text::WritingMode_TB_RL));
64  }
65  else if (nVert != XML_horz)
66  {
67  // Get the existing rotation of the shape.
68  drawing::HomogenMatrix3 aMatrix;
69  xPropertySet->getPropertyValue("Transformation") >>= aMatrix;
70  basegfx::B2DHomMatrix aTransformation;
71  aTransformation.set(0, 0, aMatrix.Line1.Column1);
72  aTransformation.set(0, 1, aMatrix.Line1.Column2);
73  aTransformation.set(0, 2, aMatrix.Line1.Column3);
74  aTransformation.set(1, 0, aMatrix.Line1.Column1);
75  aTransformation.set(1, 1, aMatrix.Line2.Column2);
76  aTransformation.set(1, 2, aMatrix.Line3.Column3);
77  aTransformation.set(2, 0, aMatrix.Line1.Column1);
78  aTransformation.set(2, 1, aMatrix.Line2.Column2);
79  aTransformation.set(2, 2, aMatrix.Line3.Column3);
80  basegfx::B2DTuple aScale;
81  basegfx::B2DTuple aTranslate;
82  double fRotate = 0;
83  double fShearX = 0;
84  aTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
85 
86  // If the text is not rotated the way the shape wants it already, set the angle.
87  const sal_Int32 nRotation = nVert == XML_vert270 ? -270 : -90;
88  if (static_cast<sal_Int32>(basegfx::rad2deg(fRotate))
89  != NormAngle36000(Degree100(nRotation * 100)).get() / 100)
90  {
91  comphelper::SequenceAsHashMap aCustomShapeGeometry(
92  xPropertySet->getPropertyValue("CustomShapeGeometry"));
93  aCustomShapeGeometry["TextPreRotateAngle"] <<= nRotation;
94  xPropertySet->setPropertyValue(
95  "CustomShapeGeometry",
96  uno::makeAny(aCustomShapeGeometry.getAsConstPropertyValueList()));
97  }
98  }
99 
100  if (bool bUpright = rAttribs.getBool(XML_upright, false))
101  {
102  uno::Sequence<beans::PropertyValue> aGrabBag;
103  xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
104  sal_Int32 length = aGrabBag.getLength();
105  aGrabBag.realloc(length + 1);
106  aGrabBag[length].Name = "Upright";
107  aGrabBag[length].Value <<= bUpright;
108  xPropertySet->setPropertyValue("InteropGrabBag", uno::makeAny(aGrabBag));
109  }
110 
111  if (xServiceInfo.is())
112  {
113  // Handle inset attributes for Writer textframes.
114  sal_Int32 aInsets[] = { XML_lIns, XML_tIns, XML_rIns, XML_bIns };
115  std::optional<sal_Int32> oInsets[4];
116  for (std::size_t i = 0; i < SAL_N_ELEMENTS(aInsets); ++i)
117  {
118  OptValue<OUString> oValue = rAttribs.getString(aInsets[i]);
119  if (oValue.has())
120  oInsets[i] = oox::drawingml::GetCoordinate(oValue.get());
121  else
122  // Defaults from the spec: left/right: 91440 EMU, top/bottom: 45720 EMU
123  oInsets[i]
124  = (aInsets[i] == XML_lIns || aInsets[i] == XML_rIns) ? 254 : 127;
125  }
126  const OUString aShapeProps[]
127  = { OUString("TextLeftDistance"), OUString("TextUpperDistance"),
128  OUString("TextRightDistance"), OUString("TextLowerDistance") };
129  for (std::size_t i = 0; i < SAL_N_ELEMENTS(aShapeProps); ++i)
130  if (oInsets[i])
131  xPropertySet->setPropertyValue(aShapeProps[i],
132  uno::makeAny(*oInsets[i]));
133  }
134 
135  // Handle text vertical adjustment inside a text frame
136  if (rAttribs.hasAttribute(XML_anchor))
137  {
138  drawing::TextVerticalAdjust eAdjust
139  = drawingml::GetTextVerticalAdjust(rAttribs.getToken(XML_anchor, XML_t));
140  xPropertySet->setPropertyValue("TextVerticalAdjust", uno::makeAny(eAdjust));
141  }
142 
143  // Apply character color of the shape to the shape's textbox.
144  uno::Reference<text::XText> xText(mxShape, uno::UNO_QUERY);
145  uno::Reference<text::XTextCursor> xTextCursor = xText->createTextCursor();
146  xTextCursor->gotoStart(false);
147  xTextCursor->gotoEnd(true);
148  const uno::Reference<beans::XPropertyState> xPropertyState(xTextCursor,
149  uno::UNO_QUERY);
150  const beans::PropertyState ePropertyState
151  = xPropertyState->getPropertyState("CharColor");
152  if (ePropertyState == beans::PropertyState_DEFAULT_VALUE)
153  {
154  uno::Reference<beans::XPropertySet> xTextBoxPropertySet(xTextCursor,
155  uno::UNO_QUERY);
156  uno::Any xCharColor = xPropertySet->getPropertyValue("CharColor");
157  Color aColor = COL_AUTO;
158  if (xCharColor >>= aColor)
159  {
160  if (aColor != COL_AUTO)
161  xTextBoxPropertySet->setPropertyValue("CharColor", xCharColor);
162  }
163  }
164 
165  auto nWrappingType = rAttribs.getToken(XML_wrap, XML_square);
166  xPropertySet->setPropertyValue("TextWordWrap",
167  uno::makeAny(nWrappingType == XML_square));
168 
169  return this;
170  }
171  break;
172  case XML_noAutofit:
173  case XML_spAutoFit:
174  {
175  uno::Reference<lang::XServiceInfo> xServiceInfo(mxShape, uno::UNO_QUERY);
176  // We can't use oox::drawingml::TextBodyPropertiesContext here, as this
177  // is a child context of bodyPr, so the shape is already sent: we need
178  // to alter the XShape directly.
179  uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
180  if (xPropertySet.is())
181  {
182  if (xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
183  xPropertySet->setPropertyValue(
184  "FrameIsAutomaticHeight",
185  uno::makeAny(getBaseToken(nElementToken) == XML_spAutoFit));
186  else
187  xPropertySet->setPropertyValue(
188  "TextAutoGrowHeight",
189  uno::makeAny(getBaseToken(nElementToken) == XML_spAutoFit));
190  }
191  }
192  break;
193  case XML_prstTxWarp:
194  if (rAttribs.hasAttribute(XML_prst))
195  {
196  uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
197  if (xPropertySet.is())
198  {
199  oox::OptValue<OUString> presetShapeName = rAttribs.getString(XML_prst);
200  const OUString& preset = presetShapeName.get();
201  comphelper::SequenceAsHashMap aCustomShapeGeometry(
202  xPropertySet->getPropertyValue("CustomShapeGeometry"));
203  aCustomShapeGeometry["PresetTextWarp"] <<= preset;
204  xPropertySet->setPropertyValue(
205  "CustomShapeGeometry",
206  uno::makeAny(aCustomShapeGeometry.getAsConstPropertyValueList()));
207  }
208  }
209  break;
210  case XML_txbx:
211  {
212  mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
213  mpShapePtr->setTextBox(true);
214  //in case if the textbox is linked, save the attributes
215  //for further processing.
216  if (rAttribs.hasAttribute(XML_id))
217  {
218  OptValue<OUString> id = rAttribs.getString(XML_id);
219  if (id.has())
220  {
221  oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr;
222  linkedTxtBoxAttr.id = id.get().toInt32();
223  mpShapePtr->setTxbxHasLinkedTxtBox(true);
224  mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr);
225  }
226  }
227  return this;
228  }
229  break;
230  case XML_linkedTxbx:
231  {
232  //in case if the textbox is linked, save the attributes
233  //for further processing.
234  mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
235  mpShapePtr->setTextBox(true);
236  OptValue<OUString> id = rAttribs.getString(XML_id);
237  OptValue<OUString> seq = rAttribs.getString(XML_seq);
238  if (id.has() && seq.has())
239  {
240  oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr;
241  linkedTxtBoxAttr.id = id.get().toInt32();
242  linkedTxtBoxAttr.seq = seq.get().toInt32();
243  mpShapePtr->setTxbxHasLinkedTxtBox(true);
244  mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr);
245  }
246  }
247  break;
248  default:
249  return ShapeContext::onCreateContext(nElementToken, rAttribs);
250  }
251  return nullptr;
252 }
253 }
254 
255 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
OptValue< bool > getBool(sal_Int32 nAttrToken) const
Returns the boolean value of the specified attribute.
TextVerticalAdjust GetTextVerticalAdjust(sal_Int32 nToken)
constexpr::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
OptValue< OUString > getString(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute.
constexpr double rad2deg(double v)
uno::Reference< drawing::XShape > const mxShape
css::uno::Reference< css::drawing::XShape > mxShape
Definition: WpsContext.hxx:38
bool hasAttribute(sal_Int32 nAttrToken) const
Returns true, if the specified attribute is present.
const Type & get() const
Definition: helper.hxx:185
Degree100 NormAngle36000(Degree100 deg100)
#define SAL_N_ELEMENTS(arr)
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
Attributes for a linked textbox.
Definition: shape.hxx:96
Provides access to attribute values of an element.
virtual ::oox::core::ContextHandlerRef onCreateContext(::sal_Int32 Element, const ::oox::AttributeList &rAttribs) override
sal_Int32 GetCoordinate(sal_Int32 nValue)
converts EMUs into 1/100th mmm
std::shared_ptr< Shape > ShapePtr
Helper class that provides a context stack.
bool has() const
Definition: helper.hxx:181
oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElementToken, const oox::AttributeList &rAttribs) override
Will be called to create a context handler for the passed element.
Definition: WpsContext.cxx:46
OptValue< sal_Int32 > getToken(sal_Int32 nAttrToken) const
Returns the token identifier of the value of the specified attribute.