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