LibreOffice Module sw (master)  1
rtfsdrexport.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  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "rtfsdrexport.hxx"
21 #include <memory>
22 #include "rtfattributeoutput.hxx"
23 #include <svtools/rtfkeywd.hxx>
24 #include <svtools/unitconv.hxx>
26 #include <editeng/editobj.hxx>
27 #include <editeng/editids.hrc>
28 #include <editeng/fontitem.hxx>
29 #include <editeng/fhgtitem.hxx>
30 #include <svx/svdotext.hxx>
31 #include <svx/unoapi.hxx>
32 #include <vcl/cvtgrf.hxx>
33 #include <textboxhelper.hxx>
34 #include <dcontact.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <sal/log.hxx>
37 #include <algorithm>
38 #include "rtfexport.hxx"
39 
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/graphic/XGraphic.hpp>
42 
43 using namespace css;
44 
46  : EscherEx(std::make_shared<EscherExGlobal>(), nullptr)
47  , m_rExport(rExport)
48  , m_rAttrOutput(static_cast<RtfAttributeOutput&>(m_rExport.AttrOutput()))
49  , m_pSdrObject(nullptr)
50  , m_nShapeType(ESCHER_ShpInst_Nil)
51  , m_nShapeFlags(ShapeFlag::NONE)
52  , m_aShapeStyle(200)
53  , m_pShapeTypeWritten(new bool[ESCHER_ShpInst_COUNT])
54 {
55  mnGroupLevel = 1;
56  memset(m_pShapeTypeWritten.get(), 0, ESCHER_ShpInst_COUNT * sizeof(bool));
57 }
58 
60 {
61  delete mpOutStrm;
62  mpOutStrm = nullptr;
63 }
64 
65 void RtfSdrExport::OpenContainer(sal_uInt16 nEscherContainer, int nRecInstance)
66 {
67  EscherEx::OpenContainer(nEscherContainer, nRecInstance);
68 
69  if (nEscherContainer == ESCHER_SpContainer)
70  {
72  m_aShapeStyle.setLength(0);
73  m_aShapeStyle.ensureCapacity(200);
74  m_aShapeProps.clear();
75  }
76 }
77 
79 {
80  if (mRecTypes.back() == ESCHER_SpContainer)
81  {
82  // write the shape now when we have all the info
83  sal_Int32 nShapeElement = StartShape();
84  EndShape(nShapeElement);
85 
86  // cleanup
88  }
89 
91 }
92 
93 sal_uInt32 RtfSdrExport::EnterGroup(const OUString& /*rShapeName*/,
94  const tools::Rectangle* /*pRect*/)
95 {
96  m_bInGroup = true;
97  return GenerateShapeId();
98 }
99 
101 
102 void RtfSdrExport::AddShape(sal_uInt32 nShapeType, ShapeFlag nShapeFlags, sal_uInt32 /*nShapeId*/)
103 {
104  m_nShapeType = nShapeType;
105  m_nShapeFlags = nShapeFlags;
106 }
107 
108 static sal_uInt16 impl_GetUInt16(const sal_uInt8*& pVal)
109 {
110  sal_uInt16 nRet = *pVal++;
111  nRet += (*pVal++) << 8;
112  return nRet;
113 }
114 
115 static sal_Int32 impl_GetPointComponent(const sal_uInt8*& pVal, std::size_t& rVerticesPos,
116  sal_uInt16 nPointSize)
117 {
118  sal_Int32 nRet = 0;
119  if ((nPointSize == 0xfff0) || (nPointSize == 4))
120  {
121  sal_uInt16 nUnsigned = *pVal++;
122  nUnsigned += (*pVal++) << 8;
123  rVerticesPos += 2;
124 
125  nRet = sal_Int16(nUnsigned);
126  }
127  else if (nPointSize == 8)
128  {
129  sal_uInt32 nUnsigned = *pVal++;
130  nUnsigned += (*pVal++) << 8;
131  nUnsigned += (*pVal++) << 16;
132  nUnsigned += (*pVal++) << 24;
133  rVerticesPos += 4;
134 
135  nRet = nUnsigned;
136  }
137 
138  return nRet;
139 }
140 
142 {
144  return;
145 
147  AddLineDimensions(rRect);
148  else
150 
151  // properties
152  const EscherProperties& rOpts = rProps.GetOpts();
153  for (const auto& rOpt : rOpts)
154  {
155  sal_uInt16 nId = (rOpt.nPropId & 0x0FFF);
156 
157  switch (nId)
158  {
160  {
161  int nWrapType = 0;
162  switch (rOpt.nPropValue)
163  {
164  case ESCHER_WrapSquare:
165  nWrapType = 2;
166  break;
167  case ESCHER_WrapByPoints:
168  nWrapType = 4;
169  break;
170  case ESCHER_WrapNone:
171  nWrapType = 3;
172  break;
174  nWrapType = 1;
175  break;
176  case ESCHER_WrapThrough:
177  nWrapType = 5;
178  break;
179  }
180  if (nWrapType)
181  m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPWR + OString::number(nWrapType));
182  }
183  break;
185  m_aShapeProps.insert(
186  std::pair<OString, OString>("fillColor", OString::number(rOpt.nPropValue)));
187  break;
189  m_aShapeProps.insert(
190  std::pair<OString, OString>("fillBackColor", OString::number(rOpt.nPropValue)));
191  break;
193  m_aShapeProps.insert(
194  std::pair<OString, OString>("anchorText", OString::number(rOpt.nPropValue)));
195  break;
197  if (rOpt.nPropValue)
198  m_aShapeProps.insert(
199  std::pair<OString, OString>("fNoFillHitTest", OString::number(1)));
200  break;
202  // for some reason the value is set to 0x90000 if lines are switched off
203  if (rOpt.nPropValue == 0x90000)
204  m_aShapeProps.insert(std::pair<OString, OString>("fLine", OString::number(0)));
205  break;
207  m_aShapeProps.insert(
208  std::pair<OString, OString>("lineColor", OString::number(rOpt.nPropValue)));
209  break;
211  m_aShapeProps.insert(
212  std::pair<OString, OString>("lineBackColor", OString::number(rOpt.nPropValue)));
213  break;
215  m_aShapeProps.insert(
216  std::pair<OString, OString>("lineJoinStyle", OString::number(rOpt.nPropValue)));
217  break;
219  if (rOpt.nPropValue)
220  m_aShapeProps.insert(std::pair<OString, OString>("fshadowObscured", "1"));
221  break;
222  case ESCHER_Prop_geoLeft:
223  case ESCHER_Prop_geoTop:
224  {
225  sal_uInt32 nLeft = 0;
226  sal_uInt32 nTop = 0;
227 
228  if (nId == ESCHER_Prop_geoLeft)
229  {
230  nLeft = rOpt.nPropValue;
231  rProps.GetOpt(ESCHER_Prop_geoTop, nTop);
232  }
233  else
234  {
235  nTop = rOpt.nPropValue;
236  rProps.GetOpt(ESCHER_Prop_geoLeft, nLeft);
237  }
238 
239  m_aShapeProps.insert(
240  std::pair<OString, OString>("geoLeft", OString::number(sal_Int32(nLeft))));
241  m_aShapeProps.insert(
242  std::pair<OString, OString>("geoTop", OString::number(sal_Int32(nTop))));
243  }
244  break;
245 
248  {
249  sal_uInt32 nLeft = 0;
250  sal_uInt32 nRight = 0;
251  sal_uInt32 nTop = 0;
252  sal_uInt32 nBottom = 0;
253  rProps.GetOpt(ESCHER_Prop_geoLeft, nLeft);
254  rProps.GetOpt(ESCHER_Prop_geoTop, nTop);
255 
256  if (nId == ESCHER_Prop_geoRight)
257  {
258  nRight = rOpt.nPropValue;
259  rProps.GetOpt(ESCHER_Prop_geoBottom, nBottom);
260  }
261  else
262  {
263  nBottom = rOpt.nPropValue;
264  rProps.GetOpt(ESCHER_Prop_geoRight, nRight);
265  }
266 
267  m_aShapeProps.insert(std::pair<OString, OString>(
268  "geoRight", OString::number(sal_Int32(nRight) - sal_Int32(nLeft))));
269  m_aShapeProps.insert(std::pair<OString, OString>(
270  "geoBottom", OString::number(sal_Int32(nBottom) - sal_Int32(nTop))));
271  }
272  break;
275  {
276  EscherPropSortStruct aVertices;
278 
279  if (rProps.GetOpt(ESCHER_Prop_pVertices, aVertices)
280  && rProps.GetOpt(ESCHER_Prop_pSegmentInfo, aSegments)
281  && aVertices.nProp.size() >= 6 && aSegments.nProp.size() >= 6)
282  {
283  const sal_uInt8* pVerticesIt = aVertices.nProp.data() + 6;
284  std::size_t nVerticesPos = 6;
285  const sal_uInt8* pSegmentIt = aSegments.nProp.data();
286 
287  OStringBuffer aSegmentInfo(512);
288  OStringBuffer aVerticies(512);
289 
290  sal_uInt16 nPointSize = aVertices.nProp[4] + (aVertices.nProp[5] << 8);
291 
292  // number of segments
293  sal_uInt16 nSegments = impl_GetUInt16(pSegmentIt);
294  sal_Int32 nVertices = 0;
295  aSegmentInfo.append("2;" + OString::number(nSegments));
296  pSegmentIt += 4;
297 
298  for (; nSegments; --nSegments)
299  {
300  sal_uInt16 nSeg = impl_GetUInt16(pSegmentIt);
301 
302  // The segment type is stored in the upper 3 bits
303  // and segment count is stored in the lower 13
304  // bits.
305  unsigned char nSegmentType = (nSeg & 0xE000) >> 13;
306  unsigned short nSegmentCount = nSeg & 0x03FF;
307 
308  aSegmentInfo.append(';').append(static_cast<sal_Int32>(nSeg));
309  switch (nSegmentType)
310  {
311  case msopathLineTo:
312  for (unsigned short i = 0; i < nSegmentCount; ++i)
313  {
314  sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos,
315  nPointSize);
316  sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos,
317  nPointSize);
318  aVerticies.append(";(" + OString::number(nX) + ","
319  + OString::number(nY) + ")");
320  nVertices++;
321  }
322  break;
323  case msopathMoveTo:
324  {
325  sal_Int32 nX
326  = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
327  sal_Int32 nY
328  = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
329  aVerticies.append(";(" + OString::number(nX) + ","
330  + OString::number(nY) + ")");
331  nVertices++;
332  break;
333  }
334  case msopathCurveTo:
335  for (unsigned short j = 0; j < nSegmentCount; ++j)
336  {
337  for (int i = 0; i < 3; i++)
338  {
339  sal_Int32 nX = impl_GetPointComponent(
340  pVerticesIt, nVerticesPos, nPointSize);
341  sal_Int32 nY = impl_GetPointComponent(
342  pVerticesIt, nVerticesPos, nPointSize);
343  aVerticies.append(";(" + OString::number(nX) + ","
344  + OString::number(nY) + ")");
345  nVertices++;
346  }
347  }
348  break;
349  case msopathEscape:
350  {
351  // If the segment type is msopathEscape, the lower 13 bits are
352  // divided in a 5 bit escape code and 8 bit
353  // vertex count (not segment count!)
354  unsigned char nVertexCount = nSegmentCount & 0x00FF;
355  nVerticesPos += nVertexCount;
356  break;
357  }
358  case msopathClientEscape:
359  case msopathClose:
360  case msopathEnd:
361  break;
362  default:
363  SAL_WARN("sw.rtf", "Totally b0rked");
364  break;
365  }
366  }
367 
368  if (!aVerticies.isEmpty())
369  {
370  // We know the number of vertices at the end only, so we have to prepend them here.
371  m_aShapeProps.insert(std::pair<OString, OString>(
372  "pVerticies",
373  "8;" + OString::number(nVertices) + aVerticies.makeStringAndClear()));
374  }
375  if (!aSegmentInfo.isEmpty())
376  m_aShapeProps.insert(std::pair<OString, OString>(
377  "pSegmentInfo", aSegmentInfo.makeStringAndClear()));
378  }
379  else
380  SAL_INFO(
381  "sw.rtf",
382  __func__
383  << ": unhandled shape path, missing either pVertices or pSegmentInfo");
384  }
385  break;
387  // noop, we use pSegmentInfo instead
388  break;
389  case ESCHER_Prop_fFillOK:
390  if (!rOpt.nPropValue)
391  m_aShapeProps.insert(std::pair<OString, OString>("fFillOK", "0"));
392  break;
394  m_aShapeProps.insert(
395  std::pair<OString, OString>("dxTextLeft", OString::number(rOpt.nPropValue)));
396  break;
398  m_aShapeProps.insert(
399  std::pair<OString, OString>("dyTextTop", OString::number(rOpt.nPropValue)));
400  break;
402  m_aShapeProps.insert(
403  std::pair<OString, OString>("dxTextRight", OString::number(rOpt.nPropValue)));
404  break;
406  m_aShapeProps.insert(
407  std::pair<OString, OString>("dyTextBottom", OString::number(rOpt.nPropValue)));
408  break;
410  // Size text to fit shape size: not supported by RTF
411  break;
413  m_aShapeProps.insert(
414  std::pair<OString, OString>("adjustValue", OString::number(rOpt.nPropValue)));
415  break;
417  m_aShapeProps.insert(
418  std::pair<OString, OString>("txflTextFlow", OString::number(rOpt.nPropValue)));
419  break;
421  m_aShapeProps.insert(
422  std::pair<OString, OString>("fillType", OString::number(rOpt.nPropValue)));
423  break;
425  m_aShapeProps.insert(
426  std::pair<OString, OString>("fillOpacity", OString::number(rOpt.nPropValue)));
427  break;
429  {
430  OStringBuffer aBuf;
433  int nHeaderSize
434  = 25; // The first bytes are WW8-specific, we're only interested in the PNG
435  aBuf.append(msfilter::rtfutil::WriteHex(rOpt.nProp.data() + nHeaderSize,
436  rOpt.nProp.size() - nHeaderSize));
437  aBuf.append('}');
438  m_aShapeProps.insert(
439  std::pair<OString, OString>("fillBlip", aBuf.makeStringAndClear()));
440  }
441  break;
442  default:
443  SAL_INFO("sw.rtf", __func__ << ": unhandled property: " << nId
444  << " (value: " << rOpt.nPropValue << ")");
445  break;
446  }
447  }
448 }
449 
451 {
452  // We get the position relative to (the current?) character
453  m_aShapeProps.insert(std::pair<OString, OString>("posrelh", "3"));
454 
455  if (m_nShapeFlags & ShapeFlag::FlipV)
456  m_aShapeProps.insert(std::pair<OString, OString>("fFlipV", "1"));
457 
458  if (m_nShapeFlags & ShapeFlag::FlipH)
459  m_aShapeProps.insert(std::pair<OString, OString>("fFlipH", "1"));
460 
461  // the actual dimensions
462  m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPLEFT + OString::number(rRectangle.Left()));
463  m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPTOP + OString::number(rRectangle.Top()));
464  m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPRIGHT + OString::number(rRectangle.Right()));
465  m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM + OString::number(rRectangle.Bottom()));
466 }
467 
468 void RtfSdrExport::AddRectangleDimensions(OStringBuffer& rBuffer,
469  const tools::Rectangle& rRectangle)
470 {
471  // We get the position relative to (the current?) character
472  m_aShapeProps.insert(std::pair<OString, OString>("posrelh", "3"));
473 
474  rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPLEFT + OString::number(rRectangle.Left()));
475  rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPTOP + OString::number(rRectangle.Top()));
476  rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPRIGHT + OString::number(rRectangle.Right()));
477  rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM + OString::number(rRectangle.Bottom()));
478 }
479 
480 static void lcl_AppendSP(OStringBuffer& rRunText, const char* cName, std::string_view rValue)
481 {
482  rRunText.append(OString::Concat("{" OOO_STRING_SVTOOLS_RTF_SP "{" OOO_STRING_SVTOOLS_RTF_SN " ")
483  + cName
484  + "}"
486  + rValue
487  + "}"
488  "}");
489 }
490 
492 {
493  // Get the Graphic object from the Sdr one.
494  uno::Reference<drawing::XShape> xShape
495  = GetXShapeForSdrObject(const_cast<SdrObject*>(m_pSdrObject));
496  uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
497 
498  uno::Reference<graphic::XGraphic> xGraphic;
499 
500  Graphic aGraphic;
501 
502  try
503  {
504  xPropertySet->getPropertyValue("Graphic") >>= xGraphic;
505  }
506  catch (beans::UnknownPropertyException const&)
507  {
508  TOOLS_WARN_EXCEPTION("sw.rtf", "failed to fetch graphic");
509  }
510 
511  if (xGraphic.is())
512  {
513  aGraphic = Graphic(xGraphic);
514  }
515 
516  // Export it to a stream.
517  SvMemoryStream aStream;
518  (void)GraphicConverter::Export(aStream, aGraphic, ConvertDataFormat::PNG);
519  sal_uInt32 nSize = aStream.TellEnd();
520  auto pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
521 
522  Size aMapped(aGraphic.GetPrefSize());
523 
524  // Add it to the properties.
527  aBuf->append(OOO_STRING_SVTOOLS_RTF_PICW + OString::number(aMapped.Width()));
528  aBuf->append(OOO_STRING_SVTOOLS_RTF_PICH + OString::number(aMapped.Height())
530  aBuf->append(msfilter::rtfutil::WriteHex(pGraphicAry, nSize));
531  aBuf->append('}');
532  m_aShapeProps.insert(std::pair<OString, OString>("pib", aBuf.makeStringAndClear()));
533 }
534 
536 {
538  return -1;
539 
540  m_aShapeProps.insert(std::pair<OString, OString>("shapeType", OString::number(m_nShapeType)));
543 
544  m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHP);
545  m_rAttrOutput.RunText().append(
547 
548  m_rAttrOutput.RunText().append(m_aShapeStyle.makeStringAndClear());
549  // Ignore \shpbxpage, \shpbxmargin, and \shpbxcolumn, in favor of the posrelh property.
551  // Ignore \shpbypage, \shpbymargin, and \shpbycolumn, in favor of the posrelh property.
553 
554  // Write ZOrder.
555  if (!m_bInGroup)
556  {
557  // Order inside the group shape is not relevant for the flat shape list
558  // we write.
560  m_rAttrOutput.RunText().append(static_cast<sal_Int64>(m_pSdrObject->GetOrdNum()));
561  }
562 
563  for (auto it = m_aShapeProps.rbegin(); it != m_aShapeProps.rend(); ++it)
564  lcl_AppendSP(m_rAttrOutput.RunText(), (*it).first.getStr(), (*it).second);
565 
566  lcl_AppendSP(m_rAttrOutput.RunText(), "wzDescription",
569  lcl_AppendSP(
570  m_rAttrOutput.RunText(), "wzName",
572 
573  // now check if we have some text
574  const SwFrameFormat* pShape = FindFrameFormat(m_pSdrObject);
575  if (pShape)
576  {
577  if (SwFrameFormat* pTextBox
579  {
580  ww8::Frame* pFrame = nullptr;
581  for (auto& rFrame : m_rExport.m_aFrames)
582  {
583  if (pTextBox == &rFrame.GetFrameFormat())
584  {
585  pFrame = &rFrame;
586  break;
587  }
588  }
589 
590  if (pFrame)
591  m_rAttrOutput.writeTextFrame(*pFrame, /*bTextBox=*/true);
592  return m_nShapeType;
593  }
594  }
595 
596  auto pTextObj = dynamic_cast<const SdrTextObj*>(m_pSdrObject);
597  if (pTextObj)
598  {
599  const OutlinerParaObject* pParaObj = nullptr;
600  std::unique_ptr<const OutlinerParaObject> pOwnedParaObj;
601 
602  /*
603  #i13885#
604  When the object is actively being edited, that text is not set into
605  the objects normal text object, but lives in a separate object.
606  */
607  if (pTextObj->IsTextEditActive())
608  {
609  pOwnedParaObj = pTextObj->CreateEditOutlinerParaObject();
610  pParaObj = pOwnedParaObj.get();
611  }
612  else
613  {
614  pParaObj = pTextObj->GetOutlinerParaObject();
615  }
616 
617  if (pParaObj)
618  {
619  // this is reached only in case some text is attached to the shape
620  // Watermark or TextBox?
621  if (pTextObj->TakeObjNameSingul().match("Text Frame"))
622  WriteOutliner(*pParaObj, TXT_HFTXTBOX);
623  else
624  {
625  const EditTextObject& rEditObj = pParaObj->GetTextObject();
626  const SfxItemSet& rItemSet = rEditObj.GetParaAttribs(0);
627 
628  lcl_AppendSP(m_rAttrOutput.RunText(), "gtextUNICODE",
631 
632  auto pFontFamily
633  = static_cast<const SvxFontItem*>(rItemSet.GetItem(SID_ATTR_CHAR_FONT));
634  if (pFontFamily)
635  {
636  lcl_AppendSP(m_rAttrOutput.RunText(), "gtextFont",
637  msfilter::rtfutil::OutString(pFontFamily->GetFamilyName(),
639  }
640 
641  auto pFontHeight = static_cast<const SvxFontHeightItem*>(
642  rItemSet.GetItem(SID_ATTR_CHAR_FONTHEIGHT));
643  if (pFontHeight)
644  {
645  tools::Long nFontHeight = TransformMetric(pFontHeight->GetHeight(),
646  FieldUnit::TWIP, FieldUnit::POINT);
647  lcl_AppendSP(
648  m_rAttrOutput.RunText(), "gtextSize",
649  msfilter::rtfutil::OutString(OUString::number(nFontHeight * RTF_MULTIPLIER),
651  }
652 
653  // RTF angle: 0-360 * 2^16 clockwise
654  // LO angle: 0-360 * 100 counter-clockwise
655  sal_Int32 nRotation
656  = -1 * pTextObj->GetGeoStat().nRotationAngle.get() * RTF_MULTIPLIER / 100;
657  lcl_AppendSP(m_rAttrOutput.RunText(), "rotation",
658  msfilter::rtfutil::OutString(OUString::number(nRotation),
660  }
661  }
662  }
663 
664  return m_nShapeType;
665 }
666 
668 {
669  SAL_INFO("sw.rtf", __func__ << " start");
670 
671  const EditTextObject& rEditObj = rParaObj.GetTextObject();
672  MSWord_SdrAttrIter aAttrIter(m_rExport, rEditObj, eType);
673 
674  sal_Int32 nPara = rEditObj.GetParagraphCount();
675 
676  bool bShape = eType == TXT_HFTXTBOX;
677  if (bShape)
678  m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHPTXT).append(' ');
679  for (sal_Int32 n = 0; n < nPara; ++n)
680  {
681  if (n)
682  aAttrIter.NextPara(n);
683 
684  rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet();
685 
686  OUString aStr(rEditObj.GetText(n));
687  sal_Int32 nCurrentPos = 0;
688  const sal_Int32 nEnd = aStr.getLength();
689 
690  aAttrIter.OutParaAttr(false);
692 
693  do
694  {
695  const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
696  rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
697 
698  aAttrIter.OutAttr(nCurrentPos);
699  m_rAttrOutput.RunText().append('{');
702  bool bTextAtr = aAttrIter.IsTextAttr(nCurrentPos);
703  if (!bTextAtr)
704  {
705  OUString aOut(aStr.copy(nCurrentPos, nNextAttr - nCurrentPos));
706  m_rAttrOutput.RunText().append(msfilter::rtfutil::OutString(aOut, eChrSet));
707  }
708 
709  m_rAttrOutput.RunText().append('}');
710 
711  nCurrentPos = nNextAttr;
712  eChrSet = eNextChrSet;
713  aAttrIter.NextPos();
714  } while (nCurrentPos < nEnd);
715  if (bShape || n + 1 < nPara)
717  }
718  if (bShape)
719  m_rAttrOutput.RunText().append('}');
720 
721  SAL_INFO("sw.rtf", __func__ << " end");
722 }
723 
724 void RtfSdrExport::EndShape(sal_Int32 nShapeElement)
725 {
726  if (nShapeElement >= 0)
727  {
728  // end of the shape
729  m_rAttrOutput.RunText().append('}').append('}');
730  }
731 }
732 
734 {
735  m_pSdrObject = &rObj;
737 }
738 
739 bool RtfSdrExport::isTextBox(const SwFrameFormat& rFrameFormat)
740 {
741  return SwTextBoxHelper::isTextBox(&rFrameFormat, RES_FLYFRMFMT);
742 }
743 
744 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::unique_ptr< bool[]> m_pShapeTypeWritten
Remember which shape types we had already written.
#define ESCHER_ShpInst_Nil
Wrapper around OStringBuffers, so less hexdump of graphics have to be kept in memory during RTF expor...
ESCHER_WrapSquare
void OutAttr(sal_Int32 nSwPos)
Definition: wrtw8esh.cxx:1116
sal_Int32 WhereNext() const
Definition: wrtww8.hxx:1487
#define OOO_STRING_SVTOOLS_RTF_SHPRIGHT
EscherProperties GetOpts() const
#define ESCHER_Prop_geoRight
#define ESCHER_Prop_geoLeft
msopathCurveTo
ESCHER_WrapTopBottom
#define ESCHER_Prop_fshadowObscured
#define OOO_STRING_SVTOOLS_RTF_SN
#define OOO_STRING_SVTOOLS_RTF_PNGBLIP
rtl_TextEncoding GetNodeCharSet() const
Definition: wrtww8.hxx:1489
void OpenContainer(sal_uInt16 nEscherContainer, int nRecInstance=0) override
#define ESCHER_Prop_dyTextTop
msopathEnd
SvStream * mpOutStrm
msopathLineTo
rtl_TextEncoding GetCurrentEncoding() const
Definition: rtfexport.hxx:177
ESCHER_WrapThrough
void OutParaAttr(bool bCharAttr, const std::set< sal_uInt16 > *pWhichsToIgnore=nullptr)
Definition: wrtw8esh.cxx:1273
void impl_writeGraphic()
Exports the pib property of the shape.
#define ESCHER_Prop_geoBottom
std::vector< sal_uInt8 > nProp
long Long
OUString GetDescription() const
std::vector< sal_uInt16 > mRecTypes
sal_Int64 n
#define ESCHER_Prop_pVertices
sal_uInt32 AddSdrObject(const SdrObject &rObj, bool ooxmlExport=false)
aBuf
sal_Int16 nId
#define OOO_STRING_SVTOOLS_RTF_PICT
tools::Long TransformMetric(tools::Long nVal, FieldUnit aOld, FieldUnit aNew)
#define ESCHER_Prop_txflTextFlow
std::shared_ptr< T > make_shared(Args &&...args)
ESCHER_WrapNone
Used to export formatted text associated to drawings.
Definition: wrtww8.hxx:1451
#define OOO_STRING_SVTOOLS_RTF_PICH
static SwFrameFormat * getOtherTextBoxFormat(const SwFrameFormat *pFormat, sal_uInt16 nType)
If we have an associated TextFrame, then return that.
#define ESCHER_Prop_pSegmentInfo
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?
virtual sal_uInt32 GenerateShapeId()
virtual sal_uInt64 TellEnd() override
static sal_uInt16 impl_GetUInt16(const sal_uInt8 *&pVal)
sal_uInt32 m_nShapeType
Remember the shape type.
constexpr TypedWhichId< SwDrawFrameFormat > RES_DRAWFRMFMT(159)
#define ESCHER_Prop_AnchorText
NONE
The class that does all the actual RTF export-related work.
Definition: rtfexport.hxx:36
tools::Long Left() const
ShapeFlag m_nShapeFlags
Remember the shape flags.
void LeaveGroup() override
#define OOO_STRING_SVTOOLS_RTF_SHPZ
The class that has handlers for various resource types when exporting as RTF.
msopathClientEscape
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType)
Is the frame format a text box?
tools::Long Bottom() const
const SfxItemSet & GetParaAttribs(sal_Int32 nPara) const
#define ESCHER_ShpInst_Line
sal_Int32 StartShape()
OString WriteHex(const sal_uInt8 *pData, sal_uInt32 nSize, SvStream *pStream=nullptr, sal_uInt32 nLimit=64)
SwFrameFormat * FindFrameFormat(SdrObject *pObj)
The Get reverse way: seeks the format to the specified object.
Definition: dcontact.cxx:120
RtfAttributeOutput & m_rAttrOutput
#define ESCHER_Prop_fillOpacity
void Commit(EscherPropertyContainer &rProps, const tools::Rectangle &rRect) override
#define OOO_STRING_SVTOOLS_RTF_SP
OUString GetText(sal_Int32 nPara) const
#define ESCHER_Prop_dyTextBottom
#define ESCHER_Prop_fNoLineDrawDash
ShapeFlag
#define OOO_STRING_SVTOOLS_RTF_SHPLEFT
#define ESCHER_Prop_lineBackColor
const EditTextObject & GetTextObject() const
Style of a layout element.
Definition: frmfmt.hxx:58
#define TOOLS_WARN_EXCEPTION(area, stream)
OString MoveCharacterProperties(bool aAutoWriteRtlLtr=false)
#define RTF_MULTIPLIER
int i
RtfExport & m_rExport
#define ESCHER_Prop_WrapText
#define OOO_STRING_SVTOOLS_RTF_SHPWR
#define ESCHER_Prop_geoTop
sal_uInt32 EnterGroup(const OUString &rShapeName, const tools::Rectangle *pBoundRect) override
msopathClose
TextTypes
Definition: wrtww8.hxx:155
void writeTextFrame(const ww8::Frame &rFrame, bool bTextBox=false)
Handles just the { ...} part of a shape export.
sal_uInt32 GetOrdNum() const
void AddShape(sal_uInt32 nShapeType, ShapeFlag nShapeFlags, sal_uInt32 nShapeId=0) override
#define OOO_STRING_SVTOOLS_RTF_SHP
#define ESCHER_Prop_FitTextToShape
#define ESCHER_ShpInst_COUNT
tools::Long Top() const
#define OOO_STRING_SVTOOLS_RTF_SHPTOP
#define OOO_STRING_SVTOOLS_RTF_PAR
OUString GetName() const
#define ESCHER_Prop_lineJoinStyle
msopathEscape
#define ESCHER_Prop_fillBlip
#define OOO_STRING_SVTOOLS_RTF_SHPINST
OStringBuffer m_aShapeStyle
Remember style, the most important shape attribute ;-)
#define ESCHER_Prop_fillBackColor
std::vector< ISegmentProgressBarRef > aSegments
#define OOO_STRING_SVTOOLS_RTF_PICW
Size GetPrefSize() const
#define ESCHER_Prop_dxTextLeft
void RunText(const OUString &rText, rtl_TextEncoding eCharSet=RTL_TEXTENCODING_UTF8) override
Output text (inside a run).
#define ESCHER_Prop_fillColor
#define ESCHER_Prop_fFillOK
sal_Int32 GetParagraphCount() const
static ErrCode Export(SvStream &rOStm, const Graphic &rGraphic, ConvertDataFormat nFormat)
#define ESCHER_SpContainer
#define OOO_STRING_SVTOOLS_RTF_IGNORE
OString OutString(const OUString &rStr, rtl_TextEncoding eDestEnc, bool bUnicode=true)
virtual void CloseContainer()
static void lcl_AppendSP(OStringBuffer &rRunText, const char *cName, std::string_view rValue)
#define ESCHER_ShpInst_PictureFrame
#define OOO_STRING_SVTOOLS_RTF_SHPBOTTOM
const SdrObject * m_pSdrObject
void WriteOutliner(const OutlinerParaObject &rParaObj, TextTypes eType)
Write editeng text, e.g. shape or comment.
unsigned char sal_uInt8
ESCHER_WrapByPoints
Make exporting a Writer Frame easy.
#define ESCHER_Prop_lineColor
~RtfSdrExport() override
#define ESCHER_Prop_fNoFillHitTest
bool IsTextAttr(sal_Int32 nSwPos)
Definition: wrtw8esh.cxx:1196
virtual void OpenContainer(sal_uInt16 nEscherContainer, int nRecInstance=0)
msopathMoveTo
#define SAL_INFO(area, stream)
SVXCORE_DLLPUBLIC css::uno::Reference< css::drawing::XShape > GetXShapeForSdrObject(SdrObject *pObj) noexcept
#define ESCHER_Prop_fillType
#define ESCHER_Prop_adjustValue
ww8::Frames m_aFrames
Definition: wrtww8.hxx:495
void AddLineDimensions(const tools::Rectangle &rRectangle)
Add starting and ending point of a line to the m_pShapeAttrList.
#define ESCHER_Prop_shapePath
#define OOO_STRING_SVTOOLS_RTF_SHPBXIGNORE
sal_uInt32 mnGroupLevel
void AddSdrObject(const SdrObject &rObj)
Export the sdr object as Sdr.
#define OOO_STRING_SVTOOLS_RTF_SV
#define SAL_WARN(area, stream)
void CloseContainer() override
#define OOO_STRING_SVTOOLS_RTF_SHPTXT
static sal_Int32 impl_GetPointComponent(const sal_uInt8 *&pVal, std::size_t &rVerticesPos, sal_uInt16 nPointSize)
#define OOO_STRING_SVTOOLS_RTF_SHPBYIGNORE
rtl_TextEncoding GetNextCharSet() const
Definition: wrtw8esh.cxx:1042
bool GetOpt(sal_uInt16 nPropertyID, sal_uInt32 &rPropValue) const
std::map< OString, OString > m_aShapeProps
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
Reference< XGraphic > xGraphic
aStr
void NextPara(sal_Int32 nPar)
Definition: wrtw8esh.cxx:1022
RtfSdrExport(RtfExport &rExport)
tools::Long Right() const
#define SAL_NEWLINE_STRING
std::vector< EscherPropSortStruct > EscherProperties
const void * GetData()
void EndShape(sal_Int32 nShapeElement)
void AddRectangleDimensions(OStringBuffer &rBuffer, const tools::Rectangle &rRectangle)
Add position and size to the OStringBuffer.
#define ESCHER_Prop_dxTextRight
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo