LibreOffice Module sw (master)  1
docxsdrexport.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 "docxsdrexport.hxx"
11 #include <com/sun/star/beans/XPropertySet.hpp>
12 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
13 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
14 #include <editeng/lrspitem.hxx>
15 #include <editeng/ulspitem.hxx>
16 #include <editeng/unoprnms.hxx>
17 #include <editeng/shaditem.hxx>
18 #include <editeng/opaqitem.hxx>
19 #include <editeng/boxitem.hxx>
20 #include <svx/svdoashp.hxx>
21 #include <svx/svdogrp.hxx>
22 #include <svx/svdopath.hxx>
23 #include <svx/svdobjkind.hxx>
24 #include <svx/svditer.hxx>
26 #include <oox/token/namespaces.hxx>
28 #include <textboxhelper.hxx>
29 #include <fmtanchr.hxx>
30 #include <fmtsrnd.hxx>
31 #include <fmtcntnt.hxx>
32 #include <fmtornt.hxx>
33 #include <fmtfsize.hxx>
34 #include <fmtfollowtextflow.hxx>
35 #include <frmatr.hxx>
37 #include "docxattributeoutput.hxx"
38 #include "docxexportfilter.hxx"
39 #include <comphelper/flagguard.hxx>
40 #include <comphelper/sequence.hxx>
42 #include <sal/log.hxx>
43 #include <frmfmt.hxx>
45 
46 #include <tools/diagnose_ex.h>
47 #include <svx/xlnwtit.hxx>
48 #include <svx/svdtrans.hxx>
50 
51 using namespace com::sun::star;
52 using namespace oox;
53 using namespace sax_fastparser;
54 
55 namespace
56 {
57 uno::Sequence<beans::PropertyValue> lclGetProperty(const uno::Reference<drawing::XShape>& rShape,
58  const OUString& rPropName)
59 {
60  uno::Sequence<beans::PropertyValue> aResult;
61  uno::Reference<beans::XPropertySet> xPropertySet(rShape, uno::UNO_QUERY);
62  uno::Reference<beans::XPropertySetInfo> xPropSetInfo;
63 
64  if (!xPropertySet.is())
65  return aResult;
66 
67  xPropSetInfo = xPropertySet->getPropertySetInfo();
68  if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(rPropName))
69  {
70  xPropertySet->getPropertyValue(rPropName) >>= aResult;
71  }
72  return aResult;
73 }
74 
75 OUString lclGetAnchorIdFromGrabBag(const SdrObject* pObj)
76 {
77  OUString aResult;
78  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(pObj)->getUnoShape(),
79  uno::UNO_QUERY);
80  OUString aGrabBagName;
81  uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
82  if (xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
83  aGrabBagName = "FrameInteropGrabBag";
84  else
85  aGrabBagName = "InteropGrabBag";
86  uno::Sequence<beans::PropertyValue> propList = lclGetProperty(xShape, aGrabBagName);
87  auto pProp
88  = std::find_if(propList.begin(), propList.end(),
89  [](const beans::PropertyValue& rProp) { return rProp.Name == "AnchorId"; });
90  if (pProp != propList.end())
91  pProp->Value >>= aResult;
92  return aResult;
93 }
94 
95 void lclMovePositionWithRotation(awt::Point& aPos, const Size& rSize, Degree100 nRotation100)
96 {
97  // code from ImplEESdrWriter::ImplFlipBoundingBox (filter/source/msfilter/eschesdo.cxx)
98  // TODO: refactor
99  // MSO uses left|top of the unrotated object rectangle as position. When you rotate that rectangle
100  // around its center and build a snap rectangle S from it, then left|top of S has to be the
101  // position used in LO. This method converts LOs aPos to the position used by MSO.
102 
103  // rSize has to be size of the logicRect of the object. For calculating the diff, we build a
104  // rectangle with left|top A = (-fWidthHalf | -fHeightHalf) and
105  // right|top B = (fWidthHalf | -fHeightHalf). The rotation matrix R is here
106  // fcos fsin
107  // -fsin fcos
108  // Left of rectangle S = X-coord of R * A, Top of rectangle S = Y-coord of R * B
109 
110  // Use nRotation in [0;9000], for to have only one and not four cases.
111  if (nRotation100 == 0_deg100)
112  return;
113  sal_Int64 nRotation = nRotation100.get();
114  if (nRotation < 0)
115  nRotation = (36000 + nRotation) % 36000;
116  if (nRotation % 18000 == 0)
117  nRotation = 0; // prevents endless loop
118  while (nRotation > 9000)
119  nRotation = (18000 - (nRotation % 18000));
120 
121  double fVal = static_cast<double>(nRotation) * F_PI18000;
122  double fCos = (nRotation == 9000) ? 0.0 : cos(fVal);
123  double fSin = sin(fVal);
124 
125  double fWidthHalf = static_cast<double>(rSize.Width()) / 2.0;
126  double fHeightHalf = static_cast<double>(rSize.Height()) / 2.0;
127 
128  double fXDiff = fSin * fHeightHalf + fCos * fWidthHalf - fWidthHalf;
129  double fYDiff = fSin * fWidthHalf + fCos * fHeightHalf - fHeightHalf;
130 
131  aPos.X += fXDiff + 0.5;
132  aPos.Y += fYDiff + 0.5;
133 }
134 
136 bool IsAnchorTypeInsideParagraph(const ww8::Frame* pFrame)
137 {
138  const SwFormatAnchor& rAnchor = pFrame->GetFrameFormat().GetAttrSet().GetAnchor();
139  return rAnchor.GetAnchorId() != RndStdIds::FLY_AT_PAGE;
140 }
141 
142 bool lcl_IsRotateAngleValid(const SdrObject& rObj)
143 {
144  // Some shape types report a rotation angle but are not actually rotated, because all rotation
145  // have been incorporated.
146  switch (rObj.GetObjIdentifier())
147  {
148  case OBJ_GRUP:
149  case OBJ_LINE:
150  case OBJ_PLIN:
151  case OBJ_PATHLINE:
152  case OBJ_PATHFILL:
153  return false;
154  default:
155  return true;
156  }
157 }
158 
159 void lcl_calculateMSOBaseRectangle(const SdrObject& rObj, double& rfMSOLeft, double& rfMSORight,
160  double& rfMSOTop, double& rfMSOBottom,
161  const bool bIsWord2007Image)
162 {
163  // Word rotates around shape center, LO around left/top. Thus logic rectangle of LO is not
164  // directly usable as 'base rectangle'.
165  double fCenterX = (rObj.GetSnapRect().Left() + rObj.GetSnapRect().Right()) / 2.0;
166  double fCenterY = (rObj.GetSnapRect().Top() + rObj.GetSnapRect().Bottom()) / 2.0;
167  double fHalfWidth = rObj.GetLogicRect().getWidth() / 2.0;
168  double fHalfHeight = rObj.GetLogicRect().getHeight() / 2.0;
169 
170  // MSO swaps width and height depending on rotation angle; exception: Word 2007 (vers 12) never
171  // swaps width and height for images.
172  double fRotation
173  = lcl_IsRotateAngleValid(rObj) ? toDegrees(NormAngle36000(rObj.GetRotateAngle())) : 0.0;
174  if (((fRotation > 45.0 && fRotation <= 135.0) || (fRotation > 225.0 && fRotation <= 315.0))
175  && !bIsWord2007Image)
176  {
177  rfMSOLeft = fCenterX - fHalfHeight;
178  rfMSORight = fCenterX + fHalfHeight;
179  rfMSOTop = fCenterY - fHalfWidth;
180  rfMSOBottom = fCenterY + fHalfWidth;
181  }
182  else
183  {
184  rfMSOLeft = fCenterX - fHalfWidth;
185  rfMSORight = fCenterX + fHalfWidth;
186  rfMSOTop = fCenterY - fHalfHeight;
187  rfMSOBottom = fCenterY + fHalfHeight;
188  }
189 }
190 
191 void lcl_calculateRawEffectExtent(sal_Int32& rLeft, sal_Int32& rTop, sal_Int32& rRight,
192  sal_Int32& rBottom, const SdrObject& rObj,
193  const bool bUseBoundRect, const bool bIsWord2007Image)
194 {
195  // This method calculates the extent needed, to let Word use the same outer area for the object
196  // as LO. Word uses as 'base rectangle' the unrotated shape rectangle, maybe having swapped width
197  // and height depending on rotation angle and version of Word.
198  double fMSOLeft;
199  double fMSORight;
200  double fMSOTop;
201  double fMSOBottom;
202  lcl_calculateMSOBaseRectangle(rObj, fMSOLeft, fMSORight, fMSOTop, fMSOBottom, bIsWord2007Image);
203 
204  tools::Rectangle aLORect = bUseBoundRect ? rObj.GetCurrentBoundRect() : rObj.GetSnapRect();
205  rLeft = fMSOLeft - aLORect.Left();
206  rRight = aLORect.Right() - fMSORight;
207  rTop = fMSOTop - aLORect.Top();
208  rBottom = aLORect.Bottom() - fMSOBottom;
209  // Result values might be negative, e.g for a custom shape 'Arc'.
210  return;
211 }
212 
213 bool lcl_makeSingleDistAndEffectExtentNonNegative(sal_Int64& rDist, sal_Int32& rExt)
214 {
215  // A negative effectExtent is allowed in OOXML, but Word cannot handle it (bug in Word). It
216  // might occur, if the BoundRect in LO is smaller than the base rect in Word.
217  // A negative wrap distance from text is allowed in ODF. LO can currently only handle left and
218  // right negative values, see bug tdf#141880. Dist must be non-negative in OOXML.
219  // We try to compensate Dist vs effectExtent to get similar visual appearance.
220  if (rExt >= 0 && rDist >= 0)
221  return true;
222  if (rExt < 0 && rDist < 0)
223  {
224  rExt = 0;
225  rDist = 0;
226  return false;
227  }
228  if (rDist + static_cast<sal_Int64>(rExt) < 0) // different sign, so no overflow
229  {
230  rExt = 0;
231  rDist = 0;
232  return false;
233  }
234  // rDist + rExt >= 0
235  if (rDist < 0)
236  {
237  rExt += rDist;
238  rDist = 0;
239  }
240  else // rExt < 0
241  {
242  rDist += rExt;
243  rExt = 0;
244  }
245  return true;
246 }
247 
248 bool lcl_makeDistAndExtentNonNegative(sal_Int64& rDistT, sal_Int64& rDistB, sal_Int64& rDistL,
249  sal_Int64& rDistR, sal_Int32& rLeftExt, sal_Int32& rTopExt,
250  sal_Int32& rRightExt, sal_Int32& rBottomExt)
251 {
252  bool bLeft = lcl_makeSingleDistAndEffectExtentNonNegative(rDistL, rLeftExt);
253  bool bTop = lcl_makeSingleDistAndEffectExtentNonNegative(rDistT, rTopExt);
254  bool bRight = lcl_makeSingleDistAndEffectExtentNonNegative(rDistR, rRightExt);
255  bool bBottom = lcl_makeSingleDistAndEffectExtentNonNegative(rDistB, rBottomExt);
256  return bLeft && bTop && bRight && bBottom;
257 }
258 
259 void lcl_makeSingleDistZeroAndExtentNonNegative(sal_Int64& rDist, sal_Int32& rExt)
260 {
261  if (static_cast<double>(rDist) + static_cast<double>(rExt)
262  >= static_cast<double>(SAL_MAX_INT32))
263  rExt = SAL_MAX_INT32;
264  else if (static_cast<double>(rDist) + static_cast<double>(rExt) <= 0)
265  rExt = 0;
266  else // 0 < rDist + rExt < SAL_MAX_INT32
267  {
268  rExt = static_cast<sal_Int32>(rDist + rExt);
269  if (rExt < 0)
270  rExt = 0;
271  }
272  rDist = 0;
273 }
274 
275 void lcl_makeDistZeroAndExtentNonNegative(sal_Int64& rDistT, sal_Int64& rDistB, sal_Int64& rDistL,
276  sal_Int64& rDistR, sal_Int32& rLeftExt,
277  sal_Int32& rTopExt, sal_Int32& rRightExt,
278  sal_Int32& rBottomExt)
279 {
280  lcl_makeSingleDistZeroAndExtentNonNegative(rDistL, rLeftExt);
281  lcl_makeSingleDistZeroAndExtentNonNegative(rDistT, rTopExt);
282  lcl_makeSingleDistZeroAndExtentNonNegative(rDistR, rRightExt);
283  lcl_makeSingleDistZeroAndExtentNonNegative(rDistB, rBottomExt);
284 }
285 
286 tools::Polygon lcl_CreateContourPolygon(SdrObject* pSdrObj)
287 {
288  tools::Polygon aContour;
289  if (!pSdrObj)
290  {
291  // use rectangular default
292  aContour.Insert(0, Point(0, 0));
293  aContour.Insert(1, Point(21600, 0));
294  aContour.Insert(2, Point(21600, 21600));
295  aContour.Insert(3, Point(0, 21600));
296  aContour.Insert(4, Point(0, 0));
297  return aContour;
298  }
299 
300  // Simple version for now: Use ready PolygonFromPolyPolygon().
301  // For that we first create a B2DPolyPolygon from the shape, that ideally contains
302  // the outline of the shape.
303  basegfx::B2DPolyPolygon aPolyPolygon;
304  switch (pSdrObj->GetObjIdentifier())
305  {
306  case OBJ_CUSTOMSHAPE:
307  {
308  // EnhancedCustomShapeEngine::GetLineGeometry() is not directly usable, because the wrap
309  // polygon acts on the untransformed shape in Word. We do here similar as in
310  // GetLineGeometry(), but without transformations.
311  EnhancedCustomShape2d aCustomShape2d(*static_cast<SdrObjCustomShape*>(pSdrObj));
312  SdrObjectUniquePtr pLineGeometryObj = aCustomShape2d.CreateLineGeometry();
313  if (!pLineGeometryObj)
314  break;
315 
316  // We might have got other object kinds than SdrPathObj, even groups.
317  SdrObjListIter aIter(*pLineGeometryObj, SdrIterMode::DeepWithGroups);
318  while (aIter.IsMore())
319  {
321  const SdrObject* pNext = aIter.Next();
322  if (auto pPathObj = dynamic_cast<const SdrPathObj*>(pNext))
323  aPP = pPathObj->GetPathPoly();
324  else
325  {
326  SdrObjectUniquePtr pNewObj = pLineGeometryObj->ConvertToPolyObj(false, false);
327  SdrPathObj* pPath = dynamic_cast<SdrPathObj*>(pNewObj.get());
328  if (pPath)
329  aPP = pPath->GetPathPoly();
330  }
331  if (aPP.count())
332  aPolyPolygon.append(aPP);
333  }
334 
335  if (!aPolyPolygon.count())
336  break;
337 
338  // Make relative to range 0..21600, 0..21600
339  Point aCenter(pSdrObj->GetSnapRect().Center());
340  basegfx::B2DHomMatrix aTranslateToOrigin(
341  basegfx::utils::createTranslateB2DHomMatrix(-aCenter.X(), -aCenter.Y()));
342  aPolyPolygon.transform(aTranslateToOrigin);
343  const double fWidth(pSdrObj->GetLogicRect().getWidth());
344  double fScaleX = fWidth == 0.0 ? 1.0 : 21600.0 / fWidth;
345  const double fHeight(pSdrObj->GetLogicRect().getHeight());
346  double fScaleY = fHeight == 0.0 ? 1.0 : 21600.0 / fHeight;
348  aPolyPolygon.transform(aScale);
349 
350  // ToDo: In some cases (see ShapeExport::WriteCustomShape()) flip is suppressed when
351  // calling WriteShapeTransformation(), because the path in custGeom contains already
352  // flipped coordinates. In such cases the wrap polygon needs to contain flipped
353  // coordinates too. That is missing here.
354 
355  // "moon" and "msp-spt89" (up-right-arrow) are currently mirrored horizontally. But
356  // that is removed on export in shapes.cxx. So need to remove it in wrap polygon too.
357  uno::Reference<drawing::XShape> xShape(pSdrObj->getUnoShape(), uno::UNO_QUERY);
358  uno::Reference<beans::XPropertySet> xProps(xShape, uno::UNO_QUERY);
359  comphelper::SequenceAsHashMap aCustomShapeGeometry(
360  xProps->getPropertyValue("CustomShapeGeometry"));
361  auto it = aCustomShapeGeometry.find("Type");
362  if (it != aCustomShapeGeometry.end()
363  && (aCustomShapeGeometry["Type"].get<OUString>() == "moon"
364  || aCustomShapeGeometry["Type"].get<OUString>() == "mso-spt89"))
365  {
367  aPolyPolygon.transform(aFlipH);
368  }
369 
370  basegfx::B2DHomMatrix aTranslateToCenter(
372  aPolyPolygon.transform(aTranslateToCenter);
373  break;
374  } // end case OBJ_CUSTOMSHAPE
375  case OBJ_LINE:
376  {
377  aContour.Insert(0, Point(0, 0));
378  aContour.Insert(1, Point(21600, 21600));
379  aContour.Insert(2, Point(0, 0));
380  return aContour;
381  }
382  case OBJ_PATHFILL:
383  case OBJ_PATHLINE:
384  case OBJ_FREEFILL:
385  case OBJ_FREELINE:
386  case OBJ_PATHPOLY:
387  case OBJ_PATHPLIN:
388  // case OBJ_POLY: FixMe: Creating wrap polygon would work, but export to DML is currently
389  // case OBJ_PLIN: disabled for unknown reason; related bug 75254.
390  {
391  // Includes removing any control points
392  SdrObjectUniquePtr pNewObj = pSdrObj->ConvertToPolyObj(false, false);
393  SdrPathObj* pConverted = dynamic_cast<SdrPathObj*>(pNewObj.get());
394  if (!pConverted)
395  break;
396  aPolyPolygon = pConverted->GetPathPoly();
397  pNewObj.reset();
398 
399  // Word adds a line from last to first point. That will cut of indentations from being
400  // filled. To prevent this, the wrap polygon is lead along the path back to the first
401  // point and so indentation is kept.
402  if (!aPolyPolygon.isClosed())
403  {
404  basegfx::B2DPolyPolygon aReverse(aPolyPolygon);
405  aReverse.flip();
406  aPolyPolygon.append(aReverse);
407  }
408 
409  // Make relative to range 0..21600, 0..21600
410  Point aCenter(pSdrObj->GetSnapRect().Center());
411  basegfx::B2DHomMatrix aTranslateToOrigin(
412  basegfx::utils::createTranslateB2DHomMatrix(-aCenter.X(), -aCenter.Y()));
413  aPolyPolygon.transform(aTranslateToOrigin);
414 
415  const double fWidth(pSdrObj->GetLogicRect().getWidth());
416  double fScaleX = fWidth == 0.0 ? 1.0 : 21600.0 / fWidth;
417  const double fHeight(pSdrObj->GetLogicRect().getHeight());
418  double fScaleY = fHeight == 0.0 ? 1.0 : 21600.0 / fHeight;
419  basegfx::B2DHomMatrix aScale(
420  basegfx::utils::createScaleB2DHomMatrix(fScaleX, fScaleY));
421  aPolyPolygon.transform(aScale);
422 
423  basegfx::B2DHomMatrix aTranslateToCenter(
425  aPolyPolygon.transform(aTranslateToCenter);
426  break;
427  }
428  case OBJ_NONE:
429  default:
430  break;
431  }
432 
433  // Simple version for now: Use ready PolygonFromPolyPolygon()
434  const tools::PolyPolygon aToolsPolyPoly(aPolyPolygon);
435  aContour = sw::util::PolygonFromPolyPolygon(aToolsPolyPoly);
436 
437  // The wrap polygon needs at least two points in OOXML and three points in Word.
438  switch (aContour.GetSize())
439  {
440  case 0:
441  // use rectangular default
442  aContour.Insert(0, Point(0, 0));
443  aContour.Insert(1, Point(21600, 0));
444  aContour.Insert(2, Point(21600, 21600));
445  aContour.Insert(3, Point(0, 21600));
446  aContour.Insert(4, Point(0, 0));
447  break;
448  case 1:
449  aContour.Insert(1, aContour.GetPoint(0));
450  aContour.Insert(2, aContour.GetPoint(0));
451  break;
452  case 2:
453  aContour.Insert(2, aContour.GetPoint(0));
454  break;
455  default:
456  break;
457  }
458  return aContour;
459 }
460 } // end anonymous namespace
461 
463  ww8::Frame const* pParentFrame)
464  : m_rExport(rExport)
465 {
466  m_rExport.SaveData(nStt, nEnd);
467  m_rExport.m_pParentFrame = pParentFrame;
468 }
469 
471 
474 {
475 private:
484  OStringBuffer m_aTextFrameStyle;
496 
497 public:
498  bool m_bFlyFrameGraphic = false;
499 
501  oox::drawingml::DrawingML* pDrawingML)
502  : m_rExport(rExport)
503  , m_pSerializer(std::move(pSerializer))
504  , m_pDrawingML(pDrawingML)
505  , m_pFlyFrameSize(nullptr)
506  , m_bTextFrameSyntax(false)
507  , m_bDMLTextFrameSyntax(false)
508  , m_bDrawingOpen(false)
509  , m_bParagraphSdtOpen(false)
510  , m_bParagraphHasDrawing(false)
511  , m_bDMLAndVMLDrawingOpen(false)
512  {
513  }
514 
516 
517  void textFrameShadow(const SwFrameFormat& rFrameFormat);
518  static bool isSupportedDMLShape(const uno::Reference<drawing::XShape>& xShape);
519 
521  {
522  m_pSerializer = pSerializer;
523  }
524 
526 
527  void setFlyFrameSize(const Size* pFlyFrameSize) { m_pFlyFrameSize = pFlyFrameSize; }
528 
529  const Size* getFlyFrameSize() const { return m_pFlyFrameSize; }
530 
531  void setTextFrameSyntax(bool bTextFrameSyntax) { m_bTextFrameSyntax = bTextFrameSyntax; }
532 
533  bool getTextFrameSyntax() const { return m_bTextFrameSyntax; }
534 
535  void setDMLTextFrameSyntax(bool bDMLTextFrameSyntax)
536  {
537  m_bDMLTextFrameSyntax = bDMLTextFrameSyntax;
538  }
539 
541 
543  {
544  m_pFlyAttrList = pFlyAttrList;
545  }
546 
548 
549  void
551  {
552  m_pTextboxAttrList = pTextboxAttrList;
553  }
554 
556  {
557  return m_pTextboxAttrList;
558  }
559 
560  OStringBuffer& getTextFrameStyle() { return m_aTextFrameStyle; }
561 
562  void setDrawingOpen(bool bDrawingOpen) { m_bDrawingOpen = bDrawingOpen; }
563 
564  bool getDrawingOpen() const { return m_bDrawingOpen; }
565 
566  void setParagraphSdtOpen(bool bParagraphSdtOpen) { m_bParagraphSdtOpen = bParagraphSdtOpen; }
567 
568  bool getParagraphSdtOpen() const { return m_bParagraphSdtOpen; }
569 
570  void setDMLAndVMLDrawingOpen(bool bDMLAndVMLDrawingOpen)
571  {
572  m_bDMLAndVMLDrawingOpen = bDMLAndVMLDrawingOpen;
573  }
574 
576 
577  void setParagraphHasDrawing(bool bParagraphHasDrawing)
578  {
579  m_bParagraphHasDrawing = bParagraphHasDrawing;
580  }
581 
583 
585  {
586  return m_pFlyFillAttrList;
587  }
588 
589  void
591  {
592  m_pFlyWrapAttrList = pFlyWrapAttrList;
593  }
594 
596  {
597  return m_pFlyWrapAttrList.get();
598  }
599 
601  {
602  m_pBodyPrAttrList = pBodyPrAttrList;
603  }
604 
605  sax_fastparser::FastAttributeList* getBodyPrAttrList() const { return m_pBodyPrAttrList.get(); }
606 
608  {
609  return m_pDashLineStyleAttr;
610  }
611 
612  bool getFlyFrameGraphic() const { return m_bFlyFrameGraphic; }
613 
615 
616  DocxExport& getExport() const { return m_rExport; }
617 
618  void setDMLandVMLTextFrameRotation(Degree100 nDMLandVMLTextFrameRotation)
619  {
620  m_nDMLandVMLTextFrameRotation = nDMLandVMLTextFrameRotation;
621  }
622 
624 };
625 
627  oox::drawingml::DrawingML* pDrawingML)
628  : m_pImpl(std::make_unique<Impl>(rExport, pSerializer, pDrawingML))
629 {
630 }
631 
633 
635 {
636  m_pImpl->setSerializer(pSerializer);
637 }
638 
639 const Size* DocxSdrExport::getFlyFrameSize() const { return m_pImpl->getFlyFrameSize(); }
640 
641 bool DocxSdrExport::getTextFrameSyntax() const { return m_pImpl->getTextFrameSyntax(); }
642 
643 bool DocxSdrExport::getDMLTextFrameSyntax() const { return m_pImpl->getDMLTextFrameSyntax(); }
644 
646 {
647  return m_pImpl->getFlyAttrList();
648 }
649 
651 {
652  return m_pImpl->getTextboxAttrList();
653 }
654 
655 OStringBuffer& DocxSdrExport::getTextFrameStyle() { return m_pImpl->getTextFrameStyle(); }
656 
657 bool DocxSdrExport::IsDrawingOpen() const { return m_pImpl->getDrawingOpen(); }
658 
659 void DocxSdrExport::setParagraphSdtOpen(bool bParagraphSdtOpen)
660 {
661  m_pImpl->setParagraphSdtOpen(bParagraphSdtOpen);
662 }
663 
664 bool DocxSdrExport::IsDMLAndVMLDrawingOpen() const { return m_pImpl->getDMLAndVMLDrawingOpen(); }
665 
666 bool DocxSdrExport::IsParagraphHasDrawing() const { return m_pImpl->getParagraphHasDrawing(); }
667 
668 void DocxSdrExport::setParagraphHasDrawing(bool bParagraphHasDrawing)
669 {
670  m_pImpl->setParagraphHasDrawing(bParagraphHasDrawing);
671 }
672 
674 {
675  return m_pImpl->getFlyFillAttrList();
676 }
677 
679 {
680  return m_pImpl->getBodyPrAttrList();
681 }
682 
684 {
685  return m_pImpl->getDashLineStyleAttr();
686 }
687 
690 {
691  m_pImpl->setFlyWrapAttrList(pAttrList);
692 }
693 
694 void DocxSdrExport::startDMLAnchorInline(const SwFrameFormat* pFrameFormat, const Size& rSize)
695 {
696  // Word uses size excluding right edge. Caller writeDMLDrawing and writeDiagram are changed for
697  // now. ToDo: Look whether the other callers give the size this way.
698  m_pImpl->setDrawingOpen(true);
699  m_pImpl->setParagraphHasDrawing(true);
700  m_pImpl->getSerializer()->startElementNS(XML_w, XML_drawing);
701  const SdrObject* pObj = pFrameFormat->FindRealSdrObject();
702 
703  // LO determines the place needed for the object from wrap type, wrap margin ('distance to text'),
704  // object type and anchor type. Word uses dist* for user set margins and effectExtent for place
705  // needed for effects like shadow and glow, for fat stroke and for rotation. We map the LO values
706  // to values needed by Word so that the appearance is the same as far as possible.
707  // All values in Twips, change to EMU is done immediately before writing out.
708 
709  bool isAnchor; // true XML_anchor, false XML_inline
710  if (m_pImpl->getFlyFrameGraphic())
711  {
712  isAnchor = false; // make Graphic object inside DMLTextFrame & VMLTextFrame as Inline
713  }
714  else
715  {
716  isAnchor = pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR;
717  }
718 
719  // tdf#135047: It must be allowed to find in parents too, but default value of bInP parameter
720  // for GetLRSpace() and GetULSpace() is true, so no direct setting is required.
721  const SvxLRSpaceItem& aLRSpaceItem = pFrameFormat->GetLRSpace();
722  const SvxULSpaceItem& aULSpaceItem = pFrameFormat->GetULSpace();
723  sal_Int64 nDistT = aULSpaceItem.GetUpper();
724  sal_Int64 nDistB = aULSpaceItem.GetLower();
725  sal_Int64 nDistL = aLRSpaceItem.GetLeft();
726  sal_Int64 nDistR = aLRSpaceItem.GetRight();
727 
728  // LibreOffice behaves different for frames and drawing objects, but MS Office treats frames
729  // as drawing objects too. Therefore we transform the values from frame so as if they come
730  // from a drawing object.
731  sal_Int32 nWidthDiff(0);
732  sal_Int32 nHeightDiff(0);
733  sal_Int32 nPosXDiff(0);
734  sal_Int32 nPosYDiff(0);
735  sal_Int32 nLeftExt(0);
736  sal_Int32 nRightExt(0);
737  sal_Int32 nTopExt(0);
738  sal_Int32 nBottomExt(0);
739 
740  if ((!pObj) || (pObj && (pObj->GetObjIdentifier() == SwFlyDrawObjIdentifier)))
741  {
742  // Frame objects have a restricted shadow and no further effects. They have border instead of
743  // stroke. LO includes shadow and border in the object size, but Word not.
744  SvxShadowItem aShadowItem = pFrameFormat->GetShadow();
745  if (aShadowItem.GetLocation() != SvxShadowLocation::NONE)
746  {
747  sal_Int32 nShadowWidth(aShadowItem.GetWidth());
748  switch (aShadowItem.GetLocation())
749  {
750  case SvxShadowLocation::TopLeft:
751  nTopExt = nLeftExt = nShadowWidth;
752  nPosXDiff = nLeftExt; // actual move is postponed
753  nPosYDiff = nTopExt;
754  nWidthDiff = -nLeftExt; // actual size extent is postponed
755  nHeightDiff = -nTopExt;
756  break;
757  case SvxShadowLocation::TopRight:
758  nTopExt = nRightExt = nShadowWidth;
759  nPosYDiff = nTopExt;
760  nWidthDiff = -nRightExt;
761  nHeightDiff = -nTopExt;
762  break;
763  case SvxShadowLocation::BottomLeft:
764  nBottomExt = nLeftExt = nShadowWidth;
765  nPosXDiff = nLeftExt;
766  nWidthDiff = -nLeftExt;
767  nHeightDiff = -nBottomExt;
768  break;
769  case SvxShadowLocation::BottomRight:
770  nBottomExt = nRightExt = nShadowWidth;
771  nWidthDiff = -nRightExt;
772  nHeightDiff = -nBottomExt;
773  break;
774  case SvxShadowLocation::NONE:
775  case SvxShadowLocation::End:
776  break;
777  }
778  }
779  // ToDo: Position refers to outer edge of border in LO, but to center of border in Word.
780  // Adaption is missing here. Frames in LO have no stroke but border. The current conversion
781  // from border to line treats borders like table borders. That might give wrong values
782  // for drawing frames.
783 
784  if (pObj && pObj->GetRotateAngle() != 0_deg100)
785  {
786  Degree100 nRotation = pObj->GetRotateAngle();
787  const SwRect aBoundRect(pFrameFormat->FindLayoutRect());
788  tools::Long nMSOWidth = rSize.Width();
789  tools::Long nMSOHeight = rSize.Height();
790  if ((nRotation > 4500_deg100 && nRotation <= 13500_deg100)
791  || (nRotation > 22500_deg100 && nRotation <= 31500_deg100))
792  std::swap(nMSOWidth, nMSOHeight);
793  nBottomExt += (aBoundRect.Height() - 1 - nMSOHeight) / 2;
794  nTopExt += (aBoundRect.Height() - 1 - nMSOHeight) / 2;
795  nLeftExt += (aBoundRect.Width() - nMSOWidth) / 2;
796  nRightExt += (aBoundRect.Width() - nMSOWidth) / 2;
797  }
798  lcl_makeDistAndExtentNonNegative(nDistT, nDistB, nDistL, nDistR, nLeftExt, nTopExt,
799  nRightExt, nBottomExt);
800 
801  // ToDo: Inline rotated image fails because it would need wrapTight, what is not possible.
802  // ToDo: Image plus shadow fails because of wrong shadow direction.
803  }
804  else // other objects than frames. pObj exists.
805  {
806  // Word 2007 makes no width-height-swap for images. Detect this situation.
807  sal_Int32 nMode = m_pImpl->getExport().getWordCompatibilityModeFromGrabBag();
808  bool bIsWord2007Image(nMode > 0 && nMode < 14 && pObj->GetObjIdentifier() == OBJ_GRAF);
809 
810  // Word cannot handle negative EffectExtent although allowed in OOXML, the 'dist' attributes
811  // may not be negative. Take care of that.
812  if (isAnchor)
813  {
814  lcl_calculateRawEffectExtent(nLeftExt, nTopExt, nRightExt, nBottomExt, *pObj, true,
815  bIsWord2007Image);
816  // We have calculated the effectExtent from boundRect, therefore half stroke width is
817  // already contained.
818  // ToDo: The other half of the stroke width needs to be subtracted from padding.
819  // Where is that?
820 
821  // The import has added a difference to dist* in case of contour wrap for to give a
822  // rendering nearer to Word. In that case, we need to subtract it on export.
823  uno::Any aAny;
824  pObj->GetGrabBagItem(aAny);
825  comphelper::SequenceAsHashMap aGrabBag(aAny);
826  auto it = aGrabBag.find("AnchorDistDiff");
827  if (it != aGrabBag.end())
828  {
829  comphelper::SequenceAsHashMap aAnchorDistDiff(it->second);
830  for (const std::pair<const OUString, uno::Any>& rDiff : aAnchorDistDiff)
831  {
832  if (rDiff.first == "distTDiff" && rDiff.second.has<sal_Int32>())
833  nDistT -= round(rDiff.second.get<sal_Int32>());
834  else if (rDiff.first == "distBDiff" && rDiff.second.has<sal_Int32>())
835  nDistB -= round(rDiff.second.get<sal_Int32>());
836  else if (rDiff.first == "distLDiff" && rDiff.second.has<sal_Int32>())
837  nDistL -= rDiff.second.get<sal_Int32>();
838  else if (rDiff.first == "distRDiff" && rDiff.second.has<sal_Int32>())
839  nDistR -= rDiff.second.get<sal_Int32>();
840  }
841  }
842  // ToDo: bool bCompansated = ... to be later able to switch from wrapSquare to wrapTight,
843  // if wrapSquare would require negative effectExtent.
844  lcl_makeDistAndExtentNonNegative(nDistT, nDistB, nDistL, nDistR, nLeftExt, nTopExt,
845  nRightExt, nBottomExt);
846  }
847  else
848  {
849  lcl_calculateRawEffectExtent(nLeftExt, nTopExt, nRightExt, nBottomExt, *pObj, false,
850  bIsWord2007Image);
851  // nDistT,... contain the needed distances from import or set by user. But Word
852  // ignores Dist attributes of inline shapes. So we move all needed distances to
853  // effectExtent and force effectExtent to non-negative.
854  lcl_makeDistZeroAndExtentNonNegative(nDistT, nDistB, nDistL, nDistR, nLeftExt, nTopExt,
855  nRightExt, nBottomExt);
856  }
857  }
858 
859  if (isAnchor)
860  {
863 
864  bool bOpaque = pFrameFormat->GetOpaque().GetValue();
865  if (pObj)
866  {
867  // SdrObjects know their layer, consider that instead of the frame format.
868  bOpaque = pObj->GetLayer()
869  != pFrameFormat->GetDoc()->getIDocumentDrawModelAccess().GetHellId()
870  && pObj->GetLayer()
871  != pFrameFormat->GetDoc()
874  }
875  attrList->add(XML_behindDoc, bOpaque ? "0" : "1");
876 
877  attrList->add(XML_distT, OString::number(TwipsToEMU(nDistT)).getStr());
878  attrList->add(XML_distB, OString::number(TwipsToEMU(nDistB)).getStr());
879  attrList->add(XML_distL, OString::number(TwipsToEMU(nDistL)).getStr());
880  attrList->add(XML_distR, OString::number(TwipsToEMU(nDistR)).getStr());
881 
882  attrList->add(XML_simplePos, "0");
883  attrList->add(XML_locked, "0");
884 
885  bool bLclInTabCell = true;
886  if (pObj)
887  {
888  uno::Reference<drawing::XShape> xShape((const_cast<SdrObject*>(pObj)->getUnoShape()),
889  uno::UNO_QUERY);
890  uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
891  if (xShapeProps.is())
892  xShapeProps->getPropertyValue("IsFollowingTextFlow") >>= bLclInTabCell;
893  }
894  if (bLclInTabCell)
895  attrList->add(XML_layoutInCell, "1");
896  else
897  attrList->add(XML_layoutInCell, "0");
898 
899  bool bAllowOverlap = pFrameFormat->GetWrapInfluenceOnObjPos().GetAllowOverlap();
900  attrList->add(XML_allowOverlap, bAllowOverlap ? "1" : "0");
901 
902  if (pObj)
903  // It seems 0 and 1 have special meaning: just start counting from 2 to avoid issues with that.
904  attrList->add(XML_relativeHeight, OString::number(pObj->GetOrdNum() + 2));
905  else
906  // relativeHeight is mandatory attribute, if value is not present, we must write default value
907  attrList->add(XML_relativeHeight, "0");
908 
909  if (pObj)
910  {
911  OUString sAnchorId = lclGetAnchorIdFromGrabBag(pObj);
912  if (!sAnchorId.isEmpty())
913  attrList->addNS(XML_wp14, XML_anchorId,
914  OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
915  }
916 
917  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_anchor, attrList);
918 
919  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_simplePos, XML_x, "0", XML_y,
920  "0"); // required, unused
921 
922  // Position is either determined by coordinates aPos or alignment keywords like 'center'.
923  // First prepare them.
924  awt::Point aPos(pFrameFormat->GetHoriOrient().GetPos(),
925  pFrameFormat->GetVertOrient().GetPos());
926 
927  aPos.X += nPosXDiff; // Make the postponed position move of frames.
928  aPos.Y += nPosYDiff;
929  if (pObj && lcl_IsRotateAngleValid(*pObj)
931  lclMovePositionWithRotation(aPos, rSize, pObj->GetRotateAngle());
932 
933  const char* relativeFromH;
934  const char* relativeFromV;
935  const char* alignH = nullptr;
936  const char* alignV = nullptr;
937  switch (pFrameFormat->GetVertOrient().GetRelationOrient())
938  {
939  case text::RelOrientation::PAGE_PRINT_AREA:
940  relativeFromV = "margin";
941  break;
942  case text::RelOrientation::PAGE_PRINT_AREA_TOP:
943  relativeFromV = "topMargin";
944  break;
945  case text::RelOrientation::PAGE_PRINT_AREA_BOTTOM:
946  relativeFromV = "bottomMargin";
947  break;
948  case text::RelOrientation::PAGE_FRAME:
949  relativeFromV = "page";
950  break;
951  case text::RelOrientation::FRAME:
952  relativeFromV = "paragraph";
953  break;
954  case text::RelOrientation::TEXT_LINE:
955  default:
956  relativeFromV = "line";
957  break;
958  }
959  switch (pFrameFormat->GetVertOrient().GetVertOrient())
960  {
961  case text::VertOrientation::TOP:
962  case text::VertOrientation::CHAR_TOP:
963  case text::VertOrientation::LINE_TOP:
964  if (pFrameFormat->GetVertOrient().GetRelationOrient()
965  == text::RelOrientation::TEXT_LINE)
966  alignV = "bottom";
967  else
968  alignV = "top";
969  break;
970  case text::VertOrientation::BOTTOM:
971  case text::VertOrientation::CHAR_BOTTOM:
972  case text::VertOrientation::LINE_BOTTOM:
973  if (pFrameFormat->GetVertOrient().GetRelationOrient()
974  == text::RelOrientation::TEXT_LINE)
975  alignV = "top";
976  else
977  alignV = "bottom";
978  break;
979  case text::VertOrientation::CENTER:
980  case text::VertOrientation::CHAR_CENTER:
981  case text::VertOrientation::LINE_CENTER:
982  alignV = "center";
983  break;
984  default:
985  break;
986  }
987  switch (pFrameFormat->GetHoriOrient().GetRelationOrient())
988  {
989  case text::RelOrientation::PAGE_PRINT_AREA:
990  relativeFromH = "margin";
991  break;
992  case text::RelOrientation::PAGE_FRAME:
993  relativeFromH = "page";
994  break;
995  case text::RelOrientation::CHAR:
996  relativeFromH = "character";
997  break;
998  case text::RelOrientation::PAGE_RIGHT:
999  relativeFromH = "rightMargin";
1000  break;
1001  case text::RelOrientation::PAGE_LEFT:
1002  relativeFromH = "leftMargin";
1003  break;
1004  case text::RelOrientation::FRAME:
1005  default:
1006  relativeFromH = "column";
1007  break;
1008  }
1009  switch (pFrameFormat->GetHoriOrient().GetHoriOrient())
1010  {
1011  case text::HoriOrientation::LEFT:
1012  alignH = "left";
1013  break;
1014  case text::HoriOrientation::RIGHT:
1015  alignH = "right";
1016  break;
1017  case text::HoriOrientation::CENTER:
1018  alignH = "center";
1019  break;
1020  case text::HoriOrientation::INSIDE:
1021  alignH = "inside";
1022  break;
1023  case text::HoriOrientation::OUTSIDE:
1024  alignH = "outside";
1025  break;
1026  default:
1027  break;
1028  }
1029 
1030  // write out horizontal position
1031  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_positionH, XML_relativeFrom,
1032  relativeFromH);
1033 
1039  const sal_Int64 MAX_INTEGER_VALUE = SAL_MAX_INT32;
1040  const sal_Int64 MIN_INTEGER_VALUE = SAL_MIN_INT32;
1041 
1042  if (alignH != nullptr)
1043  {
1044  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_align);
1045  m_pImpl->getSerializer()->write(alignH);
1046  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_align);
1047  }
1048  else
1049  {
1050  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_posOffset);
1051  sal_Int64 nPosXEMU = TwipsToEMU(aPos.X);
1052 
1053  /* Absolute Position Offset Value is of type Int. Hence it should not be greater than
1054  * Maximum value for Int OR Less than the Minimum value for Int.
1055  * - Maximum value for Int = 2147483647
1056  * - Minimum value for Int = -2147483648
1057  *
1058  * As per ECMA Specification : ECMA-376, Second Edition,
1059  * Part 1 - Fundamentals And Markup Language Reference[20.4.3.3 ST_PositionOffset (Absolute Position Offset Value)]
1060  *
1061  * Please refer : http://www.schemacentral.com/sc/xsd/t-xsd_int.html
1062  */
1063 
1064  if (nPosXEMU > MAX_INTEGER_VALUE)
1065  {
1066  nPosXEMU = MAX_INTEGER_VALUE;
1067  }
1068  else if (nPosXEMU < MIN_INTEGER_VALUE)
1069  {
1070  nPosXEMU = MIN_INTEGER_VALUE;
1071  }
1072  m_pImpl->getSerializer()->write(nPosXEMU);
1073  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_posOffset);
1074  }
1075  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_positionH);
1076 
1077  // write out vertical position
1078  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_positionV, XML_relativeFrom,
1079  relativeFromV);
1080  sal_Int64 nPosYEMU = TwipsToEMU(aPos.Y);
1081 
1082  // tdf#93675, 0 below line/paragraph and/or top line/paragraph with
1083  // wrap top+bottom or other wraps is affecting the line directly
1084  // above the anchor line, which seems odd, but a tiny adjustment
1085  // here to bring the top down convinces msoffice to wrap like us
1086  if (nPosYEMU == 0
1087  && (strcmp(relativeFromV, "line") == 0 || strcmp(relativeFromV, "paragraph") == 0)
1088  && (!alignV || strcmp(alignV, "top") == 0))
1089  {
1090  alignV = nullptr;
1091  nPosYEMU = TwipsToEMU(1);
1092  }
1093 
1094  if (alignV != nullptr)
1095  {
1096  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_align);
1097  m_pImpl->getSerializer()->write(alignV);
1098  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_align);
1099  }
1100  else
1101  {
1102  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_posOffset);
1103  if (nPosYEMU > MAX_INTEGER_VALUE)
1104  {
1105  nPosYEMU = MAX_INTEGER_VALUE;
1106  }
1107  else if (nPosYEMU < MIN_INTEGER_VALUE)
1108  {
1109  nPosYEMU = MIN_INTEGER_VALUE;
1110  }
1111  m_pImpl->getSerializer()->write(nPosYEMU);
1112  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_posOffset);
1113  }
1114  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_positionV);
1115  }
1116  else // inline
1117  {
1118  // nDist is forced to zero above and ignored by Word anyway, so write 0 directly.
1121  aAttrList->add(XML_distT, OString::number(0).getStr());
1122  aAttrList->add(XML_distB, OString::number(0).getStr());
1123  aAttrList->add(XML_distL, OString::number(0).getStr());
1124  aAttrList->add(XML_distR, OString::number(0).getStr());
1125  if (pObj)
1126  {
1127  OUString sAnchorId = lclGetAnchorIdFromGrabBag(pObj);
1128  if (!sAnchorId.isEmpty())
1129  aAttrList->addNS(XML_wp14, XML_anchorId,
1130  OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
1131  }
1132  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_inline, aAttrList);
1133  }
1134 
1135  // now the common parts 'extent' and 'effectExtent'
1153  sal_uInt64 cx = TwipsToEMU(
1154  std::clamp(rSize.Width() + nWidthDiff, tools::Long(0), tools::Long(SAL_MAX_INT32)));
1155  OString aWidth(OString::number(std::min(cx, sal_uInt64(SAL_MAX_INT32))));
1156  sal_uInt64 cy = TwipsToEMU(
1157  std::clamp(rSize.Height() + nHeightDiff, tools::Long(0), tools::Long(SAL_MAX_INT32)));
1158  OString aHeight(OString::number(std::min(cy, sal_uInt64(SAL_MAX_INT32))));
1159 
1160  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_extent, XML_cx, aWidth, XML_cy, aHeight);
1161 
1162  // XML_effectExtent, includes effects, fat stroke and rotation
1163  // FixMe: tdf141880. Because LibreOffice currently cannot handle negative vertical margins, they
1164  // were forced to zero on import. Especially bottom margin of inline anchored rotated objects are
1165  // affected. If the object was not changed, it would be better to export the original values
1166  // from grab-Bag. Unfortunately there exists no marker for "not changed", so a heuristic is used
1167  // here: If current left, top and right margins do not differ more than 1Hmm = 635EMU from the
1168  // values in grab-Bag, it is likely, that the object was not changed and we restore the values
1169  // from grab-Bag.
1170  sal_Int64 nLeftExtEMU = TwipsToEMU(nLeftExt);
1171  sal_Int64 nTopExtEMU = TwipsToEMU(nTopExt);
1172  sal_Int64 nRightExtEMU = TwipsToEMU(nRightExt);
1173  sal_Int64 nBottomExtEMU = TwipsToEMU(nBottomExt);
1174  if (pObj)
1175  {
1176  uno::Any aAny;
1177  pObj->GetGrabBagItem(aAny);
1178  comphelper::SequenceAsHashMap aGrabBag(aAny);
1179  auto it = aGrabBag.find("CT_EffectExtent");
1180  if (it != aGrabBag.end())
1181  {
1182  comphelper::SequenceAsHashMap aEffectExtent(it->second);
1183  sal_Int64 nLeftExtGrabBag(0);
1184  sal_Int64 nTopExtGrabBag(0);
1185  sal_Int64 nRightExtGrabBag(0);
1186  sal_Int64 nBottomExtGrabBag(0);
1187  for (const std::pair<const OUString, uno::Any>& rDirection : aEffectExtent)
1188  {
1189  if (rDirection.first == "l" && rDirection.second.has<sal_Int32>())
1190  nLeftExtGrabBag = rDirection.second.get<sal_Int32>();
1191  else if (rDirection.first == "t" && rDirection.second.has<sal_Int32>())
1192  nTopExtGrabBag = rDirection.second.get<sal_Int32>();
1193  else if (rDirection.first == "r" && rDirection.second.has<sal_Int32>())
1194  nRightExtGrabBag = rDirection.second.get<sal_Int32>();
1195  else if (rDirection.first == "b" && rDirection.second.has<sal_Int32>())
1196  nBottomExtGrabBag = rDirection.second.get<sal_Int32>();
1197  }
1198  if (abs(nLeftExtEMU - nLeftExtGrabBag) <= 635 && abs(nTopExtEMU - nTopExtGrabBag) <= 635
1199  && abs(nRightExtEMU - nRightExtGrabBag) <= 635)
1200  {
1201  nLeftExtEMU = nLeftExtGrabBag;
1202  nTopExtEMU = nTopExtGrabBag;
1203  nRightExtEMU = nRightExtGrabBag;
1204  nBottomExtEMU = nBottomExtGrabBag;
1205  }
1206  }
1207  }
1208  m_pImpl->getSerializer()->singleElementNS(
1209  XML_wp, XML_effectExtent, XML_l, OString::number(nLeftExtEMU), XML_t,
1210  OString::number(nTopExtEMU), XML_r, OString::number(nRightExtEMU), XML_b,
1211  OString::number(nBottomExtEMU));
1212 
1213  if (!isAnchor)
1214  return; // OOXML 'inline' has not wrap type at all
1215 
1216  // XML_anchor has exact one of types wrapNone, wrapSquare, wrapTight, wrapThrough and
1217  // WrapTopAndBottom. Map our own types to them as far as possible.
1218 
1219  if (pFrameFormat->GetSurround().GetValue() == css::text::WrapTextMode_THROUGH
1220  || pFrameFormat->GetSurround().GetValue() == css::text::WrapTextMode_THROUGHT)
1221  {
1222  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_wrapNone);
1223  return;
1224  }
1225 
1226  if (pFrameFormat->GetSurround().GetValue() == css::text::WrapTextMode_NONE)
1227  {
1228  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_wrapTopAndBottom);
1229  return;
1230  }
1231 
1232  // All remaining cases need attribute XML_wrapText
1233  OUString sWrapType;
1234  switch (pFrameFormat->GetSurround().GetSurround())
1235  {
1236  case text::WrapTextMode_DYNAMIC:
1237  sWrapType = OUString("largest");
1238  break;
1239  case text::WrapTextMode_LEFT:
1240  sWrapType = OUString("left");
1241  break;
1242  case text::WrapTextMode_RIGHT:
1243  sWrapType = OUString("right");
1244  break;
1245  case text::WrapTextMode_PARALLEL:
1246  default:
1247  sWrapType = OUString("bothSides");
1248  break;
1249  }
1250 
1251  // ToDo: Exclude cases where LibreOffice wrap without contour is different
1252  // from Word XML_wrapSquare or where direct use of distances not possible and workaround
1253  // will be done using wrapPolygon.
1254  // ToDo: handle case Writer frame, where contour can be set in LibreOffice but is not rendered.
1255 
1256  // This case needs no wrapPolygon
1257  if (!pFrameFormat->GetSurround().IsContour())
1258  {
1259  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_wrapSquare, XML_wrapText, sWrapType);
1260  return;
1261  }
1262 
1263  // Contour wrap.
1264  sal_Int32 nWrapToken
1265  = pFrameFormat->GetSurround().IsOutside() ? XML_wrapTight : XML_wrapThrough;
1266 
1267  // ToDo: cases where wrapPolygon is used as workaround.
1268 
1269  // Own wrap polygon exists only for TextGraphicObject and TextEmbeddedObject. It might be edited
1270  // by user. If such exists, we use it and we are done.
1271  if (const SwNoTextNode* pNd = sw::util::GetNoTextNodeFromSwFrameFormat(*pFrameFormat))
1272  {
1273  const tools::PolyPolygon* pPolyPoly = pNd->HasContour();
1274  if (pPolyPoly && pPolyPoly->Count())
1275  {
1276  tools::Polygon aPoly
1277  = sw::util::CorrectWordWrapPolygonForExport(*pPolyPoly, pNd, /*bCorrectCrop=*/true);
1278  if (aPoly.GetSize() >= 3)
1279  {
1280  m_pImpl->getSerializer()->startElementNS(XML_wp, nWrapToken, XML_wrapText,
1281  sWrapType);
1282  // ToDo: Test whether XML_edited true or false gives better results.
1283  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_wrapPolygon, XML_edited, "0");
1284  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_start, XML_x,
1285  OString::number(aPoly[0].X()), XML_y,
1286  OString::number(aPoly[0].Y()));
1287  for (sal_uInt16 i = 1; i < aPoly.GetSize(); ++i)
1288  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_lineTo, XML_x,
1289  OString::number(aPoly[i].X()), XML_y,
1290  OString::number(aPoly[i].Y()));
1291  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_wrapPolygon);
1292 
1293  m_pImpl->getSerializer()->endElementNS(XML_wp, nWrapToken);
1294  return;
1295  }
1296  }
1297  }
1298 
1299  // If this shape comes from ooxml import, there might be a wrap polygon in InteropGrabBag.
1300  // Wrap polygons can be edited by users in Word. They are independent from changing shape size or
1301  // rotation. So it is likely, that it is still usable.
1302  if (pObj)
1303  {
1304  uno::Any aAny;
1305  pObj->GetGrabBagItem(aAny);
1306  comphelper::SequenceAsHashMap aGrabBag(aAny);
1307  auto it = aGrabBag.find("CT_WrapPath");
1308  if (it != aGrabBag.end())
1309  {
1310  m_pImpl->getSerializer()->startElementNS(XML_wp, nWrapToken, XML_wrapText, sWrapType);
1311 
1312  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_wrapPolygon, XML_edited, "0");
1313  auto aSeqSeq = it->second.get<drawing::PointSequenceSequence>();
1314  auto aPoints(comphelper::sequenceToContainer<std::vector<awt::Point>>(aSeqSeq[0]));
1315  for (auto i = aPoints.begin(); i != aPoints.end(); ++i)
1316  {
1317  awt::Point& rPoint = *i;
1318  m_pImpl->getSerializer()->singleElementNS(
1319  XML_wp, (i == aPoints.begin() ? XML_start : XML_lineTo), XML_x,
1320  OString::number(rPoint.X), XML_y, OString::number(rPoint.Y));
1321  }
1322  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_wrapPolygon);
1323 
1324  m_pImpl->getSerializer()->endElementNS(XML_wp, nWrapToken);
1325  return;
1326  }
1327  }
1328 
1329  // In this case we likely had an odt document to be exported to docx. ODF does not know the
1330  // concept of a wrap polygon and LibreOffice has no one internally. So as a workaround, we
1331  // generate a wrap polygon from the shape geometry.
1332  tools::Polygon aContour = lcl_CreateContourPolygon(const_cast<SdrObject*>(pObj));
1333 
1334  // lcl_CreateContourPolygon() ensures at least three points
1335  m_pImpl->getSerializer()->startElementNS(XML_wp, nWrapToken, XML_wrapText, sWrapType);
1336 
1337  // ToDo: Test whether XML_edited true or false gives better results.
1338  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_wrapPolygon, XML_edited, "0");
1339  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_start, XML_x,
1340  OString::number(aContour.GetPoint(0).getX()), XML_y,
1341  OString::number(aContour.GetPoint(0).getY()));
1342  for (sal_uInt32 i = 1; i < aContour.GetSize(); i++)
1343  m_pImpl->getSerializer()->singleElementNS(
1344  XML_wp, XML_lineTo, XML_x, OString::number(aContour.GetPoint(i).getX()), XML_y,
1345  OString::number(aContour.GetPoint(i).getY()));
1346  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_wrapPolygon);
1347 
1348  m_pImpl->getSerializer()->endElementNS(XML_wp, nWrapToken);
1349 }
1350 
1352 {
1353  bool isAnchor;
1354  if (m_pImpl->getFlyFrameGraphic())
1355  {
1356  isAnchor = false; // end Inline Graphic object inside DMLTextFrame
1357  }
1358  else
1359  {
1360  isAnchor = pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR;
1361  }
1362  m_pImpl->getSerializer()->endElementNS(XML_wp, isAnchor ? XML_anchor : XML_inline);
1363 
1364  m_pImpl->getSerializer()->endElementNS(XML_w, XML_drawing);
1365  m_pImpl->setDrawingOpen(false);
1366 }
1367 
1368 void DocxSdrExport::writeVMLDrawing(const SdrObject* sdrObj, const SwFrameFormat& rFrameFormat)
1369 {
1370  m_pImpl->getSerializer()->startElementNS(XML_w, XML_pict);
1371  m_pImpl->getDrawingML()->SetFS(m_pImpl->getSerializer());
1372  // See WinwordAnchoring::SetAnchoring(), these are not part of the SdrObject, have to be passed around manually.
1373 
1374  SwFormatFollowTextFlow const& rFlow(rFrameFormat.GetFollowTextFlow());
1375  const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient();
1376  const SwFormatVertOrient& rVertOri = rFrameFormat.GetVertOrient();
1377  SwFormatSurround const& rSurround(rFrameFormat.GetSurround());
1378 
1380  m_pImpl->getExport().VMLExporter().AddSdrObject(
1381  *sdrObj, rFlow.GetValue(), rHoriOri.GetHoriOrient(), rVertOri.GetVertOrient(),
1382  rHoriOri.GetRelationOrient(), rVertOri.GetRelationOrient(), pAttrList.get(), true);
1383  m_pImpl->getSerializer()->endElementNS(XML_w, XML_pict);
1384 }
1385 
1386 static bool lcl_isLockedCanvas(const uno::Reference<drawing::XShape>& xShape)
1387 {
1388  uno::Sequence<beans::PropertyValue> propList = lclGetProperty(xShape, "InteropGrabBag");
1389  /*
1390  * Export as Locked Canvas only if the property
1391  * is in the PropertySet
1392  */
1393  return std::any_of(propList.begin(), propList.end(), [](const beans::PropertyValue& rProp) {
1394  return rProp.Name == "LockedCanvas";
1395  });
1396 }
1397 
1398 void DocxSdrExport::writeDMLDrawing(const SdrObject* pSdrObject, const SwFrameFormat* pFrameFormat,
1399  int nAnchorId)
1400 {
1401  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(pSdrObject)->getUnoShape(),
1402  uno::UNO_QUERY_THROW);
1403  if (!Impl::isSupportedDMLShape(xShape))
1404  return;
1405 
1406  m_pImpl->getExport().DocxAttrOutput().GetSdtEndBefore(pSdrObject);
1407 
1408  sax_fastparser::FSHelperPtr pFS = m_pImpl->getSerializer();
1409  Size aSize(pSdrObject->GetLogicRect().getWidth(), pSdrObject->GetLogicRect().getHeight());
1410  startDMLAnchorInline(pFrameFormat, aSize);
1411 
1414  pDocPrAttrList->add(XML_id, OString::number(nAnchorId).getStr());
1415  pDocPrAttrList->add(XML_name, OUStringToOString(pSdrObject->GetName(), RTL_TEXTENCODING_UTF8));
1416  if (!pSdrObject->GetTitle().isEmpty())
1417  pDocPrAttrList->add(XML_title,
1418  OUStringToOString(pSdrObject->GetTitle(), RTL_TEXTENCODING_UTF8));
1419  if (!pSdrObject->GetDescription().isEmpty())
1420  pDocPrAttrList->add(XML_descr,
1421  OUStringToOString(pSdrObject->GetDescription(), RTL_TEXTENCODING_UTF8));
1422  if (!pSdrObject->IsVisible()
1423  && pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
1424 
1425  pDocPrAttrList->add(XML_hidden, OString::number(1).getStr());
1426 
1427  pFS->startElementNS(XML_wp, XML_docPr, pDocPrAttrList);
1428  OUString sHyperlink = pSdrObject->getHyperlink();
1429  if (!sHyperlink.isEmpty())
1430  {
1431  OUString sRelId = m_pImpl->getExport().GetFilter().addRelation(
1432  pFS->getOutputStream(), oox::getRelationship(Relationship::HYPERLINK),
1435  pFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId,
1436  FSNS(XML_xmlns, XML_a),
1437  m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
1438  }
1439  pFS->endElementNS(XML_wp, XML_docPr);
1440 
1441  uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
1442  const char* pNamespace = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
1443  if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
1444  pNamespace = "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup";
1445  else if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
1446  pNamespace = "http://schemas.openxmlformats.org/drawingml/2006/picture";
1447  pFS->startElementNS(XML_a, XML_graphic, FSNS(XML_xmlns, XML_a),
1448  m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
1449  pFS->startElementNS(XML_a, XML_graphicData, XML_uri, pNamespace);
1450 
1451  bool bLockedCanvas = lcl_isLockedCanvas(xShape);
1452  if (bLockedCanvas)
1453  pFS->startElementNS(
1454  XML_lc, XML_lockedCanvas, FSNS(XML_xmlns, XML_lc),
1455  m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dmlLockedCanvas)));
1456 
1457  m_pImpl->getExport().OutputDML(xShape);
1458 
1459  if (bLockedCanvas)
1460  pFS->endElementNS(XML_lc, XML_lockedCanvas);
1461  pFS->endElementNS(XML_a, XML_graphicData);
1462  pFS->endElementNS(XML_a, XML_graphic);
1463 
1464  // Relative size of the drawing.
1465  if (pSdrObject->GetRelativeWidth())
1466  {
1467  // At the moment drawinglayer objects are always relative from page.
1468  OUString sValue;
1469  switch (pSdrObject->GetRelativeWidthRelation())
1470  {
1471  case text::RelOrientation::FRAME:
1472  sValue = "margin";
1473  break;
1474  case text::RelOrientation::PAGE_LEFT:
1475  if (pFrameFormat->GetDoc()->GetPageDesc(0).GetUseOn() == UseOnPage::Mirror)
1476  sValue = "outsideMargin";
1477  else
1478  sValue = "leftMargin";
1479  break;
1480  case text::RelOrientation::PAGE_RIGHT:
1481  if (pFrameFormat->GetDoc()->GetPageDesc(0).GetUseOn() == UseOnPage::Mirror)
1482  sValue = "insideMargin";
1483  else
1484  sValue = "rightMargin";
1485  break;
1486  case text::RelOrientation::PAGE_FRAME:
1487  default:
1488  sValue = "page";
1489  break;
1490  }
1491  pFS->startElementNS(XML_wp14, XML_sizeRelH, XML_relativeFrom, sValue);
1492  pFS->startElementNS(XML_wp14, XML_pctWidth);
1493  pFS->writeEscaped(
1494  OUString::number(*pSdrObject->GetRelativeWidth() * 100 * oox::drawingml::PER_PERCENT));
1495  pFS->endElementNS(XML_wp14, XML_pctWidth);
1496  pFS->endElementNS(XML_wp14, XML_sizeRelH);
1497  }
1498  if (pSdrObject->GetRelativeHeight())
1499  {
1500  OUString sValue;
1501  switch (pSdrObject->GetRelativeHeightRelation())
1502  {
1503  case text::RelOrientation::FRAME:
1504  sValue = "margin";
1505  break;
1506  case text::RelOrientation::PAGE_PRINT_AREA:
1507  sValue = "topMargin";
1508  break;
1509  case text::RelOrientation::PAGE_PRINT_AREA_BOTTOM:
1510  sValue = "bottomMargin";
1511  break;
1512  case text::RelOrientation::PAGE_FRAME:
1513  default:
1514  sValue = "page";
1515  break;
1516  }
1517  pFS->startElementNS(XML_wp14, XML_sizeRelV, XML_relativeFrom, sValue);
1518  pFS->startElementNS(XML_wp14, XML_pctHeight);
1519  pFS->writeEscaped(
1520  OUString::number(*pSdrObject->GetRelativeHeight() * 100 * oox::drawingml::PER_PERCENT));
1521  pFS->endElementNS(XML_wp14, XML_pctHeight);
1522  pFS->endElementNS(XML_wp14, XML_sizeRelV);
1523  }
1524 
1525  endDMLAnchorInline(pFrameFormat);
1526 }
1527 
1529 {
1530  const SvxShadowItem& aShadowItem = rFrameFormat.GetShadow();
1531  if (aShadowItem.GetLocation() == SvxShadowLocation::NONE)
1532  return;
1533 
1534  OString aShadowWidth(OString::number(double(aShadowItem.GetWidth()) / 20) + "pt");
1535  OString aOffset;
1536  switch (aShadowItem.GetLocation())
1537  {
1538  case SvxShadowLocation::TopLeft:
1539  aOffset = "-" + aShadowWidth + ",-" + aShadowWidth;
1540  break;
1541  case SvxShadowLocation::TopRight:
1542  aOffset = aShadowWidth + ",-" + aShadowWidth;
1543  break;
1544  case SvxShadowLocation::BottomLeft:
1545  aOffset = "-" + aShadowWidth + "," + aShadowWidth;
1546  break;
1547  case SvxShadowLocation::BottomRight:
1548  aOffset = aShadowWidth + "," + aShadowWidth;
1549  break;
1550  case SvxShadowLocation::NONE:
1551  case SvxShadowLocation::End:
1552  break;
1553  }
1554  if (aOffset.isEmpty())
1555  return;
1556 
1557  OString aShadowColor = msfilter::util::ConvertColor(aShadowItem.GetColor());
1558  m_pSerializer->singleElementNS(XML_v, XML_shadow, XML_on, "t", XML_color, "#" + aShadowColor,
1559  XML_offset, aOffset);
1560 }
1561 
1562 bool DocxSdrExport::Impl::isSupportedDMLShape(const uno::Reference<drawing::XShape>& xShape)
1563 {
1564  uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
1565  if (xServiceInfo->supportsService("com.sun.star.drawing.PolyPolygonShape")
1566  || xServiceInfo->supportsService("com.sun.star.drawing.PolyLineShape"))
1567  return false;
1568 
1569  // For signature line shapes, we don't want DML, just the VML shape.
1570  if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
1571  {
1572  uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
1573  bool bIsSignatureLineShape = false;
1574  xShapeProperties->getPropertyValue("IsSignatureLine") >>= bIsSignatureLineShape;
1575  if (bIsSignatureLineShape)
1576  return false;
1577  }
1578 
1579  return true;
1580 }
1581 
1583  const SwFrameFormat& rFrameFormat, int nAnchorId)
1584 {
1585  bool bDMLAndVMLDrawingOpen = m_pImpl->getDMLAndVMLDrawingOpen();
1586  m_pImpl->setDMLAndVMLDrawingOpen(true);
1587 
1588  // Depending on the shape type, we actually don't write the shape as DML.
1589  OUString sShapeType;
1590  ShapeFlag nMirrorFlags = ShapeFlag::NONE;
1591  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(sdrObj)->getUnoShape(),
1592  uno::UNO_QUERY_THROW);
1593 
1594  MSO_SPT eShapeType
1595  = EscherPropertyContainer::GetCustomShapeType(xShape, nMirrorFlags, sShapeType);
1596 
1597  // In case we are already inside a DML block, then write the shape only as VML, turn out that's allowed to do.
1598  // A common service created in util to check for VML shapes which are allowed to have textbox in content
1600  && (!bDMLAndVMLDrawingOpen || lcl_isLockedCanvas(xShape))) // Locked canvas is OK inside DML
1601  {
1602  m_pImpl->getSerializer()->startElementNS(XML_mc, XML_AlternateContent);
1603 
1604  auto pObjGroup = dynamic_cast<const SdrObjGroup*>(sdrObj);
1605  m_pImpl->getSerializer()->startElementNS(XML_mc, XML_Choice, XML_Requires,
1606  (pObjGroup ? "wpg" : "wps"));
1607  writeDMLDrawing(sdrObj, &rFrameFormat, nAnchorId);
1608  m_pImpl->getSerializer()->endElementNS(XML_mc, XML_Choice);
1609 
1610  m_pImpl->getSerializer()->startElementNS(XML_mc, XML_Fallback);
1611  writeVMLDrawing(sdrObj, rFrameFormat);
1612  m_pImpl->getSerializer()->endElementNS(XML_mc, XML_Fallback);
1613 
1614  m_pImpl->getSerializer()->endElementNS(XML_mc, XML_AlternateContent);
1615  }
1616  else
1617  writeVMLDrawing(sdrObj, rFrameFormat);
1618 
1619  m_pImpl->setDMLAndVMLDrawingOpen(bDMLAndVMLDrawingOpen);
1620 }
1621 
1622 // Converts ARGB transparency (0..255) to drawingml alpha (opposite, and 0..100000)
1623 static OString lcl_TransparencyToDrawingMlAlpha(const Color& rColor)
1624 {
1625  if (rColor.IsTransparent())
1626  {
1627  sal_Int32 nAlphaPercent = float(rColor.GetAlpha()) / 2.55;
1628  return OString::number(nAlphaPercent * oox::drawingml::PER_PERCENT);
1629  }
1630 
1631  return OString();
1632 }
1633 
1635 {
1636  const SvxShadowItem& aShadowItem = rFrameFormat.GetShadow();
1637 
1638  // Output effects
1639  if (aShadowItem.GetLocation() == SvxShadowLocation::NONE)
1640  return;
1641 
1642  // Distance is measured diagonally from corner
1643  double nShadowDist
1644  = sqrt(static_cast<double>(aShadowItem.GetWidth()) * aShadowItem.GetWidth() * 2.0);
1645  OString aShadowDist(OString::number(TwipsToEMU(nShadowDist)));
1646  OString aShadowColor = msfilter::util::ConvertColor(aShadowItem.GetColor());
1647  OString aShadowAlpha = lcl_TransparencyToDrawingMlAlpha(aShadowItem.GetColor());
1648  sal_uInt32 nShadowDir = 0;
1649  switch (aShadowItem.GetLocation())
1650  {
1651  case SvxShadowLocation::TopLeft:
1652  nShadowDir = 13500000;
1653  break;
1654  case SvxShadowLocation::TopRight:
1655  nShadowDir = 18900000;
1656  break;
1657  case SvxShadowLocation::BottomLeft:
1658  nShadowDir = 8100000;
1659  break;
1660  case SvxShadowLocation::BottomRight:
1661  nShadowDir = 2700000;
1662  break;
1663  case SvxShadowLocation::NONE:
1664  case SvxShadowLocation::End:
1665  break;
1666  }
1667  OString aShadowDir(OString::number(nShadowDir));
1668 
1669  m_pImpl->getSerializer()->startElementNS(XML_a, XML_effectLst);
1670  m_pImpl->getSerializer()->startElementNS(XML_a, XML_outerShdw, XML_dist, aShadowDist, XML_dir,
1671  aShadowDir);
1672  if (aShadowAlpha.isEmpty())
1673  m_pImpl->getSerializer()->singleElementNS(XML_a, XML_srgbClr, XML_val, aShadowColor);
1674  else
1675  {
1676  m_pImpl->getSerializer()->startElementNS(XML_a, XML_srgbClr, XML_val, aShadowColor);
1677  m_pImpl->getSerializer()->singleElementNS(XML_a, XML_alpha, XML_val, aShadowAlpha);
1678  m_pImpl->getSerializer()->endElementNS(XML_a, XML_srgbClr);
1679  }
1680  m_pImpl->getSerializer()->endElementNS(XML_a, XML_outerShdw);
1681  m_pImpl->getSerializer()->endElementNS(XML_a, XML_effectLst);
1682 }
1683 
1684 void DocxSdrExport::writeDiagram(const SdrObject* sdrObject, const SwFrameFormat& rFrameFormat,
1685  int nDiagramId)
1686 {
1687  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(sdrObject)->getUnoShape(),
1688  uno::UNO_QUERY);
1689 
1690  // write necessary tags to document.xml
1691  Size aSize(sdrObject->GetSnapRect().getWidth(), sdrObject->GetSnapRect().getHeight());
1692  startDMLAnchorInline(&rFrameFormat, aSize);
1693 
1694  m_pImpl->getDrawingML()->WriteDiagram(xShape, nDiagramId);
1695 
1696  endDMLAnchorInline(&rFrameFormat);
1697 }
1698 
1700 {
1701  const SwFrameFormat& rFrameFormat = pParentFrame->GetFrameFormat();
1702  const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
1703 
1704  sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : 0;
1705  sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
1706 
1707  //Save data here and restore when out of scope
1708  ExportDataSaveRestore aDataGuard(m_pImpl->getExport(), nStt, nEnd, pParentFrame);
1709 
1711  ::comphelper::FlagRestorationGuard const g(m_pImpl->m_bFlyFrameGraphic, true);
1712  comphelper::ValueRestorationGuard vg(m_pImpl->getExport().m_nTextTyp, TXT_TXTBOX);
1713  m_pImpl->getExport().WriteText();
1714 }
1715 
1717 {
1718  const editeng::SvxBorderLine* pBorderLine = nullptr;
1719 
1720  if (rBox.GetTop())
1721  {
1722  pBorderLine = rBox.GetTop();
1723  }
1724  else if (rBox.GetLeft())
1725  {
1726  pBorderLine = rBox.GetLeft();
1727  }
1728  else if (rBox.GetBottom())
1729  {
1730  pBorderLine = rBox.GetBottom();
1731  }
1732  else if (rBox.GetRight())
1733  {
1734  pBorderLine = rBox.GetRight();
1735  }
1736 
1737  if (!pBorderLine)
1738  {
1739  return;
1740  }
1741 
1742  sax_fastparser::FSHelperPtr pFS = m_pImpl->getSerializer();
1743  double fConverted(editeng::ConvertBorderWidthToWord(pBorderLine->GetBorderLineStyle(),
1744  pBorderLine->GetWidth()));
1745  OString sWidth(OString::number(TwipsToEMU(fConverted)));
1746  pFS->startElementNS(XML_a, XML_ln, XML_w, sWidth);
1747 
1748  pFS->startElementNS(XML_a, XML_solidFill);
1749  OString sColor(msfilter::util::ConvertColor(pBorderLine->GetColor()));
1750  pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, sColor);
1751  pFS->endElementNS(XML_a, XML_solidFill);
1752 
1753  if (SvxBorderLineStyle::DASHED == pBorderLine->GetBorderLineStyle()) // Line Style is Dash type
1754  pFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dash");
1755 
1756  pFS->endElementNS(XML_a, XML_ln);
1757 }
1758 
1759 void DocxSdrExport::writeDMLTextFrame(ww8::Frame const* pParentFrame, int nAnchorId,
1760  bool bTextBoxOnly)
1761 {
1762  bool bDMLAndVMLDrawingOpen = m_pImpl->getDMLAndVMLDrawingOpen();
1763  m_pImpl->setDMLAndVMLDrawingOpen(IsAnchorTypeInsideParagraph(pParentFrame));
1764 
1765  sax_fastparser::FSHelperPtr pFS = m_pImpl->getSerializer();
1766  const SwFrameFormat& rFrameFormat = pParentFrame->GetFrameFormat();
1767  const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
1768 
1769  sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : 0;
1770  sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
1771 
1772  //Save data here and restore when out of scope
1773  ExportDataSaveRestore aDataGuard(m_pImpl->getExport(), nStt, nEnd, pParentFrame);
1774 
1775  // When a frame has some low height, but automatically expanded due
1776  // to lots of contents, this size contains the real size.
1777  const Size aSize = pParentFrame->GetSize();
1778 
1779  uno::Reference<drawing::XShape> xShape;
1780  const SdrObject* pSdrObj = rFrameFormat.FindRealSdrObject();
1781  if (pSdrObj)
1782  xShape.set(const_cast<SdrObject*>(pSdrObj)->getUnoShape(), uno::UNO_QUERY);
1783  uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1784  uno::Reference<beans::XPropertySetInfo> xPropSetInfo;
1785  if (xPropertySet.is())
1786  xPropSetInfo = xPropertySet->getPropertySetInfo();
1787 
1789  {
1790  drawing::TextVerticalAdjust eAdjust = drawing::TextVerticalAdjust_TOP;
1791  if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("TextVerticalAdjust"))
1792  xPropertySet->getPropertyValue("TextVerticalAdjust") >>= eAdjust;
1793  m_pImpl->getBodyPrAttrList()->add(XML_anchor,
1795  }
1796 
1797  if (!bTextBoxOnly)
1798  {
1799  startDMLAnchorInline(&rFrameFormat, aSize);
1800 
1803  pDocPrAttrList->add(XML_id, OString::number(nAnchorId).getStr());
1804  pDocPrAttrList->add(XML_name,
1805  OUStringToOString(rFrameFormat.GetName(), RTL_TEXTENCODING_UTF8));
1806 
1807  pFS->startElementNS(XML_wp, XML_docPr, pDocPrAttrList);
1808 
1809  OUString sHyperlink;
1810  if (xPropertySet.is())
1811  xPropertySet->getPropertyValue("HyperLinkURL") >>= sHyperlink;
1812  if (!sHyperlink.isEmpty())
1813  {
1814  OUString sRelId = m_pImpl->getExport().GetFilter().addRelation(
1815  pFS->getOutputStream(), oox::getRelationship(Relationship::HYPERLINK),
1818  pFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId,
1819  FSNS(XML_xmlns, XML_a),
1820  m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
1821  }
1822 
1823  pFS->endElementNS(XML_wp, XML_docPr);
1824 
1825  pFS->startElementNS(XML_a, XML_graphic, FSNS(XML_xmlns, XML_a),
1826  m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
1827  pFS->startElementNS(XML_a, XML_graphicData, XML_uri,
1828  "http://schemas.microsoft.com/office/word/2010/wordprocessingShape");
1829  pFS->startElementNS(XML_wps, XML_wsp);
1830  pFS->singleElementNS(XML_wps, XML_cNvSpPr, XML_txBox, "1");
1831 
1832  uno::Any aRotation;
1833  m_pImpl->setDMLandVMLTextFrameRotation(0_deg100);
1834  if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("FrameInteropGrabBag"))
1835  {
1836  uno::Sequence<beans::PropertyValue> propList;
1837  xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= propList;
1838  auto pProp = std::find_if(propList.begin(), propList.end(),
1839  [](const beans::PropertyValue& rProp) {
1840  return rProp.Name == "mso-rotation-angle";
1841  });
1842  if (pProp != propList.end())
1843  aRotation = pProp->Value;
1844  }
1845  sal_Int32 nTmp;
1846  if (aRotation >>= nTmp)
1847  m_pImpl->getDMLandVMLTextFrameRotation() = Degree100(nTmp);
1848  OString sRotation(OString::number(
1849  oox::drawingml::ExportRotateClockwisify(m_pImpl->getDMLandVMLTextFrameRotation())));
1850  // Shape properties
1851  pFS->startElementNS(XML_wps, XML_spPr);
1852  if (m_pImpl->getDMLandVMLTextFrameRotation())
1853  {
1854  pFS->startElementNS(XML_a, XML_xfrm, XML_rot, sRotation);
1855  }
1856  else
1857  {
1858  pFS->startElementNS(XML_a, XML_xfrm);
1859  }
1860  pFS->singleElementNS(XML_a, XML_off, XML_x, "0", XML_y, "0");
1861  OString aWidth(OString::number(TwipsToEMU(aSize.Width())));
1862  OString aHeight(OString::number(TwipsToEMU(aSize.Height())));
1863  pFS->singleElementNS(XML_a, XML_ext, XML_cx, aWidth, XML_cy, aHeight);
1864  pFS->endElementNS(XML_a, XML_xfrm);
1865  OUString shapeType = "rect";
1866  if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("FrameInteropGrabBag"))
1867  {
1868  uno::Sequence<beans::PropertyValue> propList;
1869  xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= propList;
1870  auto pProp = std::find_if(propList.begin(), propList.end(),
1871  [](const beans::PropertyValue& rProp) {
1872  return rProp.Name == "mso-orig-shape-type";
1873  });
1874  if (pProp != propList.end())
1875  pProp->Value >>= shapeType;
1876  }
1877  //Empty shapeType will lead to corruption so to avoid that shapeType is set to default i.e. "rect"
1878  if (shapeType.isEmpty())
1879  shapeType = "rect";
1880 
1881  pFS->singleElementNS(XML_a, XML_prstGeom, XML_prst, shapeType);
1882  m_pImpl->setDMLTextFrameSyntax(true);
1883  m_pImpl->getExport().OutputFormat(pParentFrame->GetFrameFormat(), false, false, true);
1884  m_pImpl->setDMLTextFrameSyntax(false);
1885  writeDMLEffectLst(rFrameFormat);
1886  pFS->endElementNS(XML_wps, XML_spPr);
1887  }
1888 
1889  //first, loop through ALL of the chained textboxes to identify a unique ID for each chain, and sequence number for each textbox in that chain.
1890  if (!m_pImpl->getExport().m_bLinkedTextboxesHelperInitialized)
1891  {
1892  sal_Int32 nSeq = 0;
1893  for (auto& rEntry : m_pImpl->getExport().m_aLinkedTextboxesHelper)
1894  {
1895  //find the start of a textbox chain: has no PREVIOUS link, but does have NEXT link
1896  if (rEntry.second.sPrevChain.isEmpty() && !rEntry.second.sNextChain.isEmpty())
1897  {
1898  //assign this chain a unique ID and start a new sequence
1899  nSeq = 0;
1900  rEntry.second.nId = ++m_pImpl->getExport().m_nLinkedTextboxesChainId;
1901  rEntry.second.nSeq = nSeq;
1902 
1903  OUString sCheckForBrokenChains = rEntry.first;
1904 
1905  //follow the chain and assign the same id, and incremental sequence numbers.
1906  auto followChainIter
1907  = m_pImpl->getExport().m_aLinkedTextboxesHelper.find(rEntry.second.sNextChain);
1908  while (followChainIter != m_pImpl->getExport().m_aLinkedTextboxesHelper.end())
1909  {
1910  //verify that the NEXT textbox also points to me as the PREVIOUS.
1911  // A broken link indicates a leftover remnant that can be ignored.
1912  if (followChainIter->second.sPrevChain != sCheckForBrokenChains)
1913  break;
1914 
1915  followChainIter->second.nId = m_pImpl->getExport().m_nLinkedTextboxesChainId;
1916  followChainIter->second.nSeq = ++nSeq;
1917 
1918  //empty next chain indicates the end of the linked chain.
1919  if (followChainIter->second.sNextChain.isEmpty())
1920  break;
1921 
1922  sCheckForBrokenChains = followChainIter->first;
1923  followChainIter = m_pImpl->getExport().m_aLinkedTextboxesHelper.find(
1924  followChainIter->second.sNextChain);
1925  }
1926  }
1927  }
1928  m_pImpl->getExport().m_bLinkedTextboxesHelperInitialized = true;
1929  }
1930 
1931  m_pImpl->getExport().m_pParentFrame = nullptr;
1932  bool skipTxBxContent = false;
1933  bool isTxbxLinked = false;
1934 
1935  OUString sLinkChainName;
1936  if (xPropSetInfo.is())
1937  {
1938  if (xPropSetInfo->hasPropertyByName("LinkDisplayName"))
1939  xPropertySet->getPropertyValue("LinkDisplayName") >>= sLinkChainName;
1940  else if (xPropSetInfo->hasPropertyByName("ChainName"))
1941  xPropertySet->getPropertyValue("ChainName") >>= sLinkChainName;
1942  }
1943 
1944  // second, check if THIS textbox is linked and then decide whether to write the tag txbx or linkedTxbx
1945  auto linkedTextboxesIter = m_pImpl->getExport().m_aLinkedTextboxesHelper.find(sLinkChainName);
1946  if (linkedTextboxesIter != m_pImpl->getExport().m_aLinkedTextboxesHelper.end())
1947  {
1948  if ((linkedTextboxesIter->second.nId != 0) && (linkedTextboxesIter->second.nSeq != 0))
1949  {
1950  //not the first in the chain, so write the tag as linkedTxbx
1951  pFS->singleElementNS(XML_wps, XML_linkedTxbx, XML_id,
1952  OString::number(linkedTextboxesIter->second.nId), XML_seq,
1953  OString::number(linkedTextboxesIter->second.nSeq));
1954  /* no text content should be added to this tag,
1955  since the textbox is linked, the entire content
1956  is written in txbx block
1957  */
1958  skipTxBxContent = true;
1959  }
1960  else if ((linkedTextboxesIter->second.nId != 0) && (linkedTextboxesIter->second.nSeq == 0))
1961  {
1962  /* this is the first textbox in the chaining, we add the text content
1963  to this block*/
1964  //since the text box is linked, it needs an id.
1965  pFS->startElementNS(XML_wps, XML_txbx, XML_id,
1966  OString::number(linkedTextboxesIter->second.nId));
1967  isTxbxLinked = true;
1968  }
1969  }
1970 
1971  if (!skipTxBxContent)
1972  {
1973  if (!isTxbxLinked)
1974  pFS->startElementNS(XML_wps, XML_txbx); //text box is not linked, therefore no id.
1975 
1976  pFS->startElementNS(XML_w, XML_txbxContent);
1977 
1978  const SvxFrameDirectionItem& rDirection = rFrameFormat.GetFrameDir();
1979  if (rDirection.GetValue() == SvxFrameDirection::Vertical_RL_TB)
1980  m_pImpl->getBodyPrAttrList()->add(XML_vert, "eaVert");
1981  else if (rDirection.GetValue() == SvxFrameDirection::Vertical_LR_BT)
1982  m_pImpl->getBodyPrAttrList()->add(XML_vert, "vert270");
1983 
1984  {
1985  ::comphelper::FlagRestorationGuard const g(m_pImpl->m_bFlyFrameGraphic, true);
1986  comphelper::ValueRestorationGuard vg(m_pImpl->getExport().m_nTextTyp, TXT_TXTBOX);
1987  m_pImpl->getExport().WriteText();
1988  if (m_pImpl->getParagraphSdtOpen())
1989  {
1990  m_pImpl->getExport().DocxAttrOutput().EndParaSdtBlock();
1991  m_pImpl->setParagraphSdtOpen(false);
1992  }
1993  }
1994 
1995  pFS->endElementNS(XML_w, XML_txbxContent);
1996  pFS->endElementNS(XML_wps, XML_txbx);
1997  }
1998 
1999  // We need to init padding to 0, if it's not set.
2000  // In LO the default is 0 and so ins attributes are not set when padding is 0
2001  // but in MSO the default is 254 / 127, so we need to set 0 padding explicitly
2002  if (m_pImpl->getBodyPrAttrList())
2003  {
2004  if (!m_pImpl->getBodyPrAttrList()->hasAttribute(XML_lIns))
2005  m_pImpl->getBodyPrAttrList()->add(XML_lIns, OString::number(0));
2006  if (!m_pImpl->getBodyPrAttrList()->hasAttribute(XML_tIns))
2007  m_pImpl->getBodyPrAttrList()->add(XML_tIns, OString::number(0));
2008  if (!m_pImpl->getBodyPrAttrList()->hasAttribute(XML_rIns))
2009  m_pImpl->getBodyPrAttrList()->add(XML_rIns, OString::number(0));
2010  if (!m_pImpl->getBodyPrAttrList()->hasAttribute(XML_bIns))
2011  m_pImpl->getBodyPrAttrList()->add(XML_bIns, OString::number(0));
2012  }
2013 
2014  rtl::Reference<FastAttributeList> xBodyPrAttrList(m_pImpl->getBodyPrAttrList());
2015  m_pImpl->setBodyPrAttrList(nullptr);
2016  if (!bTextBoxOnly)
2017  {
2018  pFS->startElementNS(XML_wps, XML_bodyPr, xBodyPrAttrList);
2019  // AutoSize of the Text Frame.
2020  const SwFormatFrameSize& rSize = rFrameFormat.GetFrameSize();
2021  pFS->singleElementNS(
2022  XML_a,
2023  (rSize.GetHeightSizeType() == SwFrameSize::Variable ? XML_spAutoFit : XML_noAutofit));
2024  pFS->endElementNS(XML_wps, XML_bodyPr);
2025 
2026  pFS->endElementNS(XML_wps, XML_wsp);
2027  pFS->endElementNS(XML_a, XML_graphicData);
2028  pFS->endElementNS(XML_a, XML_graphic);
2029 
2030  // Relative size of the Text Frame.
2031  const sal_uInt8 nWidthPercent = rSize.GetWidthPercent();
2032  if (nWidthPercent && nWidthPercent != SwFormatFrameSize::SYNCED)
2033  {
2034  pFS->startElementNS(XML_wp14, XML_sizeRelH, XML_relativeFrom,
2035  (rSize.GetWidthPercentRelation() == text::RelOrientation::PAGE_FRAME
2036  ? "page"
2037  : "margin"));
2038  pFS->startElementNS(XML_wp14, XML_pctWidth);
2039  pFS->writeEscaped(OUString::number(nWidthPercent * oox::drawingml::PER_PERCENT));
2040  pFS->endElementNS(XML_wp14, XML_pctWidth);
2041  pFS->endElementNS(XML_wp14, XML_sizeRelH);
2042  }
2043  const sal_uInt8 nHeightPercent = rSize.GetHeightPercent();
2044  if (nHeightPercent && nHeightPercent != SwFormatFrameSize::SYNCED)
2045  {
2046  pFS->startElementNS(
2047  XML_wp14, XML_sizeRelV, XML_relativeFrom,
2048  (rSize.GetHeightPercentRelation() == text::RelOrientation::PAGE_FRAME ? "page"
2049  : "margin"));
2050  pFS->startElementNS(XML_wp14, XML_pctHeight);
2051  pFS->writeEscaped(OUString::number(nHeightPercent * oox::drawingml::PER_PERCENT));
2052  pFS->endElementNS(XML_wp14, XML_pctHeight);
2053  pFS->endElementNS(XML_wp14, XML_sizeRelV);
2054  }
2055 
2056  endDMLAnchorInline(&rFrameFormat);
2057  }
2058  m_pImpl->setDMLAndVMLDrawingOpen(bDMLAndVMLDrawingOpen);
2059 }
2060 
2061 void DocxSdrExport::writeVMLTextFrame(ww8::Frame const* pParentFrame, bool bTextBoxOnly)
2062 {
2063  bool bDMLAndVMLDrawingOpen = m_pImpl->getDMLAndVMLDrawingOpen();
2064  m_pImpl->setDMLAndVMLDrawingOpen(IsAnchorTypeInsideParagraph(pParentFrame));
2065 
2066  sax_fastparser::FSHelperPtr pFS = m_pImpl->getSerializer();
2067  const SwFrameFormat& rFrameFormat = pParentFrame->GetFrameFormat();
2068  const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
2069 
2070  sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : 0;
2071  sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
2072 
2073  //Save data here and restore when out of scope
2074  ExportDataSaveRestore aDataGuard(m_pImpl->getExport(), nStt, nEnd, pParentFrame);
2075 
2076  // When a frame has some low height, but automatically expanded due
2077  // to lots of contents, this size contains the real size.
2078  const Size aSize = pParentFrame->GetSize();
2079  m_pImpl->setFlyFrameSize(&aSize);
2080 
2081  m_pImpl->setTextFrameSyntax(true);
2084  m_pImpl->getTextFrameStyle() = "position:absolute";
2085  if (!bTextBoxOnly)
2086  {
2087  OString sRotation(OString::number(m_pImpl->getDMLandVMLTextFrameRotation().get() / -100));
2088  m_pImpl->getExport().SdrExporter().getTextFrameStyle().append(";rotation:" + sRotation);
2089  }
2090  m_pImpl->getExport().OutputFormat(pParentFrame->GetFrameFormat(), false, false, true);
2091  m_pImpl->getFlyAttrList()->add(XML_style, m_pImpl->getTextFrameStyle().makeStringAndClear());
2092 
2093  const SdrObject* pObject = pParentFrame->GetFrameFormat().FindRealSdrObject();
2094  if (pObject != nullptr)
2095  {
2096  OUString sAnchorId = lclGetAnchorIdFromGrabBag(pObject);
2097  if (!sAnchorId.isEmpty())
2098  m_pImpl->getFlyAttrList()->addNS(XML_w14, XML_anchorId,
2099  OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
2100 
2101  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(pObject)->getUnoShape(),
2102  uno::UNO_QUERY);
2103  uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
2104  OUString sHyperlink;
2105  if (xShapeProps.is())
2106  xShapeProps->getPropertyValue("HyperLinkURL") >>= sHyperlink;
2107  if (!sHyperlink.isEmpty())
2108  m_pImpl->getFlyAttrList()->add(XML_href,
2109  OUStringToOString(sHyperlink, RTL_TEXTENCODING_UTF8));
2110  }
2111  rtl::Reference<FastAttributeList> xFlyAttrList(m_pImpl->getFlyAttrList());
2112  m_pImpl->getFlyAttrList().clear();
2113  rtl::Reference<FastAttributeList> xTextboxAttrList(m_pImpl->getTextboxAttrList());
2114  m_pImpl->getTextboxAttrList().clear();
2115  m_pImpl->setTextFrameSyntax(false);
2116  m_pImpl->setFlyFrameSize(nullptr);
2117  m_pImpl->getExport().m_pParentFrame = nullptr;
2118 
2119  if (!bTextBoxOnly)
2120  {
2121  pFS->startElementNS(XML_w, XML_pict);
2122  pFS->startElementNS(XML_v, XML_rect, xFlyAttrList);
2123  m_pImpl->textFrameShadow(rFrameFormat);
2124  if (m_pImpl->getFlyFillAttrList().is())
2125  {
2126  rtl::Reference<FastAttributeList> xFlyFillAttrList(m_pImpl->getFlyFillAttrList());
2127  pFS->singleElementNS(XML_v, XML_fill, xFlyFillAttrList);
2128  }
2129  if (m_pImpl->getDashLineStyleAttr().is())
2130  {
2131  rtl::Reference<FastAttributeList> xDashLineStyleAttr(m_pImpl->getDashLineStyleAttr());
2132  pFS->singleElementNS(XML_v, XML_stroke, xDashLineStyleAttr);
2133  }
2134  pFS->startElementNS(XML_v, XML_textbox, xTextboxAttrList);
2135  }
2136  m_pImpl->getFlyFillAttrList().clear();
2137  m_pImpl->getDashLineStyleAttr().clear();
2138 
2139  pFS->startElementNS(XML_w, XML_txbxContent);
2140  {
2141  ::comphelper::FlagRestorationGuard const g(m_pImpl->m_bFlyFrameGraphic, true);
2142  comphelper::ValueRestorationGuard vg(m_pImpl->getExport().m_nTextTyp, TXT_TXTBOX);
2143  m_pImpl->getExport().WriteText();
2144  if (m_pImpl->getParagraphSdtOpen())
2145  {
2146  m_pImpl->getExport().DocxAttrOutput().EndParaSdtBlock();
2147  m_pImpl->setParagraphSdtOpen(false);
2148  }
2149  }
2150  pFS->endElementNS(XML_w, XML_txbxContent);
2151  if (!bTextBoxOnly)
2152  {
2153  pFS->endElementNS(XML_v, XML_textbox);
2154 
2155  if (m_pImpl->getFlyWrapAttrList())
2156  {
2157  rtl::Reference<FastAttributeList> xFlyWrapAttrList(m_pImpl->getFlyWrapAttrList());
2158  m_pImpl->setFlyWrapAttrList(nullptr);
2159  pFS->singleElementNS(XML_w10, XML_wrap, xFlyWrapAttrList);
2160  }
2161 
2162  pFS->endElementNS(XML_v, XML_rect);
2163  pFS->endElementNS(XML_w, XML_pict);
2164  }
2165 
2166  m_pImpl->setDMLAndVMLDrawingOpen(bDMLAndVMLDrawingOpen);
2167 }
2168 
2169 bool DocxSdrExport::isTextBox(const SwFrameFormat& rFrameFormat)
2170 {
2171  return SwTextBoxHelper::isTextBox(&rFrameFormat, RES_FLYFRMFMT);
2172 }
2173 
2174 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
bool getTextFrameSyntax() const
bool IsContour() const
Definition: fmtsrnd.hxx:53
double toDegrees(Degree10 x)
void writeDMLAndVMLDrawing(const SdrObject *sdrObj, const SwFrameFormat &rFrameFormat, int nAnchorId)
Writes shape in both DML and VML format.
sax_fastparser::FastAttributeList * getFlyWrapAttrList() const
Helper class, so that the DocxExport::RestoreData() call will always happen.
OBJ_PATHPOLY
SwNoTextNode * GetNoTextNodeFromSwFrameFormat(const SwFrameFormat &rFormat)
Get the SwNoTextNode associated with a SwFrameFormat if here is one.
static bool lcl_isLockedCanvas(const uno::Reference< drawing::XShape > &xShape)
bool getParagraphHasDrawing() const
bool IsDrawingOpen() const
sal_uInt8 GetAlpha() const
virtual const tools::Rectangle & GetCurrentBoundRect() const
OBJ_PATHPLIN
void setFlyWrapAttrList(rtl::Reference< sax_fastparser::FastAttributeList > const &pFlyWrapAttrList)
sal_uInt16 GetLower() const
const Size * m_pFlyFrameSize
double ConvertBorderWidthToWord(SvxBorderLineStyle, double)
std::unique_ptr< Impl > m_pImpl
TextVerticalAdjust GetTextVerticalAdjust(sal_Int32 nToken)
const sal_Int32 PER_PERCENT
tools::Long getWidth() const
void endDMLAnchorInline(const SwFrameFormat *pFrameFormat)
bool IsTransparent() const
OBJ_GRUP
constexpr tools::Long Left() const
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:106
oox::drawingml::DrawingML * m_pDrawingML
bool getDMLTextFrameSyntax() const
rtl::Reference< sax_fastparser::FastAttributeList > & getFlyAttrList()
sal_Int32 ExportRotateClockwisify(Degree100 input)
SwTwips GetPos() const
Definition: fmtornt.hxx:92
sal_uIntPtr sal_uLong
long Long
tools::Long GetRight() const
virtual void SaveData(sal_uLong nStt, sal_uLong nEnd)
Remember some of the members so that we can recurse in WriteText().
Definition: wrtww8.cxx:1892
void writeDMLEffectLst(const SwFrameFormat &rFrameFormat)
Write , the effect list.
OUString GetDescription() const
SwRect FindLayoutRect(const bool bPrtArea=false, const Point *pPoint=nullptr) const
Definition: atrfrm.cxx:2720
OBJ_LINE
const SvxFrameDirectionItem & GetFrameDir(bool=true) const
Definition: frmatr.hxx:94
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:78
tools::Long GetWidth() const
Holds data used by DocxSdrExport only.
DocxExport & m_rExport
void setFlyAttrList(const rtl::Reference< sax_fastparser::FastAttributeList > &pFlyAttrList)
SwNode & GetNode() const
Definition: ndindex.hxx:119
const OUString & getHyperlink() const
bool IsParagraphHasDrawing() const
Of course Writer needs its own rectangles.
Definition: swrect.hxx:34
virtual SdrObjKind GetObjIdentifier() const
const editeng::SvxBorderLine * GetRight() const
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:55
The class that does all the actual DOCX export-related work.
Definition: docxexport.hxx:66
sax_fastparser::FastAttributeList * getBodyPrAttrList()
Attributes of , used during DML export of text frames.
EmbeddedObjectRef * pObject
bool getParagraphSdtOpen() const
void startDMLAnchorInline(const SwFrameFormat *pFrameFormat, const Size &rSize)
UseOnPage GetUseOn() const
Definition: pagedesc.hxx:353
tools::Polygon PolygonFromPolyPolygon(const tools::PolyPolygon &rPolyPoly)
Make a best fit Polygon from a PolyPolygon.
rtl::Reference< sax_fastparser::FastAttributeList > & getFlyFillAttrList()
void writeDiagram(const SdrObject *sdrObject, const SwFrameFormat &rFrameFormat, int nDiagramId)
Writes a diagram (smartart).
void setFlyWrapAttrList(rtl::Reference< sax_fastparser::FastAttributeList > const &pAttrList)
void setDMLAndVMLDrawingOpen(bool bDMLAndVMLDrawingOpen)
constexpr TypedWhichId< SwFlyFrameFormat > RES_FLYFRMFMT(156)
static bool isTextBox(const SwFrameFormat &rFrameFormat)
Is this a standalone TextFrame, or used as a TextBox of a shape?
IDocumentDrawModelAccess const & getIDocumentDrawModelAccess() const
Definition: doc.cxx:155
void writeDMLTextFrame(ww8::Frame const *pParentFrame, int nAnchorId, bool bTextBoxOnly=false)
Writes text frame in DML format.
virtual const tools::Rectangle & GetSnapRect() const
bool IsVisible() const
tools::Long getHeight() const
constexpr tools::Long Width() const
DstType sequenceToContainer(const css::uno::Sequence< SrcType > &i_Sequence)
bool getDMLAndVMLDrawingOpen() const
SvxShadowLocation GetLocation() const
virtual css::uno::Reference< css::uno::XInterface > getUnoShape()
MSO_SPT
B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
bool getDMLTextFrameSyntax() const
const OUString & GetName() const
Definition: format.hxx:115
Degree100 & getDMLandVMLTextFrameRotation()
oox::drawingml::DrawingML * getDrawingML() const
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
Degree100 m_nDMLandVMLTextFrameRotation
List of TextBoxes in this document: they are exported as part of their shape, never alone...
virtual bool isExternalURL(const OUString &rURL) const
const Size * getFlyFrameSize() const
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
Degree100 NormAngle36000(Degree100 deg100)
bool HasTextBoxContent(sal_uInt32 nShapeType)
rtl::Reference< sax_fastparser::FastAttributeList > m_pBodyPrAttrList
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
OUString getRelationship(Relationship eRelationship)
const OUStringLiteral sColor
DocxSdrExport(DocxExport &rExport, const sax_fastparser::FSHelperPtr &pSerializer, oox::drawingml::DrawingML *pDrawingML)
void setParagraphSdtOpen(bool bParagraphSdtOpen)
const SwFrameFormat & GetFrameFormat() const
Get the writer SwFrameFormat that this object describes.
rtl::Reference< FastAttributeList > SurroundToVMLWrap(SwFormatSurround const &rSurround)
Impl(DocxExport &rExport, sax_fastparser::FSHelperPtr pSerializer, oox::drawingml::DrawingML *pDrawingML)
virtual SdrLayerID GetInvisibleHellId() const =0
const sax_fastparser::FSHelperPtr & getSerializer() const
ShapeFlag
void setParagraphHasDrawing(bool bParagraphHasDrawing)
const Color & GetColor() const
rtl::Reference< sax_fastparser::FastAttributeList > & getTextboxAttrList()
Attributes of the next v:textbox element.
const editeng::SvxBorderLine * GetTop() const
const SwFormatFollowTextFlow & GetFollowTextFlow(bool=true) const
tools::Polygon CorrectWordWrapPolygonForExport(const tools::PolyPolygon &rPolyPoly, const SwNoTextNode *pNd, bool bCorrectCrop)
Undo all scaling / move tricks of the wrap polygon done during import.
OBJ_PATHFILL
UNDERLYING_TYPE get() const
Style of a layout element.
Definition: frmfmt.hxx:59
static rtl::Reference< FastAttributeList > createAttrList()
#define SAL_MAX_INT32
rtl::Reference< sax_fastparser::FastAttributeList > m_pTextboxAttrList
virtual void RestoreData()
Restore what was saved in SaveData().
Definition: wrtww8.cxx:1924
bool isClosed() const
const editeng::SvxBorderLine * GetLeft() const
rtl::Reference< sax_fastparser::FastAttributeList > & getFlyAttrList()
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
int i
OStringBuffer & getTextFrameStyle()
rtl::Reference< sax_fastparser::FastAttributeList > m_pFlyWrapAttrList
void setFlyFrameSize(const Size *pFlyFrameSize)
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
const SwPageDesc & GetPageDesc(const size_t i) const
Definition: doc.hxx:881
const SwFormatHoriOrient & GetHoriOrient(bool=true) const
Definition: fmtornt.hxx:108
const Color & GetColor() const
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType, SdrObject *pObject=nullptr)
Is the frame format a text box?
ExportDataSaveRestore(DocxExport &rExport, sal_uLong nStt, sal_uLong nEnd, ww8::Frame const *pParentFrame)
bool getDrawingOpen() const
FlyAnchors.
Definition: fmtanchr.hxx:34
void setSerializer(const sax_fastparser::FSHelperPtr &pSerializer)
tools::Long GetLeft() const
sal_uInt8 GetHeightPercent() const
Definition: fmtfsize.hxx:88
const ww8::Frame * m_pParentFrame
Definition: wrtww8.hxx:518
OBJ_GRAF
constexpr tools::Long Right() const
#define SAL_MIN_INT32
OBJ_FREEFILL
OUString GetTitle() const
bool getTextFrameSyntax() const
sal_Int16 GetHoriOrient() const
Definition: fmtornt.hxx:87
void transform(const basegfx::B2DHomMatrix &rMatrix)
Object Value
sal_uInt32 GetOrdNum() const
OBJ_PLIN
OStringBuffer & getTextFrameStyle()
OBJ_FREELINE
css::text::WrapTextMode GetSurround() const
Definition: fmtsrnd.hxx:51
constexpr tools::Long Top() const
OString ConvertColor(const Color &rColor)
sal_uInt16 GetSize() const
Marks a node in the document model.
Definition: ndindex.hxx:31
void setDMLandVMLTextFrameRotation(Degree100 nDMLandVMLTextFrameRotation)
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:123
bool IsDMLAndVMLDrawingOpen() const
sal_uInt8 GetWidthPercent() const
Definition: fmtfsize.hxx:91
rtl::Reference< sax_fastparser::FastAttributeList > & getFlyFillAttrList()
virtual OUString getTransformedString(const OUString &rURL) const
std::shared_ptr< FastSerializerHelper > FSHelperPtr
void textFrameShadow(const SwFrameFormat &rFrameFormat)
Writes wp wrapper code around an SdrObject, which itself is written using drawingML syntax...
rtl::Reference< sax_fastparser::FastAttributeList > m_pFlyAttrList
const double * GetRelativeWidth() const
sax_fastparser::FSHelperPtr m_pSerializer
sal_Int16 GetRelativeWidthRelation() const
OUString GetName() const
#define Y
constexpr Point Center() const
virtual SdrLayerID GetHellId() const =0
virtual SdrLayerID GetLayer() const
sal_Int16 GetHeightPercentRelation() const
Definition: fmtfsize.hxx:89
const SwNodeIndex * GetContentIdx() const
Definition: fmtcntnt.hxx:46
constexpr tools::Long Bottom() const
void setParagraphSdtOpen(bool bParagraphSdtOpen)
Set if paragraph sdt open in the current drawing.
const Point & GetPoint(sal_uInt16 nPos) const
rtl::Reference< sax_fastparser::FastAttributeList > m_pDashLineStyleAttr
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
sal_uLong EndOfSectionIndex() const
Definition: node.hxx:678
const SvxULSpaceItem & GetULSpace(bool=true) const
Definition: frmatr.hxx:76
void writeVMLTextFrame(ww8::Frame const *pParentFrame, bool bTextBoxOnly=false)
Writes text frame in VML format.
SdrObjectUniquePtr ConvertToPolyObj(bool bBezier, bool bLineToArea) const
rtl::Reference< sax_fastparser::FastAttributeList > & getDashLineStyle()
sal_uInt32 count() const
void setBodyPrAttrList(sax_fastparser::FastAttributeList *pBodyPrAttrList)
const SvxOpaqueItem & GetOpaque(bool=true) const
Definition: frmatr.hxx:80
iterator find(const OUString &rKey)
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:88
void GetGrabBagItem(css::uno::Any &rVal) const
constexpr tools::Long Height() const
unsigned char sal_uInt8
void writeDMLDrawing(const SdrObject *pSdrObject, const SwFrameFormat *pFrameFormat, int nAnchorId)
Writes a drawing as DML.
Make exporting a Writer Frame easy.
rtl::Reference< sax_fastparser::FastAttributeList > m_pFlyFillAttrList
Flag for checking drawing in a paragraph.
SwTwips GetPos() const
Definition: fmtornt.hxx:59
void writeOnlyTextOfFrame(ww8::Frame const *pParentFrame)
Writes text from Textbox for
void setTextFrameSyntax(bool bTextFrameSyntax)
void setTextboxAttrList(const rtl::Reference< sax_fastparser::FastAttributeList > &pTextboxAttrList)
const Size & GetSize() const
The Size of the contained element.
void writeBoxItemLine(const SvxBoxItem &rBox)
Writes the drawingML markup of a box item.
std::unique_ptr< SdrObject, SdrObjectFreeOp > SdrObjectUniquePtr
sal_Int16 GetVertOrient() const
Definition: fmtornt.hxx:54
sax_fastparser::FastAttributeList * getBodyPrAttrList() const
const SwFormatWrapInfluenceOnObjPos & GetWrapInfluenceOnObjPos(bool=true) const
void setDMLTextFrameSyntax(bool bDMLTextFrameSyntax)
const basegfx::B2DPolyPolygon & GetPathPoly() const
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
constexpr sal_Int32 FSNS(sal_Int32 namespc, sal_Int32 element)
const SwFormatContent & GetContent(bool=true) const
Definition: fmtcntnt.hxx:55
void setSerializer(const sax_fastparser::FSHelperPtr &pSerializer)
OBJ_CUSTOMSHAPE
void writeVMLDrawing(const SdrObject *sdrObj, const SwFrameFormat &rFrameFormat)
Writes a drawing as VML data.
SvxBorderLineStyle GetBorderLineStyle() const
static bool isSupportedDMLShape(const uno::Reference< drawing::XShape > &xShape)
OBJ_PATHLINE
rtl::Reference< sax_fastparser::FastAttributeList > & getTextboxAttrList()
sal_Int16 GetRelativeHeightRelation() const
virtual Degree100 GetRotateAngle() const
Degree100 abs(Degree100 x)
virtual const tools::Rectangle & GetLogicRect() const
bool getFlyFrameGraphic() const
bool IsOutside() const
Definition: fmtsrnd.hxx:54
OStringBuffer m_aTextFrameStyle
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:120
Frame is variable in Var-direction.
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
void setDrawingOpen(bool bDrawingOpen)
OBJ_NONE
void setParagraphHasDrawing(bool bParagraphHasDrawing)
const editeng::SvxBorderLine * GetBottom() const
sal_Int16 GetWidthPercentRelation() const
Definition: fmtfsize.hxx:92
const Size * getFlyFrameSize() const
When exporting fly frames, this holds the real size of the frame.
static MSO_SPT GetCustomShapeType(const css::uno::Reference< css::drawing::XShape > &rXShape, ShapeFlag &nMirrorFlags, OUString &rShapeType, bool bOOXML=false)
SdrObject * FindRealSdrObject()
Definition: atrfrm.cxx:2773
const double * GetRelativeHeight() const
rtl::Reference< sax_fastparser::FastAttributeList > & getDashLineStyleAttr()
sal_uInt16 GetUpper() const
DocxExport & getExport() const
SwFrameSize GetHeightSizeType() const
Definition: fmtfsize.hxx:80
sal_uInt16 GetWidth() const
static OString lcl_TransparencyToDrawingMlAlpha(const Color &rColor)
const SvxLRSpaceItem & GetLRSpace(bool=true) const
Definition: frmatr.hxx:74
EnumT GetValue() const
const SvxShadowItem & GetShadow(bool=true) const
Definition: frmatr.hxx:88
SwFlyDrawObjIdentifier
void Insert(sal_uInt16 nPos, const Point &rPt)