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  auto pGrabBag = aGrabBag.getArray();
107  pGrabBag[length].Name = "Upright";
108  pGrabBag[length].Value <<= bUpright;
109  xPropertySet->setPropertyValue("InteropGrabBag", uno::makeAny(aGrabBag));
110  }
111 
112  if (xServiceInfo.is())
113  {
114  // Handle inset attributes for Writer textframes.
115  sal_Int32 aInsets[] = { XML_lIns, XML_tIns, XML_rIns, XML_bIns };
116  std::optional<sal_Int32> oInsets[4];
117  for (std::size_t i = 0; i < SAL_N_ELEMENTS(aInsets); ++i)
118  {
119  OptValue<OUString> oValue = rAttribs.getString(aInsets[i]);
120  if (oValue.has())
121  oInsets[i] = oox::drawingml::GetCoordinate(oValue.get());
122  else
123  // Defaults from the spec: left/right: 91440 EMU, top/bottom: 45720 EMU
124  oInsets[i]
125  = (aInsets[i] == XML_lIns || aInsets[i] == XML_rIns) ? 254 : 127;
126  }
127  const OUString aShapeProps[]
128  = { OUString("TextLeftDistance"), OUString("TextUpperDistance"),
129  OUString("TextRightDistance"), OUString("TextLowerDistance") };
130  for (std::size_t i = 0; i < SAL_N_ELEMENTS(aShapeProps); ++i)
131  if (oInsets[i])
132  xPropertySet->setPropertyValue(aShapeProps[i],
133  uno::makeAny(*oInsets[i]));
134  }
135 
136  // Handle text vertical adjustment inside a text frame
137  if (rAttribs.hasAttribute(XML_anchor))
138  {
139  drawing::TextVerticalAdjust eAdjust
140  = drawingml::GetTextVerticalAdjust(rAttribs.getToken(XML_anchor, XML_t));
141  xPropertySet->setPropertyValue("TextVerticalAdjust", uno::makeAny(eAdjust));
142  }
143 
144  // Apply character color of the shape to the shape's textbox.
145  uno::Reference<text::XText> xText(mxShape, uno::UNO_QUERY);
146  uno::Reference<text::XTextCursor> xTextCursor = xText->createTextCursor();
147  xTextCursor->gotoStart(false);
148  xTextCursor->gotoEnd(true);
149  const uno::Reference<beans::XPropertyState> xPropertyState(xTextCursor,
150  uno::UNO_QUERY);
151  const beans::PropertyState ePropertyState
152  = xPropertyState->getPropertyState("CharColor");
153  if (ePropertyState == beans::PropertyState_DEFAULT_VALUE)
154  {
155  uno::Reference<beans::XPropertySet> xTextBoxPropertySet(xTextCursor,
156  uno::UNO_QUERY);
157  uno::Any xCharColor = xPropertySet->getPropertyValue("CharColor");
158  Color aColor = COL_AUTO;
159  if (xCharColor >>= aColor)
160  {
161  if (aColor != COL_AUTO)
162  xTextBoxPropertySet->setPropertyValue("CharColor", xCharColor);
163  }
164  }
165 
166  auto nWrappingType = rAttribs.getToken(XML_wrap, XML_square);
167  xPropertySet->setPropertyValue("TextWordWrap",
168  uno::makeAny(nWrappingType == XML_square));
169 
170  return this;
171  }
172  break;
173  case XML_noAutofit:
174  case XML_spAutoFit:
175  {
176  uno::Reference<lang::XServiceInfo> xServiceInfo(mxShape, uno::UNO_QUERY);
177  // We can't use oox::drawingml::TextBodyPropertiesContext here, as this
178  // is a child context of bodyPr, so the shape is already sent: we need
179  // to alter the XShape directly.
180  uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
181  if (xPropertySet.is())
182  {
183  if (xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
184  xPropertySet->setPropertyValue(
185  "FrameIsAutomaticHeight",
186  uno::makeAny(getBaseToken(nElementToken) == XML_spAutoFit));
187  else
188  xPropertySet->setPropertyValue(
189  "TextAutoGrowHeight",
190  uno::makeAny(getBaseToken(nElementToken) == XML_spAutoFit));
191  }
192  }
193  break;
194  case XML_prstTxWarp:
195  if (rAttribs.hasAttribute(XML_prst))
196  {
197  uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
198  if (xPropertySet.is())
199  {
200  oox::OptValue<OUString> presetShapeName = rAttribs.getString(XML_prst);
201  const OUString& preset = presetShapeName.get();
202  comphelper::SequenceAsHashMap aCustomShapeGeometry(
203  xPropertySet->getPropertyValue("CustomShapeGeometry"));
204  aCustomShapeGeometry["PresetTextWarp"] <<= preset;
205  xPropertySet->setPropertyValue(
206  "CustomShapeGeometry",
207  uno::makeAny(aCustomShapeGeometry.getAsConstPropertyValueList()));
208  }
209  }
210  break;
211  case XML_txbx:
212  {
213  mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
214  mpShapePtr->setTextBox(true);
215  //in case if the textbox is linked, save the attributes
216  //for further processing.
217  if (rAttribs.hasAttribute(XML_id))
218  {
219  OptValue<OUString> id = rAttribs.getString(XML_id);
220  if (id.has())
221  {
222  oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr;
223  linkedTxtBoxAttr.id = id.get().toInt32();
224  mpShapePtr->setTxbxHasLinkedTxtBox(true);
225  mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr);
226  }
227  }
228  return this;
229  }
230  break;
231  case XML_linkedTxbx:
232  {
233  //in case if the textbox is linked, save the attributes
234  //for further processing.
235  mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true);
236  mpShapePtr->setTextBox(true);
237  OptValue<OUString> id = rAttribs.getString(XML_id);
238  OptValue<OUString> seq = rAttribs.getString(XML_seq);
239  if (id.has() && seq.has())
240  {
241  oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr;
242  linkedTxtBoxAttr.id = id.get().toInt32();
243  linkedTxtBoxAttr.seq = seq.get().toInt32();
244  mpShapePtr->setTxbxHasLinkedTxtBox(true);
245  mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr);
246  }
247  }
248  break;
249  default:
250  return ShapeContext::onCreateContext(nElementToken, rAttribs);
251  }
252  return nullptr;
253 }
254 }
255 
256 /* 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)
constexpr double rad2deg(double v)
OptValue< OUString > getString(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute.
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
#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
Degree100 NormAngle36000(Degree100 a)
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.