LibreOffice Module sw (master)  1
docxsdrexport.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include "docxsdrexport.hxx"
11 #include <com/sun/star/beans/XPropertySet.hpp>
12 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
13 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
14 #include <editeng/lrspitem.hxx>
15 #include <editeng/ulspitem.hxx>
16 #include <editeng/shaditem.hxx>
17 #include <editeng/opaqitem.hxx>
18 #include <editeng/boxitem.hxx>
19 #include <svx/svdogrp.hxx>
20 #include <oox/token/namespaces.hxx>
21 #include <textboxhelper.hxx>
22 #include <fmtanchr.hxx>
23 #include <fmtsrnd.hxx>
24 #include <fmtcntnt.hxx>
25 #include <fmtornt.hxx>
26 #include <fmtfsize.hxx>
27 #include <fmtfollowtextflow.hxx>
28 #include <frmatr.hxx>
30 #include "docxattributeoutput.hxx"
31 #include "docxexportfilter.hxx"
32 #include <comphelper/flagguard.hxx>
33 #include <comphelper/sequence.hxx>
35 #include <sal/log.hxx>
36 #include <frmfmt.hxx>
38 
39 #include <tools/diagnose_ex.h>
40 #include <svx/xlnwtit.hxx>
41 
42 using namespace com::sun::star;
43 using namespace oox;
44 using namespace sax_fastparser;
45 
46 namespace
47 {
48 uno::Sequence<beans::PropertyValue> lclGetProperty(const uno::Reference<drawing::XShape>& rShape,
49  const OUString& rPropName)
50 {
51  uno::Sequence<beans::PropertyValue> aResult;
52  uno::Reference<beans::XPropertySet> xPropertySet(rShape, uno::UNO_QUERY);
53  uno::Reference<beans::XPropertySetInfo> xPropSetInfo;
54 
55  if (!xPropertySet.is())
56  return aResult;
57 
58  xPropSetInfo = xPropertySet->getPropertySetInfo();
59  if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(rPropName))
60  {
61  xPropertySet->getPropertyValue(rPropName) >>= aResult;
62  }
63  return aResult;
64 }
65 
66 OUString lclGetAnchorIdFromGrabBag(const SdrObject* pObj)
67 {
68  OUString aResult;
69  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(pObj)->getUnoShape(),
70  uno::UNO_QUERY);
71  OUString aGrabBagName;
72  uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
73  if (xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
74  aGrabBagName = "FrameInteropGrabBag";
75  else
76  aGrabBagName = "InteropGrabBag";
77  uno::Sequence<beans::PropertyValue> propList = lclGetProperty(xShape, aGrabBagName);
78  auto pProp
79  = std::find_if(propList.begin(), propList.end(),
80  [](const beans::PropertyValue& rProp) { return rProp.Name == "AnchorId"; });
81  if (pProp != propList.end())
82  pProp->Value >>= aResult;
83  return aResult;
84 }
85 
86 void lclMovePositionWithRotation(awt::Point& aPos, const Size& rSize, Degree100 nRotation100)
87 {
88  // code from ImplEESdrWriter::ImplFlipBoundingBox (filter/source/msfilter/eschesdo.cxx)
89  // TODO: refactor
90 
91  if (nRotation100 == 0_deg100)
92  return;
93  sal_Int64 nRotation = nRotation100.get();
94  if (nRotation < 0)
95  nRotation = (36000 + nRotation) % 36000;
96  if (nRotation % 18000 == 0)
97  nRotation = 0;
98  while (nRotation > 9000)
99  nRotation = (18000 - (nRotation % 18000));
100 
101  double fVal = static_cast<double>(nRotation) * F_PI18000;
102  double fCos = cos(fVal);
103  double fSin = sin(fVal);
104 
105  double nWidthHalf = static_cast<double>(rSize.Width()) / 2;
106  double nHeightHalf = static_cast<double>(rSize.Height()) / 2;
107 
108  double nXDiff = fSin * nHeightHalf + fCos * nWidthHalf - nWidthHalf;
109  double nYDiff = fSin * nWidthHalf + fCos * nHeightHalf - nHeightHalf;
110 
111  aPos.X += nXDiff;
112  aPos.Y += nYDiff;
113 }
114 
116 bool IsAnchorTypeInsideParagraph(const ww8::Frame* pFrame)
117 {
118  const SwFormatAnchor& rAnchor = pFrame->GetFrameFormat().GetAttrSet().GetAnchor();
119  return rAnchor.GetAnchorId() != RndStdIds::FLY_AT_PAGE;
120 }
121 }
122 
124  ww8::Frame const* pParentFrame)
125  : m_rExport(rExport)
126 {
127  m_rExport.SaveData(nStt, nEnd);
128  m_rExport.m_pParentFrame = pParentFrame;
129 }
130 
132 
135 {
136 private:
145  OStringBuffer m_aTextFrameStyle;
157 
158 public:
159  bool m_bFlyFrameGraphic = false;
160 
162  oox::drawingml::DrawingML* pDrawingML)
163  : m_rExport(rExport)
164  , m_pSerializer(std::move(pSerializer))
165  , m_pDrawingML(pDrawingML)
166  , m_pFlyFrameSize(nullptr)
167  , m_bTextFrameSyntax(false)
168  , m_bDMLTextFrameSyntax(false)
169  , m_bDrawingOpen(false)
170  , m_bParagraphSdtOpen(false)
171  , m_bParagraphHasDrawing(false)
172  , m_bDMLAndVMLDrawingOpen(false)
173  {
174  }
175 
177 
178  void textFrameShadow(const SwFrameFormat& rFrameFormat);
179  static bool isSupportedDMLShape(const uno::Reference<drawing::XShape>& xShape);
180 
182  {
183  m_pSerializer = pSerializer;
184  }
185 
187 
188  void setFlyFrameSize(const Size* pFlyFrameSize) { m_pFlyFrameSize = pFlyFrameSize; }
189 
190  const Size* getFlyFrameSize() const { return m_pFlyFrameSize; }
191 
192  void setTextFrameSyntax(bool bTextFrameSyntax) { m_bTextFrameSyntax = bTextFrameSyntax; }
193 
194  bool getTextFrameSyntax() const { return m_bTextFrameSyntax; }
195 
196  void setDMLTextFrameSyntax(bool bDMLTextFrameSyntax)
197  {
198  m_bDMLTextFrameSyntax = bDMLTextFrameSyntax;
199  }
200 
202 
204  {
205  m_pFlyAttrList = pFlyAttrList;
206  }
207 
209 
210  void
212  {
213  m_pTextboxAttrList = pTextboxAttrList;
214  }
215 
217  {
218  return m_pTextboxAttrList;
219  }
220 
221  OStringBuffer& getTextFrameStyle() { return m_aTextFrameStyle; }
222 
223  void setDrawingOpen(bool bDrawingOpen) { m_bDrawingOpen = bDrawingOpen; }
224 
225  bool getDrawingOpen() const { return m_bDrawingOpen; }
226 
227  void setParagraphSdtOpen(bool bParagraphSdtOpen) { m_bParagraphSdtOpen = bParagraphSdtOpen; }
228 
229  bool getParagraphSdtOpen() const { return m_bParagraphSdtOpen; }
230 
231  void setDMLAndVMLDrawingOpen(bool bDMLAndVMLDrawingOpen)
232  {
233  m_bDMLAndVMLDrawingOpen = bDMLAndVMLDrawingOpen;
234  }
235 
237 
238  void setParagraphHasDrawing(bool bParagraphHasDrawing)
239  {
240  m_bParagraphHasDrawing = bParagraphHasDrawing;
241  }
242 
244 
246  {
247  return m_pFlyFillAttrList;
248  }
249 
250  void
252  {
253  m_pFlyWrapAttrList = pFlyWrapAttrList;
254  }
255 
257  {
258  return m_pFlyWrapAttrList.get();
259  }
260 
262  {
263  m_pBodyPrAttrList = pBodyPrAttrList;
264  }
265 
266  sax_fastparser::FastAttributeList* getBodyPrAttrList() const { return m_pBodyPrAttrList.get(); }
267 
269  {
270  return m_pDashLineStyleAttr;
271  }
272 
273  bool getFlyFrameGraphic() const { return m_bFlyFrameGraphic; }
274 
276 
277  DocxExport& getExport() const { return m_rExport; }
278 
279  void setDMLandVMLTextFrameRotation(Degree100 nDMLandVMLTextFrameRotation)
280  {
281  m_nDMLandVMLTextFrameRotation = nDMLandVMLTextFrameRotation;
282  }
283 
285 };
286 
288  oox::drawingml::DrawingML* pDrawingML)
289  : m_pImpl(std::make_unique<Impl>(rExport, pSerializer, pDrawingML))
290 {
291 }
292 
294 
296 {
297  m_pImpl->setSerializer(pSerializer);
298 }
299 
300 const Size* DocxSdrExport::getFlyFrameSize() const { return m_pImpl->getFlyFrameSize(); }
301 
302 bool DocxSdrExport::getTextFrameSyntax() const { return m_pImpl->getTextFrameSyntax(); }
303 
304 bool DocxSdrExport::getDMLTextFrameSyntax() const { return m_pImpl->getDMLTextFrameSyntax(); }
305 
307 {
308  return m_pImpl->getFlyAttrList();
309 }
310 
312 {
313  return m_pImpl->getTextboxAttrList();
314 }
315 
316 OStringBuffer& DocxSdrExport::getTextFrameStyle() { return m_pImpl->getTextFrameStyle(); }
317 
318 bool DocxSdrExport::IsDrawingOpen() const { return m_pImpl->getDrawingOpen(); }
319 
320 void DocxSdrExport::setParagraphSdtOpen(bool bParagraphSdtOpen)
321 {
322  m_pImpl->setParagraphSdtOpen(bParagraphSdtOpen);
323 }
324 
325 bool DocxSdrExport::IsDMLAndVMLDrawingOpen() const { return m_pImpl->getDMLAndVMLDrawingOpen(); }
326 
327 bool DocxSdrExport::IsParagraphHasDrawing() const { return m_pImpl->getParagraphHasDrawing(); }
328 
329 void DocxSdrExport::setParagraphHasDrawing(bool bParagraphHasDrawing)
330 {
331  m_pImpl->setParagraphHasDrawing(bParagraphHasDrawing);
332 }
333 
335 {
336  return m_pImpl->getFlyFillAttrList();
337 }
338 
340 {
341  return m_pImpl->getBodyPrAttrList();
342 }
343 
345 {
346  return m_pImpl->getDashLineStyleAttr();
347 }
348 
351 {
352  m_pImpl->setFlyWrapAttrList(pAttrList);
353 }
354 
355 void DocxSdrExport::startDMLAnchorInline(const SwFrameFormat* pFrameFormat, const Size& rSize)
356 {
357  m_pImpl->setDrawingOpen(true);
358  m_pImpl->setParagraphHasDrawing(true);
359  m_pImpl->getSerializer()->startElementNS(XML_w, XML_drawing);
360 
361  // tdf#135047: It must be allowed to find in parents too, but default value of bInP parameter
362  // for GetLRSpace() and GetULSpace() is true, so no direct setting is required.
363  const SvxLRSpaceItem& aLRSpaceItem = pFrameFormat->GetLRSpace();
364  const SvxULSpaceItem& aULSpaceItem = pFrameFormat->GetULSpace();
365 
366  bool isAnchor;
367 
368  if (m_pImpl->getFlyFrameGraphic())
369  {
370  isAnchor = false; // make Graphic object inside DMLTextFrame & VMLTextFrame as Inline
371  }
372  else
373  {
374  isAnchor = pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR;
375  }
376 
377  // Count effectExtent values, their value is needed before dist{T,B,L,R} is written.
378  SvxShadowItem aShadowItem = pFrameFormat->GetShadow();
379  sal_Int32 nLeftExt = 0;
380  sal_Int32 nRightExt = 0;
381  sal_Int32 nTopExt = 0;
382  sal_Int32 nBottomExt = 0;
383  if (aShadowItem.GetLocation() != SvxShadowLocation::NONE)
384  {
385  sal_Int32 nShadowWidth(TwipsToEMU(aShadowItem.GetWidth()));
386  switch (aShadowItem.GetLocation())
387  {
388  case SvxShadowLocation::TopLeft:
389  nTopExt = nLeftExt = nShadowWidth;
390  break;
391  case SvxShadowLocation::TopRight:
392  nTopExt = nRightExt = nShadowWidth;
393  break;
394  case SvxShadowLocation::BottomLeft:
395  nBottomExt = nLeftExt = nShadowWidth;
396  break;
397  case SvxShadowLocation::BottomRight:
398  nBottomExt = nRightExt = nShadowWidth;
399  break;
400  case SvxShadowLocation::NONE:
401  case SvxShadowLocation::End:
402  break;
403  }
404  }
405  else if (const SdrObject* pObject = pFrameFormat->FindRealSdrObject())
406  {
407  // No shadow, but we have an idea what was the original effectExtent.
408  uno::Any aAny;
409  pObject->GetGrabBagItem(aAny);
410  comphelper::SequenceAsHashMap aGrabBag(aAny);
411  auto it = aGrabBag.find("CT_EffectExtent");
412  if (it != aGrabBag.end())
413  {
414  comphelper::SequenceAsHashMap aEffectExtent(it->second);
415  for (const std::pair<const OUString, uno::Any>& rDirection : aEffectExtent)
416  {
417  if (rDirection.first == "l" && rDirection.second.has<sal_Int32>())
418  nLeftExt = rDirection.second.get<sal_Int32>();
419  else if (rDirection.first == "t" && rDirection.second.has<sal_Int32>())
420  nTopExt = rDirection.second.get<sal_Int32>();
421  else if (rDirection.first == "r" && rDirection.second.has<sal_Int32>())
422  nRightExt = rDirection.second.get<sal_Int32>();
423  else if (rDirection.first == "b" && rDirection.second.has<sal_Int32>())
424  nBottomExt = rDirection.second.get<sal_Int32>();
425  }
426  }
427  }
428 
429  if (isAnchor)
430  {
433  bool bOpaque = pFrameFormat->GetOpaque().GetValue();
434  awt::Point aPos(pFrameFormat->GetHoriOrient().GetPos(),
435  pFrameFormat->GetVertOrient().GetPos());
436  const SdrObject* pObj = pFrameFormat->FindRealSdrObject();
437  Degree100 nRotation(0);
438  if (pObj != nullptr)
439  {
440  // SdrObjects know their layer, consider that instead of the frame format.
441  bOpaque = pObj->GetLayer()
442  != pFrameFormat->GetDoc()->getIDocumentDrawModelAccess().GetHellId()
443  && pObj->GetLayer()
444  != pFrameFormat->GetDoc()
447 
448  // Do not do this with lines.
449  if (pObj->GetObjIdentifier() != OBJ_LINE)
450  {
451  nRotation = pObj->GetRotateAngle();
452  lclMovePositionWithRotation(aPos, rSize, nRotation);
453  }
454  }
455  attrList->add(XML_behindDoc, bOpaque ? "0" : "1");
456  sal_Int32 nLineWidth = 0;
457  if (const SdrObject* pObject = pFrameFormat->FindRealSdrObject())
458  {
459  nLineWidth = pObject->GetMergedItem(XATTR_LINEWIDTH).GetValue();
460  }
461 
462  // Extend distance with the effect extent if the shape is not rotated, which is the opposite
463  // of the mapping done at import time.
464  // The type of dist* attributes is unsigned, so make sure no negative value is written.
465  sal_Int64 nTopExtDist = nRotation ? 0 : nTopExt;
466  nTopExtDist -= TwipsToEMU(nLineWidth / 2);
467  sal_Int64 nDistT = std::max(static_cast<sal_Int64>(0),
468  TwipsToEMU(aULSpaceItem.GetUpper()) - nTopExtDist);
469  attrList->add(XML_distT, OString::number(nDistT).getStr());
470  sal_Int64 nBottomExtDist = nRotation ? 0 : nBottomExt;
471  nBottomExtDist -= TwipsToEMU(nLineWidth / 2);
472  sal_Int64 nDistB = std::max(static_cast<sal_Int64>(0),
473  TwipsToEMU(aULSpaceItem.GetLower()) - nBottomExtDist);
474  attrList->add(XML_distB, OString::number(nDistB).getStr());
475  sal_Int64 nLeftExtDist = nRotation ? 0 : nLeftExt;
476  nLeftExtDist -= TwipsToEMU(nLineWidth / 2);
477  sal_Int64 nDistL = std::max(static_cast<sal_Int64>(0),
478  TwipsToEMU(aLRSpaceItem.GetLeft()) - nLeftExtDist);
479  attrList->add(XML_distL, OString::number(nDistL).getStr());
480  sal_Int64 nRightExtDist = nRotation ? 0 : nRightExt;
481  nRightExtDist -= TwipsToEMU(nLineWidth / 2);
482  sal_Int64 nDistR = std::max(static_cast<sal_Int64>(0),
483  TwipsToEMU(aLRSpaceItem.GetRight()) - nRightExtDist);
484  attrList->add(XML_distR, OString::number(nDistR).getStr());
485  attrList->add(XML_simplePos, "0");
486  attrList->add(XML_locked, "0");
487  bool bLclInTabCell = true;
488  if (pObj)
489  {
490  uno::Reference<drawing::XShape> xShape((const_cast<SdrObject*>(pObj)->getUnoShape()),
491  uno::UNO_QUERY);
492  uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
493  if (xShapeProps.is())
494  xShapeProps->getPropertyValue("IsFollowingTextFlow") >>= bLclInTabCell;
495  }
496  if (bLclInTabCell)
497  attrList->add(XML_layoutInCell, "1");
498  else
499  attrList->add(XML_layoutInCell, "0");
500  bool bAllowOverlap = pFrameFormat->GetWrapInfluenceOnObjPos().GetAllowOverlap();
501  attrList->add(XML_allowOverlap, bAllowOverlap ? "1" : "0");
502  if (pObj != nullptr)
503  // It seems 0 and 1 have special meaning: just start counting from 2 to avoid issues with that.
504  attrList->add(XML_relativeHeight, OString::number(pObj->GetOrdNum() + 2));
505  else
506  // relativeHeight is mandatory attribute, if value is not present, we must write default value
507  attrList->add(XML_relativeHeight, "0");
508  if (pObj != nullptr)
509  {
510  OUString sAnchorId = lclGetAnchorIdFromGrabBag(pObj);
511  if (!sAnchorId.isEmpty())
512  attrList->addNS(XML_wp14, XML_anchorId,
513  OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
514  }
515  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_anchor, attrList);
516  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_simplePos, XML_x, "0", XML_y,
517  "0"); // required, unused
518  const char* relativeFromH;
519  const char* relativeFromV;
520  const char* alignH = nullptr;
521  const char* alignV = nullptr;
522  switch (pFrameFormat->GetVertOrient().GetRelationOrient())
523  {
524  case text::RelOrientation::PAGE_PRINT_AREA:
525  relativeFromV = "margin";
526  break;
527  case text::RelOrientation::PAGE_PRINT_AREA_TOP:
528  relativeFromV = "topMargin";
529  break;
530  case text::RelOrientation::PAGE_PRINT_AREA_BOTTOM:
531  relativeFromV = "bottomMargin";
532  break;
533  case text::RelOrientation::PAGE_FRAME:
534  relativeFromV = "page";
535  break;
536  case text::RelOrientation::FRAME:
537  relativeFromV = "paragraph";
538  break;
539  case text::RelOrientation::TEXT_LINE:
540  default:
541  relativeFromV = "line";
542  break;
543  }
544  switch (pFrameFormat->GetVertOrient().GetVertOrient())
545  {
546  case text::VertOrientation::TOP:
547  case text::VertOrientation::CHAR_TOP:
548  case text::VertOrientation::LINE_TOP:
549  if (pFrameFormat->GetVertOrient().GetRelationOrient()
550  == text::RelOrientation::TEXT_LINE)
551  alignV = "bottom";
552  else
553  alignV = "top";
554  break;
555  case text::VertOrientation::BOTTOM:
556  case text::VertOrientation::CHAR_BOTTOM:
557  case text::VertOrientation::LINE_BOTTOM:
558  if (pFrameFormat->GetVertOrient().GetRelationOrient()
559  == text::RelOrientation::TEXT_LINE)
560  alignV = "top";
561  else
562  alignV = "bottom";
563  break;
564  case text::VertOrientation::CENTER:
565  case text::VertOrientation::CHAR_CENTER:
566  case text::VertOrientation::LINE_CENTER:
567  alignV = "center";
568  break;
569  default:
570  break;
571  }
572  switch (pFrameFormat->GetHoriOrient().GetRelationOrient())
573  {
574  case text::RelOrientation::PAGE_PRINT_AREA:
575  relativeFromH = "margin";
576  break;
577  case text::RelOrientation::PAGE_FRAME:
578  relativeFromH = "page";
579  break;
580  case text::RelOrientation::CHAR:
581  relativeFromH = "character";
582  break;
583  case text::RelOrientation::PAGE_RIGHT:
584  relativeFromH = "rightMargin";
585  break;
586  case text::RelOrientation::PAGE_LEFT:
587  relativeFromH = "leftMargin";
588  break;
589  case text::RelOrientation::FRAME:
590  default:
591  relativeFromH = "column";
592  break;
593  }
594  switch (pFrameFormat->GetHoriOrient().GetHoriOrient())
595  {
596  case text::HoriOrientation::LEFT:
597  alignH = "left";
598  break;
599  case text::HoriOrientation::RIGHT:
600  alignH = "right";
601  break;
602  case text::HoriOrientation::CENTER:
603  alignH = "center";
604  break;
605  case text::HoriOrientation::INSIDE:
606  alignH = "inside";
607  break;
608  case text::HoriOrientation::OUTSIDE:
609  alignH = "outside";
610  break;
611  default:
612  break;
613  }
614  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_positionH, XML_relativeFrom,
615  relativeFromH);
621  const sal_Int64 MAX_INTEGER_VALUE = SAL_MAX_INT32;
622  const sal_Int64 MIN_INTEGER_VALUE = SAL_MIN_INT32;
623  if (alignH != nullptr)
624  {
625  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_align);
626  m_pImpl->getSerializer()->write(alignH);
627  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_align);
628  }
629  else
630  {
631  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_posOffset);
632  sal_Int64 nPosXEMU = TwipsToEMU(aPos.X);
633 
634  /* Absolute Position Offset Value is of type Int. Hence it should not be greater than
635  * Maximum value for Int OR Less than the Minimum value for Int.
636  * - Maximum value for Int = 2147483647
637  * - Minimum value for Int = -2147483648
638  *
639  * As per ECMA Specification : ECMA-376, Second Edition,
640  * Part 1 - Fundamentals And Markup Language Reference[20.4.3.3 ST_PositionOffset (Absolute Position Offset Value)]
641  *
642  * Please refer : http://www.schemacentral.com/sc/xsd/t-xsd_int.html
643  */
644 
645  if (nPosXEMU > MAX_INTEGER_VALUE)
646  {
647  nPosXEMU = MAX_INTEGER_VALUE;
648  }
649  else if (nPosXEMU < MIN_INTEGER_VALUE)
650  {
651  nPosXEMU = MIN_INTEGER_VALUE;
652  }
653  m_pImpl->getSerializer()->write(nPosXEMU);
654  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_posOffset);
655  }
656  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_positionH);
657  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_positionV, XML_relativeFrom,
658  relativeFromV);
659 
660  sal_Int64 nPosYEMU = TwipsToEMU(aPos.Y);
661 
662  // tdf#93675, 0 below line/paragraph and/or top line/paragraph with
663  // wrap top+bottom or other wraps is affecting the line directly
664  // above the anchor line, which seems odd, but a tiny adjustment
665  // here to bring the top down convinces msoffice to wrap like us
666  if (nPosYEMU == 0
667  && (strcmp(relativeFromV, "line") == 0 || strcmp(relativeFromV, "paragraph") == 0)
668  && (!alignV || strcmp(alignV, "top") == 0))
669  {
670  alignV = nullptr;
671  nPosYEMU = TwipsToEMU(1);
672  }
673 
674  if (alignV != nullptr)
675  {
676  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_align);
677  m_pImpl->getSerializer()->write(alignV);
678  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_align);
679  }
680  else
681  {
682  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_posOffset);
683  if (nPosYEMU > MAX_INTEGER_VALUE)
684  {
685  nPosYEMU = MAX_INTEGER_VALUE;
686  }
687  else if (nPosYEMU < MIN_INTEGER_VALUE)
688  {
689  nPosYEMU = MIN_INTEGER_VALUE;
690  }
691  m_pImpl->getSerializer()->write(nPosYEMU);
692  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_posOffset);
693  }
694  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_positionV);
695  }
696  else
697  {
700  aAttrList->add(XML_distT, OString::number(TwipsToEMU(aULSpaceItem.GetUpper())).getStr());
701  aAttrList->add(XML_distB, OString::number(TwipsToEMU(aULSpaceItem.GetLower())).getStr());
702  aAttrList->add(XML_distL, OString::number(TwipsToEMU(aLRSpaceItem.GetLeft())).getStr());
703  aAttrList->add(XML_distR, OString::number(TwipsToEMU(aLRSpaceItem.GetRight())).getStr());
704  const SdrObject* pObj = pFrameFormat->FindRealSdrObject();
705  if (pObj != nullptr)
706  {
707  OUString sAnchorId = lclGetAnchorIdFromGrabBag(pObj);
708  if (!sAnchorId.isEmpty())
709  aAttrList->addNS(XML_wp14, XML_anchorId,
710  OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
711  }
712  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_inline, aAttrList);
713  }
714 
715  // now the common parts
716  // extent of the image
734  sal_uInt64 cx
735  = TwipsToEMU(std::clamp(rSize.Width(), tools::Long(0), tools::Long(SAL_MAX_INT32)));
736  OString aWidth(OString::number(std::min(cx, sal_uInt64(SAL_MAX_INT32))));
737  sal_uInt64 cy
738  = TwipsToEMU(std::clamp(rSize.Height(), tools::Long(0), tools::Long(SAL_MAX_INT32)));
739  OString aHeight(OString::number(std::min(cy, sal_uInt64(SAL_MAX_INT32))));
740 
741  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_extent, XML_cx, aWidth, XML_cy, aHeight);
742 
743  // effectExtent, extent including the effect (shadow only for now)
744  m_pImpl->getSerializer()->singleElementNS(
745  XML_wp, XML_effectExtent, XML_l, OString::number(nLeftExt), XML_t, OString::number(nTopExt),
746  XML_r, OString::number(nRightExt), XML_b, OString::number(nBottomExt));
747 
748  // See if we know the exact wrap type from grab-bag.
749  sal_Int32 nWrapToken = 0;
750  if (const SdrObject* pObject = pFrameFormat->FindRealSdrObject())
751  {
752  uno::Any aAny;
753  pObject->GetGrabBagItem(aAny);
754  comphelper::SequenceAsHashMap aGrabBag(aAny);
755  auto it = aGrabBag.find("EG_WrapType");
756  if (it != aGrabBag.end())
757  {
758  auto sType = it->second.get<OUString>();
759  if (sType == "wrapTight")
760  nWrapToken = XML_wrapTight;
761  else if (sType == "wrapThrough")
762  nWrapToken = XML_wrapThrough;
763  else
764  SAL_WARN("sw.ww8",
765  "DocxSdrExport::startDMLAnchorInline: unexpected EG_WrapType value");
766 
767  m_pImpl->getSerializer()->startElementNS(XML_wp, nWrapToken, XML_wrapText, "bothSides");
768 
769  it = aGrabBag.find("CT_WrapPath");
770  if (it != aGrabBag.end())
771  {
772  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_wrapPolygon, XML_edited, "0");
773  auto aSeqSeq = it->second.get<drawing::PointSequenceSequence>();
774  auto aPoints(comphelper::sequenceToContainer<std::vector<awt::Point>>(aSeqSeq[0]));
775  for (auto i = aPoints.begin(); i != aPoints.end(); ++i)
776  {
777  awt::Point& rPoint = *i;
778  m_pImpl->getSerializer()->singleElementNS(
779  XML_wp, (i == aPoints.begin() ? XML_start : XML_lineTo), XML_x,
780  OString::number(rPoint.X), XML_y, OString::number(rPoint.Y));
781  }
782  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_wrapPolygon);
783  }
784 
785  m_pImpl->getSerializer()->endElementNS(XML_wp, nWrapToken);
786  }
787  }
788 
789  // Or if we have a contour.
790  if (!nWrapToken && pFrameFormat->GetSurround().IsContour())
791  {
792  if (const SwNoTextNode* pNd = sw::util::GetNoTextNodeFromSwFrameFormat(*pFrameFormat))
793  {
794  const tools::PolyPolygon* pPolyPoly = pNd->HasContour();
795  if (pPolyPoly && pPolyPoly->Count())
796  {
797  nWrapToken = XML_wrapTight;
798  m_pImpl->getSerializer()->startElementNS(XML_wp, nWrapToken, XML_wrapText,
799  "bothSides");
800 
801  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_wrapPolygon, XML_edited, "0");
803  *pPolyPoly, pNd, /*bCorrectCrop=*/true);
804  for (sal_uInt16 i = 0; i < aPoly.GetSize(); ++i)
805  m_pImpl->getSerializer()->singleElementNS(
806  XML_wp, (i == 0 ? XML_start : XML_lineTo), XML_x,
807  OString::number(aPoly[i].X()), XML_y, OString::number(aPoly[i].Y()));
808  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_wrapPolygon);
809 
810  m_pImpl->getSerializer()->endElementNS(XML_wp, nWrapToken);
811  }
812  }
813  else if (SdrObject* pSdrObj = const_cast<SdrObject*>(pFrameFormat->FindRealSdrObject()))
814  {
815  // In this case we likely had an odt document to be exported to docx.
816  // There is no grab-bag or something else so for a workaround,
817  // let's export the geometry of the shape...
818  // First get the UNO-shape
819  uno::Reference<drawing::XShape> xShape(pSdrObj->getUnoShape(), uno::UNO_QUERY);
820 
821  if (xShape && xShape->getShapeType() == u"com.sun.star.drawing.CustomShape")
822  {
823  try
824  {
825  // Get the properties of the Xshape
826  uno::Reference<beans::XPropertySet> XProps(xShape, uno::UNO_QUERY);
827  // Get the "CustomShapeGeometry" property and from its Any() make a hashMap
828  comphelper::SequenceAsHashMap aCustomShapeGeometry(
829  XProps->getPropertyValue("CustomShapeGeometry"));
830  // Get the "Path" property and from its Any() make a hashMap
831  comphelper::SequenceAsHashMap aPath(aCustomShapeGeometry.getValue("Path"));
832  // From the Any() of the "Coordinates" property get the points
833  uno::Sequence<css::drawing::EnhancedCustomShapeParameterPair> aCoords
834  = aPath.getValue("Coordinates")
835  .get<uno::Sequence<css::drawing::EnhancedCustomShapeParameterPair>>();
836 
837  // Check if only one side wrap allowed
838  OUString sWrapType;
839  switch (pFrameFormat->GetSurround().GetSurround())
840  {
841  case text::WrapTextMode_DYNAMIC:
842  sWrapType = OUString("largest");
843  break;
844  case text::WrapTextMode_LEFT:
845  sWrapType = OUString("left");
846  break;
847  case text::WrapTextMode_RIGHT:
848  sWrapType = OUString("right");
849  break;
850  case text::WrapTextMode_PARALLEL:
851  default:
852  sWrapType = OUString("bothSides");
853  break;
854  }
855 
856  // And export:
857  nWrapToken = XML_wrapTight;
858  m_pImpl->getSerializer()->startElementNS(XML_wp, nWrapToken, XML_wrapText,
859  sWrapType);
860 
861  m_pImpl->getSerializer()->startElementNS(XML_wp, XML_wrapPolygon, XML_edited,
862  "0");
863 
864  try
865  {
866  // There are the coordinates
867  for (sal_Int32 i = 0; i < aCoords.getLength(); i++)
868  m_pImpl->getSerializer()->singleElementNS(
869  XML_wp, (i == 0 ? XML_start : XML_lineTo), XML_x,
870  OString::number(aCoords[i].First.Value.get<double>()), XML_y,
871  OString::number(aCoords[i].Second.Value.get<double>()));
872  }
873  catch (const uno::Exception& e)
874  {
875  // e.g. on exporting first attachment of tdf#94591 to docx
877  "sw.ww8",
878  "DocxSdrExport::startDMLAnchorInline: bad coordinate: " << e.Message);
879  }
880 
881  m_pImpl->getSerializer()->endElementNS(XML_wp, XML_wrapPolygon);
882 
883  m_pImpl->getSerializer()->endElementNS(XML_wp, nWrapToken);
884  }
885  catch (uno::Exception& e)
886  {
888  "sw.ww8", "DocxSdrExport::startDMLAnchorInline: exception: " << e.Message);
889  }
890  }
891  }
892  }
893 
894  // No? Then just approximate based on what we have.
895  if (!isAnchor || nWrapToken)
896  return;
897 
898  switch (pFrameFormat->GetSurround().GetValue())
899  {
900  case css::text::WrapTextMode_NONE:
901  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_wrapTopAndBottom);
902  break;
903  case css::text::WrapTextMode_THROUGH:
904  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_wrapNone);
905  break;
906  case css::text::WrapTextMode_PARALLEL:
907  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_wrapSquare, XML_wrapText,
908  "bothSides");
909  break;
910  case css::text::WrapTextMode_DYNAMIC:
911  default:
912  m_pImpl->getSerializer()->singleElementNS(XML_wp, XML_wrapSquare, XML_wrapText,
913  "largest");
914  break;
915  }
916 }
917 
919 {
920  bool isAnchor;
921  if (m_pImpl->getFlyFrameGraphic())
922  {
923  isAnchor = false; // end Inline Graphic object inside DMLTextFrame
924  }
925  else
926  {
927  isAnchor = pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR;
928  }
929  m_pImpl->getSerializer()->endElementNS(XML_wp, isAnchor ? XML_anchor : XML_inline);
930 
931  m_pImpl->getSerializer()->endElementNS(XML_w, XML_drawing);
932  m_pImpl->setDrawingOpen(false);
933 }
934 
935 void DocxSdrExport::writeVMLDrawing(const SdrObject* sdrObj, const SwFrameFormat& rFrameFormat)
936 {
937  m_pImpl->getSerializer()->startElementNS(XML_w, XML_pict);
938  m_pImpl->getDrawingML()->SetFS(m_pImpl->getSerializer());
939  // See WinwordAnchoring::SetAnchoring(), these are not part of the SdrObject, have to be passed around manually.
940 
941  SwFormatFollowTextFlow const& rFlow(rFrameFormat.GetFollowTextFlow());
942  const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient();
943  const SwFormatVertOrient& rVertOri = rFrameFormat.GetVertOrient();
944  SwFormatSurround const& rSurround(rFrameFormat.GetSurround());
945 
947  m_pImpl->getExport().VMLExporter().AddSdrObject(
948  *sdrObj, rFlow.GetValue(), rHoriOri.GetHoriOrient(), rVertOri.GetVertOrient(),
949  rHoriOri.GetRelationOrient(), rVertOri.GetRelationOrient(), pAttrList.get(), true);
950  m_pImpl->getSerializer()->endElementNS(XML_w, XML_pict);
951 }
952 
953 static bool lcl_isLockedCanvas(const uno::Reference<drawing::XShape>& xShape)
954 {
955  uno::Sequence<beans::PropertyValue> propList = lclGetProperty(xShape, "InteropGrabBag");
956  /*
957  * Export as Locked Canvas only if the property
958  * is in the PropertySet
959  */
960  return std::any_of(propList.begin(), propList.end(), [](const beans::PropertyValue& rProp) {
961  return rProp.Name == "LockedCanvas";
962  });
963 }
964 
965 void DocxSdrExport::writeDMLDrawing(const SdrObject* pSdrObject, const SwFrameFormat* pFrameFormat,
966  int nAnchorId)
967 {
968  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(pSdrObject)->getUnoShape(),
969  uno::UNO_QUERY_THROW);
970  if (!Impl::isSupportedDMLShape(xShape))
971  return;
972 
973  m_pImpl->getExport().DocxAttrOutput().GetSdtEndBefore(pSdrObject);
974 
975  sax_fastparser::FSHelperPtr pFS = m_pImpl->getSerializer();
976  Size aSize(pSdrObject->GetLogicRect().GetWidth(), pSdrObject->GetLogicRect().GetHeight());
977  startDMLAnchorInline(pFrameFormat, aSize);
978 
981  pDocPrAttrList->add(XML_id, OString::number(nAnchorId).getStr());
982  pDocPrAttrList->add(XML_name, OUStringToOString(pSdrObject->GetName(), RTL_TEXTENCODING_UTF8));
983  if (!pSdrObject->GetTitle().isEmpty())
984  pDocPrAttrList->add(XML_title,
985  OUStringToOString(pSdrObject->GetTitle(), RTL_TEXTENCODING_UTF8));
986  if (!pSdrObject->GetDescription().isEmpty())
987  pDocPrAttrList->add(XML_descr,
988  OUStringToOString(pSdrObject->GetDescription(), RTL_TEXTENCODING_UTF8));
989  if (!pSdrObject->IsVisible()
990  && pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
991 
992  pDocPrAttrList->add(XML_hidden, OString::number(1).getStr());
993  pFS->singleElementNS(XML_wp, XML_docPr, pDocPrAttrList);
994 
995  uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
996  const char* pNamespace = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
997  if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
998  pNamespace = "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup";
999  else if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
1000  pNamespace = "http://schemas.openxmlformats.org/drawingml/2006/picture";
1001  pFS->startElementNS(XML_a, XML_graphic, FSNS(XML_xmlns, XML_a),
1002  m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
1003  pFS->startElementNS(XML_a, XML_graphicData, XML_uri, pNamespace);
1004 
1005  bool bLockedCanvas = lcl_isLockedCanvas(xShape);
1006  if (bLockedCanvas)
1007  pFS->startElementNS(
1008  XML_lc, XML_lockedCanvas, FSNS(XML_xmlns, XML_lc),
1009  m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dmlLockedCanvas)));
1010 
1011  m_pImpl->getExport().OutputDML(xShape);
1012 
1013  if (bLockedCanvas)
1014  pFS->endElementNS(XML_lc, XML_lockedCanvas);
1015  pFS->endElementNS(XML_a, XML_graphicData);
1016  pFS->endElementNS(XML_a, XML_graphic);
1017 
1018  // Relative size of the drawing.
1019  if (pSdrObject->GetRelativeWidth())
1020  {
1021  // At the moment drawinglayer objects are always relative from page.
1022  OUString sValue;
1023  switch (pSdrObject->GetRelativeWidthRelation())
1024  {
1025  case text::RelOrientation::FRAME:
1026  sValue = "margin";
1027  break;
1028  case text::RelOrientation::PAGE_LEFT:
1029  if (pFrameFormat->GetDoc()->GetPageDesc(0).GetUseOn() == UseOnPage::Mirror)
1030  sValue = "outsideMargin";
1031  else
1032  sValue = "leftMargin";
1033  break;
1034  case text::RelOrientation::PAGE_RIGHT:
1035  if (pFrameFormat->GetDoc()->GetPageDesc(0).GetUseOn() == UseOnPage::Mirror)
1036  sValue = "insideMargin";
1037  else
1038  sValue = "rightMargin";
1039  break;
1040  case text::RelOrientation::PAGE_FRAME:
1041  default:
1042  sValue = "page";
1043  break;
1044  }
1045  pFS->startElementNS(XML_wp14, XML_sizeRelH, XML_relativeFrom, sValue);
1046  pFS->startElementNS(XML_wp14, XML_pctWidth);
1047  pFS->writeEscaped(
1048  OUString::number(*pSdrObject->GetRelativeWidth() * 100 * oox::drawingml::PER_PERCENT));
1049  pFS->endElementNS(XML_wp14, XML_pctWidth);
1050  pFS->endElementNS(XML_wp14, XML_sizeRelH);
1051  }
1052  if (pSdrObject->GetRelativeHeight())
1053  {
1054  OUString sValue;
1055  switch (pSdrObject->GetRelativeHeightRelation())
1056  {
1057  case text::RelOrientation::FRAME:
1058  sValue = "margin";
1059  break;
1060  case text::RelOrientation::PAGE_PRINT_AREA:
1061  sValue = "topMargin";
1062  break;
1063  case text::RelOrientation::PAGE_PRINT_AREA_BOTTOM:
1064  sValue = "bottomMargin";
1065  break;
1066  case text::RelOrientation::PAGE_FRAME:
1067  default:
1068  sValue = "page";
1069  break;
1070  }
1071  pFS->startElementNS(XML_wp14, XML_sizeRelV, XML_relativeFrom, sValue);
1072  pFS->startElementNS(XML_wp14, XML_pctHeight);
1073  pFS->writeEscaped(
1074  OUString::number(*pSdrObject->GetRelativeHeight() * 100 * oox::drawingml::PER_PERCENT));
1075  pFS->endElementNS(XML_wp14, XML_pctHeight);
1076  pFS->endElementNS(XML_wp14, XML_sizeRelV);
1077  }
1078 
1079  endDMLAnchorInline(pFrameFormat);
1080 }
1081 
1083 {
1084  const SvxShadowItem& aShadowItem = rFrameFormat.GetShadow();
1085  if (aShadowItem.GetLocation() == SvxShadowLocation::NONE)
1086  return;
1087 
1088  OString aShadowWidth(OString::number(double(aShadowItem.GetWidth()) / 20) + "pt");
1089  OString aOffset;
1090  switch (aShadowItem.GetLocation())
1091  {
1092  case SvxShadowLocation::TopLeft:
1093  aOffset = "-" + aShadowWidth + ",-" + aShadowWidth;
1094  break;
1095  case SvxShadowLocation::TopRight:
1096  aOffset = aShadowWidth + ",-" + aShadowWidth;
1097  break;
1098  case SvxShadowLocation::BottomLeft:
1099  aOffset = "-" + aShadowWidth + "," + aShadowWidth;
1100  break;
1101  case SvxShadowLocation::BottomRight:
1102  aOffset = aShadowWidth + "," + aShadowWidth;
1103  break;
1104  case SvxShadowLocation::NONE:
1105  case SvxShadowLocation::End:
1106  break;
1107  }
1108  if (aOffset.isEmpty())
1109  return;
1110 
1111  OString aShadowColor = msfilter::util::ConvertColor(aShadowItem.GetColor());
1112  m_pSerializer->singleElementNS(XML_v, XML_shadow, XML_on, "t", XML_color, "#" + aShadowColor,
1113  XML_offset, aOffset);
1114 }
1115 
1116 bool DocxSdrExport::Impl::isSupportedDMLShape(const uno::Reference<drawing::XShape>& xShape)
1117 {
1118  uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
1119  if (xServiceInfo->supportsService("com.sun.star.drawing.PolyPolygonShape")
1120  || xServiceInfo->supportsService("com.sun.star.drawing.PolyLineShape"))
1121  return false;
1122 
1123  // For signature line shapes, we don't want DML, just the VML shape.
1124  if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
1125  {
1126  uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
1127  bool bIsSignatureLineShape = false;
1128  xShapeProperties->getPropertyValue("IsSignatureLine") >>= bIsSignatureLineShape;
1129  if (bIsSignatureLineShape)
1130  return false;
1131  }
1132 
1133  return true;
1134 }
1135 
1137  const SwFrameFormat& rFrameFormat, int nAnchorId)
1138 {
1139  bool bDMLAndVMLDrawingOpen = m_pImpl->getDMLAndVMLDrawingOpen();
1140  m_pImpl->setDMLAndVMLDrawingOpen(true);
1141 
1142  // Depending on the shape type, we actually don't write the shape as DML.
1143  OUString sShapeType;
1144  ShapeFlag nMirrorFlags = ShapeFlag::NONE;
1145  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(sdrObj)->getUnoShape(),
1146  uno::UNO_QUERY_THROW);
1147 
1148  MSO_SPT eShapeType
1149  = EscherPropertyContainer::GetCustomShapeType(xShape, nMirrorFlags, sShapeType);
1150 
1151  // In case we are already inside a DML block, then write the shape only as VML, turn out that's allowed to do.
1152  // A common service created in util to check for VML shapes which are allowed to have textbox in content
1154  && (!bDMLAndVMLDrawingOpen || lcl_isLockedCanvas(xShape))) // Locked canvas is OK inside DML
1155  {
1156  m_pImpl->getSerializer()->startElementNS(XML_mc, XML_AlternateContent);
1157 
1158  auto pObjGroup = dynamic_cast<const SdrObjGroup*>(sdrObj);
1159  m_pImpl->getSerializer()->startElementNS(XML_mc, XML_Choice, XML_Requires,
1160  (pObjGroup ? "wpg" : "wps"));
1161  writeDMLDrawing(sdrObj, &rFrameFormat, nAnchorId);
1162  m_pImpl->getSerializer()->endElementNS(XML_mc, XML_Choice);
1163 
1164  m_pImpl->getSerializer()->startElementNS(XML_mc, XML_Fallback);
1165  writeVMLDrawing(sdrObj, rFrameFormat);
1166  m_pImpl->getSerializer()->endElementNS(XML_mc, XML_Fallback);
1167 
1168  m_pImpl->getSerializer()->endElementNS(XML_mc, XML_AlternateContent);
1169  }
1170  else
1171  writeVMLDrawing(sdrObj, rFrameFormat);
1172 
1173  m_pImpl->setDMLAndVMLDrawingOpen(bDMLAndVMLDrawingOpen);
1174 }
1175 
1176 // Converts ARGB transparency (0..255) to drawingml alpha (opposite, and 0..100000)
1177 static OString lcl_TransparencyToDrawingMlAlpha(const Color& rColor)
1178 {
1179  if (rColor.IsTransparent())
1180  {
1181  sal_Int32 nAlphaPercent = float(rColor.GetAlpha()) / 2.55;
1182  return OString::number(nAlphaPercent * oox::drawingml::PER_PERCENT);
1183  }
1184 
1185  return OString();
1186 }
1187 
1189 {
1190  const SvxShadowItem& aShadowItem = rFrameFormat.GetShadow();
1191 
1192  // Output effects
1193  if (aShadowItem.GetLocation() == SvxShadowLocation::NONE)
1194  return;
1195 
1196  // Distance is measured diagonally from corner
1197  double nShadowDist
1198  = sqrt(static_cast<double>(aShadowItem.GetWidth()) * aShadowItem.GetWidth() * 2.0);
1199  OString aShadowDist(OString::number(TwipsToEMU(nShadowDist)));
1200  OString aShadowColor = msfilter::util::ConvertColor(aShadowItem.GetColor());
1201  OString aShadowAlpha = lcl_TransparencyToDrawingMlAlpha(aShadowItem.GetColor());
1202  sal_uInt32 nShadowDir = 0;
1203  switch (aShadowItem.GetLocation())
1204  {
1205  case SvxShadowLocation::TopLeft:
1206  nShadowDir = 13500000;
1207  break;
1208  case SvxShadowLocation::TopRight:
1209  nShadowDir = 18900000;
1210  break;
1211  case SvxShadowLocation::BottomLeft:
1212  nShadowDir = 8100000;
1213  break;
1214  case SvxShadowLocation::BottomRight:
1215  nShadowDir = 2700000;
1216  break;
1217  case SvxShadowLocation::NONE:
1218  case SvxShadowLocation::End:
1219  break;
1220  }
1221  OString aShadowDir(OString::number(nShadowDir));
1222 
1223  m_pImpl->getSerializer()->startElementNS(XML_a, XML_effectLst);
1224  m_pImpl->getSerializer()->startElementNS(XML_a, XML_outerShdw, XML_dist, aShadowDist, XML_dir,
1225  aShadowDir);
1226  if (aShadowAlpha.isEmpty())
1227  m_pImpl->getSerializer()->singleElementNS(XML_a, XML_srgbClr, XML_val, aShadowColor);
1228  else
1229  {
1230  m_pImpl->getSerializer()->startElementNS(XML_a, XML_srgbClr, XML_val, aShadowColor);
1231  m_pImpl->getSerializer()->singleElementNS(XML_a, XML_alpha, XML_val, aShadowAlpha);
1232  m_pImpl->getSerializer()->endElementNS(XML_a, XML_srgbClr);
1233  }
1234  m_pImpl->getSerializer()->endElementNS(XML_a, XML_outerShdw);
1235  m_pImpl->getSerializer()->endElementNS(XML_a, XML_effectLst);
1236 }
1237 
1238 void DocxSdrExport::writeDiagram(const SdrObject* sdrObject, const SwFrameFormat& rFrameFormat,
1239  int nDiagramId)
1240 {
1241  uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(sdrObject)->getUnoShape(),
1242  uno::UNO_QUERY);
1243 
1244  // write necessary tags to document.xml
1245  Size aSize(sdrObject->GetSnapRect().GetWidth(), sdrObject->GetSnapRect().GetHeight());
1246  startDMLAnchorInline(&rFrameFormat, aSize);
1247 
1248  m_pImpl->getDrawingML()->WriteDiagram(xShape, nDiagramId);
1249 
1250  endDMLAnchorInline(&rFrameFormat);
1251 }
1252 
1254 {
1255  const SwFrameFormat& rFrameFormat = pParentFrame->GetFrameFormat();
1256  const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
1257 
1258  sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : 0;
1259  sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
1260 
1261  //Save data here and restore when out of scope
1262  ExportDataSaveRestore aDataGuard(m_pImpl->getExport(), nStt, nEnd, pParentFrame);
1263 
1265  ::comphelper::FlagRestorationGuard const g(m_pImpl->m_bFlyFrameGraphic, true);
1266  comphelper::ValueRestorationGuard vg(m_pImpl->getExport().m_nTextTyp, TXT_TXTBOX);
1267  m_pImpl->getExport().WriteText();
1268 }
1269 
1271 {
1272  const editeng::SvxBorderLine* pBorderLine = nullptr;
1273 
1274  if (rBox.GetTop())
1275  {
1276  pBorderLine = rBox.GetTop();
1277  }
1278  else if (rBox.GetLeft())
1279  {
1280  pBorderLine = rBox.GetLeft();
1281  }
1282  else if (rBox.GetBottom())
1283  {
1284  pBorderLine = rBox.GetBottom();
1285  }
1286  else if (rBox.GetRight())
1287  {
1288  pBorderLine = rBox.GetRight();
1289  }
1290 
1291  if (!pBorderLine)
1292  {
1293  return;
1294  }
1295 
1296  sax_fastparser::FSHelperPtr pFS = m_pImpl->getSerializer();
1297  double fConverted(editeng::ConvertBorderWidthToWord(pBorderLine->GetBorderLineStyle(),
1298  pBorderLine->GetWidth()));
1299  OString sWidth(OString::number(TwipsToEMU(fConverted)));
1300  pFS->startElementNS(XML_a, XML_ln, XML_w, sWidth);
1301 
1302  pFS->startElementNS(XML_a, XML_solidFill);
1303  OString sColor(msfilter::util::ConvertColor(pBorderLine->GetColor()));
1304  pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, sColor);
1305  pFS->endElementNS(XML_a, XML_solidFill);
1306 
1307  if (SvxBorderLineStyle::DASHED == pBorderLine->GetBorderLineStyle()) // Line Style is Dash type
1308  pFS->singleElementNS(XML_a, XML_prstDash, XML_val, "dash");
1309 
1310  pFS->endElementNS(XML_a, XML_ln);
1311 }
1312 
1313 void DocxSdrExport::writeDMLTextFrame(ww8::Frame const* pParentFrame, int nAnchorId,
1314  bool bTextBoxOnly)
1315 {
1316  bool bDMLAndVMLDrawingOpen = m_pImpl->getDMLAndVMLDrawingOpen();
1317  m_pImpl->setDMLAndVMLDrawingOpen(IsAnchorTypeInsideParagraph(pParentFrame));
1318 
1319  sax_fastparser::FSHelperPtr pFS = m_pImpl->getSerializer();
1320  const SwFrameFormat& rFrameFormat = pParentFrame->GetFrameFormat();
1321  const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
1322 
1323  sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : 0;
1324  sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
1325 
1326  //Save data here and restore when out of scope
1327  ExportDataSaveRestore aDataGuard(m_pImpl->getExport(), nStt, nEnd, pParentFrame);
1328 
1329  // When a frame has some low height, but automatically expanded due
1330  // to lots of contents, this size contains the real size.
1331  const Size aSize = pParentFrame->GetSize();
1332 
1333  uno::Reference<drawing::XShape> xShape;
1334  const SdrObject* pSdrObj = rFrameFormat.FindRealSdrObject();
1335  if (pSdrObj)
1336  xShape.set(const_cast<SdrObject*>(pSdrObj)->getUnoShape(), uno::UNO_QUERY);
1337  uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1338  uno::Reference<beans::XPropertySetInfo> xPropSetInfo;
1339  if (xPropertySet.is())
1340  xPropSetInfo = xPropertySet->getPropertySetInfo();
1341 
1343  {
1344  drawing::TextVerticalAdjust eAdjust = drawing::TextVerticalAdjust_TOP;
1345  if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("TextVerticalAdjust"))
1346  xPropertySet->getPropertyValue("TextVerticalAdjust") >>= eAdjust;
1347  m_pImpl->getBodyPrAttrList()->add(XML_anchor,
1349  }
1350 
1351  if (!bTextBoxOnly)
1352  {
1353  startDMLAnchorInline(&rFrameFormat, aSize);
1354 
1357  pDocPrAttrList->add(XML_id, OString::number(nAnchorId).getStr());
1358  pDocPrAttrList->add(XML_name,
1359  OUStringToOString(rFrameFormat.GetName(), RTL_TEXTENCODING_UTF8));
1360  pFS->singleElementNS(XML_wp, XML_docPr, pDocPrAttrList);
1361 
1362  pFS->startElementNS(XML_a, XML_graphic, FSNS(XML_xmlns, XML_a),
1363  m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
1364  pFS->startElementNS(XML_a, XML_graphicData, XML_uri,
1365  "http://schemas.microsoft.com/office/word/2010/wordprocessingShape");
1366  pFS->startElementNS(XML_wps, XML_wsp);
1367  pFS->singleElementNS(XML_wps, XML_cNvSpPr, XML_txBox, "1");
1368 
1369  uno::Any aRotation;
1370  m_pImpl->setDMLandVMLTextFrameRotation(0_deg100);
1371  if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("FrameInteropGrabBag"))
1372  {
1373  uno::Sequence<beans::PropertyValue> propList;
1374  xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= propList;
1375  auto pProp = std::find_if(propList.begin(), propList.end(),
1376  [](const beans::PropertyValue& rProp) {
1377  return rProp.Name == "mso-rotation-angle";
1378  });
1379  if (pProp != propList.end())
1380  aRotation = pProp->Value;
1381  }
1382  sal_Int32 nTmp;
1383  if (aRotation >>= nTmp)
1384  m_pImpl->getDMLandVMLTextFrameRotation() = Degree100(nTmp);
1385  OString sRotation(OString::number(
1386  oox::drawingml::ExportRotateClockwisify(m_pImpl->getDMLandVMLTextFrameRotation())));
1387  // Shape properties
1388  pFS->startElementNS(XML_wps, XML_spPr);
1389  if (m_pImpl->getDMLandVMLTextFrameRotation())
1390  {
1391  pFS->startElementNS(XML_a, XML_xfrm, XML_rot, sRotation);
1392  }
1393  else
1394  {
1395  pFS->startElementNS(XML_a, XML_xfrm);
1396  }
1397  pFS->singleElementNS(XML_a, XML_off, XML_x, "0", XML_y, "0");
1398  OString aWidth(OString::number(TwipsToEMU(aSize.Width())));
1399  OString aHeight(OString::number(TwipsToEMU(aSize.Height())));
1400  pFS->singleElementNS(XML_a, XML_ext, XML_cx, aWidth, XML_cy, aHeight);
1401  pFS->endElementNS(XML_a, XML_xfrm);
1402  OUString shapeType = "rect";
1403  if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("FrameInteropGrabBag"))
1404  {
1405  uno::Sequence<beans::PropertyValue> propList;
1406  xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= propList;
1407  auto pProp = std::find_if(propList.begin(), propList.end(),
1408  [](const beans::PropertyValue& rProp) {
1409  return rProp.Name == "mso-orig-shape-type";
1410  });
1411  if (pProp != propList.end())
1412  pProp->Value >>= shapeType;
1413  }
1414  //Empty shapeType will lead to corruption so to avoid that shapeType is set to default i.e. "rect"
1415  if (shapeType.isEmpty())
1416  shapeType = "rect";
1417 
1418  pFS->singleElementNS(XML_a, XML_prstGeom, XML_prst, shapeType);
1419  m_pImpl->setDMLTextFrameSyntax(true);
1420  m_pImpl->getExport().OutputFormat(pParentFrame->GetFrameFormat(), false, false, true);
1421  m_pImpl->setDMLTextFrameSyntax(false);
1422  writeDMLEffectLst(rFrameFormat);
1423  pFS->endElementNS(XML_wps, XML_spPr);
1424  }
1425 
1426  //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.
1427  if (!m_pImpl->getExport().m_bLinkedTextboxesHelperInitialized)
1428  {
1429  sal_Int32 nSeq = 0;
1430  for (auto& rEntry : m_pImpl->getExport().m_aLinkedTextboxesHelper)
1431  {
1432  //find the start of a textbox chain: has no PREVIOUS link, but does have NEXT link
1433  if (rEntry.second.sPrevChain.isEmpty() && !rEntry.second.sNextChain.isEmpty())
1434  {
1435  //assign this chain a unique ID and start a new sequence
1436  nSeq = 0;
1437  rEntry.second.nId = ++m_pImpl->getExport().m_nLinkedTextboxesChainId;
1438  rEntry.second.nSeq = nSeq;
1439 
1440  OUString sCheckForBrokenChains = rEntry.first;
1441 
1442  //follow the chain and assign the same id, and incremental sequence numbers.
1443  auto followChainIter
1444  = m_pImpl->getExport().m_aLinkedTextboxesHelper.find(rEntry.second.sNextChain);
1445  while (followChainIter != m_pImpl->getExport().m_aLinkedTextboxesHelper.end())
1446  {
1447  //verify that the NEXT textbox also points to me as the PREVIOUS.
1448  // A broken link indicates a leftover remnant that can be ignored.
1449  if (followChainIter->second.sPrevChain != sCheckForBrokenChains)
1450  break;
1451 
1452  followChainIter->second.nId = m_pImpl->getExport().m_nLinkedTextboxesChainId;
1453  followChainIter->second.nSeq = ++nSeq;
1454 
1455  //empty next chain indicates the end of the linked chain.
1456  if (followChainIter->second.sNextChain.isEmpty())
1457  break;
1458 
1459  sCheckForBrokenChains = followChainIter->first;
1460  followChainIter = m_pImpl->getExport().m_aLinkedTextboxesHelper.find(
1461  followChainIter->second.sNextChain);
1462  }
1463  }
1464  }
1465  m_pImpl->getExport().m_bLinkedTextboxesHelperInitialized = true;
1466  }
1467 
1468  m_pImpl->getExport().m_pParentFrame = nullptr;
1469  bool skipTxBxContent = false;
1470  bool isTxbxLinked = false;
1471 
1472  OUString sLinkChainName;
1473  if (xPropSetInfo.is())
1474  {
1475  if (xPropSetInfo->hasPropertyByName("LinkDisplayName"))
1476  xPropertySet->getPropertyValue("LinkDisplayName") >>= sLinkChainName;
1477  else if (xPropSetInfo->hasPropertyByName("ChainName"))
1478  xPropertySet->getPropertyValue("ChainName") >>= sLinkChainName;
1479  }
1480 
1481  // second, check if THIS textbox is linked and then decide whether to write the tag txbx or linkedTxbx
1482  auto linkedTextboxesIter = m_pImpl->getExport().m_aLinkedTextboxesHelper.find(sLinkChainName);
1483  if (linkedTextboxesIter != m_pImpl->getExport().m_aLinkedTextboxesHelper.end())
1484  {
1485  if ((linkedTextboxesIter->second.nId != 0) && (linkedTextboxesIter->second.nSeq != 0))
1486  {
1487  //not the first in the chain, so write the tag as linkedTxbx
1488  pFS->singleElementNS(XML_wps, XML_linkedTxbx, XML_id,
1489  OString::number(linkedTextboxesIter->second.nId), XML_seq,
1490  OString::number(linkedTextboxesIter->second.nSeq));
1491  /* no text content should be added to this tag,
1492  since the textbox is linked, the entire content
1493  is written in txbx block
1494  */
1495  skipTxBxContent = true;
1496  }
1497  else if ((linkedTextboxesIter->second.nId != 0) && (linkedTextboxesIter->second.nSeq == 0))
1498  {
1499  /* this is the first textbox in the chaining, we add the text content
1500  to this block*/
1501  //since the text box is linked, it needs an id.
1502  pFS->startElementNS(XML_wps, XML_txbx, XML_id,
1503  OString::number(linkedTextboxesIter->second.nId));
1504  isTxbxLinked = true;
1505  }
1506  }
1507 
1508  if (!skipTxBxContent)
1509  {
1510  if (!isTxbxLinked)
1511  pFS->startElementNS(XML_wps, XML_txbx); //text box is not linked, therefore no id.
1512 
1513  pFS->startElementNS(XML_w, XML_txbxContent);
1514 
1515  const SvxFrameDirectionItem& rDirection = rFrameFormat.GetFrameDir();
1516  if (rDirection.GetValue() == SvxFrameDirection::Vertical_RL_TB)
1517  m_pImpl->getBodyPrAttrList()->add(XML_vert, "eaVert");
1518  else if (rDirection.GetValue() == SvxFrameDirection::Vertical_LR_BT)
1519  m_pImpl->getBodyPrAttrList()->add(XML_vert, "vert270");
1520 
1521  {
1522  ::comphelper::FlagRestorationGuard const g(m_pImpl->m_bFlyFrameGraphic, true);
1523  comphelper::ValueRestorationGuard vg(m_pImpl->getExport().m_nTextTyp, TXT_TXTBOX);
1524  m_pImpl->getExport().WriteText();
1525  if (m_pImpl->getParagraphSdtOpen())
1526  {
1527  m_pImpl->getExport().DocxAttrOutput().EndParaSdtBlock();
1528  m_pImpl->setParagraphSdtOpen(false);
1529  }
1530  }
1531 
1532  pFS->endElementNS(XML_w, XML_txbxContent);
1533  pFS->endElementNS(XML_wps, XML_txbx);
1534  }
1535 
1536  // We need to init padding to 0, if it's not set.
1537  // In LO the default is 0 and so ins attributes are not set when padding is 0
1538  // but in MSO the default is 254 / 127, so we need to set 0 padding explicitly
1539  if (m_pImpl->getBodyPrAttrList())
1540  {
1541  if (!m_pImpl->getBodyPrAttrList()->hasAttribute(XML_lIns))
1542  m_pImpl->getBodyPrAttrList()->add(XML_lIns, OString::number(0));
1543  if (!m_pImpl->getBodyPrAttrList()->hasAttribute(XML_tIns))
1544  m_pImpl->getBodyPrAttrList()->add(XML_tIns, OString::number(0));
1545  if (!m_pImpl->getBodyPrAttrList()->hasAttribute(XML_rIns))
1546  m_pImpl->getBodyPrAttrList()->add(XML_rIns, OString::number(0));
1547  if (!m_pImpl->getBodyPrAttrList()->hasAttribute(XML_bIns))
1548  m_pImpl->getBodyPrAttrList()->add(XML_bIns, OString::number(0));
1549  }
1550 
1551  rtl::Reference<FastAttributeList> xBodyPrAttrList(m_pImpl->getBodyPrAttrList());
1552  m_pImpl->setBodyPrAttrList(nullptr);
1553  if (!bTextBoxOnly)
1554  {
1555  pFS->startElementNS(XML_wps, XML_bodyPr, xBodyPrAttrList);
1556  // AutoSize of the Text Frame.
1557  const SwFormatFrameSize& rSize = rFrameFormat.GetFrameSize();
1558  pFS->singleElementNS(
1559  XML_a,
1560  (rSize.GetHeightSizeType() == SwFrameSize::Variable ? XML_spAutoFit : XML_noAutofit));
1561  pFS->endElementNS(XML_wps, XML_bodyPr);
1562 
1563  pFS->endElementNS(XML_wps, XML_wsp);
1564  pFS->endElementNS(XML_a, XML_graphicData);
1565  pFS->endElementNS(XML_a, XML_graphic);
1566 
1567  // Relative size of the Text Frame.
1568  const sal_uInt8 nWidthPercent = rSize.GetWidthPercent();
1569  if (nWidthPercent && nWidthPercent != SwFormatFrameSize::SYNCED)
1570  {
1571  pFS->startElementNS(XML_wp14, XML_sizeRelH, XML_relativeFrom,
1572  (rSize.GetWidthPercentRelation() == text::RelOrientation::PAGE_FRAME
1573  ? "page"
1574  : "margin"));
1575  pFS->startElementNS(XML_wp14, XML_pctWidth);
1576  pFS->writeEscaped(OUString::number(nWidthPercent * oox::drawingml::PER_PERCENT));
1577  pFS->endElementNS(XML_wp14, XML_pctWidth);
1578  pFS->endElementNS(XML_wp14, XML_sizeRelH);
1579  }
1580  const sal_uInt8 nHeightPercent = rSize.GetHeightPercent();
1581  if (nHeightPercent && nHeightPercent != SwFormatFrameSize::SYNCED)
1582  {
1583  pFS->startElementNS(
1584  XML_wp14, XML_sizeRelV, XML_relativeFrom,
1585  (rSize.GetHeightPercentRelation() == text::RelOrientation::PAGE_FRAME ? "page"
1586  : "margin"));
1587  pFS->startElementNS(XML_wp14, XML_pctHeight);
1588  pFS->writeEscaped(OUString::number(nHeightPercent * oox::drawingml::PER_PERCENT));
1589  pFS->endElementNS(XML_wp14, XML_pctHeight);
1590  pFS->endElementNS(XML_wp14, XML_sizeRelV);
1591  }
1592 
1593  endDMLAnchorInline(&rFrameFormat);
1594  }
1595  m_pImpl->setDMLAndVMLDrawingOpen(bDMLAndVMLDrawingOpen);
1596 }
1597 
1598 void DocxSdrExport::writeVMLTextFrame(ww8::Frame const* pParentFrame, bool bTextBoxOnly)
1599 {
1600  bool bDMLAndVMLDrawingOpen = m_pImpl->getDMLAndVMLDrawingOpen();
1601  m_pImpl->setDMLAndVMLDrawingOpen(IsAnchorTypeInsideParagraph(pParentFrame));
1602 
1603  sax_fastparser::FSHelperPtr pFS = m_pImpl->getSerializer();
1604  const SwFrameFormat& rFrameFormat = pParentFrame->GetFrameFormat();
1605  const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
1606 
1607  sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : 0;
1608  sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
1609 
1610  //Save data here and restore when out of scope
1611  ExportDataSaveRestore aDataGuard(m_pImpl->getExport(), nStt, nEnd, pParentFrame);
1612 
1613  // When a frame has some low height, but automatically expanded due
1614  // to lots of contents, this size contains the real size.
1615  const Size aSize = pParentFrame->GetSize();
1616  m_pImpl->setFlyFrameSize(&aSize);
1617 
1618  m_pImpl->setTextFrameSyntax(true);
1621  m_pImpl->getTextFrameStyle() = "position:absolute";
1622  if (!bTextBoxOnly)
1623  {
1624  OString sRotation(OString::number(m_pImpl->getDMLandVMLTextFrameRotation().get() / -100));
1625  m_pImpl->getExport()
1626  .SdrExporter()
1627  .getTextFrameStyle()
1628  .append(";rotation:")
1629  .append(sRotation);
1630  }
1631  m_pImpl->getExport().OutputFormat(pParentFrame->GetFrameFormat(), false, false, true);
1632  m_pImpl->getFlyAttrList()->add(XML_style, m_pImpl->getTextFrameStyle().makeStringAndClear());
1633 
1634  const SdrObject* pObject = pParentFrame->GetFrameFormat().FindRealSdrObject();
1635  if (pObject != nullptr)
1636  {
1637  OUString sAnchorId = lclGetAnchorIdFromGrabBag(pObject);
1638  if (!sAnchorId.isEmpty())
1639  m_pImpl->getFlyAttrList()->addNS(XML_w14, XML_anchorId,
1640  OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
1641  }
1642  rtl::Reference<FastAttributeList> xFlyAttrList(m_pImpl->getFlyAttrList());
1643  m_pImpl->getFlyAttrList().clear();
1644  rtl::Reference<FastAttributeList> xTextboxAttrList(m_pImpl->getTextboxAttrList());
1645  m_pImpl->getTextboxAttrList().clear();
1646  m_pImpl->setTextFrameSyntax(false);
1647  m_pImpl->setFlyFrameSize(nullptr);
1648  m_pImpl->getExport().m_pParentFrame = nullptr;
1649 
1650  if (!bTextBoxOnly)
1651  {
1652  pFS->startElementNS(XML_w, XML_pict);
1653  pFS->startElementNS(XML_v, XML_rect, xFlyAttrList);
1654  m_pImpl->textFrameShadow(rFrameFormat);
1655  if (m_pImpl->getFlyFillAttrList().is())
1656  {
1657  rtl::Reference<FastAttributeList> xFlyFillAttrList(m_pImpl->getFlyFillAttrList());
1658  m_pImpl->getFlyFillAttrList().clear();
1659  pFS->singleElementNS(XML_v, XML_fill, xFlyFillAttrList);
1660  }
1661  if (m_pImpl->getDashLineStyleAttr().is())
1662  {
1663  rtl::Reference<FastAttributeList> xDashLineStyleAttr(m_pImpl->getDashLineStyleAttr());
1664  m_pImpl->getDashLineStyleAttr().clear();
1665  pFS->singleElementNS(XML_v, XML_stroke, xDashLineStyleAttr);
1666  }
1667  pFS->startElementNS(XML_v, XML_textbox, xTextboxAttrList);
1668  }
1669  pFS->startElementNS(XML_w, XML_txbxContent);
1670  {
1671  ::comphelper::FlagRestorationGuard const g(m_pImpl->m_bFlyFrameGraphic, true);
1672  comphelper::ValueRestorationGuard vg(m_pImpl->getExport().m_nTextTyp, TXT_TXTBOX);
1673  m_pImpl->getExport().WriteText();
1674  if (m_pImpl->getParagraphSdtOpen())
1675  {
1676  m_pImpl->getExport().DocxAttrOutput().EndParaSdtBlock();
1677  m_pImpl->setParagraphSdtOpen(false);
1678  }
1679  }
1680  pFS->endElementNS(XML_w, XML_txbxContent);
1681  if (!bTextBoxOnly)
1682  {
1683  pFS->endElementNS(XML_v, XML_textbox);
1684 
1685  if (m_pImpl->getFlyWrapAttrList())
1686  {
1687  rtl::Reference<FastAttributeList> xFlyWrapAttrList(m_pImpl->getFlyWrapAttrList());
1688  m_pImpl->setFlyWrapAttrList(nullptr);
1689  pFS->singleElementNS(XML_w10, XML_wrap, xFlyWrapAttrList);
1690  }
1691 
1692  pFS->endElementNS(XML_v, XML_rect);
1693  pFS->endElementNS(XML_w, XML_pict);
1694  }
1695 
1696  m_pImpl->setDMLAndVMLDrawingOpen(bDMLAndVMLDrawingOpen);
1697 }
1698 
1699 bool DocxSdrExport::isTextBox(const SwFrameFormat& rFrameFormat)
1700 {
1701  return SwTextBoxHelper::isTextBox(&rFrameFormat, RES_FLYFRMFMT);
1702 }
1703 
1704 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
bool getTextFrameSyntax() const
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)
bool getParagraphHasDrawing() const
bool IsDrawingOpen() const
sal_uInt8 GetAlpha() 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
void endDMLAnchorInline(const SwFrameFormat *pFrameFormat)
bool IsTransparent() const
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:106
oox::drawingml::DrawingML * m_pDrawingML
bool getDMLTextFrameSyntax() const
rtl::Reference< sax_fastparser::FastAttributeList > & getFlyAttrList()
sal_Int32 ExportRotateClockwisify(Degree100 input)
SwTwips GetPos() const
Definition: fmtornt.hxx:92
sal_uIntPtr sal_uLong
long Long
tools::Long GetRight() const
virtual void SaveData(sal_uLong nStt, sal_uLong nEnd)
Remember some of the members so that we can recurse in WriteText().
Definition: wrtww8.cxx:1892
void writeDMLEffectLst(const SwFrameFormat &rFrameFormat)
Write , the effect list.
OUString GetDescription() const
OBJ_LINE
const SvxFrameDirectionItem & GetFrameDir(bool=true) const
Definition: frmatr.hxx:94
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:78
tools::Long GetWidth() const
constexpr TypedWhichId< XLineWidthItem > XATTR_LINEWIDTH(XATTR_LINE_FIRST+2)
Holds data used by DocxSdrExport only.
DocxExport & m_rExport
void setFlyAttrList(const rtl::Reference< sax_fastparser::FastAttributeList > &pFlyAttrList)
tools::Long GetWidth() const
SwNode & GetNode() const
Definition: ndindex.hxx:119
bool IsParagraphHasDrawing() const
const editeng::SvxBorderLine * GetRight() const
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:55
The class that does all the actual DOCX export-related work.
Definition: docxexport.hxx:65
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:354
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
constexpr tools::Long Width() const
DstType sequenceToContainer(const css::uno::Sequence< SrcType > &i_Sequence)
bool getDMLAndVMLDrawingOpen() const
SvxShadowLocation GetLocation() const
MSO_SPT
bool getDMLTextFrameSyntax() const
const OUString & GetName() const
Definition: format.hxx:115
Degree100 & getDMLandVMLTextFrameRotation()
oox::drawingml::DrawingML * getDrawingML() const
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType)
Is the frame format a text box?
Degree100 m_nDMLandVMLTextFrameRotation
List of TextBoxes in this document: they are exported as part of their shape, never alone...
const Size * getFlyFrameSize() const
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
bool HasTextBoxContent(sal_uInt32 nShapeType)
rtl::Reference< sax_fastparser::FastAttributeList > m_pBodyPrAttrList
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
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.
UNDERLYING_TYPE get() const
Style of a layout element.
Definition: frmfmt.hxx:58
#define TOOLS_WARN_EXCEPTION(area, stream)
static rtl::Reference< FastAttributeList > createAttrList()
#define SAL_MAX_INT32
rtl::Reference< sax_fastparser::FastAttributeList > m_pTextboxAttrList
OptionalString sType
virtual void RestoreData()
Restore what was saved in SaveData().
Definition: wrtww8.cxx:1924
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:882
const SwFormatHoriOrient & GetHoriOrient(bool=true) const
Definition: fmtornt.hxx:108
const Color & GetColor() const
ExportDataSaveRestore(DocxExport &rExport, sal_uLong nStt, sal_uLong nEnd, ww8::Frame const *pParentFrame)
bool getDrawingOpen() const
FlyAnchors.
Definition: fmtanchr.hxx:34
void setSerializer(const sax_fastparser::FSHelperPtr &pSerializer)
tools::Long GetLeft() const
sal_uInt8 GetHeightPercent() const
Definition: fmtfsize.hxx:88
const ww8::Frame * m_pParentFrame
Definition: wrtww8.hxx:516
css::uno::Any getValue(const OUString &sKey) const
#define SAL_MIN_INT32
float u
OUString GetTitle() const
bool getTextFrameSyntax() const
sal_Int16 GetHoriOrient() const
Definition: fmtornt.hxx:87
Object Value
OStringBuffer & getTextFrameStyle()
css::text::WrapTextMode GetSurround() const
Definition: fmtsrnd.hxx:51
OString ConvertColor(const Color &rColor)
sal_uInt16 GetSize() const
Marks a node in the document model.
Definition: ndindex.hxx:31
void setDMLandVMLTextFrameRotation(Degree100 nDMLandVMLTextFrameRotation)
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:123
bool IsDMLAndVMLDrawingOpen() const
sal_uInt8 GetWidthPercent() const
Definition: fmtfsize.hxx:91
rtl::Reference< sax_fastparser::FastAttributeList > & getFlyFillAttrList()
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
sal_Int32 nLineWidth
sax_fastparser::FSHelperPtr m_pSerializer
sal_Int16 GetRelativeWidthRelation() const
OUString GetName() const
#define Y
virtual SdrLayerID GetHellId() const =0
sal_Int16 GetHeightPercentRelation() const
Definition: fmtfsize.hxx:89
const SwNodeIndex * GetContentIdx() const
Definition: fmtcntnt.hxx:46
void setParagraphSdtOpen(bool bParagraphSdtOpen)
Set if paragraph sdt open in the current drawing.
rtl::Reference< sax_fastparser::FastAttributeList > m_pDashLineStyleAttr
sal_uLong EndOfSectionIndex() const
Definition: node.hxx:681
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.
rtl::Reference< sax_fastparser::FastAttributeList > & getDashLineStyle()
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
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.
sal_Int16 GetVertOrient() const
Definition: fmtornt.hxx:54
sax_fastparser::FastAttributeList * getBodyPrAttrList() const
const SwFormatWrapInfluenceOnObjPos & GetWrapInfluenceOnObjPos(bool=true) const
void setDMLTextFrameSyntax(bool bDMLTextFrameSyntax)
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.
tools::Long GetHeight() const
SvxBorderLineStyle GetBorderLineStyle() const
static bool isSupportedDMLShape(const uno::Reference< drawing::XShape > &xShape)
rtl::Reference< sax_fastparser::FastAttributeList > & getTextboxAttrList()
sal_Int16 GetRelativeHeightRelation() const
#define SAL_WARN(area, stream)
virtual const tools::Rectangle & GetLogicRect() const
bool getFlyFrameGraphic() const
OStringBuffer m_aTextFrameStyle
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:120
Frame is variable in Var-direction.
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
void setDrawingOpen(bool bDrawingOpen)
void setParagraphHasDrawing(bool bParagraphHasDrawing)
const editeng::SvxBorderLine * GetBottom() const
sal_Int16 GetWidthPercentRelation() const
Definition: fmtfsize.hxx:92
const Size * getFlyFrameSize() const
When exporting fly frames, this holds the real size of the frame.
static MSO_SPT GetCustomShapeType(const css::uno::Reference< css::drawing::XShape > &rXShape, ShapeFlag &nMirrorFlags, OUString &rShapeType, bool bOOXML=false)
SdrObject * FindRealSdrObject()
Definition: atrfrm.cxx:2713
const double * GetRelativeHeight() const
rtl::Reference< sax_fastparser::FastAttributeList > & getDashLineStyleAttr()
sal_uInt16 GetUpper() const
DocxExport & getExport() const
SwFrameSize GetHeightSizeType() const
Definition: fmtfsize.hxx:80
sal_uInt16 GetWidth() const
static OString lcl_TransparencyToDrawingMlAlpha(const Color &rColor)
const SvxLRSpaceItem & GetLRSpace(bool=true) const
Definition: frmatr.hxx:74
EnumT GetValue() const
const SvxShadowItem & GetShadow(bool=true) const
Definition: frmatr.hxx:88