xref: /trunk/main/sw/source/filter/ww8/wrtw8nds.cxx (revision 93996bb7)
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     if (pTxtAttrs)
661     {
662         xub_StrLen nTmpSwPos = m_rExport.m_aCurrentCharPropStarts.size() ?
663             m_rExport.m_aCurrentCharPropStarts.top() : 0;
664         for (sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i)
665         {
666             const SwTxtAttr* pHt = (*pTxtAttrs)[i];
667             const SfxPoolItem* pItem = &pHt->GetAttr();
668             const xub_StrLen* pAtrEnd = 0;
669             if( 0 != ( pAtrEnd = pHt->GetEnd() ) &&     // nur Attr mit Ende
670                 nWhich == pItem->Which() &&             //
671                 nTmpSwPos >= *pHt->GetStart() && nTmpSwPos < *pAtrEnd )
672             {
673                 pRet = pItem;       // gefunden
674                 break;
675             }
676             else if (nTmpSwPos < *pHt->GetStart())
677                 break;              // dann kommt da nichts mehr
678         }
679     }
680     return pRet;
681 }
682 
683 void WW8Export::GetCurrentItems(WW8Bytes& rItems) const
684 {
685     sal_uInt16 nEnd = pO ? pO->Count() : 0;
686     for (sal_uInt16 nI = 0; nI < nEnd; ++nI)
687         rItems.Insert((*pO)[nI], rItems.Count());
688 }
689 
690 const SfxPoolItem& WW8SwAttrIter::GetItem(sal_uInt16 nWhich) const
691 {
692     const SfxPoolItem* pRet = HasTextItem(nWhich);
693     return pRet ? *pRet : rNd.SwCntntNode::GetAttr(nWhich);
694 }
695 
696 void WW8AttributeOutput::StartRuby( const SwTxtNode& rNode, const SwFmtRuby& rRuby )
697 {
698     String aStr( FieldString( ww::eEQ ) );
699     aStr.APPEND_CONST_ASC( "\\* jc" );
700     sal_Int32 nJC = 0;
701     sal_Char cDirective = 0;
702     switch ( rRuby.GetAdjustment() )
703     {
704         case 0:
705             nJC = 3;
706             cDirective = 'l';
707             break;
708         case 1:
709             //defaults to 0
710             break;
711         case 2:
712             nJC = 4;
713             cDirective = 'r';
714             break;
715         case 3:
716             nJC = 1;
717             cDirective = 'd';
718             break;
719         case 4:
720             nJC = 2;
721             cDirective = 'd';
722             break;
723         default:
724             ASSERT( !this,"Unhandled Ruby justication code" );
725             break;
726     }
727     aStr += String::CreateFromInt32( nJC );
728 
729     /*
730      MS needs to know the name and size of the font used in the ruby item,
731      but we coud have written it in a mixture of asian and western
732      scripts, and each of these can be a different font and size than the
733      other, so we make a guess based upon the first character of the text,
734      defaulting to asian.
735      */
736     sal_uInt16 nRubyScript;
737     if( pBreakIt->GetBreakIter().is() )
738         nRubyScript = pBreakIt->GetBreakIter()->getScriptType( rRuby.GetText(), 0);
739     else
740         nRubyScript = i18n::ScriptType::ASIAN;
741 
742     const SwTxtRuby* pRubyTxt = rRuby.GetTxtRuby();
743     const SwCharFmt* pFmt = pRubyTxt ? pRubyTxt->GetCharFmt() : 0;
744     String sFamilyName;
745     long nHeight;
746     if ( pFmt )
747     {
748         const SvxFontItem &rFont = ItemGet< SvxFontItem >( *pFmt,
749                 GetWhichOfScript(RES_CHRATR_FONT,nRubyScript) );
750         sFamilyName = rFont.GetFamilyName();
751 
752         const SvxFontHeightItem &rHeight = ItemGet< SvxFontHeightItem >( *pFmt,
753                 GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
754         nHeight = rHeight.GetHeight();
755     }
756     else
757     {
758         /*Get defaults if no formatting on ruby text*/
759 
760         const SfxItemPool *pPool = rNode.GetSwAttrSet().GetPool();
761         const SfxItemPool &rPool = pPool ? *pPool : m_rWW8Export.pDoc->GetAttrPool();
762 
763         const SvxFontItem &rFont  = DefaultItemGet< SvxFontItem >( rPool,
764                 GetWhichOfScript( RES_CHRATR_FONT,nRubyScript ) );
765         sFamilyName = rFont.GetFamilyName();
766 
767         const SvxFontHeightItem &rHeight = DefaultItemGet< SvxFontHeightItem >
768             ( rPool, GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
769         nHeight = rHeight.GetHeight();
770     }
771     nHeight = (nHeight + 5)/10;
772 
773     aStr.APPEND_CONST_ASC( " \\* \"Font:" );
774     aStr.Append( sFamilyName );
775     aStr.APPEND_CONST_ASC( "\" \\* hps" );
776     aStr += String::CreateFromInt32( nHeight );
777     aStr.APPEND_CONST_ASC( " \\o" );
778     if ( cDirective )
779     {
780         aStr.APPEND_CONST_ASC( "\\a" );
781         aStr.Append( cDirective );
782     }
783     aStr.APPEND_CONST_ASC( "(\\s\\up " );
784 
785 
786     if ( pBreakIt->GetBreakIter().is() )
787         nRubyScript = pBreakIt->GetBreakIter()->getScriptType( rNode.GetTxt(),
788                 *( pRubyTxt->GetStart() ) );
789     else
790         nRubyScript = i18n::ScriptType::ASIAN;
791 
792     const SwAttrSet& rSet = rNode.GetSwAttrSet();
793     const SvxFontHeightItem &rHeightItem  =
794         ( const SvxFontHeightItem& )rSet.Get(
795                                              GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) );
796     nHeight = (rHeightItem.GetHeight() + 10)/20-1;
797     aStr += String::CreateFromInt32(nHeight);
798     aStr += '(';
799     aStr += rRuby.GetText();
800     aStr.APPEND_CONST_ASC( ");" );
801     m_rWW8Export.OutputField( 0, ww::eEQ, aStr,
802             WRITEFIELD_START | WRITEFIELD_CMD_START );
803 }
804 
805 void WW8AttributeOutput::EndRuby()
806 {
807     m_rWW8Export.WriteChar( ')' );
808     m_rWW8Export.OutputField( 0, ww::eEQ, aEmptyStr, WRITEFIELD_END | WRITEFIELD_CLOSE );
809 }
810 
811 /*#i15387# Better ideas welcome*/
812 String &TruncateBookmark( String &rRet )
813 {
814     if ( rRet.Len() > 40 )
815         rRet.Erase( 40 );
816     ASSERT( rRet.Len() <= 40, "Word cannot have bookmarks longer than 40 chars" );
817     return rRet;
818 }
819 
820 bool AttributeOutputBase::AnalyzeURL( const String& rUrl, const String& /*rTarget*/, String* pLinkURL, String* pMark )
821 {
822     bool bBookMarkOnly = false;
823 
824     INetURLObject aURL( rUrl );
825     String sMark;
826     String sURL;
827 
828     if ( rUrl.Len() > 1 && rUrl.GetChar(0) == INET_MARK_TOKEN )
829     {
830         sMark = BookmarkToWriter( rUrl.Copy(1) );
831 
832         xub_StrLen nPos = sMark.SearchBackward( cMarkSeperator );
833 
834         String sRefType( sMark.Copy( nPos+1 ) );
835         sRefType.EraseAllChars();
836 
837         // i21465 Only interested in outline references
838         if ( sRefType.EqualsAscii( pMarkToOutline ) )
839         {
840             String sLink = sMark.Copy(0, nPos);
841             SwImplBookmarksIter bkmkIterEnd = GetExport().maImplicitBookmarks.end();
842             for ( SwImplBookmarksIter aIter = GetExport().maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter )
843             {
844                 String bkmkName  = aIter->first;
845 
846                 if ( bkmkName == sLink )
847                 {
848                     sMark = String( RTL_CONSTASCII_STRINGPARAM( "_toc" ) );
849                     sMark += String::CreateFromInt32( aIter->second );
850                 }
851             }
852         }
853     }
854     else
855     {
856         sURL = aURL.GetURLNoMark( INetURLObject::DECODE_UNAMBIGUOUS );
857         sMark = aURL.GetMark( INetURLObject::DECODE_UNAMBIGUOUS );
858 
859     }
860 
861     if ( sMark.Len() && !sURL.Len() )
862         bBookMarkOnly = true;
863 
864 
865 
866     *pMark = sMark;
867     *pLinkURL = sURL;
868     return bBookMarkOnly;
869 }
870 
871 bool WW8AttributeOutput::AnalyzeURL( const String& rUrl, const String& rTarget, String* pLinkURL, String* pMark )
872 {
873     bool bBookMarkOnly = AttributeOutputBase::AnalyzeURL( rUrl, rTarget, pLinkURL, pMark );
874 
875     String sURL = *pLinkURL;
876     String sMark = *pMark;
877 
878     if ( sURL.Len() )
879         sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL );
880 
881     if ( bBookMarkOnly )
882         sURL = FieldString( ww::eHYPERLINK );
883     else
884     {
885         String sFld( FieldString( ww::eHYPERLINK ) );
886         sFld.APPEND_CONST_ASC( "\"" );
887         sURL.Insert( sFld, 0 );
888         sURL += '\"';
889     }
890 
891     if ( sMark.Len() )
892         ( ( sURL.APPEND_CONST_ASC( " \\l \"" ) ) += sMark ) += '\"';
893 
894     if ( rTarget.Len() )
895         ( sURL.APPEND_CONST_ASC( " \\n " ) ) += rTarget;
896 
897     *pLinkURL = sURL;
898     *pMark = sMark;
899 
900     return bBookMarkOnly;
901 }
902 
903 bool WW8AttributeOutput::StartURL( const String &rUrl, const String &rTarget )
904 {
905     // hyperlinks only in WW8
906     if ( !m_rWW8Export.bWrtWW8 )
907         return false;
908 
909     INetURLObject aURL( rUrl );
910     String sURL;
911     String sMark;
912 
913     bool bBookMarkOnly = AnalyzeURL( rUrl, rTarget, &sURL, &sMark );
914 
915 
916     m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_START | WRITEFIELD_CMD_START );
917 
918     // write the refence to the "picture" structure
919     sal_uLong nDataStt = m_rWW8Export.pDataStrm->Tell();
920     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell() );
921 
922 //  WinWord 2000 doesn't write this - so its a temp solution by W97 ?
923     m_rWW8Export.WriteChar( 0x01 );
924 
925     static sal_uInt8 aArr1[] = {
926         0x03, 0x6a, 0,0,0,0,    // sprmCPicLocation
927 
928         0x06, 0x08, 0x01,       // sprmCFData
929         0x55, 0x08, 0x01,       // sprmCFSpec
930         0x02, 0x08, 0x01        // sprmCFFldVanish
931     };
932     sal_uInt8* pDataAdr = aArr1 + 2;
933     Set_UInt32( pDataAdr, nDataStt );
934 
935     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), sizeof( aArr1 ), aArr1 );
936 
937     m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_CMD_END );
938 
939     // now write the picture structur
940     sURL = aURL.GetURLNoMark();
941 
942     //all links end up in the data stream as absolute references.
943     bool bAbsolute = !bBookMarkOnly;
944 
945     static sal_uInt8 __READONLY_DATA aURLData1[] = {
946         0,0,0,0,        // len of struct
947         0x44,0,         // the start of "next" data
948         0,0,0,0,0,0,0,0,0,0,                // PIC-Structure!
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,0,0,0,0,0,0,0,0,0,0,0,0,    //  |
952         0,0,0,0,                            // /
953     };
954     static sal_uInt8 __READONLY_DATA MAGIC_A[] = {
955         // start of "next" data
956         0xD0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11,
957         0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B
958     };
959 
960     m_rWW8Export.pDataStrm->Write( aURLData1, sizeof( aURLData1 ) );
961     sal_uInt8 nAnchor = 0x00;
962     if ( sMark.Len() )
963         nAnchor = 0x08;
964     m_rWW8Export.pDataStrm->Write( &nAnchor, 1 );
965     m_rWW8Export.pDataStrm->Write( MAGIC_A, sizeof(MAGIC_A) );
966     SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 0x00000002);
967     sal_uInt32 nFlag = bBookMarkOnly ? 0 : 0x01;
968     if ( bAbsolute )
969         nFlag |= 0x02;
970     if ( sMark.Len() )
971         nFlag |= 0x08;
972     SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nFlag );
973 
974     INetProtocol eProto = aURL.GetProtocol();
975     if ( eProto == INET_PROT_FILE )
976     {
977         // version 1 (for a document)
978 
979         static sal_uInt8 __READONLY_DATA MAGIC_C[] = {
980             0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
981             0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46,
982             0x00, 0x00
983         };
984 
985         static sal_uInt8 __READONLY_DATA MAGIC_D[] = {
986             0xFF, 0xFF, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00,
987             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
988             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
989         };
990 
991         // save the links to files as relative
992         sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL );
993         if ( sURL.EqualsAscii( "/", 0, 1 ) )
994             sURL = aURL.PathToFileName();
995 
996         // special case for the absolute windows names
997         // (convert '/c:/foo/bar.doc' into 'c:\foo\bar.doc')
998         sal_Unicode aDrive = ( sURL.Len() > 1 )? sURL.GetChar( 1 ): 0;
999         if ( sURL.EqualsAscii( "/", 0, 1 ) &&
1000              ( ( aDrive >= 'A' && aDrive <= 'Z' ) || ( aDrive >= 'a' && aDrive <= 'z' ) ) &&
1001              sURL.EqualsAscii( ":", 2, 1 ) )
1002         {
1003             sURL.Erase( 0, 1 );
1004             sURL.SearchAndReplaceAll( '/', '\\' );
1005         }
1006 
1007         m_rWW8Export.pDataStrm->Write( MAGIC_C, sizeof(MAGIC_C) );
1008         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sURL.Len()+1 );
1009         SwWW8Writer::WriteString8( *m_rWW8Export.pDataStrm, sURL, true,
1010                                     RTL_TEXTENCODING_MS_1252 );
1011         m_rWW8Export.pDataStrm->Write( MAGIC_D, sizeof( MAGIC_D ) );
1012 
1013         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() + 6 );
1014         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() );
1015         SwWW8Writer::WriteShort( *m_rWW8Export.pDataStrm, 3 );
1016         SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, false );
1017     }
1018     else if ( eProto != INET_PROT_NOT_VALID )
1019     {
1020         // version 2 (simple url)
1021         // an write some data to the data stream, but dont ask
1022         // what the data mean, except for the URL.
1023         // The First piece is the WW8_PIC structure.
1024         //
1025         static sal_uInt8 __READONLY_DATA MAGIC_B[] = {
1026             0xE0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11,
1027             0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B
1028         };
1029 
1030         m_rWW8Export.pDataStrm->Write( MAGIC_B, sizeof(MAGIC_B) );
1031         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2 * ( sURL.Len() + 1 ) );
1032         SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, true );
1033     }
1034 
1035     if ( sMark.Len() )
1036     {
1037         SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sMark.Len()+1 );
1038         SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sMark, true );
1039     }
1040     SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nDataStt,
1041         m_rWW8Export.pDataStrm->Tell() - nDataStt );
1042 
1043     return true;
1044 }
1045 
1046 bool WW8AttributeOutput::EndURL()
1047 {
1048     // hyperlinks only in WW8
1049     if ( !m_rWW8Export.bWrtWW8 )
1050         return false;
1051 
1052     m_rWW8Export.OutputField( 0, ww::eHYPERLINK, aEmptyStr, WRITEFIELD_CLOSE );
1053 
1054     return true;
1055 }
1056 
1057 String BookmarkToWord(const String &rBookmark)
1058 {
1059     String sRet(INetURLObject::encode(rBookmark,
1060         INetURLObject::PART_REL_SEGMENT_EXTRA, '%',
1061         INetURLObject::ENCODE_ALL, RTL_TEXTENCODING_ASCII_US));
1062     return TruncateBookmark(sRet);
1063 }
1064 
1065 String BookmarkToWriter(const String &rBookmark)
1066 {
1067     return INetURLObject::decode(rBookmark, '%',
1068         INetURLObject::DECODE_UNAMBIGUOUS, RTL_TEXTENCODING_ASCII_US);
1069 }
1070 
1071 void WW8SwAttrIter::OutSwFmtRefMark(const SwFmtRefMark& rAttr, bool)
1072 {
1073     if ( m_rExport.HasRefToObject( REF_SETREFATTR, &rAttr.GetRefName(), 0 ) )
1074         m_rExport.AppendBookmark( m_rExport.GetBookmarkName( REF_SETREFATTR,
1075                                             &rAttr.GetRefName(), 0 ));
1076 }
1077 
1078 void WW8AttributeOutput::FieldVanish( const String& rTxt, ww::eField /*eType*/ )
1079 {
1080     WW8Bytes aItems;
1081     m_rWW8Export.GetCurrentItems( aItems );
1082 
1083     // sprmCFFldVanish
1084     if ( m_rWW8Export.bWrtWW8 )
1085         SwWW8Writer::InsUInt16( aItems, NS_sprm::LN_CFFldVanish );
1086     else
1087         aItems.Insert( 67, aItems.Count() );
1088     aItems.Insert( 1, aItems.Count() );
1089 
1090     sal_uInt16 nStt_sprmCFSpec = aItems.Count();
1091 
1092     // sprmCFSpec --  fSpec-Attribut true
1093     if ( m_rWW8Export.bWrtWW8 )
1094         SwWW8Writer::InsUInt16( aItems, 0x855 );
1095     else
1096         aItems.Insert( 117, aItems.Count() );
1097     aItems.Insert( 1, aItems.Count() );
1098 
1099     m_rWW8Export.WriteChar( '\x13' );
1100     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.Count(),
1101                                     aItems.GetData() );
1102     m_rWW8Export.OutSwString( rTxt, 0, rTxt.Len(), m_rWW8Export.IsUnicode(),
1103                         RTL_TEXTENCODING_MS_1252 );
1104     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), nStt_sprmCFSpec,
1105                                     aItems.GetData() );
1106     m_rWW8Export.WriteChar( '\x15' );
1107     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.Count(),
1108                                     aItems.GetData() );
1109 }
1110 
1111 void AttributeOutputBase::TOXMark( const SwTxtNode& rNode, const SwTOXMark& rAttr )
1112 {
1113     // its a field; so get the Text form the Node and build the field
1114     String sTxt;
1115     ww::eField eType = ww::eNONE;
1116 
1117     const SwTxtTOXMark& rTxtTOXMark = *rAttr.GetTxtTOXMark();
1118     const xub_StrLen* pTxtEnd = rTxtTOXMark.GetEnd();
1119     if ( pTxtEnd ) // has range?
1120     {
1121         sTxt = rNode.GetExpandTxt( *rTxtTOXMark.GetStart(),
1122                                    *pTxtEnd - *rTxtTOXMark.GetStart() );
1123     }
1124     else
1125         sTxt = rAttr.GetAlternativeText();
1126 
1127     switch ( rAttr.GetTOXType()->GetType() )
1128     {
1129         case TOX_INDEX:
1130             eType = ww::eXE;
1131             if ( rAttr.GetPrimaryKey().Len() )
1132             {
1133                 if ( rAttr.GetSecondaryKey().Len() )
1134                 {
1135                     sTxt.Insert( ':', 0 );
1136                     sTxt.Insert( rAttr.GetSecondaryKey(), 0 );
1137                 }
1138 
1139                 sTxt.Insert( ':', 0 );
1140                 sTxt.Insert( rAttr.GetPrimaryKey(), 0 );
1141             }
1142             sTxt.InsertAscii( " XE \"", 0 );
1143             sTxt.InsertAscii( "\" " );
1144             break;
1145 
1146         case TOX_USER:
1147             ( sTxt.APPEND_CONST_ASC( "\" \\f \"" ) )
1148                 += (sal_Char)( 'A' + GetExport( ).GetId( *rAttr.GetTOXType() ) );
1149             // fall through - no break;
1150         case TOX_CONTENT:
1151             {
1152                 eType = ww::eTC;
1153                 sTxt.InsertAscii( " TC \"", 0 );
1154                 sal_uInt16 nLvl = rAttr.GetLevel();
1155                 if (nLvl > WW8ListManager::nMaxLevel)
1156                     nLvl = WW8ListManager::nMaxLevel;
1157 
1158                 ((sTxt.APPEND_CONST_ASC( "\" \\l " ))
1159                  += String::CreateFromInt32( nLvl )) += ' ';
1160             }
1161             break;
1162         default:
1163             ASSERT( !this, "Unhandled option for toc export" );
1164             break;
1165     }
1166 
1167     if ( sTxt.Len() )
1168         FieldVanish( sTxt, eType );
1169 }
1170 
1171 int WW8SwAttrIter::OutAttrWithRange(xub_StrLen nPos)
1172 {
1173     int nRet = 0;
1174     if ( const SwpHints* pTxtAttrs = rNd.GetpSwpHints() )
1175     {
1176         m_rExport.m_aCurrentCharPropStarts.push( nPos );
1177         const xub_StrLen* pEnd;
1178         for ( sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i )
1179         {
1180             const SwTxtAttr* pHt = (*pTxtAttrs)[i];
1181             const SfxPoolItem* pItem = &pHt->GetAttr();
1182             switch ( pItem->Which() )
1183             {
1184                 case RES_TXTATR_INETFMT:
1185                     if ( nPos == *pHt->GetStart() )
1186                     {
1187                         const SwFmtINetFmt *rINet = static_cast< const SwFmtINetFmt* >( pItem );
1188                         if ( m_rExport.AttrOutput().StartURL( rINet->GetValue(), rINet->GetTargetFrame() ) )
1189                             ++nRet;
1190                     }
1191                     if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1192                     {
1193                         if ( m_rExport.AttrOutput().EndURL() )
1194                             --nRet;
1195                     }
1196                     break;
1197                 case RES_TXTATR_REFMARK:
1198                     if ( nPos == *pHt->GetStart() )
1199                     {
1200                         OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), true );
1201                         ++nRet;
1202                     }
1203                     if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1204                     {
1205                         OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), false );
1206                         --nRet;
1207                     }
1208                     break;
1209                 case RES_TXTATR_TOXMARK:
1210                     if ( nPos == *pHt->GetStart() )
1211                         m_rExport.AttrOutput().TOXMark( rNd, *static_cast< const SwTOXMark* >( pItem ) );
1212                     break;
1213                 case RES_TXTATR_CJK_RUBY:
1214                     if ( nPos == *pHt->GetStart() )
1215                     {
1216                         m_rExport.AttrOutput().StartRuby( rNd, *static_cast< const SwFmtRuby* >( pItem ) );
1217                         ++nRet;
1218                     }
1219                     if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd )
1220                     {
1221                         m_rExport.AttrOutput().EndRuby();
1222                         --nRet;
1223                     }
1224                     break;
1225             }
1226         }
1227         m_rExport.m_aCurrentCharPropStarts.pop(); // HasTextItem nur in dem obigen Bereich erlaubt
1228     }
1229     return nRet;
1230 }
1231 
1232 bool WW8SwAttrIter::IsRedlineAtEnd( xub_StrLen nEnd ) const
1233 {
1234     bool bRet = false;
1235     // search next Redline
1236     for( sal_uInt16 nPos = nCurRedlinePos;
1237         nPos < m_rExport.pDoc->GetRedlineTbl().Count(); ++nPos )
1238     {
1239         const SwPosition* pEnd = m_rExport.pDoc->GetRedlineTbl()[ nPos ]->End();
1240         if( pEnd->nNode == rNd )
1241         {
1242             if( pEnd->nContent.GetIndex() == nEnd )
1243             {
1244                 bRet = true;
1245                 break;
1246             }
1247         }
1248         else
1249             break;
1250     }
1251     return bRet;
1252 }
1253 
1254 const SwRedlineData* WW8SwAttrIter::GetRedline( xub_StrLen nPos )
1255 {
1256     if( pCurRedline )
1257     {
1258         const SwPosition* pEnd = pCurRedline->End();
1259         if( pEnd->nNode == rNd &&
1260             pEnd->nContent.GetIndex() <= nPos )
1261         {
1262             pCurRedline = 0;
1263             ++nCurRedlinePos;
1264         }
1265         else
1266         {
1267             // write data of current redline
1268             return &( pCurRedline->GetRedlineData() );
1269         }
1270     }
1271 
1272     if( !pCurRedline )
1273     {
1274         // search next Redline
1275         for( ; nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().Count();
1276                 ++nCurRedlinePos )
1277         {
1278             const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nCurRedlinePos ];
1279 
1280             const SwPosition* pStt = pRedl->Start();
1281             const SwPosition* pEnd = pStt == pRedl->GetPoint()
1282                                         ? pRedl->GetMark()
1283                                         : pRedl->GetPoint();
1284 
1285             if( pStt->nNode == rNd )
1286             {
1287                 if( pStt->nContent.GetIndex() >= nPos )
1288                 {
1289                     if( pStt->nContent.GetIndex() == nPos )
1290                     {
1291                         // write data of this redline
1292                         pCurRedline = pRedl;
1293                         return &( pCurRedline->GetRedlineData() );
1294                     }
1295                     break;
1296                 }
1297             }
1298             else
1299                 break;
1300 
1301             if( pEnd->nNode == rNd &&
1302                 pEnd->nContent.GetIndex() < nPos )
1303             {
1304                 pCurRedline = pRedl;
1305                 break;
1306             }
1307         }
1308     }
1309     return NULL;
1310 }
1311 
1312 /*  */
1313 
1314 short MSWordExportBase::GetCurrentPageDirection() const
1315 {
1316     const SwFrmFmt &rFmt = pAktPageDesc
1317                     ? pAktPageDesc->GetMaster()
1318                     : const_cast<const SwDoc *>( pDoc )->GetPageDesc( 0 ).GetMaster();
1319     return rFmt.GetFrmDir().GetValue();
1320 }
1321 
1322 short MSWordExportBase::GetDefaultFrameDirection( ) const
1323 {
1324     short nDir = FRMDIR_ENVIRONMENT;
1325 
1326     if ( bOutPageDescs )
1327         nDir = GetCurrentPageDirection(  );
1328     else if ( pOutFmtNode )
1329     {
1330         if ( bOutFlyFrmAttrs ) //frame
1331         {
1332             nDir = TrueFrameDirection( *( const SwFrmFmt * ) pOutFmtNode );
1333         }
1334         else if ( pOutFmtNode->ISA( SwCntntNode ) )    //pagagraph
1335         {
1336             const SwCntntNode *pNd = ( const SwCntntNode * ) pOutFmtNode;
1337             SwPosition aPos( *pNd );
1338             nDir = pDoc->GetTextDirection( aPos );
1339         }
1340         else if ( pOutFmtNode->ISA( SwTxtFmtColl ) )
1341             nDir = FRMDIR_HORI_LEFT_TOP;    //what else can we do :-(
1342     }
1343 
1344     if ( nDir == FRMDIR_ENVIRONMENT )
1345         nDir = FRMDIR_HORI_LEFT_TOP;        //Set something
1346 
1347     return nDir;
1348 }
1349 
1350 short MSWordExportBase::TrueFrameDirection( const SwFrmFmt &rFlyFmt ) const
1351 {
1352     const SwFrmFmt *pFlyFmt = &rFlyFmt;
1353     const SvxFrameDirectionItem* pItem = 0;
1354     while ( pFlyFmt )
1355     {
1356         pItem = &pFlyFmt->GetFrmDir();
1357         if ( FRMDIR_ENVIRONMENT == pItem->GetValue() )
1358         {
1359             pItem = 0;
1360             const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor();
1361             if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) &&
1362                 pAnchor->GetCntntAnchor() )
1363             {
1364                 pFlyFmt = pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt();
1365             }
1366             else
1367                 pFlyFmt = 0;
1368         }
1369         else
1370             pFlyFmt = 0;
1371     }
1372 
1373     short nRet;
1374     if ( pItem )
1375         nRet = pItem->GetValue();
1376     else
1377         nRet = GetCurrentPageDirection();
1378 
1379     ASSERT( nRet != FRMDIR_ENVIRONMENT, "leaving with environment direction" );
1380     return nRet;
1381 }
1382 
1383 const SvxBrushItem* WW8Export::GetCurrentPageBgBrush() const
1384 {
1385     const SwFrmFmt  &rFmt = pAktPageDesc
1386                     ? pAktPageDesc->GetMaster()
1387                     : const_cast<const SwDoc *>(pDoc)->GetPageDesc(0).GetMaster();
1388 
1389     const SfxPoolItem* pItem = 0;
1390     //If not set, or "no fill", get real bg
1391     SfxItemState eState = rFmt.GetItemState(RES_BACKGROUND, true, &pItem);
1392 
1393     const SvxBrushItem* pRet = (const SvxBrushItem*)pItem;
1394     if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() &&
1395         pRet->GetColor() == COL_TRANSPARENT))
1396     {
1397         pRet = &(DefaultItemGet<SvxBrushItem>(*pDoc,RES_BACKGROUND));
1398     }
1399     return pRet;
1400 }
1401 
1402 SvxBrushItem WW8Export::TrueFrameBgBrush(const SwFrmFmt &rFlyFmt) const
1403 {
1404     const SwFrmFmt *pFlyFmt = &rFlyFmt;
1405     const SvxBrushItem* pRet = 0;
1406 
1407     while (pFlyFmt)
1408     {
1409         //If not set, or "no fill", get real bg
1410         const SfxPoolItem* pItem = 0;
1411         SfxItemState eState =
1412             pFlyFmt->GetItemState(RES_BACKGROUND, true, &pItem);
1413         pRet = (const SvxBrushItem*)pItem;
1414         if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() &&
1415             pRet->GetColor() == COL_TRANSPARENT))
1416         {
1417             pRet = 0;
1418             const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor();
1419             if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) &&
1420                 pAnchor->GetCntntAnchor())
1421             {
1422                 pFlyFmt =
1423                     pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt();
1424             }
1425             else
1426                 pFlyFmt = 0;
1427         }
1428         else
1429             pFlyFmt = 0;
1430     }
1431 
1432     if (!pRet)
1433         pRet = GetCurrentPageBgBrush();
1434 
1435     const Color aTmpColor( COL_WHITE );
1436     SvxBrushItem aRet( aTmpColor, RES_BACKGROUND );
1437     if (pRet && (pRet->GetGraphic() ||( pRet->GetColor() != COL_TRANSPARENT)))
1438         aRet = *pRet;
1439 
1440     return aRet;
1441 }
1442 
1443 
1444 /*
1445 Convert characters that need to be converted, the basic replacements and the
1446 ridicously complicated title case attribute mapping to hardcoded upper case
1447 because word doesn't have the feature
1448 */
1449 String WW8SwAttrIter::GetSnippet(const String &rStr, xub_StrLen nAktPos,
1450     xub_StrLen nLen) const
1451 {
1452     String aSnippet(rStr, nAktPos, nLen);
1453     if (!nLen)
1454         return aSnippet;
1455 
1456     // 0x0a     ( Hard Line Break ) -> 0x0b
1457     // 0xad     ( soft hyphen )     -> 0x1f
1458     // 0x2011   ( hard hyphen )     -> 0x1e
1459     aSnippet.SearchAndReplaceAll(0x0A, 0x0B);
1460     aSnippet.SearchAndReplaceAll(CHAR_HARDHYPHEN, 0x1e);
1461     aSnippet.SearchAndReplaceAll(CHAR_SOFTHYPHEN, 0x1f);
1462 
1463     m_rExport.m_aCurrentCharPropStarts.push( nAktPos );
1464     const SfxPoolItem &rItem = GetItem(RES_CHRATR_CASEMAP);
1465 
1466     if (SVX_CASEMAP_TITEL == ((const SvxCaseMapItem&)rItem).GetValue())
1467     {
1468         sal_uInt16 nScriptType = i18n::ScriptType::LATIN;
1469         if (pBreakIt->GetBreakIter().is())
1470             nScriptType = pBreakIt->GetBreakIter()->getScriptType(aSnippet, 0);
1471 
1472         LanguageType nLanguage;
1473         switch (nScriptType)
1474         {
1475         case i18n::ScriptType::ASIAN:
1476                 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CJK_LANGUAGE)).GetLanguage();
1477                 break;
1478         case i18n::ScriptType::COMPLEX:
1479                 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CTL_LANGUAGE)).GetLanguage();
1480                 break;
1481         case i18n::ScriptType::LATIN:
1482             default:
1483                 nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_LANGUAGE)).GetLanguage();
1484                 break;
1485         }
1486 
1487         SvxFont aFontHelper;
1488         aFontHelper.SetCaseMap(SVX_CASEMAP_TITEL);
1489         aFontHelper.SetLanguage(nLanguage);
1490         aSnippet = aFontHelper.CalcCaseMap(aSnippet);
1491 
1492         //If we weren't at the begin of a word undo the case change.
1493         //not done before doing the casemap because the sequence might start
1494         //with whitespace
1495         if (pBreakIt->GetBreakIter().is() && !pBreakIt->GetBreakIter()->isBeginWord(
1496             rStr, nAktPos, pBreakIt->GetLocale(nLanguage),
1497             i18n::WordType::ANYWORD_IGNOREWHITESPACES ) )
1498         {
1499             aSnippet.SetChar(0, rStr.GetChar(nAktPos));
1500         }
1501     }
1502     m_rExport.m_aCurrentCharPropStarts.pop();
1503 
1504     return aSnippet;
1505 }
1506 
1507 /** Delivers the right paragraph style
1508 
1509     Because of the different style handling for delete operations,
1510     the track changes have to be analysed. A deletion, starting in paragraph A
1511     with style A, ending in paragraph B with style B, needs a hack.
1512 */
1513 static SwTxtFmtColl& lcl_getFormatCollection( MSWordExportBase& rExport, const SwTxtNode* pTxtNode )
1514 {
1515     sal_uInt16 nPos = 0;
1516     sal_uInt16 nMax = rExport.pDoc->GetRedlineTbl().Count();
1517     while( nPos < nMax )
1518     {
1519         const SwRedline* pRedl = rExport.pDoc->GetRedlineTbl()[ nPos++ ];
1520         const SwPosition* pStt = pRedl->Start();
1521         const SwPosition* pEnd = pStt == pRedl->GetPoint()
1522                                     ? pRedl->GetMark()
1523                                     : pRedl->GetPoint();
1524         // Looking for deletions, which ends in current pTxtNode
1525         if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetRedlineData().GetType() &&
1526             pEnd->nNode == *pTxtNode && pStt->nNode != *pTxtNode &&
1527             pStt->nNode.GetNode().IsTxtNode() )
1528         {
1529             pTxtNode = pStt->nNode.GetNode().GetTxtNode();
1530             nMax = nPos;
1531             nPos = 0;
1532         }
1533     }
1534     return static_cast<SwTxtFmtColl&>( pTxtNode->GetAnyFmtColl() );
1535 }
1536 
1537 void WW8AttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop &rSwFmtDrop, sal_uInt16 nStyle,
1538         ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo, ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner )
1539 {
1540     short nDropLines = rSwFmtDrop.GetLines();
1541     short nDistance = rSwFmtDrop.GetDistance();
1542     int rFontHeight, rDropHeight, rDropDescent;
1543 
1544     SVBT16 nSty;
1545     ShortToSVBT16( nStyle, nSty );
1546     m_rWW8Export.pO->Insert( (sal_uInt8*)&nSty, 2, m_rWW8Export.pO->Count() );     // Style #
1547 
1548     if ( m_rWW8Export.bWrtWW8 )
1549     {
1550         m_rWW8Export.InsUInt16( NS_sprm::LN_PPc );            // Alignment (sprmPPc)
1551         m_rWW8Export.pO->Insert( 0x20, m_rWW8Export.pO->Count() );
1552 
1553         m_rWW8Export.InsUInt16( NS_sprm::LN_PWr );            // Wrapping (sprmPWr)
1554         m_rWW8Export.pO->Insert( 0x02, m_rWW8Export.pO->Count() );
1555 
1556         m_rWW8Export.InsUInt16( NS_sprm::LN_PDcs );            // Dropcap (sprmPDcs)
1557         int nDCS = ( nDropLines << 3 ) | 0x01;
1558         m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( nDCS ) );
1559 
1560         m_rWW8Export.InsUInt16( NS_sprm::LN_PDxaFromText );            // Distance from text (sprmPDxaFromText)
1561         m_rWW8Export.InsUInt16( nDistance );
1562 
1563         if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) )
1564         {
1565             m_rWW8Export.InsUInt16( NS_sprm::LN_PDyaLine );            // Line spacing
1566             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -rDropHeight ) );
1567             m_rWW8Export.InsUInt16( 0 );
1568         }
1569     }
1570     else
1571     {
1572         m_rWW8Export.pO->Insert( 29, m_rWW8Export.pO->Count() );    // Alignment (sprmPPc)
1573         m_rWW8Export.pO->Insert( 0x20, m_rWW8Export.pO->Count() );
1574 
1575         m_rWW8Export.pO->Insert( 37, m_rWW8Export.pO->Count() );    // Wrapping (sprmPWr)
1576         m_rWW8Export.pO->Insert( 0x02, m_rWW8Export.pO->Count() );
1577 
1578         m_rWW8Export.pO->Insert( 46, m_rWW8Export.pO->Count() );    // Dropcap (sprmPDcs)
1579         int nDCS = ( nDropLines << 3 ) | 0x01;
1580         m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( nDCS ) );
1581 
1582         m_rWW8Export.pO->Insert( 49, m_rWW8Export.pO->Count() );      // Distance from text (sprmPDxaFromText)
1583         m_rWW8Export.InsUInt16( nDistance );
1584 
1585         if (rNode.GetDropSize(rFontHeight, rDropHeight, rDropDescent))
1586         {
1587             m_rWW8Export.pO->Insert( 20, m_rWW8Export.pO->Count() );  // Line spacing
1588             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -rDropHeight ) );
1589             m_rWW8Export.InsUInt16( 0 );
1590         }
1591     }
1592 
1593     m_rWW8Export.WriteCR( pTextNodeInfoInner );
1594 
1595     if ( pTextNodeInfo.get() != NULL )
1596     {
1597 #ifdef DEBUG
1598         ::std::clog << pTextNodeInfo->toString() << ::std::endl;
1599 #endif
1600 
1601         TableInfoCell( pTextNodeInfoInner );
1602     }
1603 
1604     m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() );
1605     m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() );
1606 
1607     if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) )
1608     {
1609         if ( m_rWW8Export.bWrtWW8 )
1610         {
1611             const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt();
1612             if ( pSwCharFmt )
1613             {
1614                 m_rWW8Export.InsUInt16( NS_sprm::LN_CIstd );
1615                 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) );
1616             }
1617 
1618             m_rWW8Export.InsUInt16( NS_sprm::LN_CHpsPos );            // Lower the chars
1619             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) );
1620 
1621             m_rWW8Export.InsUInt16( NS_sprm::LN_CHps );            // Font Size
1622             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( rFontHeight / 10 ) );
1623         }
1624         else
1625         {
1626             const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt();
1627             if ( pSwCharFmt )
1628             {
1629                 m_rWW8Export.InsUInt16( 80 );
1630                 m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) );
1631             }
1632 
1633             m_rWW8Export.pO->Insert( 101, m_rWW8Export.pO->Count() );      // Lower the chars
1634             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) );
1635 
1636             m_rWW8Export.pO->Insert( 99, m_rWW8Export.pO->Count() );      // Font Size
1637             m_rWW8Export.InsUInt16( static_cast< sal_uInt16 >( rFontHeight / 10 ) );
1638         }
1639     }
1640 
1641     m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() );
1642     m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() );
1643 }
1644 
1645 xub_StrLen MSWordExportBase::GetNextPos( WW8SwAttrIter* aAttrIter, const SwTxtNode& rNode, xub_StrLen nAktPos  )
1646 {
1647     // Get the bookmarks for the normal run
1648     xub_StrLen nNextPos = aAttrIter->WhereNext();
1649     xub_StrLen nNextBookmark = nNextPos;
1650 
1651     if( nNextBookmark > nAktPos )//no need to search for bookmarks otherwise
1652     {
1653         GetSortedBookmarks( rNode, nAktPos, nNextBookmark - nAktPos );
1654         NearestBookmark( nNextBookmark, nAktPos, false );
1655     }
1656     return std::min( nNextPos, nNextBookmark );
1657 }
1658 
1659 void MSWordExportBase::UpdatePosition( WW8SwAttrIter* aAttrIter, xub_StrLen nAktPos, xub_StrLen /*nEnd*/ )
1660 {
1661     xub_StrLen nNextPos;
1662 
1663     // go to next attribute if no bookmark is found and if the next attribute position if at the current position
1664     bool bNextBookmark = NearestBookmark( nNextPos, nAktPos, true );
1665     if( !bNextBookmark && nAktPos >= aAttrIter->WhereNext() )
1666         aAttrIter->NextPos();
1667 }
1668 
1669 bool MSWordExportBase::GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt,
1670                     xub_StrLen nEnd, IMarkVector& rArr )
1671 {
1672     IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1673     sal_uLong nNd = rNd.GetIndex( );
1674 
1675     const sal_Int32 nMarks = pMarkAccess->getMarksCount();
1676     for ( sal_Int32 i = 0; i < nMarks; i++ )
1677     {
1678         IMark* pMark = ( pMarkAccess->getMarksBegin() + i )->get();
1679 
1680         // Only keep the bookmarks starting or ending in this node
1681         if ( pMark->GetMarkStart().nNode == nNd ||
1682              pMark->GetMarkEnd().nNode == nNd )
1683         {
1684             xub_StrLen nBStart = pMark->GetMarkStart().nContent.GetIndex();
1685             xub_StrLen nBEnd = pMark->GetMarkEnd().nContent.GetIndex();
1686 
1687             // Keep only the bookmars starting or ending in the snippet
1688             bool bIsStartOk = ( pMark->GetMarkStart().nNode == nNd ) && ( nBStart >= nStt ) && ( nBStart <= nEnd );
1689             bool bIsEndOk = ( pMark->GetMarkEnd().nNode == nNd ) && ( nBEnd >= nStt ) && ( nBEnd <= nEnd );
1690 
1691             if ( bIsStartOk || bIsEndOk )
1692                 rArr.push_back( pMark );
1693         }
1694     }
1695     return ( rArr.size() > 0 );
1696 }
1697 
1698 class CompareMarksEnd : public std::binary_function < const IMark *, const IMark *, bool >
1699 {
1700 public:
1701     inline bool operator() ( const IMark * pOneB, const IMark * pTwoB ) const
1702     {
1703         xub_StrLen nOEnd = pOneB->GetMarkEnd().nContent.GetIndex();
1704         xub_StrLen nTEnd = pTwoB->GetMarkEnd().nContent.GetIndex();
1705 
1706         return nOEnd < nTEnd;
1707     }
1708 };
1709 
1710 bool MSWordExportBase::NearestBookmark( xub_StrLen& rNearest, const xub_StrLen nAktPos, bool bNextPositionOnly )
1711 {
1712     bool bHasBookmark = false;
1713 
1714     if ( m_rSortedMarksStart.size( ) > 0 )
1715     {
1716         IMark* pMarkStart = m_rSortedMarksStart.front();
1717         xub_StrLen nNext = pMarkStart->GetMarkStart().nContent.GetIndex();
1718         if( !bNextPositionOnly || (nNext > nAktPos ))
1719         {
1720             rNearest = nNext;
1721             bHasBookmark = true;
1722         }
1723     }
1724 
1725     if ( m_rSortedMarksEnd.size( ) > 0 )
1726     {
1727         IMark* pMarkEnd = m_rSortedMarksEnd[0];
1728         xub_StrLen nNext = pMarkEnd->GetMarkEnd().nContent.GetIndex();
1729         if( !bNextPositionOnly || nNext > nAktPos )
1730         {
1731             if ( !bHasBookmark )
1732                 rNearest = nNext;
1733             else
1734                 rNearest = std::min( rNearest, nNext );
1735             bHasBookmark = true;
1736         }
1737     }
1738 
1739     return bHasBookmark;
1740 }
1741 
1742 void MSWordExportBase::GetSortedBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen )
1743 {
1744     IMarkVector aMarksStart;
1745     if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarksStart ) )
1746     {
1747         IMarkVector aSortedEnd;
1748         IMarkVector aSortedStart;
1749         for ( IMarkVector::const_iterator it = aMarksStart.begin(), end = aMarksStart.end();
1750               it < end; ++it )
1751         {
1752             IMark* pMark = (*it);
1753 
1754             // Remove the positions egals to the current pos
1755             xub_StrLen nStart = pMark->GetMarkStart().nContent.GetIndex();
1756             xub_StrLen nEnd = pMark->GetMarkEnd().nContent.GetIndex();
1757 
1758             if ( nStart > nAktPos && ( pMark->GetMarkStart().nNode == rNode.GetIndex()) )
1759                 aSortedStart.push_back( pMark );
1760 
1761             if ( nEnd > nAktPos && nEnd <= ( nAktPos + nLen ) && (pMark->GetMarkEnd().nNode == rNode.GetIndex()) )
1762                 aSortedEnd.push_back( pMark );
1763         }
1764 
1765         // Sort the bookmarks by end position
1766         std::sort( aSortedEnd.begin(), aSortedEnd.end(), CompareMarksEnd() );
1767 
1768         m_rSortedMarksStart.swap( aSortedStart );
1769         m_rSortedMarksEnd.swap( aSortedEnd );
1770     }
1771     else
1772     {
1773         m_rSortedMarksStart.clear( );
1774         m_rSortedMarksEnd.clear( );
1775     }
1776 }
1777 
1778 void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode )
1779 {
1780 #ifdef DEBUG
1781     ::std::clog << "<OutWW8_SwTxtNode>" << ::std::endl;
1782 #endif
1783 
1784     ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo( mpTableInfo->getTableNodeInfo( &rNode ) );
1785 
1786 	//For i120928,identify the last node
1787 	bool bLastCR = false;
1788 	bool bExported = false;
1789 	{
1790 		SwNodeIndex aNextIdx(rNode,1);
1791 		SwNodeIndex aLastIdx(rNode.GetNodes().GetEndOfContent());
1792 		if (aNextIdx == aLastIdx)
1793 			bLastCR = true;
1794 	}
1795 
1796     AttrOutput().StartParagraph( pTextNodeInfo );
1797 
1798     bool bFlyInTable = mpParentFrame && IsInTable();
1799 
1800     if ( !bFlyInTable )
1801         nStyleBeforeFly = GetId( lcl_getFormatCollection( *this, &rNode ) );
1802 
1803     // nStyleBeforeFly may change when we recurse into another node, so we
1804     // have to remember it in nStyle
1805     sal_uInt16 nStyle = nStyleBeforeFly;
1806 
1807     WW8SwAttrIter aAttrIter( *this, rNode );
1808     rtl_TextEncoding eChrSet = aAttrIter.GetCharSet();
1809 
1810     if ( bStartTOX )
1811     {
1812         // ignore TOX header section
1813         const SwSectionNode* pSectNd = rNode.FindSectionNode();
1814         if ( pSectNd && TOX_CONTENT_SECTION == pSectNd->GetSection().GetType() )
1815         {
1816             AttrOutput().StartTOX( pSectNd->GetSection() );
1817             m_aCurrentCharPropStarts.push( 0 );
1818         }
1819     }
1820 
1821     const SwSection* pTOXSect = 0;
1822     if( bInWriteTOX )
1823     {
1824         // check for end of TOX
1825         SwNodeIndex aIdx( rNode, 1 );
1826         if( !aIdx.GetNode().IsTxtNode() )
1827         {
1828             const SwSectionNode* pTOXSectNd = rNode.FindSectionNode();
1829             pTOXSect = &pTOXSectNd->GetSection();
1830 
1831             const SwNode* pNxt = rNode.GetNodes().GoNext( &aIdx );
1832             if( pNxt && pNxt->FindSectionNode() == pTOXSectNd )
1833                 pTOXSect = 0;
1834         }
1835     }
1836 
1837     if ( aAttrIter.RequiresImplicitBookmark() )
1838     {
1839         String sBkmkName = String( RTL_CONSTASCII_STRINGPARAM( "_toc" ) );
1840         sBkmkName += String::CreateFromInt32( rNode.GetIndex() );
1841         AppendWordBookmark( sBkmkName );
1842     }
1843 
1844     //Would need to move into WW8Export, probably not worth it
1845     //ASSERT( pO->Count(), " pO ist am Zeilenanfang nicht leer" );
1846 
1847     String aStr( rNode.GetTxt() );
1848 
1849     xub_StrLen nAktPos = 0;
1850     xub_StrLen const nEnd = aStr.Len();
1851     bool bRedlineAtEnd = false;
1852     int nOpenAttrWithRange = 0;
1853 
1854     ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner;
1855     if ( pTextNodeInfo.get() != NULL )
1856         pTextNodeInfoInner = pTextNodeInfo->getFirstInner();
1857 
1858     do {
1859         const SwRedlineData* pRedlineData = aAttrIter.GetRedline( nAktPos );
1860 
1861         AttrOutput().StartRun( pRedlineData );
1862 
1863         xub_StrLen nNextAttr = GetNextPos( &aAttrIter, rNode, nAktPos );
1864 
1865         if( nNextAttr > nEnd )
1866             nNextAttr = nEnd;
1867 
1868         aAttrIter.OutFlys( nAktPos );
1869         //Append bookmarks in this range after flys, exclusive of final
1870         //position of this range
1871         AppendBookmarks( rNode, nAktPos, nNextAttr - nAktPos );
1872         bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos );
1873         nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nAktPos);
1874 
1875         xub_StrLen nLen = nNextAttr - nAktPos;
1876         if ( !bTxtAtr && nLen )
1877         {
1878             sal_Unicode ch = aStr.GetChar( nAktPos );
1879             int ofs = ( ch == CH_TXT_ATR_FIELDSTART || ch == CH_TXT_ATR_FIELDEND || ch == CH_TXT_ATR_FORMELEMENT? 1: 0 );
1880 
1881             IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1882             if ( ch == CH_TXT_ATR_FIELDSTART )
1883             {
1884                 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos + 1 ) );
1885                 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1886                 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
1887 
1888                 if ( pFieldmark->GetFieldname().equalsAscii( ODF_FORMTEXT ) )
1889                     AppendBookmark( pFieldmark->GetName(), false );
1890                 OutputField( NULL, lcl_getFieldId( pFieldmark ), lcl_getFieldCode( pFieldmark ), WRITEFIELD_START | WRITEFIELD_CMD_START );
1891                 if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) )
1892                     WriteFormData( *pFieldmark );
1893                 else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) )
1894                     WriteHyperlinkData( *pFieldmark );
1895                 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CMD_END );
1896             }
1897             else if ( ch == CH_TXT_ATR_FIELDEND )
1898             {
1899                 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) );
1900                 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1901                 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
1902 
1903                 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE );
1904                 if ( pFieldmark->GetFieldname().equalsAscii( ODF_FORMTEXT ) )
1905                     AppendBookmark( pFieldmark->GetName(), false );
1906             }
1907             else if ( ch == CH_TXT_ATR_FORMELEMENT )
1908             {
1909                 SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) );
1910                 ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition );
1911                 OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" );
1912 
1913                 bool isDropdownOrCheckbox = pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ||
1914                     pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX );
1915 
1916                 if ( isDropdownOrCheckbox )
1917                     AppendBookmark( pFieldmark->GetName(), 0 );
1918                 OutputField( NULL, lcl_getFieldId( pFieldmark ),
1919                         lcl_getFieldCode( pFieldmark ),
1920                         WRITEFIELD_START | WRITEFIELD_CMD_START );
1921                 if ( isDropdownOrCheckbox )
1922                     WriteFormData( *pFieldmark );
1923                 OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE );
1924                 if ( isDropdownOrCheckbox )
1925                     AppendBookmark( pFieldmark->GetName(), false );
1926             }
1927             nLen -= static_cast< sal_uInt16 >( ofs );
1928 
1929             String aSnippet( aAttrIter.GetSnippet( aStr, nAktPos + static_cast< sal_uInt16 >( ofs ), nLen ) );
1930             if ( ( nTxtTyp == TXT_EDN || nTxtTyp == TXT_FTN ) && nAktPos == 0 && nLen > 0 )
1931             {
1932                 // Insert tab for aesthetic puposes #i24762#
1933                 if ( aSnippet.GetChar( 0 ) != 0x09 )
1934                     aSnippet.Insert( 0x09, 0 );
1935             }
1936             AttrOutput().RunText( aSnippet, eChrSet );
1937         }
1938 
1939         if ( aAttrIter.IsDropCap( nNextAttr ) )
1940             AttrOutput().FormatDrop( rNode, aAttrIter.GetSwFmtDrop(), nStyle, pTextNodeInfo, pTextNodeInfoInner );
1941 
1942         if (0 != nEnd)
1943         {
1944             // Output the character attributes
1945             // #i51277# do this before writing flys at end of paragraph
1946             AttrOutput().StartRunProperties();
1947             aAttrIter.OutAttr( nAktPos );
1948             AttrOutput().EndRunProperties( pRedlineData );
1949         }
1950 
1951         // At the end of line, output the attributes until the CR.
1952         // Exception: footnotes at the end of line
1953         if ( nNextAttr == nEnd )
1954         {
1955             ASSERT( nOpenAttrWithRange >= 0, "odd to see this happening, expected >= 0" );
1956             if ( !bTxtAtr && nOpenAttrWithRange <= 0 )
1957             {
1958                 if ( aAttrIter.IsRedlineAtEnd( nEnd ) )
1959                     bRedlineAtEnd = true;
1960                 else
1961                 {
1962                     // insert final graphic anchors if any before CR
1963                     aAttrIter.OutFlys( nEnd );
1964                     // insert final bookmarks if any before CR and after flys
1965                     AppendBookmarks( rNode, nEnd, 1 );
1966                     if ( pTOXSect )
1967                     {
1968                         m_aCurrentCharPropStarts.pop();
1969                         AttrOutput().EndTOX( *pTOXSect ,false);
1970                     }
1971 			//For i120928,the position of the bullet's graphic is at end of doc
1972 			if (bLastCR && (!bExported))
1973 			{
1974 				ExportGrfBullet(rNode);
1975 				bExported = true;
1976 			}
1977 
1978                     WriteCR( pTextNodeInfoInner );
1979                 }
1980             }
1981         }
1982 
1983         if (0 == nEnd)
1984         {
1985             // Output the character attributes
1986             // do it after WriteCR for an empty paragraph (otherwise
1987             // WW8_WrFkp::Append throws SPRMs away...)
1988             AttrOutput().StartRunProperties();
1989             aAttrIter.OutAttr( nAktPos );
1990             AttrOutput().EndRunProperties( pRedlineData );
1991         }
1992 
1993         // Exception: footnotes at the end of line
1994         if ( nNextAttr == nEnd )
1995         {
1996             ASSERT(nOpenAttrWithRange >= 0,
1997                 "odd to see this happening, expected >= 0");
1998             bool bAttrWithRange = (nOpenAttrWithRange > 0);
1999             if ( nAktPos != nEnd )
2000             {
2001                 nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nEnd);
2002                 ASSERT(nOpenAttrWithRange == 0,
2003                     "odd to see this happening, expected 0");
2004             }
2005 
2006             AttrOutput().OutputFKP();
2007 
2008             if ( bTxtAtr || bAttrWithRange || bRedlineAtEnd )
2009             {
2010                 // insert final graphic anchors if any before CR
2011                 aAttrIter.OutFlys( nEnd );
2012                 // insert final bookmarks if any before CR and after flys
2013                 AppendBookmarks( rNode, nEnd, 1 );
2014                 WriteCR( pTextNodeInfoInner );
2015               //For i120928,the position of the bullet's graphic is at end of doc
2016 		if (bLastCR && (!bExported))
2017 		{
2018 			ExportGrfBullet(rNode);
2019 			bExported = true;
2020 		}
2021 
2022                 if ( pTOXSect )
2023                 {
2024                     m_aCurrentCharPropStarts.pop();
2025                     AttrOutput().EndTOX( *pTOXSect );
2026                 }
2027 
2028                 if ( bRedlineAtEnd )
2029                 {
2030                     AttrOutput().Redline( aAttrIter.GetRedline( nEnd ) );
2031                     AttrOutput().OutputFKP();
2032                 }
2033             }
2034         }
2035 
2036         AttrOutput().EndRun();
2037 
2038         nAktPos = nNextAttr;
2039         UpdatePosition( &aAttrIter, nAktPos, nEnd );
2040         eChrSet = aAttrIter.GetCharSet();
2041     }
2042     while ( nAktPos < nEnd );
2043 
2044     AttrOutput().StartParagraphProperties( rNode );
2045 
2046     AttrOutput().ParagraphStyle( nStyle );
2047 
2048     if ( mpParentFrame && IsInTable() )    // Fly-Attrs
2049         OutputFormat( mpParentFrame->GetFrmFmt(), false, false, true );
2050 
2051     if ( pTextNodeInfo.get() != NULL )
2052     {
2053 #ifdef DEBUG
2054         ::std::clog << pTextNodeInfo->toString() << ::std::endl;
2055 #endif
2056 
2057         AttrOutput().TableInfoCell( pTextNodeInfoInner );
2058         if (pTextNodeInfoInner->isFirstInTable())
2059         {
2060             const SwTable * pTable = pTextNodeInfoInner->getTable();
2061 
2062             const SwTableFmt * pTabFmt = pTable->GetTableFmt();
2063             if (pTabFmt != NULL)
2064             {
2065                 if (pTabFmt->GetBreak().GetBreak() == SVX_BREAK_PAGE_BEFORE)
2066                     AttrOutput().PageBreakBefore(true);
2067             }
2068         }
2069     }
2070 
2071     if ( !bFlyInTable )
2072     {
2073         SfxItemSet* pTmpSet = 0;
2074         const sal_uInt8 nPrvNxtNd = rNode.HasPrevNextLayNode();
2075 
2076         if( (ND_HAS_PREV_LAYNODE|ND_HAS_NEXT_LAYNODE ) != nPrvNxtNd )
2077         {
2078             const SfxPoolItem* pItem;
2079             if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState(
2080                     RES_UL_SPACE, true, &pItem ) &&
2081                 ( ( !( ND_HAS_PREV_LAYNODE & nPrvNxtNd ) &&
2082                    ((SvxULSpaceItem*)pItem)->GetUpper()) ||
2083                   ( !( ND_HAS_NEXT_LAYNODE & nPrvNxtNd ) &&
2084                    ((SvxULSpaceItem*)pItem)->GetLower()) ))
2085             {
2086                 pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
2087                 SvxULSpaceItem aUL( *(SvxULSpaceItem*)pItem );
2088                 // OD, MMAHER 2004-03-01 #i25901#- consider compatibility option
2089                 if (!pDoc->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES))
2090                 {
2091                     if( !(ND_HAS_PREV_LAYNODE & nPrvNxtNd ))
2092                         aUL.SetUpper( 0 );
2093                 }
2094                 // OD, MMAHER 2004-03-01 #i25901# - consider compatibility option
2095                 if (!pDoc->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS))
2096                 {
2097                     if( !(ND_HAS_NEXT_LAYNODE & nPrvNxtNd ))
2098                         aUL.SetLower( 0 );
2099                 }
2100                 pTmpSet->Put( aUL );
2101             }
2102         }
2103 
2104         sal_Bool bParaRTL = sal_False;
2105         const SvxFrameDirectionItem* pItem = (const SvxFrameDirectionItem*)
2106             rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR);
2107         if ( aAttrIter.IsParaRTL())
2108             bParaRTL = sal_True;
2109 
2110         if( rNode.IsNumbered())
2111         {
2112             const SwNumRule* pRule = rNode.GetNumRule();
2113             sal_uInt8 nLvl = static_cast< sal_uInt8 >( rNode.GetActualListLevel() );
2114             const SwNumFmt* pFmt = pRule->GetNumFmt( nLvl );
2115             if( !pFmt )
2116                 pFmt = &pRule->Get( nLvl );
2117 
2118             if( !pTmpSet )
2119                 pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() );
2120 
2121             SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*pTmpSet, RES_LR_SPACE));
2122             // --> OD 2008-06-03 #i86652#
2123             if ( pFmt->GetPositionAndSpaceMode() ==
2124                                     SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2125             {
2126                 aLR.SetTxtLeft( aLR.GetTxtLeft() + pFmt->GetAbsLSpace() );
2127             }
2128             // <--
2129 
2130             if( rNode.IsNumbered() && rNode.IsCountedInList() )
2131             {
2132                 // --> OD 2008-06-03 #i86652#
2133                 if ( pFmt->GetPositionAndSpaceMode() ==
2134                                         SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2135                 {
2136                     if (bParaRTL)
2137                         aLR.SetTxtFirstLineOfstValue(pFmt->GetAbsLSpace() - pFmt->GetFirstLineOffset());
2138                     else
2139                         aLR.SetTxtFirstLineOfst(GetWordFirstLineOffset(*pFmt));
2140                 }
2141                 // <--
2142 
2143                 // --> OD 2009-03-09 #100020#
2144                 // correct fix for issue i94187
2145                 if (SFX_ITEM_SET !=
2146                     pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
2147                 {
2148                     // List style set via paragraph style - then put it into the itemset.
2149                     // This is needed to get list level and list id exported for
2150                     // the paragraph.
2151                     pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
2152 
2153                     // Put indent values into the itemset in case that the list
2154                     // style is applied via paragraph style and the list level
2155                     // indent values are not applicable.
2156                     if ( pFmt->GetPositionAndSpaceMode() ==
2157                                             SvxNumberFormat::LABEL_ALIGNMENT &&
2158                          !rNode.AreListLevelIndentsApplicable() )
2159                     {
2160                         pTmpSet->Put( aLR );
2161                     }
2162                 }
2163             }
2164             else
2165                 pTmpSet->ClearItem(RES_PARATR_NUMRULE);
2166 
2167             // --> OD 2008-06-03 #i86652#
2168             if ( pFmt->GetPositionAndSpaceMode() ==
2169                                     SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2170             {
2171                 pTmpSet->Put(aLR);
2172 
2173                 //#i21847#
2174                 SvxTabStopItem aItem(
2175                     ItemGet<SvxTabStopItem>(*pTmpSet, RES_PARATR_TABSTOP));
2176                 SvxTabStop aTabStop(pFmt->GetAbsLSpace());
2177                 aItem.Insert(aTabStop);
2178                 pTmpSet->Put(aItem);
2179 
2180                 MSWordExportBase::CorrectTabStopInSet(*pTmpSet, pFmt->GetAbsLSpace());
2181             }
2182         }
2183 
2184         /*
2185         If a given para is using the FRMDIR_ENVIRONMENT direction we
2186         cannot export that, its its ltr then that's ok as thats word's
2187         default. Otherwise we must add a RTL attribute to our export list
2188         */
2189         pItem = (const SvxFrameDirectionItem*)
2190             rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR);
2191         if (
2192             (!pItem || pItem->GetValue() == FRMDIR_ENVIRONMENT) &&
2193             aAttrIter.IsParaRTL()
2194            )
2195         {
2196             if ( !pTmpSet )
2197                 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2198 
2199             pTmpSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_RIGHT_TOP, RES_FRAMEDIR));
2200         }
2201         // --> OD 2005-10-18 #126238# - move code for handling of numbered,
2202         // but not counted paragraphs to this place. Otherwise, the paragraph
2203         // isn't exported as numbered, but not counted, if no other attribute
2204         // is found in <pTmpSet>
2205         // #i44815# adjust numbering/indents for numbered paragraphs
2206         //          without number (NO_NUMLEVEL)
2207         // #i47013# need to check rNode.GetNumRule()!=NULL as well.
2208         if ( ! rNode.IsCountedInList() && rNode.GetNumRule()!=NULL )
2209         {
2210             // WW8 does not know numbered paragraphs without number
2211             // (NO_NUMLEVEL). In WW8AttributeOutput::ParaNumRule(), we will export
2212             // the RES_PARATR_NUMRULE as list-id 0, which in WW8 means
2213             // no numbering. Here, we will adjust the indents to match
2214             // visually.
2215 
2216             if ( !pTmpSet )
2217                 pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2218 
2219             // create new LRSpace item, based on the current (if present)
2220             const SfxPoolItem* pPoolItem = NULL;
2221             pTmpSet->GetItemState(RES_LR_SPACE, sal_True, &pPoolItem);
2222             SvxLRSpaceItem aLRSpace(
2223                 ( pPoolItem == NULL )
2224                     ? SvxLRSpaceItem(0, 0, 0, 0, RES_LR_SPACE)
2225                     : *static_cast<const SvxLRSpaceItem*>( pPoolItem ) );
2226 
2227             // new left margin = old left + label space
2228             const SwNumRule* pRule = rNode.GetNumRule();
2229             const SwNumFmt& rNumFmt = pRule->Get( static_cast< sal_uInt16 >(rNode.GetActualListLevel()) );
2230             // --> OD 2008-06-03 #i86652#
2231             if ( rNumFmt.GetPositionAndSpaceMode() ==
2232                                     SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2233             {
2234                 aLRSpace.SetTxtLeft( aLRSpace.GetLeft() + rNumFmt.GetAbsLSpace() );
2235 
2236                 // new first line indent = 0
2237                 // (first line indent is ignored for NO_NUMLEVEL)
2238                 if (!bParaRTL)
2239                     aLRSpace.SetTxtFirstLineOfst( 0 );
2240 
2241                 // put back the new item
2242                 pTmpSet->Put( aLRSpace );
2243             }
2244             // <--
2245 
2246             // assure that numbering rule is in <pTmpSet>
2247             if (SFX_ITEM_SET != pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) )
2248             {
2249                 pTmpSet->Put( SwNumRuleItem( pRule->GetName() ));
2250             }
2251         }
2252 
2253         // --> OD 2007-04-24 #i75457#
2254         // Export page break after attribute from paragraph style.
2255         // If page break attribute at the text node exist, an existing page
2256         // break after at the paragraph style hasn't got to be considered.
2257         if ( !rNode.GetpSwAttrSet() ||
2258              SFX_ITEM_SET != rNode.GetpSwAttrSet()->GetItemState(RES_BREAK, false) )
2259         {
2260             const SvxFmtBreakItem* pBreakAtParaStyle =
2261                 &(ItemGet<SvxFmtBreakItem>(rNode.GetSwAttrSet(), RES_BREAK));
2262             if ( pBreakAtParaStyle &&
2263                  pBreakAtParaStyle->GetBreak() == SVX_BREAK_PAGE_AFTER )
2264             {
2265                 if ( !pTmpSet )
2266                 {
2267                     pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2268                 }
2269                 pTmpSet->Put( *pBreakAtParaStyle );
2270             }
2271             else if( pTmpSet )
2272             {   // Even a pagedesc item is set, the break item can be set 'NONE',
2273                 // this has to be overruled.
2274                 const SwFmtPageDesc& rPageDescAtParaStyle =
2275                     ItemGet<SwFmtPageDesc>( rNode, RES_PAGEDESC );
2276                 if( rPageDescAtParaStyle.KnowsPageDesc() )
2277                     pTmpSet->ClearItem( RES_BREAK );
2278             }
2279         }
2280 
2281         // --> FME 2007-05-30 #i76520# Emulate non-splitting tables
2282         if ( bOutTable )
2283         {
2284             const SwTableNode* pTableNode = rNode.FindTableNode();
2285 
2286             if ( pTableNode )
2287             {
2288                 const SwTable& rTable = pTableNode->GetTable();
2289                 const SvxFmtKeepItem& rKeep = rTable.GetFrmFmt()->GetKeep();
2290                 const bool bKeep = rKeep.GetValue();
2291                 const bool bDontSplit = !bKeep ?
2292                                         !rTable.GetFrmFmt()->GetLayoutSplit().GetValue() :
2293                                         false;
2294 
2295                 if ( bKeep || bDontSplit )
2296                 {
2297                     // bKeep: set keep at first paragraphs in all lines
2298                     // bDontSplit : set keep at first paragraphs in all lines except from last line
2299                     // but only for non-complex tables
2300                     const SwTableBox* pBox = rNode.GetTblBox();
2301                     const SwTableLine* pLine = pBox ? pBox->GetUpper() : 0;
2302 
2303                     if ( pLine && !pLine->GetUpper() )
2304                     {
2305                         // check if box is first in that line:
2306                         if ( 0 == pLine->GetTabBoxes().GetPos( pBox ) && pBox->GetSttNd() )
2307                         {
2308                             // check if paragraph is first in that line:
2309                             if ( 1 == ( rNode.GetIndex() - pBox->GetSttNd()->GetIndex() ) )
2310                             {
2311                                 bool bSetAtPara = false;
2312                                 if ( bKeep )
2313                                     bSetAtPara = true;
2314                                 else if ( bDontSplit )
2315                                 {
2316                                     // check if pLine isn't last line in table
2317                                     if ( rTable.GetTabLines().Count() - rTable.GetTabLines().GetPos( pLine ) != 1 )
2318                                         bSetAtPara = true;
2319                                 }
2320 
2321                                 if ( bSetAtPara )
2322                                 {
2323                                     if ( !pTmpSet )
2324                                         pTmpSet = new SfxItemSet(rNode.GetSwAttrSet());
2325 
2326                                     const SvxFmtKeepItem aKeepItem( sal_True, RES_KEEP );
2327                                     pTmpSet->Put( aKeepItem );
2328                                 }
2329                             }
2330                         }
2331                     }
2332                 }
2333             }
2334         }
2335         // <--
2336 
2337         const SfxItemSet* pNewSet = pTmpSet ? pTmpSet : rNode.GetpSwAttrSet();
2338         if( pNewSet )
2339         {                                               // Para-Attrs
2340             pStyAttr = &rNode.GetAnyFmtColl().GetAttrSet();
2341 
2342             const SwModify* pOldMod = pOutFmtNode;
2343             pOutFmtNode = &rNode;
2344 
2345             // Pap-Attrs, so script is not necessary
2346             OutputItemSet( *pNewSet, true, false, i18n::ScriptType::LATIN, false);
2347 
2348             pStyAttr = 0;
2349             pOutFmtNode = pOldMod;
2350 
2351             if( pNewSet != rNode.GetpSwAttrSet() )
2352                 delete pNewSet;
2353         }
2354     }
2355 
2356     AttrOutput().EndParagraphProperties();
2357 
2358     AttrOutput().EndParagraph( pTextNodeInfoInner );
2359 
2360 #ifdef DEBUG
2361     ::std::clog << "</OutWW8_SwTxtNode>" << ::std::endl;
2362 #endif
2363 }
2364 
2365 void WW8AttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t pNodeInfo )
2366 {
2367     SVBT16 nSty;
2368     ShortToSVBT16( GetExport().nStyleBeforeFly, nSty );
2369 
2370     ww8::WW8TableNodeInfo::Inners_t::const_iterator aIt( pNodeInfo->getInners().begin() );
2371     ww8::WW8TableNodeInfo::Inners_t::const_iterator aItEnd( pNodeInfo->getInners().end() );
2372 
2373     while (aIt != aItEnd)
2374     {
2375         ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second;
2376         if ( pInner->isEndOfCell() )
2377         {
2378             TableRowEnd( pInner->getDepth() );
2379 
2380             m_rWW8Export.pO->Insert( (sal_uInt8*)&nSty, 2, m_rWW8Export.pO->Count() );     // Style #
2381             TableInfoRow( pInner );
2382             m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(),
2383                                      m_rWW8Export.pO->GetData() );
2384             m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() );                       // leeren
2385         }
2386 
2387         if ( pInner->isEndOfLine() )
2388         {
2389         }
2390 
2391         aIt++;
2392     }
2393 }
2394 
2395 #if 0
2396 /*  */
2397 
2398 sal_uInt16 WW8Export::StartTableFromFrmFmt( WW8Bytes &rAt, const SwFrmFmt *pFmt )
2399 {
2400     // Tell the undocumented table hack that everything between here and
2401     // the last table position is nontable text
2402     if ( WW8_CP nPos = Fc2Cp( Strm().Tell() ) )
2403         pMagicTable->Append(nPos,0);
2404 
2405     // sprmPDxaFromText10
2406     if( bWrtWW8 )
2407     {
2408         static sal_uInt8 __READONLY_DATA  aTabLineAttr[] = {
2409                 0, 0,               // Sty # 0
2410                 0x16, 0x24, 1,      // sprmPFInTable
2411                 0x17, 0x24, 1 };    // sprmPFTtp
2412         rAt.Insert( aTabLineAttr, sizeof( aTabLineAttr ), rAt.Count() );
2413     }
2414     else
2415     {
2416         static sal_uInt8 __READONLY_DATA  aTabLineAttr[] = {
2417                 0, 0,               // Sty # 0
2418                 24, 1,              // sprmPFInTable
2419                 25, 1 };            // sprmPFTtp
2420         rAt.Insert( aTabLineAttr, sizeof( aTabLineAttr ), rAt.Count() );
2421     }
2422 
2423     ASSERT( pFmt, "No pFmt!" );
2424     if ( pFmt )
2425     {
2426         const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient();
2427         const SwFmtVertOrient &rVert = pFmt->GetVertOrient();
2428         if (
2429             (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ||
2430              text::RelOrientation::FRAME == rHori.GetRelationOrient())
2431             &&
2432             (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() ||
2433              text::RelOrientation::FRAME == rVert.GetRelationOrient())
2434            )
2435         {
2436             sal_Int16 eHOri = rHori.GetHoriOrient();
2437             switch (eHOri)
2438             {
2439                 case text::HoriOrientation::CENTER:
2440                 case text::HoriOrientation::RIGHT:
2441                     if( bWrtWW8 )
2442                         SwWW8Writer::InsUInt16( rAt, NS_sprm::LN_TJc );
2443                     else
2444                         rAt.Insert( 182, rAt.Count() );
2445                     SwWW8Writer::InsUInt16( rAt, (text::HoriOrientation::RIGHT == eHOri ? 2 : 1 ));
2446                     break;
2447                 default:
2448                     break;
2449             }
2450         }
2451     }
2452     return rAt.Count();
2453 }
2454 
2455 //See #i19484# for why we need this
2456 static bool CellContainsProblematicGraphic( const SwWriteTableCell *pCell,
2457     const MSWordExportBase &rExport )
2458 {
2459     const SwNode *pStart = pCell ? pCell->GetBox()->GetSttNd() : 0;
2460     const SwNode *pEnd = pStart ? pStart->EndOfSectionNode() : 0;
2461     ASSERT( pStart && pEnd, "No start or end?" );
2462     if ( !pStart || !pEnd )
2463         return false;
2464 
2465     bool bHasGraphic = false;
2466 
2467     sw::Frames aFrames( GetFramesBetweenNodes( rExport.maFrames, *pStart, *pEnd ) );
2468     sw::FrameIter aEnd = aFrames.end();
2469     for ( sw::FrameIter aIter = aFrames.begin(); aIter != aEnd; ++aIter )
2470     {
2471         const SwFrmFmt &rEntry = aIter->GetFrmFmt();
2472         if ( rEntry.GetSurround().GetSurround() == SURROUND_THROUGHT )
2473         {
2474             bHasGraphic = true;
2475             break;
2476         }
2477     }
2478     return bHasGraphic;
2479 }
2480 
2481 static bool RowContainsProblematicGraphic( const SwWriteTableCellPtr *pRow,
2482     sal_uInt16 nCols, const MSWordExportBase &rExport )
2483 {
2484     bool bHasGraphic = false;
2485     for ( sal_uInt16 nI = 0; nI < nCols; ++nI )
2486     {
2487         if ( CellContainsProblematicGraphic( pRow[nI], rExport ) )
2488         {
2489             bHasGraphic = true;
2490             break;
2491         }
2492     }
2493     return bHasGraphic;
2494 }
2495 #endif
2496 //---------------------------------------------------------------------------
2497 //       Tabellen
2498 //---------------------------------------------------------------------------
2499 
2500 void WW8AttributeOutput::EmptyParagraph()
2501 {
2502     m_rWW8Export.WriteStringAsPara( aEmptyStr );
2503 }
2504 
2505 bool MSWordExportBase::NoPageBreakSection( const SfxItemSet* pSet )
2506 {
2507     bool bRet = false;
2508     const SfxPoolItem* pI;
2509     if( pSet)
2510     {
2511         bool bNoPageBreak = false;
2512         if ( SFX_ITEM_ON != pSet->GetItemState(RES_PAGEDESC, true, &pI)
2513             || 0 == ((SwFmtPageDesc*)pI)->GetPageDesc() )
2514         {
2515             bNoPageBreak = true;
2516         }
2517 
2518         if (bNoPageBreak)
2519         {
2520             if (SFX_ITEM_ON != pSet->GetItemState(RES_BREAK, true, &pI))
2521                 bNoPageBreak = true;
2522             else
2523             {
2524                 SvxBreak eBreak = ((const SvxFmtBreakItem*)pI)->GetBreak();
2525                 switch (eBreak)
2526                 {
2527                     case SVX_BREAK_PAGE_BEFORE:
2528                     case SVX_BREAK_PAGE_AFTER:
2529                         bNoPageBreak = false;
2530                         break;
2531                     default:
2532                         break;
2533                 }
2534             }
2535         }
2536         bRet = bNoPageBreak;
2537     }
2538     return bRet;
2539 }
2540 
2541 /*  */
2542 
2543 void MSWordExportBase::OutputSectionNode( const SwSectionNode& rSectionNode )
2544 {
2545     const SwSection& rSection = rSectionNode.GetSection();
2546 
2547     SwNodeIndex aIdx( rSectionNode, 1 );
2548     const SwNode& rNd = aIdx.GetNode();
2549     if ( !rNd.IsSectionNode() && !IsInTable()
2550 		&& rSection.GetType() != TOX_CONTENT_SECTION && rSection.GetType() != TOX_HEADER_SECTION) //No sections in table
2551     {
2552         // Bug 74245 - if the first Node inside the section has an own
2553         //              PageDesc or PageBreak attribut, then dont write
2554         //              here the section break
2555         sal_uLong nRstLnNum = 0;
2556         const SfxItemSet* pSet;
2557         if ( rNd.IsTableNode() )
2558             pSet = &rNd.GetTableNode()->GetTable().GetFrmFmt()->GetAttrSet();
2559         else if ( rNd.IsCntntNode() )
2560         {
2561             pSet = &rNd.GetCntntNode()->GetSwAttrSet();
2562             nRstLnNum = ((SwFmtLineNumber&)pSet->Get(
2563                             RES_LINENUMBER )).GetStartValue();
2564         }
2565         else
2566             pSet = 0;
2567 
2568         if ( pSet && NoPageBreakSection( pSet ) )
2569             pSet = 0;
2570 
2571         if ( !pSet )
2572         {
2573             // new Section with no own PageDesc/-Break
2574             //  -> write follow section break;
2575             const SwSectionFmt& rFmt = *rSection.GetFmt();
2576             ReplaceCr( msword::PageBreak ); // Indikator fuer Page/Section-Break
2577 
2578             //Get the page in use at the top of this section
2579             SwNodeIndex aIdxTmp(rSectionNode, 1);
2580             const SwPageDesc *pCurrent =
2581                 SwPageDesc::GetPageDescOfNode(aIdxTmp.GetNode());
2582             if (!pCurrent)
2583                 pCurrent = pAktPageDesc;
2584 
2585             AppendSection( pCurrent, &rFmt, nRstLnNum );
2586         }
2587     }
2588     if ( TOX_CONTENT_SECTION == rSection.GetType() )
2589         bStartTOX = true;
2590 }
2591 
2592 
2593 void WW8Export::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFmt* pFmt, sal_uLong nLnNum )
2594 {
2595     pSepx->AppendSep(Fc2Cp(Strm().Tell()), pPageDesc, pFmt, nLnNum);
2596 }
2597 
2598 /*  */
2599 
2600 //---------------------------------------------------------------------------
2601 //       Flys
2602 //---------------------------------------------------------------------------
2603 
2604 void WW8Export::OutWW6FlyFrmsInCntnt( const SwTxtNode& rNd )
2605 {
2606     ASSERT(!bWrtWW8, "I shouldn't be needed for Word >=8");
2607     if ( bWrtWW8 )
2608         return;
2609 
2610     if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints())
2611     {
2612         for( sal_uInt16 n=0; n < pTxtAttrs->Count(); ++n )
2613         {
2614             const SwTxtAttr* pAttr = (*pTxtAttrs)[ n ];
2615             if( RES_TXTATR_FLYCNT == pAttr->Which() )
2616             {
2617                 // zeichengebundenes Attribut
2618                 const SwFmtFlyCnt& rFlyCntnt = pAttr->GetFlyCnt();
2619                 const SwFlyFrmFmt& rFlyFrmFmt = *(SwFlyFrmFmt*)rFlyCntnt.GetFrmFmt();
2620                 const SwNodeIndex* pNodeIndex = rFlyFrmFmt.GetCntnt().GetCntntIdx();
2621 
2622                 if( pNodeIndex )
2623                 {
2624                     sal_uLong nStt = pNodeIndex->GetIndex()+1,
2625                           nEnd = pNodeIndex->GetNode().EndOfSectionIndex();
2626 
2627                     if( (nStt < nEnd) && !pDoc->GetNodes()[ nStt ]->IsNoTxtNode() )
2628                     {
2629                         Point aOffset;
2630                         // Rechtecke des Flys und des Absatzes besorgen
2631                         SwRect aParentRect(rNd.FindLayoutRect(false, &aOffset)),
2632                                aFlyRect(rFlyFrmFmt.FindLayoutRect(false, &aOffset ) );
2633 
2634                         aOffset = aFlyRect.Pos() - aParentRect.Pos();
2635 
2636                         // PaM umsetzen: auf Inhalt des Fly-Frameformats
2637                         SaveData( nStt, nEnd );
2638 
2639                         // wird in OutputFormat() ausgewertet
2640                         pFlyOffset = &aOffset;
2641                         eNewAnchorType = rFlyFrmFmt.GetAnchor().GetAnchorId();
2642                         sw::Frame aFrm(rFlyFrmFmt, SwPosition(rNd));
2643                         mpParentFrame = &aFrm;
2644                         // Ok, rausschreiben:
2645                         WriteText();
2646 
2647                         RestoreData();
2648                     }
2649                 }
2650             }
2651         }
2652     }
2653 }
2654 
2655 void WW8AttributeOutput::OutputFlyFrame_Impl( const sw::Frame& rFmt, const Point& rNdTopLeft )
2656 {
2657     const SwFrmFmt &rFrmFmt = rFmt.GetFrmFmt();
2658     const SwFmtAnchor& rAnch = rFrmFmt.GetAnchor();
2659 
2660     bool bUseEscher = m_rWW8Export.bWrtWW8;
2661 
2662     if ( m_rWW8Export.bWrtWW8 && rFmt.IsInline() )
2663     {
2664         sw::Frame::WriterSource eType = rFmt.GetWriterType();
2665         if ((eType == sw::Frame::eGraphic) || (eType == sw::Frame::eOle))
2666             bUseEscher = false;
2667         else
2668             bUseEscher = true;
2669 
2670         /*
2671          #110185#
2672          A special case for converting some inline form controls to form fields
2673          when in winword 8+ mode
2674         */
2675         if ((bUseEscher == true) && (eType == sw::Frame::eFormControl))
2676         {
2677             if ( m_rWW8Export.MiserableFormFieldExportHack( rFrmFmt ) )
2678                 return ;
2679         }
2680     }
2681 
2682     if (bUseEscher)
2683     {
2684         ASSERT( m_rWW8Export.bWrtWW8, "this has gone horribly wrong" );
2685         // write as escher
2686         m_rWW8Export.AppendFlyInFlys(rFmt, rNdTopLeft);
2687     }
2688     else
2689     {
2690         bool bDone = false;
2691 
2692         // Hole vom Node und vom letzten Node die Position in der Section
2693         const SwNodeIndex* pNodeIndex = rFrmFmt.GetCntnt().GetCntntIdx();
2694 
2695         sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex()+1                  : 0;
2696         sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
2697 
2698         if( nStt >= nEnd )      // kein Bereich, also kein gueltiger Node
2699             return;
2700 
2701         if ( !m_rWW8Export.IsInTable() && rFmt.IsInline() )
2702         {
2703             //Test to see if this textbox contains only a single graphic/ole
2704             SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode();
2705             if ( pParTxtNode && !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode() )
2706                 bDone = true;
2707         }
2708         if( !bDone )
2709         {
2710             // ein NICHT zeichengebundener Rahmen liegt vor
2711 
2712             // --> OD 2007-04-19 #i43447# - removed
2713 //            const SwFmtFrmSize& rS = rFrmFmt.GetFrmSize();
2714 //            nFlyWidth  = rS.GetWidth();  // Fuer Anpassung Graphic-Groesse
2715 //            nFlyHeight = rS.GetHeight();
2716             // <--
2717 
2718             m_rWW8Export.SaveData( nStt, nEnd );
2719 
2720             Point aOffset;
2721             if ( m_rWW8Export.mpParentFrame )
2722             {
2723                 /*
2724                 #90804#
2725                 Munge flys in fly into absolutely positioned elements for
2726                 word 6
2727                 */
2728                 const SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode();
2729                 const SwRect aPageRect = pParTxtNode->FindPageFrmRect( sal_False, 0, sal_False );
2730 
2731                 aOffset = rFrmFmt.FindLayoutRect().Pos();
2732                 aOffset -= aPageRect.Pos();
2733 
2734                 m_rWW8Export.pFlyOffset = &aOffset;
2735                 m_rWW8Export.eNewAnchorType = FLY_AT_PAGE;
2736             }
2737 
2738             m_rWW8Export.mpParentFrame = &rFmt;
2739             if (
2740                 m_rWW8Export.IsInTable() &&
2741                  (FLY_AT_PAGE != rAnch.GetAnchorId()) &&
2742                  !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode()
2743                )
2744             {
2745                 // Beachten: Flag  bOutTable  wieder setzen,
2746                 //           denn wir geben ja ganz normalen Content der
2747                 //           Tabelenzelle aus und keinen Rahmen
2748                 //           (Flag wurde oben in  aSaveData()  geloescht)
2749                 m_rWW8Export.bOutTable = true;
2750                 const String& rName = rFrmFmt.GetName();
2751                 m_rWW8Export.StartCommentOutput(rName);
2752                 m_rWW8Export.WriteText();
2753                 m_rWW8Export.EndCommentOutput(rName);
2754             }
2755             else
2756                 m_rWW8Export.WriteText();
2757 
2758             m_rWW8Export.RestoreData();
2759         }
2760     }
2761 }
2762 
2763 void AttributeOutputBase::OutputFlyFrame( const sw::Frame& rFmt )
2764 {
2765     if ( !rFmt.GetCntntNode() )
2766         return;
2767 
2768     const SwCntntNode &rNode = *rFmt.GetCntntNode();
2769     Point aNdPos, aPgPos;
2770     Point* pLayPos;
2771     bool bValidNdPos = false, bValidPgPos = false;
2772 
2773     if (FLY_AT_PAGE == rFmt.GetFrmFmt().GetAnchor().GetAnchorId())
2774     {
2775         // get the Layout Node-Position.
2776         if ( !bValidPgPos )
2777         {
2778             aPgPos = rNode.FindPageFrmRect(false, &aPgPos).Pos();
2779             bValidPgPos = true;
2780         }
2781         pLayPos = &aPgPos;
2782     }
2783     else
2784     {
2785         // get the Layout Node-Position.
2786         if ( !bValidNdPos )
2787         {
2788             aNdPos = rNode.FindLayoutRect(false, &aNdPos).Pos();
2789             bValidNdPos = true;
2790         }
2791         pLayPos = &aNdPos;
2792     }
2793 
2794     OutputFlyFrame_Impl( rFmt, *pLayPos );
2795 }
2796 
2797 // write data of any redline
2798 void WW8AttributeOutput::Redline( const SwRedlineData* pRedline )
2799 {
2800     if ( !pRedline )
2801         return;
2802 
2803     if ( pRedline->Next() )
2804         Redline( pRedline->Next() );
2805 
2806     static sal_uInt16 __READONLY_DATA aSprmIds[ 2 * 2 * 3 ] =
2807     {
2808         // Ids for insert
2809             NS_sprm::LN_CFRMark, NS_sprm::LN_CIbstRMark, NS_sprm::LN_CDttmRMark,         // for WW8
2810             0x0042, 0x0045, 0x0046,         // for WW6
2811         // Ids for delete
2812             NS_sprm::LN_CFRMarkDel, NS_sprm::LN_CIbstRMarkDel, NS_sprm::LN_CDttmRMarkDel,         // for WW8
2813             0x0041, 0x0045, 0x0046          // for WW6
2814     };
2815 
2816     const sal_uInt16* pSprmIds = 0;
2817     switch( pRedline->GetType() )
2818     {
2819     case nsRedlineType_t::REDLINE_INSERT:
2820         pSprmIds = aSprmIds;
2821         break;
2822 
2823     case nsRedlineType_t::REDLINE_DELETE:
2824         pSprmIds = aSprmIds + (2 * 3);
2825         break;
2826 
2827     case nsRedlineType_t::REDLINE_FORMAT:
2828         if( m_rWW8Export.bWrtWW8 )
2829         {
2830             m_rWW8Export.InsUInt16( NS_sprm::LN_CPropRMark );
2831             m_rWW8Export.pO->Insert( 7, m_rWW8Export.pO->Count() );       // len
2832             m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() );
2833             m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) );
2834             m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() ));
2835         }
2836         break;
2837     default:
2838         ASSERT(!this, "Unhandled redline type for export");
2839         break;
2840     }
2841 
2842     if ( pSprmIds )
2843     {
2844         if ( !m_rWW8Export.bWrtWW8 )
2845             pSprmIds += 3;
2846 
2847         if ( m_rWW8Export.bWrtWW8 )
2848             m_rWW8Export.InsUInt16( pSprmIds[0] );
2849         else
2850             m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[0]), m_rWW8Export.pO->Count() );
2851         m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() );
2852 
2853         if ( m_rWW8Export.bWrtWW8 )
2854             m_rWW8Export.InsUInt16( pSprmIds[1] );
2855         else
2856             m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[1]), m_rWW8Export.pO->Count() );
2857         m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) );
2858 
2859         if ( m_rWW8Export.bWrtWW8 )
2860             m_rWW8Export.InsUInt16( pSprmIds[2] );
2861         else
2862             m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[2]), m_rWW8Export.pO->Count() );
2863         m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() ));
2864     }
2865 }
2866 
2867 /*  */
2868 
2869 void MSWordExportBase::OutputContentNode( const SwCntntNode& rNode )
2870 {
2871     switch ( rNode.GetNodeType() )
2872     {
2873         case ND_TEXTNODE:
2874         {
2875             const SwTxtNode& rTextNode = *rNode.GetTxtNode();
2876             if( !mbOutOutlineOnly || rTextNode.IsOutline() )
2877                 OutputTextNode( rTextNode );
2878         }
2879         break;
2880         case ND_GRFNODE:
2881             OutputGrfNode( *rNode.GetGrfNode() );
2882             break;
2883         case ND_OLENODE:
2884             OutputOLENode( *rNode.GetOLENode() );
2885             break;
2886         default:
2887 #if OSL_DEBUG_LEVEL > 0
2888             OSL_TRACE("Unhandled node, type == %d\n", rNode.GetNodeType() );
2889 #endif
2890             break;
2891     }
2892 }
2893 
2894 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
2895