xref: /trunk/main/sw/source/filter/ww8/rtfsdrexport.cxx (revision c2eaa082)
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 separate 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_uInt32 nPara = rEditObj.GetParagraphCount();
519 
520     m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHPTXT).append(' ');
521     for (sal_uInt32 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