Line data Source code
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 "rtfattributeoutput.hxx"
22 : #include <svtools/rtfkeywd.hxx>
23 : #include <filter/msfilter/rtfutil.hxx>
24 : #include <editeng/editobj.hxx>
25 : #include <svx/svdotext.hxx>
26 : #include <svx/unoapi.hxx>
27 : #include <vcl/cvtgrf.hxx>
28 : #include <textboxhelper.hxx>
29 : #include <dcontact.hxx>
30 : #include <algorithm>
31 :
32 : using namespace css;
33 :
34 96 : RtfSdrExport::RtfSdrExport(RtfExport& rExport)
35 96 : : EscherEx(EscherExGlobalRef(new EscherExGlobal), 0),
36 : m_rExport(rExport),
37 96 : m_rAttrOutput(static_cast<RtfAttributeOutput&>(m_rExport.AttrOutput())),
38 : m_pSdrObject(NULL),
39 : m_nShapeType(ESCHER_ShpInst_Nil),
40 : m_nShapeFlags(0) ,
41 : m_aShapeStyle(200),
42 96 : m_pShapeTypeWritten(new bool[ ESCHER_ShpInst_COUNT ]),
43 384 : m_aTextBoxes(SwTextBoxHelper::findTextBoxes(m_rExport.m_pDoc))
44 : {
45 96 : mnGroupLevel = 1;
46 96 : memset(m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof(bool));
47 96 : }
48 :
49 288 : RtfSdrExport::~RtfSdrExport()
50 : {
51 96 : delete mpOutStrm, mpOutStrm = NULL;
52 96 : delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL;
53 192 : }
54 :
55 117 : void RtfSdrExport::OpenContainer(sal_uInt16 nEscherContainer, int nRecInstance)
56 : {
57 117 : EscherEx::OpenContainer(nEscherContainer, nRecInstance);
58 :
59 117 : if (nEscherContainer == ESCHER_SpContainer)
60 : {
61 117 : m_nShapeType = ESCHER_ShpInst_Nil;
62 117 : if (!m_aShapeStyle.isEmpty())
63 0 : m_aShapeStyle.makeStringAndClear();
64 117 : m_aShapeStyle.ensureCapacity(200);
65 117 : m_aShapeProps.clear();
66 : }
67 117 : }
68 :
69 117 : void RtfSdrExport::CloseContainer()
70 : {
71 117 : if (mRecTypes.back() == ESCHER_SpContainer)
72 : {
73 : // write the shape now when we have all the info
74 117 : sal_Int32 nShapeElement = StartShape();
75 117 : EndShape(nShapeElement);
76 :
77 : // cleanup
78 117 : m_nShapeType = ESCHER_ShpInst_Nil;
79 : }
80 :
81 117 : EscherEx::CloseContainer();
82 117 : }
83 :
84 8 : sal_uInt32 RtfSdrExport::EnterGroup(const OUString& /*rShapeName*/, const Rectangle* /*pRect*/)
85 : {
86 8 : return GenerateShapeId();
87 : }
88 :
89 8 : void RtfSdrExport::LeaveGroup()
90 : {
91 : /* noop */
92 8 : }
93 :
94 117 : void RtfSdrExport::AddShape(sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uInt32 /*nShapeId*/)
95 : {
96 117 : m_nShapeType = nShapeType;
97 117 : m_nShapeFlags = nShapeFlags;
98 117 : }
99 :
100 3802 : inline sal_uInt16 impl_GetUInt16(const sal_uInt8*& pVal)
101 : {
102 3802 : sal_uInt16 nRet = *pVal++;
103 3802 : nRet += (*pVal++) << 8;
104 3802 : return nRet;
105 : }
106 :
107 10060 : inline sal_Int32 impl_GetPointComponent(const sal_uInt8*& pVal, sal_Size& rVerticesPos, sal_uInt16 nPointSize)
108 : {
109 10060 : sal_Int32 nRet = 0;
110 10060 : if ((nPointSize == 0xfff0) || (nPointSize == 4))
111 : {
112 9996 : sal_uInt16 nUnsigned = *pVal++;
113 9996 : nUnsigned += (*pVal++) << 8;
114 9996 : rVerticesPos += 2;
115 :
116 9996 : nRet = sal_Int16(nUnsigned);
117 : }
118 64 : else if (nPointSize == 8)
119 : {
120 64 : sal_uInt32 nUnsigned = *pVal++;
121 64 : nUnsigned += (*pVal++) << 8;
122 64 : nUnsigned += (*pVal++) << 16;
123 64 : nUnsigned += (*pVal++) << 24;
124 64 : rVerticesPos += 4;
125 :
126 64 : nRet = nUnsigned;
127 : }
128 :
129 10060 : return nRet;
130 : }
131 :
132 117 : void RtfSdrExport::Commit(EscherPropertyContainer& rProps, const Rectangle& rRect)
133 : {
134 117 : if (m_nShapeType == ESCHER_ShpInst_Nil)
135 117 : return;
136 :
137 117 : if (m_nShapeType == ESCHER_ShpInst_Line)
138 0 : AddLineDimensions(rRect);
139 : else
140 117 : AddRectangleDimensions(m_aShapeStyle, rRect);
141 :
142 : // properties
143 117 : const EscherProperties& rOpts = rProps.GetOpts();
144 2024 : for (EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it)
145 : {
146 1907 : sal_uInt16 nId = (it->nPropId & 0x0FFF);
147 :
148 1907 : switch (nId)
149 : {
150 : case ESCHER_Prop_WrapText:
151 : {
152 90 : int nWrapType = 0;
153 90 : switch (it->nPropValue)
154 : {
155 : case ESCHER_WrapSquare:
156 13 : nWrapType = 2;
157 13 : break;
158 : case ESCHER_WrapByPoints:
159 0 : nWrapType = 4;
160 0 : break;
161 : case ESCHER_WrapNone:
162 77 : nWrapType = 3;
163 77 : break;
164 : case ESCHER_WrapTopBottom:
165 0 : nWrapType = 1;
166 0 : break;
167 : case ESCHER_WrapThrough:
168 0 : nWrapType = 5;
169 0 : break;
170 : }
171 90 : if (nWrapType)
172 90 : m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPWR).append((sal_Int32)nWrapType);
173 : }
174 90 : break;
175 : case ESCHER_Prop_fillColor:
176 69 : m_aShapeProps.insert(std::pair<OString,OString>("fillColor", OString::number(it->nPropValue)));
177 69 : break;
178 : case ESCHER_Prop_fillBackColor:
179 69 : m_aShapeProps.insert(std::pair<OString,OString>("fillBackColor", OString::number(it->nPropValue)));
180 69 : break;
181 : case ESCHER_Prop_AnchorText:
182 90 : m_aShapeProps.insert(std::pair<OString,OString>("anchorText", OString::number(it->nPropValue)));
183 90 : break;
184 : case ESCHER_Prop_fNoFillHitTest:
185 117 : if (it->nPropValue)
186 117 : m_aShapeProps.insert(std::pair<OString,OString>("fNoFillHitTest", OString::number(1)));
187 117 : break;
188 : case ESCHER_Prop_fNoLineDrawDash:
189 : // for some reason the value is set to 0x90000 if lines are switched off
190 117 : if (it->nPropValue == 0x90000)
191 68 : m_aShapeProps.insert(std::pair<OString,OString>("fLine", OString::number(0)));
192 117 : break;
193 : case ESCHER_Prop_lineColor:
194 117 : m_aShapeProps.insert(std::pair<OString,OString>("lineColor", OString::number(it->nPropValue)));
195 117 : break;
196 : case ESCHER_Prop_lineBackColor:
197 117 : m_aShapeProps.insert(std::pair<OString,OString>("lineBackColor", OString::number(it->nPropValue)));
198 117 : break;
199 : case ESCHER_Prop_lineJoinStyle:
200 117 : m_aShapeProps.insert(std::pair<OString,OString>("lineJoinStyle", OString::number(it->nPropValue)));
201 117 : break;
202 : case ESCHER_Prop_fshadowObscured:
203 117 : if (it->nPropValue)
204 117 : m_aShapeProps.insert(std::pair<OString,OString>("fshadowObscured", "1"));
205 117 : break;
206 : case ESCHER_Prop_geoLeft:
207 : case ESCHER_Prop_geoTop:
208 : {
209 4 : sal_uInt32 nLeft = 0, nTop = 0;
210 :
211 4 : if (nId == ESCHER_Prop_geoLeft)
212 : {
213 2 : nLeft = it->nPropValue;
214 2 : rProps.GetOpt(ESCHER_Prop_geoTop, nTop);
215 : }
216 : else
217 : {
218 2 : nTop = it->nPropValue;
219 2 : rProps.GetOpt(ESCHER_Prop_geoLeft, nLeft);
220 : }
221 :
222 : m_aShapeProps.insert(std::pair<OString,OString>("geoLeft",
223 4 : OString::number(sal_Int32(nLeft))));
224 : m_aShapeProps.insert(std::pair<OString,OString>("geoTop",
225 4 : OString::number(sal_Int32(nTop))));
226 : }
227 4 : break;
228 :
229 : case ESCHER_Prop_geoRight:
230 : case ESCHER_Prop_geoBottom:
231 : {
232 106 : sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
233 106 : rProps.GetOpt(ESCHER_Prop_geoLeft, nLeft);
234 106 : rProps.GetOpt(ESCHER_Prop_geoTop, nTop);
235 :
236 106 : if (nId == ESCHER_Prop_geoRight)
237 : {
238 53 : nRight = it->nPropValue;
239 53 : rProps.GetOpt(ESCHER_Prop_geoBottom, nBottom);
240 : }
241 : else
242 : {
243 53 : nBottom = it->nPropValue;
244 53 : rProps.GetOpt(ESCHER_Prop_geoRight, nRight);
245 : }
246 :
247 : m_aShapeProps.insert(std::pair<OString,OString>("geoRight",
248 106 : OString::number(sal_Int32(nRight) - sal_Int32(nLeft))));
249 : m_aShapeProps.insert(std::pair<OString,OString>("geoBottom",
250 106 : OString::number(sal_Int32(nBottom) - sal_Int32(nTop))));
251 : }
252 106 : break;
253 : case ESCHER_Prop_pVertices:
254 : case ESCHER_Prop_pSegmentInfo:
255 : {
256 : EscherPropSortStruct aVertices;
257 : EscherPropSortStruct aSegments;
258 :
259 318 : if (rProps.GetOpt(ESCHER_Prop_pVertices, aVertices) &&
260 212 : rProps.GetOpt(ESCHER_Prop_pSegmentInfo, aSegments) &&
261 316 : aVertices.nPropSize >= 6 && aSegments.nPropSize >= 6)
262 : {
263 104 : const sal_uInt8* pVerticesIt = aVertices.pBuf + 6;
264 104 : sal_Size nVerticesPos = 6;
265 104 : const sal_uInt8* pSegmentIt = aSegments.pBuf;
266 :
267 104 : OStringBuffer aSegmentInfo(512);
268 208 : OStringBuffer aVerticies(512);
269 :
270 104 : sal_uInt16 nPointSize = aVertices.pBuf[4] + (aVertices.pBuf[5] << 8);
271 :
272 : // number of segments
273 104 : sal_uInt16 nSegments = impl_GetUInt16(pSegmentIt);
274 104 : sal_Int32 nVertices = 0;
275 104 : aSegmentInfo.append("2;").append((sal_Int32)nSegments);
276 104 : pSegmentIt += 4;
277 :
278 3802 : for (; nSegments; --nSegments)
279 : {
280 3698 : sal_uInt16 nSeg = impl_GetUInt16(pSegmentIt);
281 :
282 : // The segment type is stored in the upper 3 bits
283 : // and segment count is stored in the lower 13
284 : // bits.
285 3698 : unsigned char nSegmentType = (nSeg & 0xE000) >> 13;
286 3698 : unsigned short nSegmentCount = nSeg & 0x03FF;
287 :
288 3698 : aSegmentInfo.append(';').append((sal_Int32)nSeg);
289 3698 : switch (nSegmentType)
290 : {
291 : case msopathLineTo:
292 32 : for (unsigned short i = 0; i < nSegmentCount; ++i)
293 : {
294 30 : sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
295 30 : sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
296 30 : aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
297 30 : nVertices ++;
298 : }
299 2 : break;
300 : case msopathMoveTo:
301 : {
302 140 : sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
303 140 : sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
304 140 : aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
305 140 : nVertices++;
306 140 : break;
307 : }
308 : case msopathCurveTo:
309 3240 : for (unsigned short j = 0; j < nSegmentCount; ++j)
310 : {
311 6480 : for (int i = 0; i < 3; i++)
312 : {
313 4860 : sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
314 4860 : sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
315 4860 : aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
316 4860 : nVertices ++;
317 : }
318 : }
319 1620 : break;
320 : case msopathEscape:
321 : {
322 : // If the segment type is msopathEscape, the lower 13 bits are
323 : // divided in a 5 bit escape code and 8 bit
324 : // vertex count (not segment count!)
325 1758 : unsigned char nVertexCount = nSegmentCount & 0x00FF;
326 1758 : nVerticesPos += nVertexCount;
327 1758 : break;
328 : }
329 : case msopathClientEscape:
330 : case msopathClose:
331 : case msopathEnd:
332 178 : break;
333 : default:
334 : SAL_WARN("oox", "Totally b0rked\n");
335 0 : break;
336 : }
337 : }
338 :
339 104 : if (!aVerticies.isEmpty())
340 : {
341 : // We know the number of vertices at the end only, so we have to prepend them here.
342 104 : m_aShapeProps.insert(std::pair<OString,OString>("pVerticies", "8;" + OString::number(nVertices) + aVerticies.makeStringAndClear()));
343 : }
344 104 : if (!aSegmentInfo.isEmpty())
345 208 : m_aShapeProps.insert(std::pair<OString,OString>("pSegmentInfo", aSegmentInfo.makeStringAndClear()));
346 : }
347 : else
348 : SAL_INFO("sw.rtf", OSL_THIS_FUNC << ": unhandled shape path, missing either pVertices or pSegmentInfo");
349 : }
350 106 : break;
351 : case ESCHER_Prop_shapePath:
352 : // noop, we use pSegmentInfo instead
353 51 : break;
354 : case ESCHER_Prop_fFillOK:
355 27 : if (!it->nPropValue)
356 0 : m_aShapeProps.insert(std::pair<OString,OString>("fFillOK", "0"));
357 27 : break;
358 : case ESCHER_Prop_dxTextLeft:
359 18 : m_aShapeProps.insert(std::pair<OString,OString>("dxTextLeft", OString::number(it->nPropValue)));
360 18 : break;
361 : case ESCHER_Prop_dyTextTop:
362 18 : m_aShapeProps.insert(std::pair<OString,OString>("dyTextTop", OString::number(it->nPropValue)));
363 18 : break;
364 : case ESCHER_Prop_dxTextRight:
365 18 : m_aShapeProps.insert(std::pair<OString,OString>("dxTextRight", OString::number(it->nPropValue)));
366 18 : break;
367 : case ESCHER_Prop_dyTextBottom:
368 18 : m_aShapeProps.insert(std::pair<OString,OString>("dyTextBottom", OString::number(it->nPropValue)));
369 18 : break;
370 : case ESCHER_Prop_FitTextToShape:
371 : // Size text to fit shape size: not supported by RTF
372 18 : break;
373 : case ESCHER_Prop_adjustValue:
374 2 : m_aShapeProps.insert(std::pair<OString,OString>("adjustValue", OString::number(it->nPropValue)));
375 2 : break;
376 : case ESCHER_Prop_txflTextFlow:
377 6 : m_aShapeProps.insert(std::pair<OString,OString>("txflTextFlow", OString::number(it->nPropValue)));
378 6 : break;
379 : case ESCHER_Prop_fillType:
380 75 : m_aShapeProps.insert(std::pair<OString,OString>("fillType", OString::number(it->nPropValue)));
381 75 : break;
382 : case ESCHER_Prop_fillOpacity:
383 16 : m_aShapeProps.insert(std::pair<OString,OString>("fillOpacity", OString::number(it->nPropValue)));
384 16 : break;
385 : case ESCHER_Prop_fillBlip:
386 : {
387 5 : OStringBuffer aBuf;
388 5 : aBuf.append('{').append(OOO_STRING_SVTOOLS_RTF_PICT).append(OOO_STRING_SVTOOLS_RTF_PNGBLIP).append(SAL_NEWLINE_STRING);
389 5 : int nHeaderSize = 25; // The first bytes are WW8-specific, we're only interested in the PNG
390 5 : aBuf.append(RtfAttributeOutput::WriteHex(it->pBuf + nHeaderSize, it->nPropSize - nHeaderSize));
391 5 : aBuf.append('}');
392 5 : m_aShapeProps.insert(std::pair<OString,OString>("fillBlip", aBuf.makeStringAndClear()));
393 : }
394 5 : break;
395 : default:
396 : SAL_INFO("sw.rtf", OSL_THIS_FUNC << ": unhandled property: " << nId << " (value: " << it->nPropValue << ")");
397 399 : break;
398 : }
399 117 : }
400 : }
401 :
402 0 : void RtfSdrExport::AddLineDimensions(const Rectangle& rRectangle)
403 : {
404 : // We get the position relative to (the current?) character
405 0 : m_aShapeProps.insert(std::pair<OString,OString>("posrelh", "3"));
406 :
407 0 : switch (m_nShapeFlags & 0xC0)
408 : {
409 : case 0x40:
410 0 : m_aShapeProps.insert(std::pair<OString,OString>("fFlipV", "1"));
411 0 : break;
412 : case 0x80:
413 0 : m_aShapeProps.insert(std::pair<OString,OString>("fFlipH", "1"));
414 0 : break;
415 : case 0xC0:
416 0 : m_aShapeProps.insert(std::pair<OString,OString>("fFlipV", "1"));
417 0 : m_aShapeProps.insert(std::pair<OString,OString>("fFlipH", "1"));
418 0 : break;
419 : }
420 :
421 : // the actual dimensions
422 0 : m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPLEFT).append(rRectangle.Left());
423 0 : m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPTOP).append(rRectangle.Top());
424 0 : m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPRIGHT).append(rRectangle.Right());
425 0 : m_aShapeStyle.append(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM).append(rRectangle.Bottom());
426 0 : }
427 :
428 117 : void RtfSdrExport::AddRectangleDimensions(OStringBuffer& rBuffer, const Rectangle& rRectangle)
429 : {
430 : // We get the position relative to (the current?) character
431 117 : m_aShapeProps.insert(std::pair<OString,OString>("posrelh", "3"));
432 :
433 117 : rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPLEFT).append(rRectangle.Left());
434 117 : rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPTOP).append(rRectangle.Top());
435 117 : rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPRIGHT).append(rRectangle.Right());
436 117 : rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM).append(rRectangle.Bottom());
437 117 : }
438 :
439 : extern const char* pShapeTypes[];
440 :
441 1741 : static void lcl_AppendSP(OStringBuffer& rRunText, const char cName[], const OString& rValue)
442 : {
443 1741 : rRunText.append('{').append(OOO_STRING_SVTOOLS_RTF_SP)
444 1741 : .append('{').append(OOO_STRING_SVTOOLS_RTF_SN " ").append(cName).append('}')
445 1741 : .append('{').append(OOO_STRING_SVTOOLS_RTF_SV " ").append(rValue).append('}')
446 1741 : .append('}');
447 1741 : }
448 :
449 8 : void RtfSdrExport::impl_writeGraphic()
450 : {
451 : // Get the Graphic object from the Sdr one.
452 8 : uno::Reference<drawing::XShape> xShape = GetXShapeForSdrObject(const_cast<SdrObject*>(m_pSdrObject));
453 10 : uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
454 10 : OUString sGraphicURL;
455 : try
456 : {
457 14 : xPropertySet->getPropertyValue("GraphicURL") >>= sGraphicURL;
458 : }
459 12 : catch (beans::UnknownPropertyException& rException)
460 : {
461 : // ATM groupshapes are not supported, just make sure we don't crash on them.
462 : SAL_WARN("sw.rtf", "failed. Message: " << rException.Message);
463 14 : return;
464 : }
465 4 : OString aURLBS(OUStringToOString(sGraphicURL, RTL_TEXTENCODING_UTF8));
466 4 : Graphic aGraphic = GraphicObject(aURLBS.copy(RTL_CONSTASCII_LENGTH("vnd.sun.star.GraphicObject:"))).GetTransformedGraphic();
467 :
468 : // Export it to a stream.
469 4 : SvMemoryStream aStream;
470 2 : GraphicConverter::Export(aStream, aGraphic, ConvertDataFormat::PNG);
471 2 : aStream.Seek(STREAM_SEEK_TO_END);
472 2 : sal_uInt32 nSize = aStream.Tell();
473 2 : const sal_uInt8* pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
474 :
475 2 : Size aMapped(aGraphic.GetPrefSize());
476 :
477 : // Add it to the properties.
478 4 : RtfStringBuffer aBuf;
479 2 : aBuf->append('{').append(OOO_STRING_SVTOOLS_RTF_PICT).append(OOO_STRING_SVTOOLS_RTF_PNGBLIP);
480 2 : aBuf->append(OOO_STRING_SVTOOLS_RTF_PICW).append(sal_Int32(aMapped.Width()));
481 2 : aBuf->append(OOO_STRING_SVTOOLS_RTF_PICH).append(sal_Int32(aMapped.Height())).append(SAL_NEWLINE_STRING);
482 2 : aBuf->append(RtfAttributeOutput::WriteHex(pGraphicAry, nSize));
483 2 : aBuf->append('}');
484 4 : m_aShapeProps.insert(std::pair<OString,OString>("pib", aBuf.makeStringAndClear()));
485 : }
486 :
487 117 : sal_Int32 RtfSdrExport::StartShape()
488 : {
489 117 : if (m_nShapeType == ESCHER_ShpInst_Nil)
490 0 : return -1;
491 :
492 117 : m_aShapeProps.insert(std::pair<OString,OString>("shapeType", OString::number(m_nShapeType)));
493 117 : if (ESCHER_ShpInst_PictureFrame == m_nShapeType)
494 8 : impl_writeGraphic();
495 :
496 117 : m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHP);
497 117 : m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_IGNORE).append(OOO_STRING_SVTOOLS_RTF_SHPINST);
498 :
499 117 : m_rAttrOutput.RunText().append(m_aShapeStyle.makeStringAndClear());
500 : // Ignore \shpbxpage, \shpbxmargin, and \shpbxcolumn, in favor of the posrelh property.
501 117 : m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_SHPBXIGNORE);
502 : // Ignore \shpbypage, \shpbymargin, and \shpbycolumn, in favor of the posrelh property.
503 117 : m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_SHPBYIGNORE);
504 :
505 1624 : for (std::map<OString,OString>::reverse_iterator i = m_aShapeProps.rbegin(); i != m_aShapeProps.rend(); ++i)
506 1507 : lcl_AppendSP(m_rAttrOutput.RunText(), (*i).first.getStr(), (*i).second);
507 :
508 117 : lcl_AppendSP(m_rAttrOutput.RunText(), "wzDescription", msfilter::rtfutil::OutString(m_pSdrObject->GetDescription(), m_rExport.eCurrentEncoding));
509 117 : lcl_AppendSP(m_rAttrOutput.RunText(), "wzName", msfilter::rtfutil::OutString(m_pSdrObject->GetTitle(), m_rExport.eCurrentEncoding));
510 :
511 : // now check if we have some text
512 117 : const SwFrameFormat* pShape = FindFrameFormat(m_pSdrObject);
513 117 : if (pShape)
514 : {
515 117 : if (SwFrameFormat* pTextBox = SwTextBoxHelper::findTextBox(pShape))
516 : {
517 1 : sw::Frame* pFrame = 0;
518 2 : for (sw::FrameIter it = m_rExport.m_aFrames.begin(); it != m_rExport.m_aFrames.end(); ++it)
519 : {
520 2 : if (pTextBox == &it->GetFrameFormat())
521 : {
522 1 : pFrame = &(*it);
523 1 : break;
524 : }
525 : }
526 :
527 1 : if (pFrame)
528 1 : m_rAttrOutput.writeTextFrame(*pFrame, /*bTextBox=*/true);
529 1 : return m_nShapeType;
530 : }
531 : }
532 :
533 116 : const SdrTextObj* pTextObj = dynamic_cast<const SdrTextObj*>(m_pSdrObject);
534 116 : if (pTextObj)
535 : {
536 5 : const OutlinerParaObject* pParaObj = 0;
537 5 : std::unique_ptr<const OutlinerParaObject> pOwnedParaObj;
538 :
539 : /*
540 : #i13885#
541 : When the object is actively being edited, that text is not set into
542 : the objects normal text object, but lives in a separate object.
543 : */
544 5 : if (pTextObj->IsTextEditActive())
545 : {
546 0 : pOwnedParaObj.reset(pTextObj->GetEditOutlinerParaObject());
547 0 : pParaObj = pOwnedParaObj.get();
548 : }
549 : else
550 : {
551 5 : pParaObj = pTextObj->GetOutlinerParaObject();
552 : }
553 :
554 5 : if (pParaObj)
555 : {
556 : // this is reached only in case some text is attached to the shape
557 2 : WriteOutliner(*pParaObj);
558 5 : }
559 : }
560 :
561 116 : return m_nShapeType;
562 : }
563 :
564 2 : void RtfSdrExport::WriteOutliner(const OutlinerParaObject& rParaObj)
565 : {
566 : SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start");
567 :
568 2 : const EditTextObject& rEditObj = rParaObj.GetTextObject();
569 2 : MSWord_SdrAttrIter aAttrIter(m_rExport, rEditObj, TXT_HFTXTBOX);
570 :
571 2 : sal_Int32 nPara = rEditObj.GetParagraphCount();
572 :
573 2 : m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHPTXT).append(' ');
574 4 : for (sal_Int32 n = 0; n < nPara; ++n)
575 : {
576 2 : if (n)
577 0 : aAttrIter.NextPara(n);
578 :
579 2 : rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet();
580 :
581 2 : OUString aStr(rEditObj.GetText(n));
582 2 : sal_Int32 nAktPos = 0;
583 2 : const sal_Int32 nEnd = aStr.getLength();
584 :
585 2 : aAttrIter.OutParaAttr(false);
586 2 : m_rAttrOutput.RunText().append(m_rAttrOutput.Styles().makeStringAndClear());
587 :
588 2 : do
589 : {
590 2 : const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
591 2 : rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
592 :
593 2 : aAttrIter.OutAttr(nAktPos);
594 2 : m_rAttrOutput.RunText().append('{').append(m_rAttrOutput.Styles().makeStringAndClear()).append(SAL_NEWLINE_STRING);
595 2 : bool bTextAtr = aAttrIter.IsTextAttr(nAktPos);
596 2 : if (!bTextAtr)
597 : {
598 2 : OUString aOut(aStr.copy(nAktPos, nNextAttr - nAktPos));
599 2 : m_rAttrOutput.RunText().append(msfilter::rtfutil::OutString(aOut, eChrSet));
600 : }
601 :
602 2 : m_rAttrOutput.RunText().append('}');
603 :
604 2 : nAktPos = nNextAttr;
605 2 : eChrSet = eNextChrSet;
606 2 : aAttrIter.NextPos();
607 : }
608 2 : while (nAktPos < nEnd);
609 2 : }
610 2 : m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_PAR).append('}');
611 :
612 2 : SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end");
613 2 : }
614 :
615 117 : void RtfSdrExport::EndShape(sal_Int32 nShapeElement)
616 : {
617 117 : if (nShapeElement >= 0)
618 : {
619 : // end of the shape
620 117 : m_rAttrOutput.RunText().append('}').append('}');
621 : }
622 117 : }
623 :
624 11 : sal_uInt32 RtfSdrExport::AddSdrObject(const SdrObject& rObj)
625 : {
626 11 : m_pSdrObject = &rObj;
627 11 : return EscherEx::AddSdrObject(rObj);
628 : }
629 :
630 13 : bool RtfSdrExport::isTextBox(const SwFrameFormat& rFrameFormat)
631 : {
632 13 : return m_aTextBoxes.find(&rFrameFormat) != m_aTextBoxes.end();
633 60 : }
634 :
635 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|