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