1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "rtfsdrexport.hxx"
25 #include "rtfexport.hxx"
26 #include "writerhelper.hxx"
27
28 #include <com/sun/star/i18n/ScriptType.hdl>
29 #include <osl/diagnose.h>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/ustring.hxx>
32 #include <svl/itemiter.hxx>
33 #include <svtools/rtfkeywd.hxx>
34 #include <editeng/editdata.hxx>
35 #include <editeng/editobj.hxx>
36 #include <editeng/flditem.hxx>
37 #include <editeng/fontitem.hxx>
38 #include <svx/svdotext.hxx>
39 #include <tools/stream.hxx>
40 #include <breakit.hxx>
41
42 using rtl::OString;
43 using rtl::OStringBuffer;
44 using rtl::OUString;
45 using rtl::OUStringBuffer;
46 using namespace sw::util;
47
48 /// Implementation of an empty stream that silently succeeds, but does nothing.
49 ///
50 /// In fact, this is a hack. The right solution is to abstract EscherEx to be
51 /// able to work without SvStream; but at the moment it is better to live with
52 /// this I guess.
53 class SvNullStream : public SvStream
54 {
55 protected:
GetData(void * pData,sal_Size nSize)56 virtual sal_Size GetData( void* pData, sal_Size nSize ) { memset( pData, 0, nSize ); return nSize; }
PutData(const void *,sal_Size nSize)57 virtual sal_Size PutData( const void*, sal_Size nSize ) { return nSize; }
SeekPos(sal_Size nPos)58 virtual sal_Size SeekPos( sal_Size nPos ) { return nPos; }
SetSize(sal_Size)59 virtual void SetSize( sal_Size ) {}
FlushData()60 virtual void FlushData() {}
61
62 public:
SvNullStream()63 SvNullStream() : SvStream() {}
~SvNullStream()64 virtual ~SvNullStream() {}
65 };
66
RtfSdrExport(RtfExport & rExport)67 RtfSdrExport::RtfSdrExport( RtfExport &rExport )
68 : EscherEx( EscherExGlobalRef( new EscherExGlobal ), *( new SvNullStream )),
69 m_rExport( rExport ),
70 m_rAttrOutput( (RtfAttributeOutput&)m_rExport.AttrOutput() ),
71 m_nShapeType( ESCHER_ShpInst_Nil ),
72 m_pShapeStyle( new OStringBuffer( 200 ) ),
73 m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] )
74 {
75 mnGroupLevel = 1;
76 memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) );
77 }
78
~RtfSdrExport()79 RtfSdrExport::~RtfSdrExport()
80 {
81 delete mpOutStrm, mpOutStrm = NULL;
82 delete m_pShapeStyle, m_pShapeStyle = NULL;
83 delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL;
84 }
85
OpenContainer(sal_uInt16 nEscherContainer,int nRecInstance)86 void RtfSdrExport::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
87 {
88 OSL_TRACE("%s", OSL_THIS_FUNC);
89
90 EscherEx::OpenContainer( nEscherContainer, nRecInstance );
91
92 if ( nEscherContainer == ESCHER_SpContainer )
93 {
94 m_nShapeType = ESCHER_ShpInst_Nil;
95 if ( m_pShapeStyle->getLength() )
96 m_pShapeStyle->makeStringAndClear();
97 m_pShapeStyle->ensureCapacity( 200 );
98 m_aShapeProps.clear();
99 }
100 }
101
CloseContainer()102 void RtfSdrExport::CloseContainer()
103 {
104 OSL_TRACE("%s", OSL_THIS_FUNC);
105
106 if ( mRecTypes.back() == ESCHER_SpContainer )
107 {
108 // write the shape now when we have all the info
109 sal_Int32 nShapeElement = StartShape();
110 EndShape( nShapeElement );
111
112 // cleanup
113 m_nShapeType = ESCHER_ShpInst_Nil;
114 }
115
116 EscherEx::CloseContainer();
117 }
118
EnterGroup(const String &,const Rectangle *)119 sal_uInt32 RtfSdrExport::EnterGroup( const String& /*rShapeName*/, const Rectangle* /*pRect*/ )
120 {
121 OSL_TRACE("%s", OSL_THIS_FUNC);
122
123 return GenerateShapeId();
124 }
125
LeaveGroup()126 void RtfSdrExport::LeaveGroup()
127 {
128 OSL_TRACE("%s", OSL_THIS_FUNC);
129
130 /* noop */
131 }
132
AddShape(sal_uInt32 nShapeType,sal_uInt32 nShapeFlags,sal_uInt32)133 void RtfSdrExport::AddShape( sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uInt32 /*nShapeId*/ )
134 {
135 OSL_TRACE("%s", OSL_THIS_FUNC);
136
137 m_nShapeType = nShapeType;
138 m_nShapeFlags = nShapeFlags;
139 }
140
impl_GetUInt16(const sal_uInt8 * & pVal)141 inline sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal )
142 {
143 sal_uInt16 nRet = *pVal++;
144 nRet += ( *pVal++ ) << 8;
145 return nRet;
146 }
147
impl_GetPointComponent(const sal_uInt8 * & pVal,sal_uInt16 nPointSize)148 inline sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize )
149 {
150 sal_Int32 nRet = 0;
151 if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) )
152 {
153 sal_uInt16 nUnsigned = *pVal++;
154 nUnsigned += ( *pVal++ ) << 8;
155
156 nRet = sal_Int16( nUnsigned );
157 }
158 else if ( nPointSize == 8 )
159 {
160 sal_uInt32 nUnsigned = *pVal++;
161 nUnsigned += ( *pVal++ ) << 8;
162 nUnsigned += ( *pVal++ ) << 16;
163 nUnsigned += ( *pVal++ ) << 24;
164
165 nRet = nUnsigned;
166 }
167
168 return nRet;
169 }
170
Commit(EscherPropertyContainer & rProps,const Rectangle & rRect)171 void RtfSdrExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect )
172 {
173 OSL_TRACE("%s", OSL_THIS_FUNC);
174
175 if ( m_nShapeType == ESCHER_ShpInst_Nil )
176 return;
177
178 if ( m_nShapeType == ESCHER_ShpInst_Line )
179 AddLineDimensions( rRect );
180 else
181 AddRectangleDimensions( *m_pShapeStyle, rRect );
182
183 // properties
184 const EscherProperties &rOpts = rProps.GetOpts();
185 for ( EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it )
186 {
187 sal_uInt16 nId = ( it->nPropId & 0x0FFF );
188
189 switch ( nId )
190 {
191 case ESCHER_Prop_WrapText:
192 {
193 int nWrapType = 0;
194 switch ( it->nPropValue )
195 {
196 case ESCHER_WrapSquare: nWrapType = 2; break;
197 case ESCHER_WrapByPoints: nWrapType = 4; break;
198 case ESCHER_WrapNone: nWrapType = 3; break;
199 case ESCHER_WrapTopBottom: nWrapType = 1; break;
200 case ESCHER_WrapThrough: nWrapType = 5; break;
201 }
202 if ( nWrapType )
203 m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPWR).append((sal_Int32)nWrapType);
204 }
205 break;
206 case ESCHER_Prop_fillColor:
207 m_aShapeProps.insert(std::pair<OString,OString>(OString("fillColor"), OString::valueOf(sal_Int32(it->nPropValue))));
208 break;
209 case ESCHER_Prop_fillBackColor:
210 m_aShapeProps.insert(std::pair<OString,OString>(OString("fillBackColor"), OString::valueOf(sal_Int32(it->nPropValue))));
211 break;
212 case ESCHER_Prop_AnchorText:
213 m_aShapeProps.insert(std::pair<OString,OString>(OString("anchorText"), OString::valueOf(sal_Int32(it->nPropValue))));
214 break;
215 case ESCHER_Prop_fNoFillHitTest:
216 if (it->nPropValue)
217 m_aShapeProps.insert(std::pair<OString,OString>(OString("fNoFillHitTest"), OString::valueOf(sal_Int32(1))));
218 break;
219 case ESCHER_Prop_fNoLineDrawDash:
220 // for some reason the value is set to 0x90000 if lines are switched off
221 if( it->nPropValue == 0x90000 )
222 m_aShapeProps.insert(std::pair<OString,OString>(OString("fLine"), OString::valueOf(sal_Int32(0))));
223 break;
224 case ESCHER_Prop_lineColor:
225 m_aShapeProps.insert(std::pair<OString,OString>(OString("lineColor"), OString::valueOf(sal_Int32(it->nPropValue))));
226 break;
227 case ESCHER_Prop_lineBackColor:
228 m_aShapeProps.insert(std::pair<OString,OString>(OString("lineBackColor"), OString::valueOf(sal_Int32(it->nPropValue))));
229 break;
230 case ESCHER_Prop_lineJoinStyle:
231 m_aShapeProps.insert(std::pair<OString,OString>(OString("lineJoinStyle"), OString::valueOf(sal_Int32(it->nPropValue))));
232 break;
233 case ESCHER_Prop_fshadowObscured:
234 if (it->nPropValue)
235 m_aShapeProps.insert(std::pair<OString,OString>(OString("fshadowObscured"), OString::valueOf(sal_Int32(1))));
236 break;
237 case ESCHER_Prop_geoLeft:
238 case ESCHER_Prop_geoTop:
239 {
240 sal_uInt32 nLeft = 0, nTop = 0;
241
242 if ( nId == ESCHER_Prop_geoLeft )
243 {
244 nLeft = it->nPropValue;
245 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
246 }
247 else
248 {
249 nTop = it->nPropValue;
250 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
251 }
252
253 m_aShapeProps.insert(std::pair<OString,OString>(OString("geoLeft"),
254 OString::valueOf(sal_Int32(sal_Int32( nLeft )))));
255 m_aShapeProps.insert(std::pair<OString,OString>(OString("geoTop"),
256 OString::valueOf(sal_Int32(sal_Int32( nTop )))));
257 }
258 break;
259
260 case ESCHER_Prop_geoRight:
261 case ESCHER_Prop_geoBottom:
262 {
263 sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0;
264 rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft );
265 rProps.GetOpt( ESCHER_Prop_geoTop, nTop );
266
267 if ( nId == ESCHER_Prop_geoRight )
268 {
269 nRight = it->nPropValue;
270 rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom );
271 }
272 else
273 {
274 nBottom = it->nPropValue;
275 rProps.GetOpt( ESCHER_Prop_geoRight, nRight );
276 }
277
278 m_aShapeProps.insert(std::pair<OString,OString>(OString("geoRight"),
279 OString::valueOf(sal_Int32(sal_Int32( nRight ) - sal_Int32( nLeft )))));
280 m_aShapeProps.insert(std::pair<OString,OString>(OString("geoBottom"),
281 OString::valueOf(sal_Int32(sal_Int32( nBottom ) - sal_Int32( nTop )))));
282 }
283 break;
284 case ESCHER_Prop_pVertices:
285 case ESCHER_Prop_pSegmentInfo:
286 {
287 EscherPropSortStruct aVertices;
288 EscherPropSortStruct aSegments;
289
290 if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) &&
291 rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) )
292 {
293 const sal_uInt8 *pVerticesIt = aVertices.pBuf + 6;
294 const sal_uInt8 *pSegmentIt = aSegments.pBuf;
295
296 OStringBuffer aSegmentInfo( 512 );
297 OStringBuffer aVerticies( 512 );
298
299 sal_uInt16 nPointSize = aVertices.pBuf[4] + ( aVertices.pBuf[5] << 8 );
300
301 // number of segments
302 sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt );
303 sal_Int32 nVertices = 0;
304 aSegmentInfo.append("2;").append((sal_Int32)nSegments);
305 pSegmentIt += 4;
306
307 for ( ; nSegments; --nSegments )
308 {
309 sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
310 aSegmentInfo.append(';').append((sal_Int32)nSeg);
311 switch ( nSeg )
312 {
313 case 0x0001: // lineto
314 case 0x4000: // moveto
315 {
316 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
317 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
318 aVerticies.append( ";(" ).append( nX ).append( "," ).append( nY ).append( ")" );
319 nVertices ++;
320 }
321 break;
322 case 0x2001: // curveto
323 {
324 for (int i = 0; i < 3; i++)
325 {
326 sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
327 sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
328 aVerticies.append( ";(" ).append( nX ).append( "," ).append( nY ).append( ")" );
329 nVertices ++;
330 }
331 }
332 break;
333 case 0xb300:
334 case 0xac00:
335 case 0xaa00: // nofill
336 case 0xab00: // nostroke
337 case 0x6001: // close
338 case 0x8000: // end
339 break;
340 default:
341 OSL_TRACE("%s: unhandled segment '%x' in the path", OSL_THIS_FUNC, nSeg);
342 break;
343 }
344 }
345
346 if (aVerticies.getLength() )
347 {
348 // We know the number of vertices at the end only, so we have to prepend them here.
349 OStringBuffer aBuf;
350 aBuf.append("8;").append((sal_Int32)nVertices);
351 aBuf.append(aVerticies.makeStringAndClear());
352 m_aShapeProps.insert(std::pair<OString,OString>(OString("pVerticies"), aBuf.makeStringAndClear()));
353 }
354 if ( aSegmentInfo.getLength() )
355 m_aShapeProps.insert(std::pair<OString,OString>(OString("pSegmentInfo"), aSegmentInfo.makeStringAndClear()));
356 }
357 else
358 OSL_TRACE("%s: unhandled shape path, missing either pVertices or pSegmentInfo", OSL_THIS_FUNC);
359 }
360 break;
361 case ESCHER_Prop_shapePath:
362 // noop, we use pSegmentInfo instead
363 break;
364 case ESCHER_Prop_fFillOK:
365 if (!it->nPropValue)
366 m_aShapeProps.insert(std::pair<OString,OString>(OString("fFillOK"), OString::valueOf(sal_Int32(0))));
367 break;
368 case ESCHER_Prop_dxTextLeft:
369 m_aShapeProps.insert(std::pair<OString,OString>(OString("dxTextLeft"), OString::valueOf(sal_Int32(it->nPropValue))));
370 break;
371 case ESCHER_Prop_dyTextTop:
372 m_aShapeProps.insert(std::pair<OString,OString>(OString("dyTextTop"), OString::valueOf(sal_Int32(it->nPropValue))));
373 break;
374 case ESCHER_Prop_dxTextRight:
375 m_aShapeProps.insert(std::pair<OString,OString>(OString("dxTextRight"), OString::valueOf(sal_Int32(it->nPropValue))));
376 break;
377 case ESCHER_Prop_dyTextBottom:
378 m_aShapeProps.insert(std::pair<OString,OString>(OString("dyTextBottom"), OString::valueOf(sal_Int32(it->nPropValue))));
379 break;
380 case ESCHER_Prop_FitTextToShape:
381 // Size text to fit shape size: not supported by RTF
382 break;
383 case ESCHER_Prop_adjustValue:
384 m_aShapeProps.insert(std::pair<OString,OString>(OString("adjustValue"), OString::valueOf(sal_Int32(it->nPropValue))));
385 break;
386 case ESCHER_Prop_txflTextFlow:
387 m_aShapeProps.insert(std::pair<OString,OString>(OString("txflTextFlow"), OString::valueOf(sal_Int32(it->nPropValue))));
388 break;
389 default:
390 OSL_TRACE("%s: unhandled property: %d (value: %d)", OSL_THIS_FUNC, nId, it->nPropValue);
391 break;
392 }
393 }
394 }
395
AddLineDimensions(const Rectangle & rRectangle)396 void RtfSdrExport::AddLineDimensions( const Rectangle& rRectangle )
397 {
398 OSL_TRACE("%s", OSL_THIS_FUNC);
399
400 // We get the position relative to (the current?) character
401 m_aShapeProps.insert(std::pair<OString,OString>(OString("posrelh"), OString::valueOf(sal_Int32(3))));
402
403 switch ( m_nShapeFlags & 0xC0 )
404 {
405 case 0x40:
406 m_aShapeProps.insert(std::pair<OString,OString>(OString("fFlipV"), OString::valueOf(sal_Int32(1))));
407 break;
408 case 0x80:
409 m_aShapeProps.insert(std::pair<OString,OString>(OString("fFlipH"), OString::valueOf(sal_Int32(1))));
410 break;
411 case 0xC0:
412 m_aShapeProps.insert(std::pair<OString,OString>(OString("fFlipV"), OString::valueOf(sal_Int32(1))));
413 m_aShapeProps.insert(std::pair<OString,OString>(OString("fFlipH"), OString::valueOf(sal_Int32(1))));
414 break;
415 }
416
417 // the actual dimensions
418 m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPLEFT).append(rRectangle.Left());
419 m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPTOP).append(rRectangle.Top());
420 m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPRIGHT).append(rRectangle.Right());
421 m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM).append(rRectangle.Bottom());
422 }
423
AddRectangleDimensions(rtl::OStringBuffer & rBuffer,const Rectangle & rRectangle)424 void RtfSdrExport::AddRectangleDimensions( rtl::OStringBuffer& rBuffer, const Rectangle& rRectangle )
425 {
426 OSL_TRACE("%s", OSL_THIS_FUNC);
427
428 // We get the position relative to (the current?) character
429 m_aShapeProps.insert(std::pair<OString,OString>(OString("posrelh"), OString::valueOf(sal_Int32(3))));
430
431 rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPLEFT).append(rRectangle.Left());
432 rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPTOP).append(rRectangle.Top());
433 rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPRIGHT).append(rRectangle.Right());
434 rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM).append(rRectangle.Bottom());
435 }
436
AddShapeAttribute(sal_Int32,const rtl::OString &)437 void RtfSdrExport::AddShapeAttribute( sal_Int32 /*nAttribute*/, const rtl::OString& /*rValue*/ )
438 {
439 OSL_TRACE("%s", OSL_THIS_FUNC);
440
441 /* noop */
442 }
443
444 extern const char* pShapeTypes[];
445
lcl_AppendSP(::rtl::OStringBuffer & rRunText,const char cName[],const::rtl::OString & rValue)446 void lcl_AppendSP( ::rtl::OStringBuffer& rRunText, const char cName[], const ::rtl::OString& rValue)
447 {
448 rRunText.append('{').append(OOO_STRING_SVTOOLS_RTF_SP)
449 .append('{').append(OOO_STRING_SVTOOLS_RTF_SN " ").append(cName).append('}')
450 .append('{').append(OOO_STRING_SVTOOLS_RTF_SV " ").append(rValue).append('}')
451 .append('}');
452 }
StartShape()453 sal_Int32 RtfSdrExport::StartShape()
454 {
455 OSL_TRACE("%s", OSL_THIS_FUNC);
456
457 if ( m_nShapeType == ESCHER_ShpInst_Nil )
458 return -1;
459
460 m_aShapeProps.insert(std::pair<OString,OString>(OString("shapeType"), OString::valueOf(sal_Int32(m_nShapeType))));
461
462 m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHP);
463 m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_IGNORE).append(OOO_STRING_SVTOOLS_RTF_SHPINST);
464
465 m_rAttrOutput.RunText().append(m_pShapeStyle->makeStringAndClear());
466 // Ignore \shpbxpage, \shpbxmargin, and \shpbxcolumn, in favor of the posrelh property.
467 m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_SHPBXIGNORE);
468 // Ignore \shpbypage, \shpbymargin, and \shpbycolumn, in favor of the posrelh property.
469 m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_SHPBYIGNORE);
470
471 for(std::map<OString,OString>::reverse_iterator i = m_aShapeProps.rbegin(); i != m_aShapeProps.rend(); i++)
472 lcl_AppendSP(m_rAttrOutput.RunText(), (*i).first.getStr(), (*i).second );
473
474 lcl_AppendSP(m_rAttrOutput.RunText(), "wzDescription", RtfExport::OutString( m_pSdrObject->GetDescription(), m_rExport.eCurrentEncoding));
475 lcl_AppendSP(m_rAttrOutput.RunText(), "wzName", RtfExport::OutString( m_pSdrObject->GetTitle(), m_rExport.eCurrentEncoding));
476
477 // now check if we have some text
478 const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, m_pSdrObject);
479 if (pTxtObj)
480 {
481 const OutlinerParaObject* pParaObj = 0;
482 bool bOwnParaObj = false;
483
484 /*
485 #i13885#
486 When the object is actively being edited, that text is not set into
487 the objects normal text object, but lives in a seperate object.
488 */
489 if (pTxtObj->IsTextEditActive())
490 {
491 pParaObj = pTxtObj->GetEditOutlinerParaObject();
492 bOwnParaObj = true;
493 }
494 else
495 {
496 pParaObj = pTxtObj->GetOutlinerParaObject();
497 }
498
499 if( pParaObj )
500 {
501 // this is reached only in case some text is attached to the shape
502 WriteOutliner(*pParaObj);
503 if( bOwnParaObj )
504 delete pParaObj;
505 }
506 }
507
508 return m_nShapeType;
509 }
510
WriteOutliner(const OutlinerParaObject & rParaObj)511 void RtfSdrExport::WriteOutliner(const OutlinerParaObject& rParaObj)
512 {
513 OSL_TRACE("%s start", OSL_THIS_FUNC);
514
515 const EditTextObject& rEditObj = rParaObj.GetTextObject();
516 MSWord_SdrAttrIter aAttrIter( m_rExport, rEditObj, TXT_HFTXTBOX );
517
518 sal_uInt16 nPara = rEditObj.GetParagraphCount();
519
520 m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHPTXT).append(' ');
521 for (sal_uInt16 n = 0; n < nPara; ++n)
522 {
523 if( n )
524 aAttrIter.NextPara( n );
525
526 rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet();
527
528 String aStr( rEditObj.GetText( n ));
529 xub_StrLen nAktPos = 0;
530 xub_StrLen nEnd = aStr.Len();
531
532 aAttrIter.OutParaAttr(false);
533 m_rAttrOutput.RunText().append(m_rAttrOutput.Styles().makeStringAndClear());
534
535 do {
536 xub_StrLen nNextAttr = aAttrIter.WhereNext();
537 rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
538
539 if( nNextAttr > nEnd )
540 nNextAttr = nEnd;
541
542 aAttrIter.OutAttr( nAktPos );
543 m_rAttrOutput.RunText().append('{').append(m_rAttrOutput.Styles().makeStringAndClear()).append(m_rExport.sNewLine);
544 bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos );
545 if( !bTxtAtr )
546 {
547 String aOut( aStr.Copy( nAktPos, nNextAttr - nAktPos ) );
548 m_rAttrOutput.RunText().append( m_rExport.OutString( aOut, eChrSet ) );
549 }
550
551 m_rAttrOutput.RunText().append('}');
552
553 nAktPos = nNextAttr;
554 eChrSet = eNextChrSet;
555 aAttrIter.NextPos();
556 }
557 while( nAktPos < nEnd );
558 }
559 m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_PAR).append('}');
560
561 OSL_TRACE("%s end", OSL_THIS_FUNC);
562 }
563
EndShape(sal_Int32 nShapeElement)564 void RtfSdrExport::EndShape( sal_Int32 nShapeElement )
565 {
566 OSL_TRACE("%s", OSL_THIS_FUNC);
567
568 if ( nShapeElement >= 0 )
569 {
570 // end of the shape
571 m_rAttrOutput.RunText().append('}').append('}');
572 }
573 }
574
AddSdrObject(const SdrObject & rObj)575 sal_uInt32 RtfSdrExport::AddSdrObject( const SdrObject& rObj )
576 {
577 m_pSdrObject = &rObj;
578 return EscherEx::AddSdrObject(rObj);
579 }
580
581 /* vi:set shiftwidth=4 expandtab: */
582