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