xref: /aoo41x/main/sw/source/filter/ww8/wrtw8nds.cxx (revision 6d87d7f9)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
31 
32 #include <vector>
33 #include <list>
34 #include <utility>
35 #include <algorithm>
36 #include <functional>
37 #include <iostream>
38 #if OSL_DEBUG_LEVEL > 0
39 #   include <cstdio>
40 #endif
41 
42 #include <hintids.hxx>
43 #include <tools/urlobj.hxx>
44 #include <editeng/boxitem.hxx>
45 #include <editeng/cmapitem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <editeng/svxfont.hxx>
48 #include <editeng/lrspitem.hxx>
49 #include <editeng/brshitem.hxx>
50 #include <editeng/fontitem.hxx>
51 #include <editeng/keepitem.hxx>
52 #include <editeng/fhgtitem.hxx>
53 #include <editeng/ulspitem.hxx>
54 #include <editeng/brkitem.hxx>
55 #include <editeng/frmdiritem.hxx>
56 #include <editeng/tstpitem.hxx>
57 #include "svl/urihelper.hxx"
58 #include <svl/whiter.hxx>
59 #include <fmtpdsc.hxx>
60 #include <fmtfsize.hxx>
61 #include <fmtornt.hxx>
62 #include <fmtlsplt.hxx>
63 #include <fmtflcnt.hxx>
64 #include <fmtanchr.hxx>
65 #include <fmtcntnt.hxx>
66 #include <frmatr.hxx>
67 #include <paratr.hxx>
68 #include <txatbase.hxx>
69 #include <fmtinfmt.hxx>
70 #include <fmtrfmrk.hxx>
71 #include <fchrfmt.hxx>
72 #include <fmtautofmt.hxx>
73 #include <charfmt.hxx>
74 #include <tox.hxx>
75 #include <ndtxt.hxx>
76 #include <pam.hxx>
77 #include <doc.hxx>
78 #include <docary.hxx>
79 #include <swtable.hxx>
80 #include <swtblfmt.hxx>
81 #include <section.hxx>
82 #include <pagedesc.hxx>
83 #include <swrect.hxx>
84 #include <reffld.hxx>
85 #include <redline.hxx>
86 #include <wrtswtbl.hxx>
87 #include <htmltbl.hxx>
88 #include <txttxmrk.hxx>
89 #include <fmtline.hxx>
90 #include <fmtruby.hxx>
91 #include <breakit.hxx>
92 #include <txtatr.hxx>
93 #include <fmtsrnd.hxx>
94 #include <fmtrowsplt.hxx>
95 #include <com/sun/star/i18n/ScriptType.hdl>
96 #include <com/sun/star/i18n/WordType.hpp>
97 
98 #include <writerfilter/doctok/sprmids.hxx>
99 
100 #include "writerhelper.hxx"
101 #include "writerwordglue.hxx"
102 #include <numrule.hxx>
103 #include "wrtww8.hxx"
104 #include "ww8par.hxx"
105 #include <IMark.hxx>
106 #include "ww8attributeoutput.hxx"
107 
108 #include <ndgrf.hxx>
109 #include <ndole.hxx>
110 
111 #include <cstdio>
112 
113 using namespace ::com::sun::star;
114 using namespace ::com::sun::star::i18n;
115 using namespace sw::util;
116 using namespace sw::types;
117 using namespace sw::mark;
118 using namespace nsFieldFlags;
119 
120 
121 static String lcl_getFieldCode( const IFieldmark* pFieldmark ) {
122     ASSERT(pFieldmark!=NULL, "where is my fieldmark???");
123     if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) ) {
124         return String::CreateFromAscii(" FORMTEXT ");
125     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) {
126         return String::CreateFromAscii(" FORMDROPDOWN ");
127     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) {
128         return String::CreateFromAscii(" FORMCHECKBOX ");
129     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_TOC ) ) {
130         return String::CreateFromAscii(" TOC ");
131     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) ) {
132         return String::CreateFromAscii(" HYPERLINK ");
133     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_PAGEREF ) ) {
134         return String::CreateFromAscii(" PAGEREF ");
135     } else {
136         return pFieldmark->GetFieldname();
137     }
138 }
139 
140 ww::eField lcl_getFieldId( const IFieldmark* pFieldmark ) {
141     ASSERT(pFieldmark!=NULL, "where is my fieldmark???");
142     if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) ) {
143         return ww::eFORMTEXT;
144     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) {
145         return ww::eFORMDROPDOWN;
146     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) {
147         return ww::eFORMCHECKBOX;
148     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_TOC ) ) {
149         return ww::eTOC;
150     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) ) {
151         return ww::eHYPERLINK;
152     } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_PAGEREF ) ) {
153         return ww::ePAGEREF;
154     } else {
155         return ww::eUNKNOWN;
156     }
157 }
158 
159 /*  */
160 
161 MSWordAttrIter::MSWordAttrIter( MSWordExportBase& rExport )
162     : pOld( rExport.pChpIter ), m_rExport( rExport )
163 {
164     m_rExport.pChpIter = this;
165 }
166 
167 MSWordAttrIter::~MSWordAttrIter()
168 {
169     m_rExport.pChpIter = pOld;
170 }
171 
172 // Die Klasse SwAttrIter ist eine Hilfe zum Aufbauen der Fkp.chpx.
173 // Dabei werden nur Zeichen-Attribute beachtet; Absatz-Attribute brauchen
174 // diese Behandlung nicht.
175 // Die Absatz- und Textattribute des Writers kommen rein, und es wird
176 // mit Where() die naechste Position geliefert, an der sich die Attribute
177 // aendern. IsTxtAtr() sagt, ob sich an der mit Where() gelieferten Position
178 // ein Attribut ohne Ende und mit \xff im Text befindet.
179 // Mit OutAttr() werden die Attribute an der angegebenen SwPos
180 // ausgegeben.
181 
182 class WW8SwAttrIter : public MSWordAttrIter
183 {
184 private:
185     const SwTxtNode& rNd;
186 
187     CharRuns maCharRuns;
188     cCharRunIter maCharRunIter;
189 
190     rtl_TextEncoding meChrSet;
191     sal_uInt16 mnScript;
192     bool mbCharIsRTL;
193 
194     const SwRedline* pCurRedline;
195     xub_StrLen nAktSwPos;
196     sal_uInt16 nCurRedlinePos;
197 
198     bool mbParaIsRTL;
199 
200     const SwFmtDrop &mrSwFmtDrop;
201 
202     sw::Frames maFlyFrms;     // #i2916#
203     sw::FrameIter maFlyIter;
204 
205     xub_StrLen SearchNext( xub_StrLen nStartPos );
206     void FieldVanish( const String& rTxt );
207 
208     void OutSwFmtRefMark(const SwFmtRefMark& rAttr, bool bStart);
209 
210     void IterToCurrent();
211 
212     //No copying
213     WW8SwAttrIter(const WW8SwAttrIter&);
214     WW8SwAttrIter& operator=(const WW8SwAttrIter&);
215 public:
216     WW8SwAttrIter( MSWordExportBase& rWr, const SwTxtNode& rNd );
217 
218     bool IsTxtAttr( xub_StrLen nSwPos );
219     bool IsRedlineAtEnd( xub_StrLen nPos ) const;
220     bool IsDropCap( int nSwPos );
221     bool RequiresImplicitBookmark();
222 
223     void NextPos() { nAktSwPos = SearchNext( nAktSwPos + 1 ); }
224 
225     void OutAttr( xub_StrLen nSwPos );
226     virtual const SfxPoolItem* HasTextItem( sal_uInt16 nWhich ) const;
227     virtual const SfxPoolItem& GetItem( sal_uInt16 nWhich ) const;
228     int OutAttrWithRange(xub_StrLen nPos);
229     const SwRedlineData* GetRedline( xub_StrLen nPos );
230     void OutFlys(xub_StrLen nSwPos);
231 
232     xub_StrLen WhereNext() const    { return nAktSwPos; }
233     sal_uInt16 GetScript() const { return mnScript; }
234     bool IsCharRTL() const { return mbCharIsRTL; }
235     bool IsParaRTL() const { return mbParaIsRTL; }
236     rtl_TextEncoding GetCharSet() const { return meChrSet; }
237     String GetSnippet(const String &rStr, xub_StrLen nAktPos,
238         xub_StrLen nLen) const;
239     const SwFmtDrop& GetSwFmtDrop() const { return mrSwFmtDrop; }
240 };
241 
242 class sortswflys :
243     public std::binary_function<const sw::Frame&, const sw::Frame&, bool>
244 {
245 public:
246     bool operator()(const sw::Frame &rOne, const sw::Frame &rTwo) const
247     {
248         return rOne.GetPosition() < rTwo.GetPosition();
249     }
250 };
251 
252 void WW8SwAttrIter::IterToCurrent()
253 {
254     ASSERT(maCharRuns.begin() != maCharRuns.end(), "Impossible");
255     mnScript = maCharRunIter->mnScript;
256     meChrSet = maCharRunIter->meCharSet;
257     mbCharIsRTL = maCharRunIter->mbRTL;
258 }
259 
260 WW8SwAttrIter::WW8SwAttrIter(MSWordExportBase& rWr, const SwTxtNode& rTxtNd) :
261     MSWordAttrIter(rWr),
262     rNd(rTxtNd),
263     maCharRuns(GetPseudoCharRuns(rTxtNd, 0, !rWr.HackIsWW8OrHigher())),
264     pCurRedline(0),
265     nAktSwPos(0),
266     nCurRedlinePos(USHRT_MAX),
267     mrSwFmtDrop(rTxtNd.GetSwAttrSet().GetDrop())
268 {
269 
270     SwPosition aPos(rTxtNd);
271     if (FRMDIR_HORI_RIGHT_TOP == rWr.pDoc->GetTextDirection(aPos))
272         mbParaIsRTL = true;
273     else
274         mbParaIsRTL = false;
275 
276     maCharRunIter = maCharRuns.begin();
277     IterToCurrent();
278 
279     /*
280      #i2916#
281      Get list of any graphics which may be anchored from this paragraph.
282     */
283     maFlyFrms = GetFramesInNode(rWr.maFrames, rNd);
284     std::sort(maFlyFrms.begin(), maFlyFrms.end(), sortswflys());
285 
286     /*
287      #i18480#
288      If we are inside a frame then anything anchored inside this frame can
289      only be supported by word anchored inline ("as character"), so force
290      this in the supportable case.
291     */
292     if (rWr.HackIsWW8OrHigher() && rWr.bInWriteEscher)
293     {
294         std::for_each(maFlyFrms.begin(), maFlyFrms.end(),
295             std::mem_fun_ref(&sw::Frame::ForceTreatAsInline));
296     }
297 
298     maFlyIter = maFlyFrms.begin();
299 
300     if ( m_rExport.pDoc->GetRedlineTbl().Count() )
301     {
302         SwPosition aPosition( rNd, SwIndex( (SwTxtNode*)&rNd ) );
303         pCurRedline = m_rExport.pDoc->GetRedline( aPosition, &nCurRedlinePos );
304     }
305 
306     nAktSwPos = SearchNext(1);
307 }
308 
309 xub_StrLen lcl_getMinPos( xub_StrLen pos1, xub_StrLen pos2 )
310 {
311     xub_StrLen min = STRING_NOTFOUND;
312     if ( pos1 == STRING_NOTFOUND && pos2 != STRING_NOTFOUND )
313         min = pos2;
314     else if ( pos2 == STRING_NOTFOUND && pos1 != STRING_NOTFOUND )
315         min = pos1;
316     else if ( pos2 != STRING_NOTFOUND && pos2 != STRING_NOTFOUND )
317     {
318         if ( pos1 < pos2 )
319             min = pos1;
320         else
321             min = pos2;
322     }
323 
324     return min;
325 }
326 
327 xub_StrLen WW8SwAttrIter::SearchNext( xub_StrLen nStartPos )
328 {
329     xub_StrLen nPos;
330     xub_StrLen nMinPos = STRING_MAXLEN;
331     xub_StrLen i=0;
332 
333 	const String aTxt = rNd.GetTxt();
334     xub_StrLen fieldEndPos = aTxt.Search(CH_TXT_ATR_FIELDEND, nStartPos);
335     xub_StrLen fieldStartPos = aTxt.Search(CH_TXT_ATR_FIELDSTART, nStartPos);
336     xub_StrLen formElementPos = aTxt.Search(CH_TXT_ATR_FORMELEMENT, nStartPos);
337 
338     xub_StrLen pos = lcl_getMinPos( fieldEndPos, fieldStartPos );
339     pos = lcl_getMinPos( pos, formElementPos );
340 
341 	if (pos!=STRING_NOTFOUND)
342         nMinPos=pos;
343 
344     // first the redline, then the attributes
345     if( pCurRedline )
346     {
347         const SwPosition* pEnd = pCurRedline->End();
348         if (pEnd->nNode == rNd && ((i = pEnd->nContent.GetIndex()) >= nStartPos) && i < nMinPos )
349 				nMinPos = i;
350     }
351 
352     if ( nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().Count() )
353     {
354         // nCurRedlinePos point to the next redline
355         nPos = nCurRedlinePos;
356         if( pCurRedline )
357             ++nPos;
358 
359         for ( ; nPos < m_rExport.pDoc->GetRedlineTbl().Count(); ++nPos )
360         {
361             const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nPos ];
362 
363             const SwPosition* pStt = pRedl->Start();
364             const SwPosition* pEnd = pStt == pRedl->GetPoint()
365                                         ? pRedl->GetMark()
366                                         : pRedl->GetPoint();
367 
368             if( pStt->nNode == rNd )
369             {
370                 if( ( i = pStt->nContent.GetIndex() ) >= nStartPos &&
371                     i < nMinPos )
372                     nMinPos = i;
373             }
374             else
375                 break;
376 
377             if( pEnd->nNode == rNd &&
378                 ( i = pEnd->nContent.GetIndex() ) < nMinPos &&
379                 i >= nStartPos )
380                     nMinPos = i;
381         }
382     }
383 
384 
385     if (mrSwFmtDrop.GetWholeWord() && nStartPos <= rNd.GetDropLen(0))
386         nMinPos = rNd.GetDropLen(0);
387     else if(nStartPos <= mrSwFmtDrop.GetChars())
388         nMinPos = mrSwFmtDrop.GetChars();
389 
390     if(const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
391     {
392 
393 // kann noch optimiert werden, wenn ausgenutzt wird, dass die TxtAttrs
394 // nach der Anfangsposition geordnet sind. Dann muessten
395 // allerdings noch 2 Indices gemerkt werden
396         for( i = 0; i < pTxtAttrs->Count(); i++ )
397         {
398             const SwTxtAttr* pHt = (*pTxtAttrs)[i];
399             nPos = *pHt->GetStart();    // gibt erstes Attr-Zeichen
400             if( nPos >= nStartPos && nPos <= nMinPos )
401                 nMinPos = nPos;
402 
403             if( pHt->GetEnd() )         // Attr mit Ende
404             {
405                 nPos = *pHt->GetEnd();      // gibt letztes Attr-Zeichen + 1
406                 if( nPos >= nStartPos && nPos <= nMinPos )
407                     nMinPos = nPos;
408             }
409             if (pHt->HasDummyChar())
410             {
411                 // pos + 1 because of CH_TXTATR in Text
412                 nPos = *pHt->GetStart() + 1;
413                 if( nPos >= nStartPos && nPos <= nMinPos )
414                     nMinPos = nPos;
415             }
416         }
417     }
418 
419     if (maCharRunIter != maCharRuns.end())
420     {
421         if (maCharRunIter->mnEndPos < nMinPos)
422             nMinPos = maCharRunIter->mnEndPos;
423         IterToCurrent();
424     }
425 
426     /*
427      #i2916#
428      Check to see if there are any graphics anchored to characters in this
429      paragraph's text.  Set nMinPos to 1 past the placement for anchored to
430      character because anchors in Word appear after the character they are
431      anchored to.
432     */
433     if (maFlyIter != maFlyFrms.end())
434     {
435         const SwPosition &rAnchor = maFlyIter->GetPosition();
436 
437         nPos = rAnchor.nContent.GetIndex();
438         if (nPos >= nStartPos && nPos <= nMinPos)
439             nMinPos = nPos;
440 
441         if (maFlyIter->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AT_CHAR)
442         {
443             ++nPos;
444             if (nPos >= nStartPos && nPos <= nMinPos)
445                 nMinPos = nPos;
446         }
447     }
448 
449     //nMinPos found and not going to change at this point
450 
451     if (maCharRunIter != maCharRuns.end())
452     {
453         if (maCharRunIter->mnEndPos == nMinPos)
454             ++maCharRunIter;
455     }
456 
457     return nMinPos;
458 }
459 
460 void WW8SwAttrIter::OutAttr( xub_StrLen nSwPos )
461 {
462     m_rExport.AttrOutput().RTLAndCJKState( IsCharRTL(), GetScript() );
463 
464     /*
465      Depending on whether text is in CTL/CJK or Western, get the id of that
466      script, the idea is that the font that is actually in use to render this
467      range of text ends up in pFont
468     */
469     sal_uInt16 nFontId = GetWhichOfScript( RES_CHRATR_FONT, GetScript() );
470 
471     const SvxFontItem &rParentFont = ItemGet<SvxFontItem>(
472         (const SwTxtFmtColl&)rNd.GetAnyFmtColl(), nFontId);
473     const SvxFontItem *pFont = &rParentFont;
474 
475     SfxItemSet aExportSet(*rNd.GetSwAttrSet().GetPool(),
476         RES_CHRATR_BEGIN, RES_TXTATR_END - 1);
477 
478     //The hard formatting properties that affect the entire paragraph
479     if (rNd.HasSwAttrSet())
480     {
481         sal_Bool bDeep = sal_False;
482         // only copy hard attributes - bDeep = false
483         aExportSet.Set(rNd.GetSwAttrSet(), bDeep);
484         // get the current font item. Use rNd.GetSwAttrSet instead of aExportSet:
485         const SvxFontItem &rNdFont = ItemGet<SvxFontItem>(rNd.GetSwAttrSet(), nFontId);
486         pFont = &rNdFont;
487         aExportSet.ClearItem(nFontId);
488     }
489 
490     //The additional hard formatting properties that affect this range in the
491     //paragraph
492     sw::PoolItems aRangeItems;
493     if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
494     {
495         for (xub_StrLen i = 0; i < pTxtAttrs->Count(); ++i)
496         {
497             const SwTxtAttr* pHt = (*pTxtAttrs)[i];
498             const xub_StrLen* pEnd = pHt->GetEnd();
499 
500             if (pEnd ? ( nSwPos >= *pHt->GetStart() && nSwPos < *pEnd)
501                         : nSwPos == *pHt->GetStart() )
502             {
503                 sal_uInt16 nWhich = pHt->GetAttr().Which();
504                 if (nWhich == RES_TXTATR_AUTOFMT)
505                 {
506                     const SwFmtAutoFmt& rAutoFmt = static_cast<const SwFmtAutoFmt&>(pHt->GetAttr());
507                     const boost::shared_ptr<SfxItemSet> pSet = rAutoFmt.GetStyleHandle();
508                     SfxWhichIter aIter( *pSet );
509                     const SfxPoolItem* pItem;
510                     sal_uInt16 nWhichId = aIter.FirstWhich();
511                     while( nWhichId )
512                     {
513                         if( SFX_ITEM_SET == pSet->GetItemState( nWhichId, sal_False, &pItem ))
514                         {
515                             if (nWhichId == nFontId)
516                                 pFont = &(item_cast<SvxFontItem>(*pItem));
517                             else
518                                 aRangeItems[nWhichId] = pItem;
519                         }
520                         nWhichId = aIter.NextWhich();
521                     }
522                 }
523                 else
524                     aRangeItems[nWhich] = (&(pHt->GetAttr()));
525             }
526             else if (nSwPos < *pHt->GetStart())
527                 break;
528         }
529     }
530 
531     /*
532      For #i24291# we need to explictly remove any properties from the
533      aExportSet which a SwCharFmt would override, we can't rely on word doing
534      this for us like writer does
535     */
536     const SwFmtCharFmt *pCharFmtItem =
537         HasItem< SwFmtCharFmt >( aRangeItems, RES_TXTATR_CHARFMT );
538     if ( pCharFmtItem )
539         ClearOverridesFromSet( *pCharFmtItem, aExportSet );
540 
541     sw::PoolItems aExportItems;
542     GetPoolItems( aExportSet, aExportItems, false );
543 
544     sw::cPoolItemIter aEnd = aRangeItems.end();
545     for ( sw::cPoolItemIter aI = aRangeItems.begin(); aI != aEnd; ++aI )
546         aExportItems[aI->first] = aI->second;
547 
548     if ( !aExportItems.empty() )
549     {
550         const SwModify* pOldMod = m_rExport.pOutFmtNode;
551         m_rExport.pOutFmtNode = &rNd;
552         m_rExport.m_aCurrentCharPropStarts.push( nSwPos );
553 
554         m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript() );
555 
556         // HasTextItem nur in dem obigen Bereich erlaubt
557         m_rExport.m_aCurrentCharPropStarts.pop();
558         m_rExport.pOutFmtNode = pOldMod;
559     }
560 
561     ASSERT( pFont, "must be *some* font associated with this txtnode" );
562     if ( pFont )
563     {
564         SvxFontItem aFont( *pFont );
565 
566         /*
567          If we are a nonunicode aware format then we set the charset we want to
568          use for export of this range. If necessary this will generate a pseudo
569          font to use for this range.
570 
571          So now we are guaranteed to have a font with the correct charset set
572          for WW6/95 which will match the script we have exported this range in,
573          this makes older nonunicode aware versions of word display the correct
574          characters.
575         */
576         if ( !m_rExport.HackIsWW8OrHigher() )
577             aFont.SetCharSet( GetCharSet() );
578 
579         if ( rParentFont != aFont )
580             m_rExport.AttrOutput().OutputItem( aFont );
581     }
582 }
583 
584 void WW8SwAttrIter::OutFlys(xub_StrLen nSwPos)
585 {
586     /*
587      #i2916#
588      May have an anchored graphic to be placed, loop through sorted array
589      and output all at this position
590     */
591     while ( maFlyIter != maFlyFrms.end() )
592     {
593         const SwPosition &rAnchor = maFlyIter->GetPosition();
594         xub_StrLen nPos = rAnchor.nContent.GetIndex();
595 
596         if ( nPos != nSwPos )
597             break;
598         else
599         {
600             m_rExport.AttrOutput().OutputFlyFrame( *maFlyIter );
601             ++maFlyIter;
602         }
603     }
604 }
605 
606 bool WW8SwAttrIter::IsTxtAttr( xub_StrLen nSwPos )
607 {
608     // search for attrs with CH_TXTATR
609     if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
610     {
611         for (sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i)
612         {
613             const SwTxtAttr* pHt = (*pTxtAttrs)[i];
614             if ( pHt->HasDummyChar() && (*pHt->GetStart() == nSwPos) )
615                 return true;
616         }
617     }
618 
619     return false;
620 }
621 
622 bool WW8SwAttrIter::IsDropCap( int nSwPos )
623 {
624     // see if the current position falls on a DropCap
625     int nDropChars = mrSwFmtDrop.GetChars();
626     bool bWholeWord = mrSwFmtDrop.GetWholeWord();
627     if (bWholeWord)
628     {
629         short nWordLen = rNd.GetDropLen(0);
630         if(nSwPos == nWordLen && nSwPos != 0)
631             return true;
632     }
633     else
634     {
635         if (nSwPos == nDropChars && nSwPos != 0)
636             return true;
637     }
638     return false;
639 }
640 
641 bool WW8SwAttrIter::RequiresImplicitBookmark()
642 {
643     SwImplBookmarksIter bkmkIterEnd = m_rExport.maImplicitBookmarks.end();
644     for ( SwImplBookmarksIter aIter = m_rExport.maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter )
645     {
646         sal_uLong sample  = aIter->second;
647 
648         if ( sample == rNd.GetIndex() )
649             return true;
650     }
651     return false;
652 }
653 
654 // HasItem ist fuer die Zusammenfassung des Doppel-Attributes Underline
655 // und WordLineMode als TextItems. OutAttr() ruft die Ausgabefunktion,
656 // die dann ueber HasItem() nach anderen Items an der
657 // Attribut-Anfangposition fragen kann.
658 // Es koennen nur Attribute mit Ende abgefragt werden.
659 // Es wird mit bDeep gesucht
660 const SfxPoolItem* WW8SwAttrIter::HasTextItem( sal_uInt16 nWhich ) const
661 {
662     const SfxPoolItem* pRet = 0;
663     const SwpHints* pTxtAttrs = rNd.GetpSwpHints();
664     xub_StrLen nTmpSwPos = m_rExport.m_aCurrentCharPropStarts.top();
665     if (pTxtAttrs)
666     {
667         for (sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i)
668         {
669             const SwTxtAttr* pHt = (*pTxtAttrs)[i];
670             const SfxPoolItem* pItem = &pHt->GetAttr();
671             const xub_StrLen* pAtrEnd = 0;
672             if( 0 != ( pAtrEnd = pHt->GetEnd() ) &&     // nur Attr mit Ende
673                 nWhich == pItem->Which() &&             //
674                 nTmpSwPos >= *pHt->GetStart() && nTmpSwPos < *pAtrEnd )
675             {
676                 pRet = pItem;       // gefunden
677                 break;
678             }
679             else if (nTmpSwPos < *pHt->GetStart())
680                 break;              // dann kommt da nichts mehr
681         }
682     }
683     return pRet;
684 }
685 
686 void WW8Export::GetCurrentItems(WW8Bytes& rItems) const
687 {
688     sal_uInt16 nEnd = pO ? pO->Count() : 0;
689     for (sal_uInt16 nI = 0; nI < nEnd; ++nI)
690         rItems.Insert((*pO)[nI], rItems.Count());
691 }
692 
693 const SfxPoolItem& WW8SwAttrIter::GetItem(sal_uInt16 nWhich) const
694 {
695     const SfxPoolItem* pRet = HasTextItem(nWhich);
696     return pRet ? *pRet : rNd.SwCntntNode::GetAttr(nWhich);
697 }
698 
699 void WW8AttributeOutput::StartRuby( const SwTxtNode& rNode, const SwFmtRuby& rRuby )
700 {
701     String aStr( FieldString( ww::eEQ ) );
702     aStr.APPEND_CONST_ASC( "\\* jc" );
703     sal_Int32 nJC = 0;
704     sal_Char cDirective = 0;
705     switch ( rRuby.GetAdjustment() )
706     {
707         case 0:
708             nJC = 3;
709             cDirective = 'l';
710             break;
711         case 1:
712             //defaults to 0
713             break;
714         case 2:
715             nJC = 4;
716             cDirective = 'r';
717             break;
718         case 3:
719             nJC = 1;
720             cDirective = 'd';
721             break;
722         case 4:
723             nJC = 2;
724             cDirective = 'd';
725             break;
726         default:
727             ASSERT( !this,"Unhandled Ruby justication code" );
728             break;
729     }
730     aStr += String::CreateFromInt32( nJC );
731 
732     /*
733      MS needs to know the name and size of the font used in the ruby item,
734      but we coud have written it in a mixture of asian and western
735      scripts, and each of these can be a different font and size than the
736      other, so we make a guess based upon the first character of the text,
737      defaulting to asian.
738      */
739     sal_uInt16 nRubyScript;
740     if( pBreakIt->GetBreakIter().is() )
741         nRubyScript = pBreakIt->GetBreakIter()->getScriptType( rRuby.GetText(), 0);
742     else
743         nRubyScript = i18n::ScriptType::ASIAN;
744 
745     const SwTxtRuby* pRubyTxt = rRuby.GetTxtRuby();
746     const SwCharFmt* pFmt = pRubyTxt ? pRubyTxt->GetCharFmt() : 0;
747     String sFamilyName;
748     long nHeight;
749     if ( pFmt )
750     {
751         const SvxFontItem &rFont = ItemGet< SvxFontItem >( *pFmt,
752                 GetWhichOfScript(RES_CHRATR_FONT,nRubyScript) );
753         sFamilyName = rFont.GetFamilyName();
754 
755         const SvxFontHeightItem &rHeight = ItemGet< SvxFontHeightItem >( *pFmt,
756                 GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
757         nHeight = rHeight.GetHeight();
758     }
759     else
760     {
761         /*Get defaults if no formatting on ruby text*/
762 
763         const SfxItemPool *pPool = rNode.GetSwAttrSet().GetPool();
764         const SfxItemPool &rPool = pPool ? *pPool : m_rWW8Export.pDoc->GetAttrPool();
765 
766         const SvxFontItem &rFont  = DefaultItemGet< SvxFontItem >( rPool,
767                 GetWhichOfScript( RES_CHRATR_FONT,nRubyScript ) );
768         sFamilyName = rFont.GetFamilyName();
769 
770         const SvxFontHeightItem &rHeight = DefaultItemGet< SvxFontHeightItem >
771             ( rPool, GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
772         nHeight = rHeight.GetHeight();
773     }
774     nHeight = (nHeight + 5)/10;
775 
776     aStr.APPEND_CONST_ASC( " \\* \"Font:" );
777     aStr.Append( sFamilyName );
778     aStr.APPEND_CONST_ASC( "\" \\* hps" );
779     aStr += String::CreateFromInt32( nHeight );
780     aStr.APPEND_CONST_ASC( " \\o" );
781     if ( cDirective )
782     {
783         aStr.APPEND_CONST_ASC( "\\a" );
784         aStr.Append( cDirective );
785     }
786     aStr.APPEND_CONST_ASC( "(\\s\\up " );
787 
788 
789     if ( pBreakIt->GetBreakIter().is() )
790         nRubyScript = pBreakIt->GetBreakIter()->getScriptType( rNode.GetTxt(),
791                 *( pRubyTxt->GetStart() ) );
792     else
793         nRubyScript = i18n::ScriptType::ASIAN;
794 
795     const SwAttrSet& rSet = rNode.GetSwAttrSet();
796     const SvxFontHeightItem &rHeightItem  =
797         ( const SvxFontHeightItem& )rSet.Get(
798                                              GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
799     nHeight = (rHeightItem.GetHeight() + 10)/20-1;
800     aStr += String::CreateFromInt32(nHeight);
801     aStr += '(';
802     aStr += rRuby.GetText();
803     aStr.APPEND_CONST_ASC( ");" );
804     m_rWW8Export.OutputField( 0, ww::eEQ, aStr,
805             WRITEFIELD_START | WRITEFIELD_CMD_START );
806 }
807 
808 void WW8AttributeOutput::EndRuby()
809 {
810     m_rWW8Export.WriteChar( ')' );
811     m_rWW8Export.OutputField( 0, ww::eEQ, aEmptyStr, WRITEFIELD_END | WRITEFIELD_CLOSE );
812 }
813 
814 /*#i15387# Better ideas welcome*/
815 String &TruncateBookmark( String &rRet )
816 {
817     if ( rRet.Len() > 40 )
818         rRet.Erase( 40 );
819     ASSERT( rRet.Len() <= 40, "Word cannot have bookmarks longer than 40 chars" );
820     return rRet;
821 }
822 
823 bool AttributeOutputBase::AnalyzeURL( const String& rUrl, const String& /*rTarget*/, String* pLinkURL, String* pMark )
824 {
825     bool bBookMarkOnly = false;
826 
827     INetURLObject aURL( rUrl );
828     String sMark;
829     String sURL;
830 
831     if ( rUrl.Len() > 1 && rUrl.GetChar(0) == INET_MARK_TOKEN )
832     {
833         sMark = BookmarkToWriter( rUrl.Copy(1) );
834 
835         xub_StrLen nPos = sMark.SearchBackward( cMarkSeperator );
836 
837         String sRefType( sMark.Copy( nPos+1 ) );
838         sRefType.EraseAllChars();
839 
840         // i21465 Only interested in outline references
841         if ( sRefType.EqualsAscii( pMarkToOutline ) )
842         {
843             String sLink = sMark.Copy(0, nPos);
844             SwImplBookmarksIter bkmkIterEnd = GetExport().maImplicitBookmarks.end();
845             for ( SwImplBookmarksIter aIter = GetExport().maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter )
846             {
847                 String bkmkName  = aIter->first;
848 
849                 if ( bkmkName == sLink )
850                 {
851                     sMark = String( RTL_CONSTASCII_STRINGPARAM( "_toc" ) );
852                     sMark += String::CreateFromInt32( aIter->second );
853                 }
854             }
855         }
856     }
857     else
858     {
859         sURL = aURL.GetURLNoMark( INetURLObject::DECODE_UNAMBIGUOUS );
860         sMark = aURL.GetMark( INetURLObject::DECODE_UNAMBIGUOUS );
861 
862     }
863 
864     if ( sMark.Len() && !sURL.Len() )
865         bBookMarkOnly = true;
866 
867 
868 
869     *pMark = sMark;
870     *pLinkURL = sURL;
871     return bBookMarkOnly;
872 }
873 
874 bool WW8AttributeOutput::AnalyzeURL( const String& rUrl, const String& rTarget, String* pLinkURL, String* pMark )
875 {
876     bool bBookMarkOnly = AttributeOutputBase::AnalyzeURL( rUrl, rTarget, pLinkURL, pMark );
877 
878     String sURL = *pLinkURL;
879     String sMark = *pMark;
880 
881     if ( sURL.Len() )
882         sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL );
883 
884     if ( bBookMarkOnly )
885         sURL = FieldString( ww::eHYPERLINK );
886     else
887     {
888         String sFld( FieldString( ww::eHYPERLINK ) );
889         sFld.APPEND_CONST_ASC( "\"" );
890         sURL.Insert( sFld, 0 );
891         sURL += '\"';
892     }
893 
894     if ( sMark.Len() )
895         ( ( sURL.APPEND_CONST_ASC( " \\l \"" ) ) += sMark ) += '\"';
896 
897     if ( rTarget.Len() )
898         ( sURL.APPEND_CONST_ASC( " \\n " ) ) += rTarget;
899 
900     *pLinkURL = sURL;
901     *pMark = sMark;
902 
903     return bBookMarkOnly;
904 }
905 
906 bool WW8AttributeOutput::StartURL( const String &rUrl, const String &rTarget )
907 {
908     // hyperlinks only in WW8
909     if ( !m_rWW8Export.bWrtWW8 )
910         return false;
911 
912     INetURLObject aURL( rUrl );
913     String sURL;
914     String sMark;
915 
916     bool bBookMarkOnly = AnalyzeURL( rUrl, rTarget, &sURL, &sMark );
917 
918 
919     m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_START | WRITEFIELD_CMD_START );
920 
921     // write the refence to the "picture" structure
922     sal_uLong nDataStt = m_rWW8Export.pDataStrm->Tell();
923     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell() );
924 
925 //  WinWord 2000 doesn't write this - so its a temp solution by W97 ?
926     m_rWW8Export.WriteChar( 0x01 );
927 
928     static sal_uInt8 aArr1[] = {
929         0x03, 0x6a, 0,0,0,0,    // sprmCPicLocation
930 
931         0x06, 0x08, 0x01,       // sprmCFData
932         0x55, 0x08, 0x01,       // sprmCFSpec
933         0x02, 0x08, 0x01        // sprmCFFldVanish
934     };
935     sal_uInt8* pDataAdr = aArr1 + 2;
936     Set_UInt32( pDataAdr, nDataStt );
937 
938     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), sizeof( aArr1 ), aArr1 );
939 
940     m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_CMD_END );
941 
942     // now write the picture structur
943     sURL = aURL.GetURLNoMark();
944 
945     //all links end up in the data stream as absolute references.
946     bool bAbsolute = !bBookMarkOnly;
947 
948     static sal_uInt8 __READONLY_DATA aURLData1[] = {
949         0,0,0,0,        // len of struct
950         0x44,0,         // the start of "next" data
951         0,0,0,0,0,0,0,0,0,0,                // PIC-Structure!
952         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    //  |
953         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    //  |
954         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    //  |
955         0,0,0,0,                            // /
956     };
957     static sal_uInt8 __READONLY_DATA MAGIC_A[] = {
958         // start of "next" data
959         0xD0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11,
960         0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B
961     };
962 
963     m_rWW8Export.pDataStrm->Write( aURLData1, sizeof( aURLData1 ) );
964     sal_uInt8 nAnchor = 0x00;
965     if ( sMark.Len() )
966         nAnchor = 0x08;
967     m_rWW8Export.pDataStrm->Write( &nAnchor, 1 );
968     m_rWW8Export.pDataStrm->Write( MAGIC_A, sizeof(MAGIC_A) );
969     SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 0x00000002);
970     sal_uInt32 nFlag = bBookMarkOnly ? 0 : 0x01;
971     if ( bAbsolute )
972         nFlag |= 0x02;
973     if ( sMark.Len() )
974         nFlag |= 0x08;
975     SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nFlag );
976 
977     INetProtocol eProto = aURL.GetProtocol();
978     if ( eProto == INET_PROT_FILE )
979     {
980         // version 1 (for a document)
981 
982         static sal_uInt8 __READONLY_DATA MAGIC_C[] = {
983             0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
984             0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46,
985             0x00, 0x00
986         };
987 
988         static sal_uInt8 __READONLY_DATA MAGIC_D[] = {
989             0xFF, 0xFF, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00,
990             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
991             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
992         };
993 
994         // save the links to files as relative
995         sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL );
996         if ( sURL.EqualsAscii( "/", 0, 1 ) )
997             sURL = aURL.PathToFileName();
998 
999         // special case for the absolute windows names
1000         // (convert '/c:/foo/bar.doc' into 'c:\foo\bar.doc')
1001         sal_Unicode aDrive = ( sURL.Len() > 1 )? sURL.GetChar( 1 ): 0;
1002         if ( sURL.EqualsAscii( "/", 0, 1 ) &&
1003              ( ( aDrive >= 'A' && aDrive <= 'Z' ) || ( aDrive >= 'a' && aDrive <= 'z' ) ) &&
1004              sURL.EqualsAscii( ":", 2, 1 ) )
1005         {
1006             sURL.Erase( 0, 1 );
1007             sURL.SearchAndReplaceAll( '/', '\\' );
1008         }
1009 
1010         m_rWW8Export.pDataStrm->Write( MAGIC_C, sizeof(MAGIC_C) );
1011         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sURL.Len()+1 );
1012         SwWW8Writer::WriteString8( *m_rWW8Export.pDataStrm, sURL, true,
1013                                     RTL_TEXTENCODING_MS_1252 );
1014         m_rWW8Export.pDataStrm->Write( MAGIC_D, sizeof( MAGIC_D ) );
1015 
1016         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() + 6 );
1017         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() );
1018         SwWW8Writer::WriteShort( *m_rWW8Export.pDataStrm, 3 );
1019         SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, false );
1020     }
1021     else if ( eProto != INET_PROT_NOT_VALID )
1022     {
1023         // version 2 (simple url)
1024         // an write some data to the data stream, but dont ask
1025         // what the data mean, except for the URL.
1026         // The First piece is the WW8_PIC structure.
1027         //
1028         static sal_uInt8 __READONLY_DATA MAGIC_B[] = {
1029             0xE0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11,
1030             0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B
1031         };
1032 
1033         m_rWW8Export.pDataStrm->Write( MAGIC_B, sizeof(MAGIC_B) );
1034         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2 * ( sURL.Len() + 1 ) );
1035         SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, true );
1036     }
1037 
1038     if ( sMark.Len() )
1039     {
1040         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sMark.Len()+1 );
1041         SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sMark, true );
1042     }
1043     SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nDataStt,
1044         m_rWW8Export.pDataStrm->Tell() - nDataStt );
1045 
1046     return true;
1047 }
1048 
1049 bool WW8AttributeOutput::EndURL()
1050 {
1051     // hyperlinks only in WW8
1052     if ( !m_rWW8Export.bWrtWW8 )
1053         return false;
1054 
1055     m_rWW8Export.OutputField( 0, ww::eHYPERLINK, aEmptyStr, WRITEFIELD_CLOSE );
1056 
1057     return true;
1058 }
1059 
1060 String BookmarkToWord(const String &rBookmark)
1061 {
1062     String sRet(INetURLObject::encode(rBookmark,
1063         INetURLObject::PART_REL_SEGMENT_EXTRA, '%',
1064         INetURLObject::ENCODE_ALL, RTL_TEXTENCODING_ASCII_US));
1065     return TruncateBookmark(sRet);
1066 }
1067 
1068 String BookmarkToWriter(const String &rBookmark)
1069 {
1070     return INetURLObject::decode(rBookmark, '%',
1071         INetURLObject::DECODE_UNAMBIGUOUS, RTL_TEXTENCODING_ASCII_US);
1072 }
1073 
1074 void WW8SwAttrIter::OutSwFmtRefMark(const SwFmtRefMark& rAttr, bool)
1075 {
1076     if ( m_rExport.HasRefToObject( REF_SETREFATTR, &rAttr.GetRefName(), 0 ) )
1077         m_rExport.AppendBookmark( m_rExport.GetBookmarkName( REF_SETREFATTR,
1078                                             &rAttr.GetRefName(), 0 ));
1079 }
1080 
1081 void WW8AttributeOutput::FieldVanish( const String& rTxt, ww::eField /*eType*/ )
1082 {
1083     WW8Bytes aItems;
1084     m_rWW8Export.GetCurrentItems( aItems );
1085 
1086     // sprmCFFldVanish
1087     if ( m_rWW8Export.bWrtWW8 )
1088         SwWW8Writer::InsUInt16( aItems, NS_sprm::LN_CFFldVanish );
1089     else
1090         aItems.Insert( 67, aItems.Count() );
1091     aItems.Insert( 1, aItems.Count() );
1092 
1093     sal_uInt16 nStt_sprmCFSpec = aItems.Count();
1094 
1095     // sprmCFSpec --  fSpec-Attribut true
1096     if ( m_rWW8Export.bWrtWW8 )
1097         SwWW8Writer::InsUInt16( aItems, 0x855 );
1098     else
1099         aItems.Insert( 117, aItems.Count() );
1100     aItems.Insert( 1, aItems.Count() );
1101 
1102     m_rWW8Export.WriteChar( '\x13' );
1103     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.Count(),
1104                                     aItems.GetData() );
1105     m_rWW8Export.OutSwString( rTxt, 0, rTxt.Len(), m_rWW8Export.IsUnicode(),
1106                         RTL_TEXTENCODING_MS_1252 );
1107     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), nStt_sprmCFSpec,
1108                                     aItems.GetData() );
1109     m_rWW8Export.WriteChar( '\x15' );
1110     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.Count(),
1111                                     aItems.GetData() );
1112 }
1113 
1114 void AttributeOutputBase::TOXMark( const SwTxtNode& rNode, const SwTOXMark& rAttr )
1115 {
1116     // its a field; so get the Text form the Node and build the field
1117     String sTxt;
1118     ww::eField eType = ww::eNONE;
1119 
1120     const SwTxtTOXMark& rTxtTOXMark = *rAttr.GetTxtTOXMark();
1121     const xub_StrLen* pTxtEnd = rTxtTOXMark.GetEnd();
1122     if ( pTxtEnd ) // has range?
1123     {
1124         sTxt = rNode.GetExpandTxt( *rTxtTOXMark.GetStart(),
1125                                    *pTxtEnd - *rTxtTOXMark.GetStart() );
1126     }
1127     else
1128         sTxt = rAttr.GetAlternativeText();
1129 
1130     switch ( rAttr.GetTOXType()->GetType() )
1131     {
1132         case TOX_INDEX:
1133             eType = ww::eXE;
1134             if ( rAttr.GetPrimaryKey().Len() )
1135             {
1136                 if ( rAttr.GetSecondaryKey().Len() )
1137                 {
1138                     sTxt.Insert( ':', 0 );
1139                     sTxt.Insert( rAttr.GetSecondaryKey(), 0 );
1140                 }
1141 
1142                 sTxt.Insert( ':', 0 );
1143                 sTxt.Insert( rAttr.GetPrimaryKey(), 0 );
1144             }
1145             sTxt.InsertAscii( " XE \"", 0 );
1146             sTxt.InsertAscii( "\" " );
1147             break;
1148 
1149         case TOX_USER:
1150             ( sTxt.APPEND_CONST_ASC( "\" \\f \"" ) )
1151                 += (sal_Char)( 'A' + GetExport( ).GetId( *rAttr.GetTOXType() ) );
1152             // fall through - no break;
1153         case TOX_CONTENT:
1154             {
1155                 eType = ww::eTC;
1156                 sTxt.InsertAscii( " TC \"", 0 );
1157                 sal_uInt16 nLvl = rAttr.GetLevel();
1158                 if (nLvl > WW8ListManager::nMaxLevel)
1159                     nLvl = WW8ListManager::nMaxLevel;
1160 
1161                 ((sTxt.APPEND_CONST_ASC( "\" \\l " ))
1162                  += String::CreateFromInt32( nLvl )) += ' ';
1163             }
1164             break;
1165         default:
1166             ASSERT( !this, "Unhandled option for toc export" );
1167             break;
1168     }
1169 
1170     if ( sTxt.Len() )
1171         FieldVanish( sTxt, eType );
1172 }
1173 
1174 int WW8SwAttrIter::OutAttrWithRange(xub_StrLen nPos)
1175 {
1176     int nRet = 0;
1177     if ( const SwpHints* pTxtAttrs = rNd.GetpSwpHints() )
1178     {
1179         m_rExport.m_aCurrentCharPropStarts.push( nPos );
1180         const xub_StrLen* pEnd;
1181         for ( sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i )
1182         {
1183             const SwTxtAttr* pHt = (*pTxtAttrs)[i];
1184             const SfxPoolItem* pItem = &pHt->GetAttr();
1185             switch ( pItem->Which() )
1186             {
1187                 case RES_TXTATR_INETFMT:
1188                     if ( nPos == *pHt->GetStart() )
1189                     {
1190                         const SwFmtINetFmt *rINet = static_cast< const SwFmtINetFmt* >( pItem );
1191                         if ( m_rExport.AttrOutput().StartURL( rINet->GetValue(), rINet->GetTargetFrame() ) )
1192                             ++nRet;
1193                     }
1194                     if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1195                     {
1196                         if ( m_rExport.AttrOutput().EndURL() )
1197                             --nRet;
1198                     }
1199                     break;
1200                 case RES_TXTATR_REFMARK:
1201                     if ( nPos == *pHt->GetStart() )
1202                     {
1203                         OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), true );
1204                         ++nRet;
1205                     }
1206                     if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1207                     {
1208                         OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), false );
1209                         --nRet;
1210                     }
1211                     break;
1212                 case RES_TXTATR_TOXMARK:
1213                     if ( nPos == *pHt->GetStart() )
1214                         m_rExport.AttrOutput().TOXMark( rNd, *static_cast< const SwTOXMark* >( pItem ) );
1215                     break;
1216                 case RES_TXTATR_CJK_RUBY:
1217                     if ( nPos == *pHt->GetStart() )
1218                     {
1219                         m_rExport.AttrOutput().StartRuby( rNd, *static_cast< const SwFmtRuby* >( pItem ) );
1220                         ++nRet;
1221                     }
1222                     if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1223                     {
1224                         m_rExport.AttrOutput().EndRuby();
1225                         --nRet;
1226                     }
1227                     break;
1228             }
1229         }
1230         m_rExport.m_aCurrentCharPropStarts.pop(); // HasTextItem nur in dem obigen Bereich erlaubt
1231     }
1232     return nRet;
1233 }
1234 
1235 bool WW8SwAttrIter::IsRedlineAtEnd( xub_StrLen nEnd ) const
1236 {
1237     bool bRet = false;
1238     // search next Redline
1239     for( sal_uInt16 nPos = nCurRedlinePos;
1240         nPos < m_rExport.pDoc->GetRedlineTbl().Count(); ++nPos )
1241     {
1242         const SwPosition* pEnd = m_rExport.pDoc->GetRedlineTbl()[ nPos ]->End();
1243         if( pEnd->nNode == rNd )
1244         {
1245             if( pEnd->nContent.GetIndex() == nEnd )
1246             {
1247                 bRet = true;
1248                 break;
1249             }
1250         }
1251         else
1252             break;
1253     }
1254     return bRet;
1255 }
1256 
1257 const SwRedlineData* WW8SwAttrIter::GetRedline( xub_StrLen nPos )
1258 {
1259     if( pCurRedline )
1260     {
1261         const SwPosition* pEnd = pCurRedline->End();
1262         if( pEnd->nNode == rNd &&
1263             pEnd->nContent.GetIndex() <= nPos )
1264         {
1265             pCurRedline = 0;
1266             ++nCurRedlinePos;
1267         }
1268         else
1269         {
1270             // write data of current redline
1271             return &( pCurRedline->GetRedlineData() );
1272         }
1273     }
1274 
1275     if( !pCurRedline )
1276     {
1277         // search next Redline
1278         for( ; nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().Count();
1279                 ++nCurRedlinePos )
1280         {
1281             const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nCurRedlinePos ];
1282 
1283             const SwPosition* pStt = pRedl->Start();
1284             const SwPosition* pEnd = pStt == pRedl->GetPoint()
1285                                         ? pRedl->GetMark()
1286                                         : pRedl->GetPoint();
1287 
1288             if( pStt->nNode == rNd )
1289             {
1290                 if( pStt->nContent.GetIndex() >= nPos )
1291                 {
1292                     if( pStt->nContent.GetIndex() == nPos )
1293                     {
1294                         // write data of this redline
1295                         pCurRedline = pRedl;
1296                         return &( pCurRedline->GetRedlineData() );
1297                     }
1298                     break;
1299                 }
1300             }
1301             else
1302                 break;
1303 
1304             if( pEnd->nNode == rNd &&
1305                 pEnd->nContent.GetIndex() < nPos )
1306             {
1307                 pCurRedline = pRedl;
1308                 break;
1309             }
1310         }
1311     }
1312     return NULL;
1313 }
1314 
1315 /*  */
1316 
1317 short MSWordExportBase::GetCurrentPageDirection() const
1318 {
1319     const SwFrmFmt &rFmt = pAktPageDesc
1320                     ? pAktPageDesc->GetMaster()
1321                     : const_cast<const SwDoc *>( pDoc )->GetPageDesc( 0 ).GetMaster();
1322     return rFmt.GetFrmDir().GetValue();
1323 }
1324 
1325 short MSWordExportBase::GetDefaultFrameDirection( ) const
1326 {
1327     short nDir = FRMDIR_ENVIRONMENT;
1328 
1329     if ( bOutPageDescs )
1330         nDir = GetCurrentPageDirection(  );
1331     else if ( pOutFmtNode )
1332     {
1333         if ( bOutFlyFrmAttrs ) //frame
1334         {
1335             nDir = TrueFrameDirection( *( const SwFrmFmt * ) pOutFmtNode );
1336         }
1337         else if ( pOutFmtNode->ISA( SwCntntNode ) )    //pagagraph
1338         {
1339             const SwCntntNode *pNd = ( const SwCntntNode * ) pOutFmtNode;
1340             SwPosition aPos( *pNd );
1341             nDir = pDoc->GetTextDirection( aPos );
1342         }
1343         else if ( pOutFmtNode->ISA( SwTxtFmtColl ) )
1344             nDir = FRMDIR_HORI_LEFT_TOP;    //what else can we do :-(
1345     }
1346 
1347     if ( nDir == FRMDIR_ENVIRONMENT )
1348         nDir = FRMDIR_HORI_LEFT_TOP;        //Set something
1349 
1350     return nDir;
1351 }
1352 
1353 short MSWordExportBase::TrueFrameDirection( const SwFrmFmt &rFlyFmt ) const
1354 {
1355     const SwFrmFmt *pFlyFmt = &rFlyFmt;
1356     const SvxFrameDirectionItem* pItem = 0;
1357     while ( pFlyFmt )
1358     {
1359         pItem = &pFlyFmt->GetFrmDir();
1360         if ( FRMDIR_ENVIRONMENT == pItem->GetValue() )
1361         {
1362             pItem = 0;
1363             const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor();
1364             if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) &&
1365                 pAnchor->GetCntntAnchor() )
1366             {
1367                 pFlyFmt = pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt();
1368             }
1369             else
1370                 pFlyFmt = 0;
1371         }
1372         else
1373             pFlyFmt = 0;
1374     }
1375 
1376     short nRet;
1377     if ( pItem )
1378         nRet = pItem->GetValue();
1379     else
1380         nRet = GetCurrentPageDirection();
1381 
1382     ASSERT( nRet != FRMDIR_ENVIRONMENT, "leaving with environment direction" );
1383     return nRet;
1384 }
1385 
1386 const SvxBrushItem* WW8Export::GetCurrentPageBgBrush() const
1387 {
1388     const SwFrmFmt  &rFmt = pAktPageDesc
1389                     ? pAktPageDesc->GetMaster()
1390                     : const_cast<const SwDoc *>(pDoc)->GetPageDesc(0).GetMaster();
1391 
1392     const SfxPoolItem* pItem = 0;
1393     //If not set, or "no fill", get real bg
1394     SfxItemState eState = rFmt.GetItemState(RES_BACKGROUND, true, &pItem);
1395 
1396     const SvxBrushItem* pRet = (const SvxBrushItem*)pItem;
1397     if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() &&
1398         pRet->GetColor() == COL_TRANSPARENT))
1399     {
1400         pRet = &(DefaultItemGet<SvxBrushItem>(*pDoc,RES_BACKGROUND));
1401     }
1402     return pRet;
1403 }
1404 
1405 SvxBrushItem WW8Export::TrueFrameBgBrush(const SwFrmFmt &rFlyFmt) const
1406 {
1407     const SwFrmFmt *pFlyFmt = &rFlyFmt;
1408     const SvxBrushItem* pRet = 0;
1409 
1410     while (pFlyFmt)
1411     {
1412         //If not set, or "no fill", get real bg
1413         const SfxPoolItem* pItem = 0;
1414         SfxItemState eState =
1415             pFlyFmt->GetItemState(RES_BACKGROUND, true, &pItem);
1416         pRet = (const SvxBrushItem*)pItem;
1417         if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() &&
1418             pRet->GetColor() == COL_TRANSPARENT))
1419         {
1420             pRet = 0;
1421             const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor();
1422             if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) &&
1423                 pAnchor->GetCntntAnchor())
1424             {
1425                 pFlyFmt =
1426                     pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt();
1427             }
1428             else
1429                 pFlyFmt = 0;
1430         }
1431         else
1432             pFlyFmt = 0;
1433     }
1434 
1435     if (!pRet)
1436         pRet = GetCurrentPageBgBrush();
1437 
1438     const Color aTmpColor( COL_WHITE );
1439     SvxBrushItem aRet( aTmpColor, RES_BACKGROUND );
1440     if (pRet && (pRet->GetGraphic() ||( pRet->GetColor() != COL_TRANSPARENT)))
1441         aRet = *pRet;
1442 
1443     return aRet;
1444 }
1445 
1446 
1447 /*
1448 Convert characters that need to be converted, the basic replacements and the
1449 ridicously complicated title case attribute mapping to hardcoded upper case
1450 because word doesn't have the feature
1451 */
1452 String WW8SwAttrIter::GetSnippet(const String &rStr, xub_StrLen nAktPos,
1453     xub_StrLen nLen) const
1454 {
1455     String aSnippet(rStr, nAktPos, nLen);
1456     if (!nLen)
1457         return aSnippet;
1458 
1459     // 0x0a     ( Hard Line Break ) -> 0x0b
1460     // 0xad     ( soft hyphen )     -> 0x1f
1461     // 0x2011   ( hard hyphen )     -> 0x1e
1462     aSnippet.SearchAndReplaceAll(0x0A, 0x0B);
1463     aSnippet.SearchAndReplaceAll(CHAR_HARDHYPHEN, 0x1e);
1464     aSnippet.SearchAndReplaceAll(CHAR_SOFTHYPHEN, 0x1f);
1465 
1466     m_rExport.m_aCurrentCharPropStarts.push( nAktPos );
1467     const SfxPoolItem &rItem = GetItem(RES_CHRATR_CASEMAP);
1468 
1469     if (SVX_CASEMAP_TITEL == ((const SvxCaseMapItem&)rItem).GetValue())
1470     {
1471         sal_uInt16 nScriptType = i18n::ScriptType::LATIN;
1472         if (pBreakIt->GetBreakIter().is())
1473             nScriptType = pBreakIt->GetBreakIter()->getScriptType(aSnippet, 0);
1474 
1475         LanguageType nLanguage;
1476         switch (nScriptType)
1477         {
1478         case i18n::ScriptType::ASIAN:
1479                 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CJK_LANGUAGE)).GetLanguage();
1480                 break;
1481         case i18n::ScriptType::COMPLEX:
1482                 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CTL_LANGUAGE)).GetLanguage();
1483                 break;
1484         case i18n::ScriptType::LATIN:
1485             default:
1486                 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_LANGUAGE)).GetLanguage();
1487                 break;
1488         }
1489 
1490         SvxFont aFontHelper;
1491         aFontHelper.SetCaseMap(SVX_CASEMAP_TITEL);
1492         aFontHelper.SetLanguage(nLanguage);
1493         aSnippet = aFontHelper.CalcCaseMap(aSnippet);
1494 
1495         //If we weren't at the begin of a word undo the case change.
1496         //not done before doing the casemap because the sequence might start
1497         //with whitespace
1498         if (pBreakIt->GetBreakIter().is() && !pBreakIt->GetBreakIter()->isBeginWord(
1499             rStr, nAktPos, pBreakIt->GetLocale(nLanguage),
1500             i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
1501         {
1502             aSnippet.SetChar(0, rStr.GetChar(nAktPos));
1503         }
1504     }
1505     m_rExport.m_aCurrentCharPropStarts.pop();
1506 
1507     return aSnippet;
1508 }
1509 
1510 /** Delivers the right paragraph style
1511 
1512     Because of the different style handling for delete operations,
1513     the track changes have to be analysed. A deletion, starting in paragraph A
1514     with style A, ending in paragraph B with style B, needs a hack.
1515 */
1516 static SwTxtFmtColl& lcl_getFormatCollection( MSWordExportBase& rExport, const SwTxtNode* pTxtNode )
1517 {
1518     sal_uInt16 nPos = 0;
1519     sal_uInt16 nMax = rExport.pDoc->GetRedlineTbl().Count();
1520     while( nPos < nMax )
1521     {
1522         const SwRedline* pRedl = rExport.pDoc->GetRedlineTbl()[ nPos++ ];
1523         const SwPosition* pStt = pRedl->Start();
1524         const SwPosition* pEnd = pStt == pRedl->GetPoint()
1525                                     ? pRedl->GetMark()
1526                                     : pRedl->GetPoint();
1527         // Looking for deletions, which ends in current pTxtNode
1528         if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetRedlineData().GetType() &&
1529             pEnd->nNode == *pTxtNode && pStt->nNode != *pTxtNode &&
1530             pStt->nNode.GetNode().IsTxtNode() )
1531         {
1532             pTxtNode = pStt->nNode.GetNode().GetTxtNode();
1533             nMax = nPos;
1534             nPos = 0;
1535         }
1536     }
1537     return static_cast<SwTxtFmtColl&>( pTxtNode->GetAnyFmtColl() );
1538 }
1539 
1540 void WW8AttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop &rSwFmtDrop, sal_uInt16 nStyle,
1541         ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo, ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner )
1542 {
1543     short nDropLines = rSwFmtDrop.GetLines();
1544     short nDistance = rSwFmtDrop.GetDistance();
1545     int rFontHeight, rDropHeight, rDropDescent;
1546 
1547     SVBT16 nSty;
1548     ShortToSVBT16( nStyle, nSty );
1549     m_rWW8Export.pO->Insert( (sal_uInt8*)&nSty, 2, m_rWW8Export.pO->Count() );     // Style #
1550 
1551     if ( m_rWW8Export.bWrtWW8 )
1552     {
1553         m_rWW8Export.InsUInt16( NS_sprm::LN_PPc );            // Alignment (sprmPPc)
1554         m_rWW8Export.pO->Insert( 0x20, m_rWW8Export.pO->Count() );
1555 
1556         m_rWW8Export.InsUInt16( NS_sprm::LN_PWr );            // Wrapping (sprmPWr)
1557         m_rWW8Export.pO->Insert( 0x02, m_rWW8Export.pO->Count() );
1558 
1559         m_rWW8Export.InsUInt16( NS_sprm::LN_PDcs );            // Dropcap (sprmPDcs)
1560         int nDCS = ( nDropLines << 3 ) | 0x01;
1561         m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( nDCS ) );
1562 
1563         m_rWW8Export.InsUInt16( NS_sprm::LN_PDxaFromText );            // Distance from text (sprmPDxaFromText)
1564         m_rWW8Export.InsUInt16( nDistance );
1565 
1566         if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) )
1567         {
1568             m_rWW8Export.InsUInt16( NS_sprm::LN_PDyaLine );            // Line spacing
1569             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -rDropHeight ) );
1570             m_rWW8Export.InsUInt16( 0 );
1571         }
1572     }
1573     else
1574     {
1575         m_rWW8Export.pO->Insert( 29, m_rWW8Export.pO->Count() );    // Alignment (sprmPPc)
1576         m_rWW8Export.pO->Insert( 0x20, m_rWW8Export.pO->Count() );
1577 
1578         m_rWW8Export.pO->Insert( 37, m_rWW8Export.pO->Count() );    // Wrapping (sprmPWr)
1579         m_rWW8Export.pO->Insert( 0x02, m_rWW8Export.pO->Count() );
1580 
1581         m_rWW8Export.pO->Insert( 46, m_rWW8Export.pO->Count() );    // Dropcap (sprmPDcs)
1582         int nDCS = ( nDropLines << 3 ) | 0x01;
1583         m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( nDCS ) );
1584 
1585         m_rWW8Export.pO->Insert( 49, m_rWW8Export.pO->Count() );      // Distance from text (sprmPDxaFromText)
1586         m_rWW8Export.InsUInt16( nDistance );
1587 
1588         if (rNode.GetDropSize(rFontHeight, rDropHeight, rDropDescent))
1589         {
1590             m_rWW8Export.pO->Insert( 20, m_rWW8Export.pO->Count() );  // Line spacing
1591             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -rDropHeight ) );
1592             m_rWW8Export.InsUInt16( 0 );
1593         }
1594     }
1595 
1596     m_rWW8Export.WriteCR( pTextNodeInfoInner );
1597 
1598     if ( pTextNodeInfo.get() != NULL )
1599     {
1600 #ifdef DEBUG
1601         ::std::clog << pTextNodeInfo->toString() << ::std::endl;
1602 #endif
1603 
1604         TableInfoCell( pTextNodeInfoInner );
1605     }
1606 
1607     m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() );
1608     m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() );
1609 
1610     if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) )
1611     {
1612         if ( m_rWW8Export.bWrtWW8 )
1613         {
1614             const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt();
1615             if ( pSwCharFmt )
1616             {
1617                 m_rWW8Export.InsUInt16( NS_sprm::LN_CIstd );
1618                 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) );
1619             }
1620 
1621             m_rWW8Export.InsUInt16( NS_sprm::LN_CHpsPos );            // Lower the chars
1622             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) );
1623 
1624             m_rWW8Export.InsUInt16( NS_sprm::LN_CHps );            // Font Size
1625             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( rFontHeight / 10 ) );
1626         }
1627         else
1628         {
1629             const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt();
1630             if ( pSwCharFmt )
1631             {
1632                 m_rWW8Export.InsUInt16( 80 );
1633                 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) );
1634             }
1635 
1636             m_rWW8Export.pO->Insert( 101, m_rWW8Export.pO->Count() );      // Lower the chars
1637             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) );
1638 
1639             m_rWW8Export.pO->Insert( 99, m_rWW8Export.pO->Count() );      // Font Size
1640             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( rFontHeight / 10 ) );
1641         }
1642     }
1643 
1644     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() );
1645     m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() );
1646 }
1647 
1648 xub_StrLen MSWordExportBase::GetNextPos( WW8SwAttrIter* aAttrIter, const SwTxtNode& rNode, xub_StrLen nAktPos  )
1649 {
1650     // Get the bookmarks for the normal run
1651     xub_StrLen nNextPos = aAttrIter->WhereNext();
1652     xub_StrLen nNextBookmark = nNextPos;
1653 
1654     if( nNextBookmark > nAktPos )//no need to search for bookmarks otherwise
1655     {
1656         GetSortedBookmarks( rNode, nAktPos, nNextBookmark - nAktPos );
1657         NearestBookmark( nNextBookmark, nAktPos, false );
1658     }
1659     return std::min( nNextPos, nNextBookmark );
1660 }
1661 
1662 void MSWordExportBase::UpdatePosition( WW8SwAttrIter* aAttrIter, xub_StrLen nAktPos, xub_StrLen /*nEnd*/ )
1663 {
1664     xub_StrLen nNextPos;
1665 
1666     // go to next attribute if no bookmark is found and if the next attribute position if at the current position
1667     bool bNextBookmark = NearestBookmark( nNextPos, nAktPos, true );
1668     if( !bNextBookmark && nAktPos >= aAttrIter->WhereNext() )
1669         aAttrIter->NextPos();
1670 }
1671 
1672 bool MSWordExportBase::GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt,
1673                     xub_StrLen nEnd, IMarkVector& rArr )
1674 {
1675     IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1676     sal_uLong nNd = rNd.GetIndex( );
1677 
1678     const sal_Int32 nMarks = pMarkAccess->getMarksCount();
1679     for ( sal_Int32 i = 0; i < nMarks; i++ )
1680     {
1681         IMark* pMark = ( pMarkAccess->getMarksBegin() + i )->get();
1682 
1683         // Only keep the bookmarks starting or ending in this node
1684         if ( pMark->GetMarkStart().nNode == nNd ||
1685              pMark->GetMarkEnd().nNode == nNd )
1686         {
1687             xub_StrLen nBStart = pMark->GetMarkStart().nContent.GetIndex();
1688             xub_StrLen nBEnd = pMark->GetMarkEnd().nContent.GetIndex();
1689 
1690             // Keep only the bookmars starting or ending in the snippet
1691             bool bIsStartOk = ( nBStart >= nStt ) && ( nBStart <= nEnd );
1692             bool bIsEndOk = ( nBEnd >= nStt ) && ( nBEnd <= nEnd );
1693 
1694             if ( bIsStartOk || bIsEndOk )
1695                 rArr.push_back( pMark );
1696         }
1697     }
1698     return ( rArr.size() > 0 );
1699 }
1700 
1701 class CompareMarksEnd : public std::binary_function < const IMark *, const IMark *, bool >
1702 {
1703 public:
1704     inline bool operator() ( const IMark * pOneB, const IMark * pTwoB ) const
1705     {
1706         xub_StrLen nOEnd = pOneB->GetMarkEnd().nContent.GetIndex();
1707         xub_StrLen nTEnd = pTwoB->GetMarkEnd().nContent.GetIndex();
1708 
1709         return nOEnd < nTEnd;
1710     }
1711 };
1712 
1713 bool MSWordExportBase::NearestBookmark( xub_StrLen& rNearest, const xub_StrLen nAktPos, bool bNextPositionOnly )
1714 {
1715     bool bHasBookmark = false;
1716 
1717     if ( m_rSortedMarksStart.size( ) > 0 )
1718     {
1719         IMark* pMarkStart = m_rSortedMarksStart.front();
1720         xub_StrLen nNext = pMarkStart->GetMarkStart().nContent.GetIndex();
1721         if( !bNextPositionOnly || (nNext > nAktPos ))
1722         {
1723             rNearest = nNext;
1724             bHasBookmark = true;
1725         }
1726     }
1727 
1728     if ( m_rSortedMarksEnd.size( ) > 0 )
1729     {
1730         IMark* pMarkEnd = m_rSortedMarksEnd[0];
1731         xub_StrLen nNext = pMarkEnd->GetMarkEnd().nContent.GetIndex();
1732         if( !bNextPositionOnly || nNext > nAktPos )
1733         {
1734             if ( !bHasBookmark )
1735                 rNearest = nNext;
1736             else
1737                 rNearest = std::min( rNearest, nNext );
1738             bHasBookmark = true;
1739         }
1740     }
1741 
1742     return bHasBookmark;
1743 }
1744 
1745 void MSWordExportBase::GetSortedBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen )
1746 {
1747     IMarkVector aMarksStart;
1748     if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarksStart ) )
1749     {
1750         IMarkVector aSortedEnd;
1751         IMarkVector aSortedStart;
1752         for ( IMarkVector::const_iterator it = aMarksStart.begin(), end = aMarksStart.end();
1753               it < end; ++it )
1754         {
1755             IMark* pMark = (*it);
1756 
1757             // Remove the positions egals to the current pos
1758             xub_StrLen nStart = pMark->GetMarkStart().nContent.GetIndex();
1759             xub_StrLen nEnd = pMark->GetMarkEnd().nContent.GetIndex();
1760 
1761             if ( nStart > nAktPos && ( pMark->GetMarkStart().nNode == rNode.GetIndex()) )
1762                 aSortedStart.push_back( pMark );
1763 
1764             if ( nEnd > nAktPos && nEnd <= ( nAktPos + nLen ) && (pMark->GetMarkEnd().nNode == rNode.GetIndex()) )
1765                 aSortedEnd.push_back( pMark );
1766         }
1767 
1768         // Sort the bookmarks by end position
1769         std::sort( aSortedEnd.begin(), aSortedEnd.end(), CompareMarksEnd() );
1770 
1771         m_rSortedMarksStart.swap( aSortedStart );
1772         m_rSortedMarksEnd.swap( aSortedEnd );
1773     }
1774     else
1775     {
1776         m_rSortedMarksStart.clear( );
1777         m_rSortedMarksEnd.clear( );
1778     }
1779 }
1780 
1781 void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode )
1782 {
1783 #ifdef DEBUG
1784     ::std::clog << "<OutWW8_SwTxtNode>" << ::std::endl;
1785 #endif
1786 
1787     ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo( mpTableInfo->getTableNodeInfo( &rNode ) );
1788 
1789     AttrOutput().StartParagraph( pTextNodeInfo );
1790 
1791     bool bFlyInTable = mpParentFrame && IsInTable();
1792 
1793     if ( !bFlyInTable )
1794         nStyleBeforeFly = GetId( lcl_getFormatCollection( *this, &rNode ) );
1795 
1796     // nStyleBeforeFly may change when we recurse into another node, so we
1797     // have to remember it in nStyle
1798     sal_uInt16 nStyle = nStyleBeforeFly;
1799 
1800     WW8SwAttrIter aAttrIter( *this, rNode );
1801     rtl_TextEncoding eChrSet = aAttrIter.GetCharSet();
1802 
1803     if ( bStartTOX )
1804     {
1805         // ignore TOX header section
1806         const SwSectionNode* pSectNd = rNode.FindSectionNode();
1807         if ( pSectNd && TOX_CONTENT_SECTION == pSectNd->GetSection().GetType() )
1808         {
1809             AttrOutput().StartTOX( pSectNd->GetSection() );
1810             m_aCurrentCharPropStarts.push( 0 );
1811         }
1812     }
1813 
1814     const SwSection* pTOXSect = 0;
1815     if( bInWriteTOX )
1816     {
1817         // check for end of TOX
1818         SwNodeIndex aIdx( rNode, 1 );
1819         if( !aIdx.GetNode().IsTxtNode() )
1820         {
1821             const SwSectionNode* pTOXSectNd = rNode.FindSectionNode();
1822             pTOXSect = &pTOXSectNd->GetSection();
1823 
1824             const SwNode* pNxt = rNode.GetNodes().GoNext( &aIdx );
1825             if( pNxt && pNxt->FindSectionNode() == pTOXSectNd )
1826                 pTOXSect = 0;
1827         }
1828     }
1829 
1830     if ( aAttrIter.RequiresImplicitBookmark() )
1831     {
1832         String sBkmkName = String( RTL_CONSTASCII_STRINGPARAM( "_toc" ) );
1833         sBkmkName += String::CreateFromInt32( rNode.GetIndex() );
1834         AppendWordBookmark( sBkmkName );
1835     }
1836 
1837     //Would need to move into WW8Export, probably not worth it
1838     //ASSERT( pO->Count(), " pO ist am Zeilenanfang nicht leer" );
1839 
1840     String aStr( rNode.GetTxt() );
1841 
1842     xub_StrLen nAktPos = 0;
1843     xub_StrLen const nEnd = aStr.Len();
1844     bool bRedlineAtEnd = false;
1845     int nOpenAttrWithRange = 0;
1846 
1847     ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner;
1848     if ( pTextNodeInfo.get() != NULL )
1849         pTextNodeInfoInner = pTextNodeInfo->getFirstInner();
1850 
1851     do {
1852         const SwRedlineData* pRedlineData = aAttrIter.GetRedline( nAktPos );
1853 
1854         AttrOutput().StartRun( pRedlineData );
1855 
1856         xub_StrLen nNextAttr = GetNextPos( &aAttrIter, rNode, nAktPos );
1857 
1858         if( nNextAttr > nEnd )
1859             nNextAttr = nEnd;
1860 
1861         aAttrIter.OutFlys( nAktPos );
1862         //Append bookmarks in this range after flys, exclusive of final
1863         //position of this range
1864         AppendBookmarks( rNode, nAktPos, nNextAttr - nAktPos );
1865         bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos );
1866         nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nAktPos);
1867 
1868         xub_StrLen nLen = nNextAttr - nAktPos;
1869         if ( !bTxtAtr && nLen )
1870         {
1871             sal_Unicode ch = aStr.GetChar( nAktPos );
1872             int ofs = ( ch == CH_TXT_ATR_FIELDSTART || ch == CH_TXT_ATR_FIELDEND || ch == CH_TXT_ATR_FORMELEMENT? 1: 0 );
1873 
1874             IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1875             if ( ch == CH_TXT_ATR_FIELDSTART )
1876             {
1877                 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos + 1 ) );
1878                 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1879                 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
1880 
1881                 if ( pFieldmark->GetFieldname().equalsAscii( ODF_FORMTEXT ) )
1882                     AppendBookmark( pFieldmark->GetName(), false );
1883                 OutputField( NULL, lcl_getFieldId( pFieldmark ), lcl_getFieldCode( pFieldmark ), WRITEFIELD_START | WRITEFIELD_CMD_START );
1884                 if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) )
1885                     WriteFormData( *pFieldmark );
1886                 else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) )
1887                     WriteHyperlinkData( *pFieldmark );
1888                 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CMD_END );
1889             }
1890             else if ( ch == CH_TXT_ATR_FIELDEND )
1891             {
1892                 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) );
1893                 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1894                 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
1895 
1896                 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE );
1897                 if ( pFieldmark->GetFieldname().equalsAscii( ODF_FORMTEXT ) )
1898                     AppendBookmark( pFieldmark->GetName(), false );
1899             }
1900             else if ( ch == CH_TXT_ATR_FORMELEMENT )
1901             {
1902                 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) );
1903                 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1904                 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
1905 
1906                 bool isDropdownOrCheckbox = pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ||
1907                     pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX );
1908 
1909                 if ( isDropdownOrCheckbox )
1910                     AppendBookmark( pFieldmark->GetName(), 0 );
1911                 OutputField( NULL, lcl_getFieldId( pFieldmark ),
1912                         lcl_getFieldCode( pFieldmark ),
1913                         WRITEFIELD_START | WRITEFIELD_CMD_START );
1914                 if ( isDropdownOrCheckbox )
1915                     WriteFormData( *pFieldmark );
1916                 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE );
1917                 if ( isDropdownOrCheckbox )
1918                     AppendBookmark( pFieldmark->GetName(), false );
1919             }
1920             nLen -= static_cast< sal_uInt16 >( ofs );
1921 
1922             String aSnippet( aAttrIter.GetSnippet( aStr, nAktPos + static_cast< sal_uInt16 >( ofs ), nLen ) );
1923             if ( ( nTxtTyp == TXT_EDN || nTxtTyp == TXT_FTN ) && nAktPos == 0 && nLen > 0 )
1924             {
1925                 // Insert tab for aesthetic puposes #i24762#
1926                 if ( aSnippet.GetChar( 0 ) != 0x09 )
1927                     aSnippet.Insert( 0x09, 0 );
1928             }
1929             AttrOutput().RunText( aSnippet, eChrSet );
1930         }
1931 
1932         if ( aAttrIter.IsDropCap( nNextAttr ) )
1933             AttrOutput().FormatDrop( rNode, aAttrIter.GetSwFmtDrop(), nStyle, pTextNodeInfo, pTextNodeInfoInner );
1934 
1935         if (0 != nEnd)
1936         {
1937             // Output the character attributes
1938             // #i51277# do this before writing flys at end of paragraph
1939             AttrOutput().StartRunProperties();
1940             aAttrIter.OutAttr( nAktPos );
1941             AttrOutput().EndRunProperties( pRedlineData );
1942         }
1943 
1944         // At the end of line, output the attributes until the CR.
1945         // Exception: footnotes at the end of line
1946         if ( nNextAttr == nEnd )
1947         {
1948             ASSERT( nOpenAttrWithRange >= 0, "odd to see this happening, expected >= 0" );
1949             if ( !bTxtAtr && nOpenAttrWithRange <= 0 )
1950             {
1951                 if ( aAttrIter.IsRedlineAtEnd( nEnd ) )
1952                     bRedlineAtEnd = true;
1953                 else
1954                 {
1955                     // insert final graphic anchors if any before CR
1956                     aAttrIter.OutFlys( nEnd );
1957                     // insert final bookmarks if any before CR and after flys
1958                     AppendBookmarks( rNode, nEnd, 1 );
1959                     if ( pTOXSect )
1960                     {
1961                         m_aCurrentCharPropStarts.pop();
1962                         AttrOutput().EndTOX( *pTOXSect );
1963                     }
1964                     WriteCR( pTextNodeInfoInner );
1965                 }
1966             }
1967         }
1968 
1969         if (0 == nEnd)
1970         {
1971             // Output the character attributes
1972             // do it after WriteCR for an empty paragraph (otherwise
1973             // WW8_WrFkp::Append throws SPRMs away...)
1974             AttrOutput().StartRunProperties();
1975             aAttrIter.OutAttr( nAktPos );
1976             AttrOutput().EndRunProperties( pRedlineData );
1977         }
1978 
1979         // Exception: footnotes at the end of line
1980         if ( nNextAttr == nEnd )
1981         {
1982             ASSERT(nOpenAttrWithRange >= 0,
1983                 "odd to see this happening, expected >= 0");
1984             bool bAttrWithRange = (nOpenAttrWithRange > 0);
1985             if ( nAktPos != nEnd )
1986             {
1987                 nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nEnd);
1988                 ASSERT(nOpenAttrWithRange == 0,
1989                     "odd to see this happening, expected 0");
1990             }
1991 
1992             AttrOutput().OutputFKP();
1993 
1994             if ( bTxtAtr || bAttrWithRange || bRedlineAtEnd )
1995             {
1996                 // insert final graphic anchors if any before CR
1997                 aAttrIter.OutFlys( nEnd );
1998                 // insert final bookmarks if any before CR and after flys
1999                 AppendBookmarks( rNode, nEnd, 1 );
2000 
2001                 if ( pTOXSect )
2002                 {
2003                     m_aCurrentCharPropStarts.pop();
2004                     AttrOutput().EndTOX( *pTOXSect );
2005                 }
2006 
2007                 WriteCR( pTextNodeInfoInner );
2008 
2009                 if ( bRedlineAtEnd )
2010                 {
2011                     AttrOutput().Redline( aAttrIter.GetRedline( nEnd ) );
2012                     AttrOutput().OutputFKP();
2013                 }
2014             }
2015         }
2016 
2017         AttrOutput().EndRun();
2018 
2019         nAktPos = nNextAttr;
2020         UpdatePosition( &aAttrIter, nAktPos, nEnd );
2021         eChrSet = aAttrIter.GetCharSet();
2022     }
2023     while ( nAktPos < nEnd );
2024 
2025     AttrOutput().StartParagraphProperties( rNode );
2026 
2027     AttrOutput().ParagraphStyle( nStyle );
2028 
2029     if ( mpParentFrame && IsInTable() )    // Fly-Attrs
2030         OutputFormat( mpParentFrame->GetFrmFmt(), false, false, true );
2031 
2032     if ( pTextNodeInfo.get() != NULL )
2033     {
2034 #ifdef DEBUG
2035         ::std::clog << pTextNodeInfo->toString() << ::std::endl;
2036 #endif
2037 
2038         AttrOutput().TableInfoCell( pTextNodeInfoInner );
2039         if (pTextNodeInfoInner->isFirstInTable())
2040         {
2041             const SwTable * pTable = pTextNodeInfoInner->getTable();
2042 
2043             const SwTableFmt * pTabFmt = pTable->GetTableFmt();
2044             if (pTabFmt != NULL)
2045             {
2046                 if (pTabFmt->GetBreak().GetBreak() == SVX_BREAK_PAGE_BEFORE)
2047                     AttrOutput().PageBreakBefore(true);
2048             }
2049         }
2050     }
2051 
2052     if ( !bFlyInTable )
2053     {
2054         SfxItemSet* pTmpSet = 0;
2055         const sal_uInt8 nPrvNxtNd = rNode.HasPrevNextLayNode();
2056 
2057         if( (ND_HAS_PREV_LAYNODE|ND_HAS_NEXT_LAYNODE ) != nPrvNxtNd )
2058         {
2059             const SfxPoolItem* pItem;
2060             if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState(
2061                     RES_UL_SPACE, true, &pItem ) &&
2062                 ( ( !( ND_HAS_PREV_LAYNODE & nPrvNxtNd ) &&
2063                    ((SvxULSpaceItem*)pItem)->GetUpper()) ||
2064                   ( !( ND_HAS_NEXT_LAYNODE & nPrvNxtNd ) &&
2065                    ((SvxULSpaceItem*)pItem)->GetLower()) ))
2066             {
2067                 pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
2068                 SvxULSpaceItem aUL( *(SvxULSpaceItem*)pItem );
2069                 // OD, MMAHER 2004-03-01 #i25901#- consider compatibility option
2070                 if (!pDoc->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES))
2071                 {
2072                     if( !(ND_HAS_PREV_LAYNODE & nPrvNxtNd ))
2073                         aUL.SetUpper( 0 );
2074                 }
2075                 // OD, MMAHER 2004-03-01 #i25901# - consider compatibility option
2076                 if (!pDoc->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS))
2077                 {
2078                     if( !(ND_HAS_NEXT_LAYNODE & nPrvNxtNd ))
2079                         aUL.SetLower( 0 );
2080                 }
2081                 pTmpSet->Put( aUL );
2082             }
2083         }
2084 
2085         sal_Bool bParaRTL = sal_False;
2086         const SvxFrameDirectionItem* pItem = (const SvxFrameDirectionItem*)
2087             rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR);
2088         if ( aAttrIter.IsParaRTL())
2089             bParaRTL = sal_True;
2090 
2091         if( rNode.IsNumbered())
2092         {
2093             const SwNumRule* pRule = rNode.GetNumRule();
2094             sal_uInt8 nLvl = static_cast< sal_uInt8 >( rNode.GetActualListLevel() );
2095             const SwNumFmt* pFmt = pRule->GetNumFmt( nLvl );
2096             if( !pFmt )
2097                 pFmt = &pRule->Get( nLvl );
2098 
2099             if( !pTmpSet )
2100                 pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
2101 
2102             SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*pTmpSet, RES_LR_SPACE));
2103             // --> OD 2008-06-03 #i86652#
2104             if ( pFmt->GetPositionAndSpaceMode() ==
2105                                     SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2106             {
2107                 aLR.SetTxtLeft( aLR.GetTxtLeft() + pFmt->GetAbsLSpace() );
2108             }
2109             // <--
2110 
2111             if( rNode.IsNumbered() && rNode.IsCountedInList() )
2112             {
2113                 // --> OD 2008-06-03 #i86652#
2114                 if ( pFmt->GetPositionAndSpaceMode() ==
2115                                         SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2116                 {
2117                     if (bParaRTL)
2118                         aLR.SetTxtFirstLineOfstValue(pFmt->GetAbsLSpace() - pFmt->GetFirstLineOffset());
2119                     else
2120                         aLR.SetTxtFirstLineOfst(GetWordFirstLineOffset(*pFmt));
2121                 }
2122                 // <--
2123 
2124                 // --> OD 2009-03-09 #100020#
2125                 // correct fix for issue i94187
2126                 if (SFX_ITEM_SET !=
2127                     pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
2128                 {
2129                     // List style set via paragraph style - then put it into the itemset.
2130                     // This is needed to get list level and list id exported for
2131                     // the paragraph.
2132                     pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
2133 
2134                     // Put indent values into the itemset in case that the list
2135                     // style is applied via paragraph style and the list level
2136                     // indent values are not applicable.
2137                     if ( pFmt->GetPositionAndSpaceMode() ==
2138                                             SvxNumberFormat::LABEL_ALIGNMENT &&
2139                          !rNode.AreListLevelIndentsApplicable() )
2140                     {
2141                         pTmpSet->Put( aLR );
2142                     }
2143                 }
2144             }
2145             else
2146                 pTmpSet->ClearItem(RES_PARATR_NUMRULE);
2147 
2148             // --> OD 2008-06-03 #i86652#
2149             if ( pFmt->GetPositionAndSpaceMode() ==
2150                                     SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2151             {
2152                 pTmpSet->Put(aLR);
2153 
2154                 //#i21847#
2155                 SvxTabStopItem aItem(
2156                     ItemGet<SvxTabStopItem>(*pTmpSet, RES_PARATR_TABSTOP));
2157                 SvxTabStop aTabStop(pFmt->GetAbsLSpace());
2158                 aItem.Insert(aTabStop);
2159                 pTmpSet->Put(aItem);
2160 
2161                 MSWordExportBase::CorrectTabStopInSet(*pTmpSet, pFmt->GetAbsLSpace());
2162             }
2163         }
2164 
2165         /*
2166         If a given para is using the FRMDIR_ENVIRONMENT direction we
2167         cannot export that, its its ltr then that's ok as thats word's
2168         default. Otherwise we must add a RTL attribute to our export list
2169         */
2170         pItem = (const SvxFrameDirectionItem*)
2171             rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR);
2172         if (
2173             (!pItem || pItem->GetValue() == FRMDIR_ENVIRONMENT) &&
2174             aAttrIter.IsParaRTL()
2175            )
2176         {
2177             if ( !pTmpSet )
2178                 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2179 
2180             pTmpSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_RIGHT_TOP, RES_FRAMEDIR));
2181         }
2182         // --> OD 2005-10-18 #126238# - move code for handling of numbered,
2183         // but not counted paragraphs to this place. Otherwise, the paragraph
2184         // isn't exported as numbered, but not counted, if no other attribute
2185         // is found in <pTmpSet>
2186         // #i44815# adjust numbering/indents for numbered paragraphs
2187         //          without number (NO_NUMLEVEL)
2188         // #i47013# need to check rNode.GetNumRule()!=NULL as well.
2189         if ( ! rNode.IsCountedInList() && rNode.GetNumRule()!=NULL )
2190         {
2191             // WW8 does not know numbered paragraphs without number
2192             // (NO_NUMLEVEL). In WW8AttributeOutput::ParaNumRule(), we will export
2193             // the RES_PARATR_NUMRULE as list-id 0, which in WW8 means
2194             // no numbering. Here, we will adjust the indents to match
2195             // visually.
2196 
2197             if ( !pTmpSet )
2198                 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2199 
2200             // create new LRSpace item, based on the current (if present)
2201             const SfxPoolItem* pPoolItem = NULL;
2202             pTmpSet->GetItemState(RES_LR_SPACE, sal_True, &pPoolItem);
2203             SvxLRSpaceItem aLRSpace(
2204                 ( pPoolItem == NULL )
2205                     ? SvxLRSpaceItem(0, 0, 0, 0, RES_LR_SPACE)
2206                     : *static_cast<const SvxLRSpaceItem*>( pPoolItem ) );
2207 
2208             // new left margin = old left + label space
2209             const SwNumRule* pRule = rNode.GetNumRule();
2210             const SwNumFmt& rNumFmt = pRule->Get( static_cast< sal_uInt16 >(rNode.GetActualListLevel()) );
2211             // --> OD 2008-06-03 #i86652#
2212             if ( rNumFmt.GetPositionAndSpaceMode() ==
2213                                     SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2214             {
2215                 aLRSpace.SetTxtLeft( aLRSpace.GetLeft() + rNumFmt.GetAbsLSpace() );
2216 
2217                 // new first line indent = 0
2218                 // (first line indent is ignored for NO_NUMLEVEL)
2219                 if (!bParaRTL)
2220                     aLRSpace.SetTxtFirstLineOfst( 0 );
2221 
2222                 // put back the new item
2223                 pTmpSet->Put( aLRSpace );
2224             }
2225             // <--
2226 
2227             // assure that numbering rule is in <pTmpSet>
2228             if (SFX_ITEM_SET != pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
2229             {
2230                 pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
2231             }
2232         }
2233 
2234         // --> OD 2007-04-24 #i75457#
2235         // Export page break after attribute from paragraph style.
2236         // If page break attribute at the text node exist, an existing page
2237         // break after at the paragraph style hasn't got to be considered.
2238         if ( !rNode.GetpSwAttrSet() ||
2239              SFX_ITEM_SET != rNode.GetpSwAttrSet()->GetItemState(RES_BREAK, false) )
2240         {
2241             const SvxFmtBreakItem* pBreakAtParaStyle =
2242                 &(ItemGet<SvxFmtBreakItem>(rNode.GetSwAttrSet(), RES_BREAK));
2243             if ( pBreakAtParaStyle &&
2244                  pBreakAtParaStyle->GetBreak() == SVX_BREAK_PAGE_AFTER )
2245             {
2246                 if ( !pTmpSet )
2247                 {
2248                     pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2249                 }
2250                 pTmpSet->Put( *pBreakAtParaStyle );
2251             }
2252             else if( pTmpSet )
2253             {   // Even a pagedesc item is set, the break item can be set 'NONE',
2254                 // this has to be overruled.
2255                 const SwFmtPageDesc& rPageDescAtParaStyle =
2256                     ItemGet<SwFmtPageDesc>( rNode, RES_PAGEDESC );
2257                 if( rPageDescAtParaStyle.KnowsPageDesc() )
2258                     pTmpSet->ClearItem( RES_BREAK );
2259             }
2260         }
2261 
2262         // --> FME 2007-05-30 #i76520# Emulate non-splitting tables
2263         if ( bOutTable )
2264         {
2265             const SwTableNode* pTableNode = rNode.FindTableNode();
2266 
2267             if ( pTableNode )
2268             {
2269                 const SwTable& rTable = pTableNode->GetTable();
2270                 const SvxFmtKeepItem& rKeep = rTable.GetFrmFmt()->GetKeep();
2271                 const bool bKeep = rKeep.GetValue();
2272                 const bool bDontSplit = !bKeep ?
2273                                         !rTable.GetFrmFmt()->GetLayoutSplit().GetValue() :
2274                                         false;
2275 
2276                 if ( bKeep || bDontSplit )
2277                 {
2278                     // bKeep: set keep at first paragraphs in all lines
2279                     // bDontSplit : set keep at first paragraphs in all lines except from last line
2280                     // but only for non-complex tables
2281                     const SwTableBox* pBox = rNode.GetTblBox();
2282                     const SwTableLine* pLine = pBox ? pBox->GetUpper() : 0;
2283 
2284                     if ( pLine && !pLine->GetUpper() )
2285                     {
2286                         // check if box is first in that line:
2287                         if ( 0 == pLine->GetTabBoxes().GetPos( pBox ) && pBox->GetSttNd() )
2288                         {
2289                             // check if paragraph is first in that line:
2290                             if ( 1 == ( rNode.GetIndex() - pBox->GetSttNd()->GetIndex() ) )
2291                             {
2292                                 bool bSetAtPara = false;
2293                                 if ( bKeep )
2294                                     bSetAtPara = true;
2295                                 else if ( bDontSplit )
2296                                 {
2297                                     // check if pLine isn't last line in table
2298                                     if ( rTable.GetTabLines().Count() - rTable.GetTabLines().GetPos( pLine ) != 1 )
2299                                         bSetAtPara = true;
2300                                 }
2301 
2302                                 if ( bSetAtPara )
2303                                 {
2304                                     if ( !pTmpSet )
2305                                         pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2306 
2307                                     const SvxFmtKeepItem aKeepItem( sal_True, RES_KEEP );
2308                                     pTmpSet->Put( aKeepItem );
2309                                 }
2310                             }
2311                         }
2312                     }
2313                 }
2314             }
2315         }
2316         // <--
2317 
2318         const SfxItemSet* pNewSet = pTmpSet ? pTmpSet : rNode.GetpSwAttrSet();
2319         if( pNewSet )
2320         {                                               // Para-Attrs
2321             pStyAttr = &rNode.GetAnyFmtColl().GetAttrSet();
2322 
2323             const SwModify* pOldMod = pOutFmtNode;
2324             pOutFmtNode = &rNode;
2325 
2326             // Pap-Attrs, so script is not necessary
2327             OutputItemSet( *pNewSet, true, false, i18n::ScriptType::LATIN, false);
2328 
2329             pStyAttr = 0;
2330             pOutFmtNode = pOldMod;
2331 
2332             if( pNewSet != rNode.GetpSwAttrSet() )
2333                 delete pNewSet;
2334         }
2335     }
2336 
2337     AttrOutput().EndParagraphProperties();
2338 
2339     AttrOutput().EndParagraph( pTextNodeInfoInner );
2340 
2341 #ifdef DEBUG
2342     ::std::clog << "</OutWW8_SwTxtNode>" << ::std::endl;
2343 #endif
2344 }
2345 
2346 void WW8AttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t pNodeInfo )
2347 {
2348     SVBT16 nSty;
2349     ShortToSVBT16( GetExport().nStyleBeforeFly, nSty );
2350 
2351     ww8::WW8TableNodeInfo::Inners_t::const_iterator aIt( pNodeInfo->getInners().begin() );
2352     ww8::WW8TableNodeInfo::Inners_t::const_iterator aItEnd( pNodeInfo->getInners().end() );
2353 
2354     while (aIt != aItEnd)
2355     {
2356         ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second;
2357         if ( pInner->isEndOfCell() )
2358         {
2359             TableRowEnd( pInner->getDepth() );
2360 
2361             m_rWW8Export.pO->Insert( (sal_uInt8*)&nSty, 2, m_rWW8Export.pO->Count() );     // Style #
2362             TableInfoRow( pInner );
2363             m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(),
2364                                      m_rWW8Export.pO->GetData() );
2365             m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() );                       // leeren
2366         }
2367 
2368         if ( pInner->isEndOfLine() )
2369         {
2370         }
2371 
2372         aIt++;
2373     }
2374 }
2375 
2376 #if 0
2377 /*  */
2378 
2379 sal_uInt16 WW8Export::StartTableFromFrmFmt( WW8Bytes &rAt, const SwFrmFmt *pFmt )
2380 {
2381     // Tell the undocumented table hack that everything between here and
2382     // the last table position is nontable text
2383     if ( WW8_CP nPos = Fc2Cp( Strm().Tell() ) )
2384         pMagicTable->Append(nPos,0);
2385 
2386     // sprmPDxaFromText10
2387     if( bWrtWW8 )
2388     {
2389         static sal_uInt8 __READONLY_DATA  aTabLineAttr[] = {
2390                 0, 0,               // Sty # 0
2391                 0x16, 0x24, 1,      // sprmPFInTable
2392                 0x17, 0x24, 1 };    // sprmPFTtp
2393         rAt.Insert( aTabLineAttr, sizeof( aTabLineAttr ), rAt.Count() );
2394     }
2395     else
2396     {
2397         static sal_uInt8 __READONLY_DATA  aTabLineAttr[] = {
2398                 0, 0,               // Sty # 0
2399                 24, 1,              // sprmPFInTable
2400                 25, 1 };            // sprmPFTtp
2401         rAt.Insert( aTabLineAttr, sizeof( aTabLineAttr ), rAt.Count() );
2402     }
2403 
2404     ASSERT( pFmt, "No pFmt!" );
2405     if ( pFmt )
2406     {
2407         const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient();
2408         const SwFmtVertOrient &rVert = pFmt->GetVertOrient();
2409         if (
2410             (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ||
2411              text::RelOrientation::FRAME == rHori.GetRelationOrient())
2412             &&
2413             (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() ||
2414              text::RelOrientation::FRAME == rVert.GetRelationOrient())
2415            )
2416         {
2417             sal_Int16 eHOri = rHori.GetHoriOrient();
2418             switch (eHOri)
2419             {
2420                 case text::HoriOrientation::CENTER:
2421                 case text::HoriOrientation::RIGHT:
2422                     if( bWrtWW8 )
2423                         SwWW8Writer::InsUInt16( rAt, NS_sprm::LN_TJc );
2424                     else
2425                         rAt.Insert( 182, rAt.Count() );
2426                     SwWW8Writer::InsUInt16( rAt, (text::HoriOrientation::RIGHT == eHOri ? 2 : 1 ));
2427                     break;
2428                 default:
2429                     break;
2430             }
2431         }
2432     }
2433     return rAt.Count();
2434 }
2435 
2436 //See #i19484# for why we need this
2437 static bool CellContainsProblematicGraphic( const SwWriteTableCell *pCell,
2438     const MSWordExportBase &rExport )
2439 {
2440     const SwNode *pStart = pCell ? pCell->GetBox()->GetSttNd() : 0;
2441     const SwNode *pEnd = pStart ? pStart->EndOfSectionNode() : 0;
2442     ASSERT( pStart && pEnd, "No start or end?" );
2443     if ( !pStart || !pEnd )
2444         return false;
2445 
2446     bool bHasGraphic = false;
2447 
2448     sw::Frames aFrames( GetFramesBetweenNodes( rExport.maFrames, *pStart, *pEnd ) );
2449     sw::FrameIter aEnd = aFrames.end();
2450     for ( sw::FrameIter aIter = aFrames.begin(); aIter != aEnd; ++aIter )
2451     {
2452         const SwFrmFmt &rEntry = aIter->GetFrmFmt();
2453         if ( rEntry.GetSurround().GetSurround() == SURROUND_THROUGHT )
2454         {
2455             bHasGraphic = true;
2456             break;
2457         }
2458     }
2459     return bHasGraphic;
2460 }
2461 
2462 static bool RowContainsProblematicGraphic( const SwWriteTableCellPtr *pRow,
2463     sal_uInt16 nCols, const MSWordExportBase &rExport )
2464 {
2465     bool bHasGraphic = false;
2466     for ( sal_uInt16 nI = 0; nI < nCols; ++nI )
2467     {
2468         if ( CellContainsProblematicGraphic( pRow[nI], rExport ) )
2469         {
2470             bHasGraphic = true;
2471             break;
2472         }
2473     }
2474     return bHasGraphic;
2475 }
2476 #endif
2477 //---------------------------------------------------------------------------
2478 //       Tabellen
2479 //---------------------------------------------------------------------------
2480 
2481 void WW8AttributeOutput::EmptyParagraph()
2482 {
2483     m_rWW8Export.WriteStringAsPara( aEmptyStr );
2484 }
2485 
2486 bool MSWordExportBase::NoPageBreakSection( const SfxItemSet* pSet )
2487 {
2488     bool bRet = false;
2489     const SfxPoolItem* pI;
2490     if( pSet)
2491     {
2492         bool bNoPageBreak = false;
2493         if ( SFX_ITEM_ON != pSet->GetItemState(RES_PAGEDESC, true, &pI)
2494             || 0 == ((SwFmtPageDesc*)pI)->GetPageDesc() )
2495         {
2496             bNoPageBreak = true;
2497         }
2498 
2499         if (bNoPageBreak)
2500         {
2501             if (SFX_ITEM_ON != pSet->GetItemState(RES_BREAK, true, &pI))
2502                 bNoPageBreak = true;
2503             else
2504             {
2505                 SvxBreak eBreak = ((const SvxFmtBreakItem*)pI)->GetBreak();
2506                 switch (eBreak)
2507                 {
2508                     case SVX_BREAK_PAGE_BEFORE:
2509                     case SVX_BREAK_PAGE_AFTER:
2510                         bNoPageBreak = false;
2511                         break;
2512                     default:
2513                         break;
2514                 }
2515             }
2516         }
2517         bRet = bNoPageBreak;
2518     }
2519     return bRet;
2520 }
2521 
2522 /*  */
2523 
2524 void MSWordExportBase::OutputSectionNode( const SwSectionNode& rSectionNode )
2525 {
2526     const SwSection& rSection = rSectionNode.GetSection();
2527 
2528     SwNodeIndex aIdx( rSectionNode, 1 );
2529     const SwNode& rNd = aIdx.GetNode();
2530     if ( !rNd.IsSectionNode() && !IsInTable() ) //No sections in table
2531     {
2532         // Bug 74245 - if the first Node inside the section has an own
2533         //              PageDesc or PageBreak attribut, then dont write
2534         //              here the section break
2535         sal_uLong nRstLnNum = 0;
2536         const SfxItemSet* pSet;
2537         if ( rNd.IsTableNode() )
2538             pSet = &rNd.GetTableNode()->GetTable().GetFrmFmt()->GetAttrSet();
2539         else if ( rNd.IsCntntNode() )
2540         {
2541             pSet = &rNd.GetCntntNode()->GetSwAttrSet();
2542             nRstLnNum = ((SwFmtLineNumber&)pSet->Get(
2543                             RES_LINENUMBER )).GetStartValue();
2544         }
2545         else
2546             pSet = 0;
2547 
2548         if ( pSet && NoPageBreakSection( pSet ) )
2549             pSet = 0;
2550 
2551         if ( !pSet )
2552         {
2553             // new Section with no own PageDesc/-Break
2554             //  -> write follow section break;
2555             const SwSectionFmt& rFmt = *rSection.GetFmt();
2556             ReplaceCr( msword::PageBreak ); // Indikator fuer Page/Section-Break
2557 
2558             //Get the page in use at the top of this section
2559             SwNodeIndex aIdxTmp(rSectionNode, 1);
2560             const SwPageDesc *pCurrent =
2561                 SwPageDesc::GetPageDescOfNode(aIdxTmp.GetNode());
2562             if (!pCurrent)
2563                 pCurrent = pAktPageDesc;
2564 
2565             AppendSection( pCurrent, &rFmt, nRstLnNum );
2566         }
2567     }
2568     if ( TOX_CONTENT_SECTION == rSection.GetType() )
2569         bStartTOX = true;
2570 }
2571 
2572 
2573 void WW8Export::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFmt* pFmt, sal_uLong nLnNum )
2574 {
2575     pSepx->AppendSep(Fc2Cp(Strm().Tell()), pPageDesc, pFmt, nLnNum);
2576 }
2577 
2578 /*  */
2579 
2580 //---------------------------------------------------------------------------
2581 //       Flys
2582 //---------------------------------------------------------------------------
2583 
2584 void WW8Export::OutWW6FlyFrmsInCntnt( const SwTxtNode& rNd )
2585 {
2586     ASSERT(!bWrtWW8, "I shouldn't be needed for Word >=8");
2587     if ( bWrtWW8 )
2588         return;
2589 
2590     if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
2591     {
2592         for( sal_uInt16 n=0; n < pTxtAttrs->Count(); ++n )
2593         {
2594             const SwTxtAttr* pAttr = (*pTxtAttrs)[ n ];
2595             if( RES_TXTATR_FLYCNT == pAttr->Which() )
2596             {
2597                 // zeichengebundenes Attribut
2598                 const SwFmtFlyCnt& rFlyCntnt = pAttr->GetFlyCnt();
2599                 const SwFlyFrmFmt& rFlyFrmFmt = *(SwFlyFrmFmt*)rFlyCntnt.GetFrmFmt();
2600                 const SwNodeIndex* pNodeIndex = rFlyFrmFmt.GetCntnt().GetCntntIdx();
2601 
2602                 if( pNodeIndex )
2603                 {
2604                     sal_uLong nStt = pNodeIndex->GetIndex()+1,
2605                           nEnd = pNodeIndex->GetNode().EndOfSectionIndex();
2606 
2607                     if( (nStt < nEnd) && !pDoc->GetNodes()[ nStt ]->IsNoTxtNode() )
2608                     {
2609                         Point aOffset;
2610                         // Rechtecke des Flys und des Absatzes besorgen
2611                         SwRect aParentRect(rNd.FindLayoutRect(false, &aOffset)),
2612                                aFlyRect(rFlyFrmFmt.FindLayoutRect(false, &aOffset ) );
2613 
2614                         aOffset = aFlyRect.Pos() - aParentRect.Pos();
2615 
2616                         // PaM umsetzen: auf Inhalt des Fly-Frameformats
2617                         SaveData( nStt, nEnd );
2618 
2619                         // wird in OutputFormat() ausgewertet
2620                         pFlyOffset = &aOffset;
2621                         eNewAnchorType = rFlyFrmFmt.GetAnchor().GetAnchorId();
2622                         sw::Frame aFrm(rFlyFrmFmt, SwPosition(rNd));
2623                         mpParentFrame = &aFrm;
2624                         // Ok, rausschreiben:
2625                         WriteText();
2626 
2627                         RestoreData();
2628                     }
2629                 }
2630             }
2631         }
2632     }
2633 }
2634 
2635 void WW8AttributeOutput::OutputFlyFrame_Impl( const sw::Frame& rFmt, const Point& rNdTopLeft )
2636 {
2637     const SwFrmFmt &rFrmFmt = rFmt.GetFrmFmt();
2638     const SwFmtAnchor& rAnch = rFrmFmt.GetAnchor();
2639 
2640     bool bUseEscher = m_rWW8Export.bWrtWW8;
2641 
2642     if ( m_rWW8Export.bWrtWW8 && rFmt.IsInline() )
2643     {
2644         sw::Frame::WriterSource eType = rFmt.GetWriterType();
2645         if ((eType == sw::Frame::eGraphic) || (eType == sw::Frame::eOle))
2646             bUseEscher = false;
2647         else
2648             bUseEscher = true;
2649 
2650         /*
2651          #110185#
2652          A special case for converting some inline form controls to form fields
2653          when in winword 8+ mode
2654         */
2655         if ((bUseEscher == true) && (eType == sw::Frame::eFormControl))
2656         {
2657             if ( m_rWW8Export.MiserableFormFieldExportHack( rFrmFmt ) )
2658                 return ;
2659         }
2660     }
2661 
2662     if (bUseEscher)
2663     {
2664         ASSERT( m_rWW8Export.bWrtWW8, "this has gone horribly wrong" );
2665         // write as escher
2666         m_rWW8Export.AppendFlyInFlys(rFmt, rNdTopLeft);
2667     }
2668     else
2669     {
2670         bool bDone = false;
2671 
2672         // Hole vom Node und vom letzten Node die Position in der Section
2673         const SwNodeIndex* pNodeIndex = rFrmFmt.GetCntnt().GetCntntIdx();
2674 
2675         sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex()+1                  : 0;
2676         sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
2677 
2678         if( nStt >= nEnd )      // kein Bereich, also kein gueltiger Node
2679             return;
2680 
2681         if ( !m_rWW8Export.IsInTable() && rFmt.IsInline() )
2682         {
2683             //Test to see if this textbox contains only a single graphic/ole
2684             SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode();
2685             if ( pParTxtNode && !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode() )
2686                 bDone = true;
2687         }
2688         if( !bDone )
2689         {
2690             // ein NICHT zeichengebundener Rahmen liegt vor
2691 
2692             // --> OD 2007-04-19 #i43447# - removed
2693 //            const SwFmtFrmSize& rS = rFrmFmt.GetFrmSize();
2694 //            nFlyWidth  = rS.GetWidth();  // Fuer Anpassung Graphic-Groesse
2695 //            nFlyHeight = rS.GetHeight();
2696             // <--
2697 
2698             m_rWW8Export.SaveData( nStt, nEnd );
2699 
2700             Point aOffset;
2701             if ( m_rWW8Export.mpParentFrame )
2702             {
2703                 /*
2704                 #90804#
2705                 Munge flys in fly into absolutely positioned elements for
2706                 word 6
2707                 */
2708                 const SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode();
2709                 const SwRect aPageRect = pParTxtNode->FindPageFrmRect( sal_False, 0, sal_False );
2710 
2711                 aOffset = rFrmFmt.FindLayoutRect().Pos();
2712                 aOffset -= aPageRect.Pos();
2713 
2714                 m_rWW8Export.pFlyOffset = &aOffset;
2715                 m_rWW8Export.eNewAnchorType = FLY_AT_PAGE;
2716             }
2717 
2718             m_rWW8Export.mpParentFrame = &rFmt;
2719             if (
2720                 m_rWW8Export.IsInTable() &&
2721                  (FLY_AT_PAGE != rAnch.GetAnchorId()) &&
2722                  !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode()
2723                )
2724             {
2725                 // Beachten: Flag  bOutTable  wieder setzen,
2726                 //           denn wir geben ja ganz normalen Content der
2727                 //           Tabelenzelle aus und keinen Rahmen
2728                 //           (Flag wurde oben in  aSaveData()  geloescht)
2729                 m_rWW8Export.bOutTable = true;
2730                 const String& rName = rFrmFmt.GetName();
2731                 m_rWW8Export.StartCommentOutput(rName);
2732                 m_rWW8Export.WriteText();
2733                 m_rWW8Export.EndCommentOutput(rName);
2734             }
2735             else
2736                 m_rWW8Export.WriteText();
2737 
2738             m_rWW8Export.RestoreData();
2739         }
2740     }
2741 }
2742 
2743 void AttributeOutputBase::OutputFlyFrame( const sw::Frame& rFmt )
2744 {
2745     if ( !rFmt.GetCntntNode() )
2746         return;
2747 
2748     const SwCntntNode &rNode = *rFmt.GetCntntNode();
2749     Point aNdPos, aPgPos;
2750     Point* pLayPos;
2751     bool bValidNdPos = false, bValidPgPos = false;
2752 
2753     if (FLY_AT_PAGE == rFmt.GetFrmFmt().GetAnchor().GetAnchorId())
2754     {
2755         // get the Layout Node-Position.
2756         if ( !bValidPgPos )
2757         {
2758             aPgPos = rNode.FindPageFrmRect(false, &aPgPos).Pos();
2759             bValidPgPos = true;
2760         }
2761         pLayPos = &aPgPos;
2762     }
2763     else
2764     {
2765         // get the Layout Node-Position.
2766         if ( !bValidNdPos )
2767         {
2768             aNdPos = rNode.FindLayoutRect(false, &aNdPos).Pos();
2769             bValidNdPos = true;
2770         }
2771         pLayPos = &aNdPos;
2772     }
2773 
2774     OutputFlyFrame_Impl( rFmt, *pLayPos );
2775 }
2776 
2777 // write data of any redline
2778 void WW8AttributeOutput::Redline( const SwRedlineData* pRedline )
2779 {
2780     if ( !pRedline )
2781         return;
2782 
2783     if ( pRedline->Next() )
2784         Redline( pRedline->Next() );
2785 
2786     static sal_uInt16 __READONLY_DATA aSprmIds[ 2 * 2 * 3 ] =
2787     {
2788         // Ids for insert
2789             NS_sprm::LN_CFRMark, NS_sprm::LN_CIbstRMark, NS_sprm::LN_CDttmRMark,         // for WW8
2790             0x0042, 0x0045, 0x0046,         // for WW6
2791         // Ids for delete
2792             NS_sprm::LN_CFRMarkDel, NS_sprm::LN_CIbstRMarkDel, NS_sprm::LN_CDttmRMarkDel,         // for WW8
2793             0x0041, 0x0045, 0x0046          // for WW6
2794     };
2795 
2796     const sal_uInt16* pSprmIds = 0;
2797     switch( pRedline->GetType() )
2798     {
2799     case nsRedlineType_t::REDLINE_INSERT:
2800         pSprmIds = aSprmIds;
2801         break;
2802 
2803     case nsRedlineType_t::REDLINE_DELETE:
2804         pSprmIds = aSprmIds + (2 * 3);
2805         break;
2806 
2807     case nsRedlineType_t::REDLINE_FORMAT:
2808         if( m_rWW8Export.bWrtWW8 )
2809         {
2810             m_rWW8Export.InsUInt16( NS_sprm::LN_CPropRMark );
2811             m_rWW8Export.pO->Insert( 7, m_rWW8Export.pO->Count() );       // len
2812             m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() );
2813             m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) );
2814             m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() ));
2815         }
2816         break;
2817     default:
2818         ASSERT(!this, "Unhandled redline type for export");
2819         break;
2820     }
2821 
2822     if ( pSprmIds )
2823     {
2824         if ( !m_rWW8Export.bWrtWW8 )
2825             pSprmIds += 3;
2826 
2827         if ( m_rWW8Export.bWrtWW8 )
2828             m_rWW8Export.InsUInt16( pSprmIds[0] );
2829         else
2830             m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[0]), m_rWW8Export.pO->Count() );
2831         m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() );
2832 
2833         if ( m_rWW8Export.bWrtWW8 )
2834             m_rWW8Export.InsUInt16( pSprmIds[1] );
2835         else
2836             m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[1]), m_rWW8Export.pO->Count() );
2837         m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) );
2838 
2839         if ( m_rWW8Export.bWrtWW8 )
2840             m_rWW8Export.InsUInt16( pSprmIds[2] );
2841         else
2842             m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[2]), m_rWW8Export.pO->Count() );
2843         m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() ));
2844     }
2845 }
2846 
2847 /*  */
2848 
2849 void MSWordExportBase::OutputContentNode( const SwCntntNode& rNode )
2850 {
2851     switch ( rNode.GetNodeType() )
2852     {
2853         case ND_TEXTNODE:
2854         {
2855             const SwTxtNode& rTextNode = *rNode.GetTxtNode();
2856             if( !mbOutOutlineOnly || rTextNode.IsOutline() )
2857                 OutputTextNode( rTextNode );
2858         }
2859         break;
2860         case ND_GRFNODE:
2861             OutputGrfNode( *rNode.GetGrfNode() );
2862             break;
2863         case ND_OLENODE:
2864             OutputOLENode( *rNode.GetOLENode() );
2865             break;
2866         default:
2867 #if OSL_DEBUG_LEVEL > 0
2868             OSL_TRACE("Unhandled node, type == %d\n", rNode.GetNodeType() );
2869 #endif
2870             break;
2871     }
2872 }
2873 
2874 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
2875