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