xref: /AOO41X/main/sw/source/filter/html/htmlatr.cxx (revision dec99bbd1eb6ae693d6ee672c1a69e3a32d917e7)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <hintids.hxx>
29 #include <com/sun/star/i18n/ScriptType.hpp>
30 #include <vcl/svapp.hxx>
31 #include <vcl/wrkwin.hxx>
32 #include <tools/urlobj.hxx>
33 #include <sfx2/sfx.hrc>
34 #if !defined _SVSTDARR_XUB_STRLEN_DECL || !defined _SVSTDARR_USHORTS_DECL
35 #define _SVSTDARR_XUB_STRLEN
36 #define _SVSTDARR_USHORTS
37 #include <svl/svstdarr.hxx>
38 #endif
39 #include <svtools/htmlout.hxx>
40 #include <svtools/htmlkywd.hxx>
41 #include <svtools/htmltokn.h>
42 #include <svl/whiter.hxx>
43 #include <svx/htmlmode.hxx>
44 #include <editeng/escpitem.hxx>
45 #include <editeng/brkitem.hxx>
46 #include <editeng/boxitem.hxx>
47 #include <editeng/ulspitem.hxx>
48 #include <editeng/udlnitem.hxx>
49 #include <editeng/crsditem.hxx>
50 #include <editeng/blnkitem.hxx>
51 #include <editeng/cmapitem.hxx>
52 #include <editeng/colritem.hxx>
53 #include <editeng/fontitem.hxx>
54 #include <editeng/fhgtitem.hxx>
55 #include <editeng/postitem.hxx>
56 #include <editeng/kernitem.hxx>
57 #include <editeng/wghtitem.hxx>
58 #include <editeng/lspcitem.hxx>
59 #include <editeng/adjitem.hxx>
60 #include <editeng/lrspitem.hxx>
61 #include <editeng/brshitem.hxx>
62 #include <editeng/langitem.hxx>
63 #include <editeng/frmdiritem.hxx>
64 #include <fchrfmt.hxx>
65 #include <fmtautofmt.hxx>
66 #include <fmtfsize.hxx>
67 #include <fmtclds.hxx>
68 #include <fmtpdsc.hxx>
69 #include <fmtflcnt.hxx>
70 #include <fmtinfmt.hxx>
71 #include <fmtftn.hxx>
72 #include <txatbase.hxx>
73 #include <frmatr.hxx>
74 #include <charfmt.hxx>
75 #include <fmtfld.hxx>
76 #include <doc.hxx>
77 #include <pam.hxx>
78 #include <ndtxt.hxx>
79 #include <paratr.hxx>
80 #include <poolfmt.hxx>
81 #include <pagedesc.hxx>
82 #include <swtable.hxx>
83 #include "fldbas.hxx"
84 #include <breakit.hxx>
85 #include <htmlnum.hxx>
86 #include <wrthtml.hxx>
87 #include <htmlfly.hxx>
88 #include <numrule.hxx>
89 
90 using namespace ::com::sun::star;
91 
92 /*
93  * um nicht immer wieder nach einem Update festzustellen, das irgendwelche
94  * Hint-Ids dazugekommen sind, wird hier definiert, die Groesse der Tabelle
95  * definiert und mit der akt. verglichen. Bei unterschieden wird der
96  * Compiler schon meckern.
97  *
98  * diese Section und die dazugeherigen Tabellen muessen in folgenden Files
99  * gepflegt werden: rtf\rtfatr.cxx, sw6\sw6atr.cxx, w4w\w4watr.cxx
100  */
101 #if !defined(UNX) && !defined(MSC) && !defined(PPC) && !defined(CSET) && !defined(__MWERKS__) && !defined(WTC) && !defined(__MINGW32__) && !defined(OS2)
102 
103 #define ATTRFNTAB_SIZE 130
104 #if ATTRFNTAB_SIZE != POOLATTR_END - POOLATTR_BEGIN
105 #error Attribut-Tabelle ist ungueltigt. Wurden neue Hint-IDs zugefuegt ??
106 #endif
107 
108 #ifdef FORMAT_TABELLE
109 // da sie nicht benutzt wird!
110 #define FORMATTAB_SIZE 7
111 #if FORMATTAB_SIZE != RES_FMT_END - RES_FMT_BEGIN
112 #error Format-Tabelle ist ungueltigt. Wurden neue Hint-IDs zugefuegt ??
113 #endif
114 #endif
115 
116 #define NODETAB_SIZE 3
117 #if NODETAB_SIZE != RES_NODE_END - RES_NODE_BEGIN
118 #error Node-Tabelle ist ungueltigt. Wurden neue Hint-IDs zugefuegt ??
119 #endif
120 
121 #endif
122 
123 #define HTML_BULLETCHAR_DISC    34
124 #define HTML_BULLETCHAR_CIRCLE  38
125 #define HTML_BULLETCHAR_SQUARE  36
126 
127 #define COLFUZZY 20
128 
129 //-----------------------------------------------------------------------
130 
131 HTMLOutEvent __FAR_DATA aAnchorEventTable[] =
132 {
133     { OOO_STRING_SVTOOLS_HTML_O_SDonclick,      OOO_STRING_SVTOOLS_HTML_O_onclick,      SFX_EVENT_MOUSECLICK_OBJECT },
134     { OOO_STRING_SVTOOLS_HTML_O_SDonmouseover,  OOO_STRING_SVTOOLS_HTML_O_onmouseover,  SFX_EVENT_MOUSEOVER_OBJECT  },
135     { OOO_STRING_SVTOOLS_HTML_O_SDonmouseout,       OOO_STRING_SVTOOLS_HTML_O_onmouseout,       SFX_EVENT_MOUSEOUT_OBJECT   },
136     { 0,                        0,                      0                           }
137 };
138 
139 static Writer& OutHTML_SvxAdjust( Writer& rWrt, const SfxPoolItem& rHt );
140 
OutHTML_HoriSpacer(Writer & rWrt,sal_Int16 nSize)141 static Writer& OutHTML_HoriSpacer( Writer& rWrt, sal_Int16 nSize )
142 {
143     ASSERT( nSize>0, "horizontaler SPACER mit negativem Wert?" )
144     if( nSize <= 0 )
145         return rWrt;
146 
147     if( Application::GetDefaultDevice() )
148     {
149         nSize = (sal_Int16)Application::GetDefaultDevice()
150             ->LogicToPixel( Size(nSize,0), MapMode(MAP_TWIP) ).Width();
151     }
152 
153     ByteString sOut( '<' );
154     (((((((((sOut += OOO_STRING_SVTOOLS_HTML_spacer)
155         += ' ') += OOO_STRING_SVTOOLS_HTML_O_type) += '=') += OOO_STRING_SVTOOLS_HTML_SPTYPE_horizontal)
156         += ' ') += OOO_STRING_SVTOOLS_HTML_O_size) += '=')
157                         +=ByteString::CreateFromInt32(nSize)) += '>';
158 
159     rWrt.Strm() << sOut.GetBuffer();
160 
161     return rWrt;
162 }
163 
GetDefListLvl(const String & rNm,sal_uInt16 nPoolId)164 sal_uInt16 SwHTMLWriter::GetDefListLvl( const String& rNm, sal_uInt16 nPoolId )
165 {
166     if( nPoolId == RES_POOLCOLL_HTML_DD )
167     {
168         return 1 | HTML_DLCOLL_DD;
169     }
170     else if( nPoolId == RES_POOLCOLL_HTML_DT )
171     {
172         return 1 | HTML_DLCOLL_DT;
173     }
174 
175     String sDTDD( String::CreateFromAscii(OOO_STRING_SVTOOLS_HTML_dt) );
176     sDTDD += ' ';
177     if( COMPARE_EQUAL == sDTDD.CompareTo( rNm, sDTDD.Len() ) )
178         // DefinitionList - term
179         return (sal_uInt16)rNm.Copy( sDTDD.Len() ).ToInt32() | HTML_DLCOLL_DT;
180 
181     sDTDD.AssignAscii( OOO_STRING_SVTOOLS_HTML_dd );
182     sDTDD += ' ';
183     if( COMPARE_EQUAL == sDTDD.CompareTo( rNm, sDTDD.Len() ) )
184         // DefinitionList - definition
185         return (sal_uInt16)rNm.Copy( sDTDD.Len() ).ToInt32() | HTML_DLCOLL_DD;
186 
187     return 0;
188 }
189 
OutAndSetDefList(sal_uInt16 nNewLvl)190 void SwHTMLWriter::OutAndSetDefList( sal_uInt16 nNewLvl )
191 {
192     // eventuell muss erst mal eine Liste aufgemacht werden
193     if( nDefListLvl < nNewLvl )
194     {
195         // output </pre> for the previous(!) pararagraph, if required.
196         // Preferable, the <pre> is exported by OutHTML_SwFmtOff for the
197         // previous paragraph already, but that's not possible, because a very
198         // deep look at the next paragraph (this one) is required to figure
199         // out that a def list starts here.
200 
201         ChangeParaToken( 0 );
202 
203         // entsprechend dem Level-Unterschied schreiben!
204         for( sal_uInt16 i=nDefListLvl; i<nNewLvl; i++ )
205         {
206             if( bLFPossible )
207                 OutNewLine();
208             HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_deflist, sal_True );
209             IncIndentLevel();
210             bLFPossible = sal_True;
211         }
212     }
213     else if( nDefListLvl > nNewLvl )
214     {
215         for( sal_uInt16 i=nNewLvl ; i < nDefListLvl; i++ )
216         {
217             DecIndentLevel();
218             if( bLFPossible )
219                 OutNewLine();
220             HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_deflist, sal_False );
221             bLFPossible = sal_True;
222         }
223     }
224 
225     nDefListLvl = nNewLvl;
226 }
227 
228 
ChangeParaToken(sal_uInt16 nNew)229 void SwHTMLWriter::ChangeParaToken( sal_uInt16 nNew )
230 {
231     if( nNew != nLastParaToken && HTML_PREFORMTXT_ON == nLastParaToken )
232     {
233         HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_preformtxt, sal_False );
234         bLFPossible = sal_True;
235     }
236     nLastParaToken = nNew;
237 }
238 
GetCSS1ScriptForScriptType(sal_uInt16 nScriptType)239 sal_uInt16 SwHTMLWriter::GetCSS1ScriptForScriptType( sal_uInt16 nScriptType )
240 {
241     sal_uInt16 nRet = CSS1_OUTMODE_ANY_SCRIPT;
242 
243     switch( nScriptType )
244     {
245     case i18n::ScriptType::LATIN:
246         nRet = CSS1_OUTMODE_WESTERN;
247         break;
248     case i18n::ScriptType::ASIAN:
249         nRet = CSS1_OUTMODE_CJK;
250         break;
251     case i18n::ScriptType::COMPLEX:
252         nRet = CSS1_OUTMODE_CTL;
253         break;
254     }
255 
256     return nRet;
257 }
258 
259 // fuer die Formate muesste eine einzige Ausgabe-Funktion genuegen !
260 /*
261  * Formate wie folgt ausgeben:
262  * - fuer Formate, fuer die es entsprechende HTML-Tags gibt wird das
263  *   Tag ausgegeben
264  * - fuer alle anderen wird ein Absatz-Tag <P> ausgegeben und bUserFmt
265  *   gesetzt
266  * - Wenn eine Absatz-Ausrichtung am uebergebenen Item-Set des Nodes
267  *   oder im Item-Set des Format gesetzt ist, wird ein ALIGN=xxx ausgegeben,
268  *   sofern HTML es zulaesst
269  * - in jedem Fall wird harte Attributierung als STYLE-Option geschrieben.
270  *   Wenn bUserFmt nicht gesetzt ist, wird nur der uebergebene Item-Set
271  *   betrachtet. Sonst werden auch Attribute des Formats ausgegeben.
272  */
273 
274 struct SwHTMLTxtCollOutputInfo
275 {
276     ByteString aToken;              // auszugendens End-Token
277     SfxItemSet *pItemSet;       // harte Attributierung
278 
279     sal_Bool bInNumBulList;         // in einer Aufzaehlungs-Liste;
280     sal_Bool bParaPossible;         // ein </P> darf zusaetzlich ausgegeben werden
281     sal_Bool bOutPara;              // ein </P> soll ausgegeben werden
282     sal_Bool bOutDiv;               // write a </DIV>
283 
SwHTMLTxtCollOutputInfoSwHTMLTxtCollOutputInfo284     SwHTMLTxtCollOutputInfo() :
285         pItemSet( 0 ),
286         bInNumBulList( sal_False ),
287         bParaPossible( sal_False ),
288         bOutPara( sal_False ),
289         bOutDiv( sal_False )
290     {}
291 
292     ~SwHTMLTxtCollOutputInfo();
293 
HasParaTokenSwHTMLTxtCollOutputInfo294     sal_Bool HasParaToken() const { return aToken.Len()==1 && aToken.GetChar(0)=='P'; }
ShouldOutputTokenSwHTMLTxtCollOutputInfo295     sal_Bool ShouldOutputToken() const { return bOutPara || !HasParaToken(); }
296 };
297 
~SwHTMLTxtCollOutputInfo()298 SwHTMLTxtCollOutputInfo::~SwHTMLTxtCollOutputInfo()
299 {
300     delete pItemSet;
301 }
302 
303 struct SwHTMLFmtInfo
304 {
305     const SwFmt *pFmt;      // das Format selbst
306     const SwFmt *pRefFmt;   // das Vergleichs-Format
307 
308     ByteString aToken;          // das auszugebende Token
309     String aClass;          // die auszugebende Klasse
310 
311     SfxItemSet *pItemSet;   // der auszugebende Attribut-Set
312 
313     sal_Int32 nLeftMargin;      // ein par default-Werte fuer
314     sal_Int32 nRightMargin; // Absatz-Vorlagen
315     short nFirstLineIndent;
316 
317     sal_uInt16 nTopMargin;
318     sal_uInt16 nBottomMargin;
319 
320     sal_Bool bScriptDependent;
321 
322     // Konstruktor fuer einen Dummy zum Suchen
SwHTMLFmtInfoSwHTMLFmtInfo323     SwHTMLFmtInfo( const SwFmt *pF ) :
324         pFmt( pF ), pItemSet( 0 )
325     {}
326 
327 
328     // Konstruktor zum Erstellen der Format-Info
329     SwHTMLFmtInfo( const SwFmt *pFmt, SwDoc *pDoc, SwDoc *pTemlate,
330                    sal_Bool bOutStyles, LanguageType eDfltLang=LANGUAGE_DONTKNOW,
331                    sal_uInt16 nScript=CSS1_OUTMODE_ANY_SCRIPT,
332                    sal_Bool bHardDrop=sal_False );
333     ~SwHTMLFmtInfo();
334 
operator ==(const SwHTMLFmtInfo & rInfo1,const SwHTMLFmtInfo & rInfo2)335     friend sal_Bool operator==( const SwHTMLFmtInfo& rInfo1,
336                             const SwHTMLFmtInfo& rInfo2 )
337     {
338         return (long)rInfo1.pFmt == (long)rInfo2.pFmt;
339     }
340 
operator <(const SwHTMLFmtInfo & rInfo1,const SwHTMLFmtInfo & rInfo2)341     friend sal_Bool operator<( const SwHTMLFmtInfo& rInfo1,
342                             const SwHTMLFmtInfo& rInfo2 )
343     {
344         return (long)rInfo1.pFmt < (long)rInfo2.pFmt;
345     }
346 
347 };
348 
SV_IMPL_OP_PTRARR_SORT(SwHTMLFmtInfos,SwHTMLFmtInfo *)349 SV_IMPL_OP_PTRARR_SORT( SwHTMLFmtInfos, SwHTMLFmtInfo* )
350 
351 SwHTMLFmtInfo::SwHTMLFmtInfo( const SwFmt *pF, SwDoc *pDoc, SwDoc *pTemplate,
352                               sal_Bool bOutStyles,
353                               LanguageType eDfltLang,
354                               sal_uInt16 nCSS1Script, sal_Bool bHardDrop ) :
355     pFmt( pF ), pItemSet( 0 ), bScriptDependent( sal_False )
356 {
357     sal_uInt16 nRefPoolId = 0;
358     // Den Selektor des Formats holen
359     sal_uInt16 nDeep = SwHTMLWriter::GetCSS1Selector( pFmt, aToken, aClass,
360                                                   nRefPoolId );
361     ASSERT( nDeep ? aToken.Len()>0 : aToken.Len()==0,
362             "Hier stimmt doch was mit dem Token nicht!" );
363     ASSERT( nDeep ? nRefPoolId : !nRefPoolId,
364             "Hier stimmt doch was mit der Vergleichs-Vorlage nicht!" );
365 
366     sal_Bool bTxtColl = pFmt->Which() == RES_TXTFMTCOLL ||
367                     pFmt->Which() == RES_CONDTXTFMTCOLL;
368 
369     const SwFmt *pReferenceFmt = 0; // Vergleichs-Format
370     sal_Bool bSetDefaults = sal_True, bClearSame = sal_True;
371     if( nDeep != 0 )
372     {
373         // Es ist eine HTML-Tag-Vorlage oder die Vorlage ist von einer
374         // solchen abgeleitet
375         if( !bOutStyles )
376         {
377             // wenn keine Styles exportiert werden, muss evtl. zusaetlich
378             // harte Attributierung geschrieben werden
379             switch( nDeep )
380             {
381             case CSS1_FMT_ISTAG:
382             case CSS1_FMT_CMPREF:
383                 // fuer HTML-Tag-Vorlagen die Unterscheide zum Original
384                 // (sofern verfuegbar)
385                 pReferenceFmt = SwHTMLWriter::GetTemplateFmt( nRefPoolId,
386                                                         pTemplate );
387                 break;
388 
389             default:
390                 // sonst die zur HTML-Tag-Vorlage des Originals oder des
391                 // aktuellen Doks, wenn die nicht verfuegbar ist
392                 if( pTemplate )
393                     pReferenceFmt = SwHTMLWriter::GetTemplateFmt( nRefPoolId,
394                                                             pTemplate );
395                 else
396                     pReferenceFmt = SwHTMLWriter::GetParentFmt( *pFmt, nDeep );
397                 break;
398             }
399         }
400     }
401     else if( bTxtColl )
402     {
403         // Nicht von einer HTML-Tag-Vorlage abgeleitete Absatz-Vorlagen
404         // muessen als harte Attributierung relativ zur Textkoerper-Volage
405         // exportiert werden. Fuer Nicht-Styles-Export sollte die der
406         // HTML-Vorlage als Referenz dienen
407         if( !bOutStyles && pTemplate )
408             pReferenceFmt = pTemplate->GetTxtCollFromPool( RES_POOLCOLL_TEXT, false );
409         else
410             pReferenceFmt = pDoc->GetTxtCollFromPool( RES_POOLCOLL_TEXT, false );
411     }
412 
413     if( pReferenceFmt || nDeep==0 )
414     {
415         pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
416                                     pFmt->GetAttrSet().GetRanges() );
417         // wenn Unterschiede zu einer anderen Vorlage geschrieben werden
418         // sollen ist harte Attributierung noetig. Fuer Vorlagen, die
419         // nicht von HTML-Tag-Vorlagen abgeleitet sind, gilt das immer
420 
421         pItemSet->Set( pFmt->GetAttrSet(), sal_True );
422 
423         if( pReferenceFmt )
424             SwHTMLWriter::SubtractItemSet( *pItemSet, pReferenceFmt->GetAttrSet(),
425                                            bSetDefaults, bClearSame );
426 
427         // einen leeren Item-Set gleich loeschen, das spart speater
428         // Arbeit
429         if( !pItemSet->Count() )
430         {
431             delete pItemSet;
432             pItemSet = 0;
433         }
434     }
435 
436     if( bTxtColl )
437     {
438         if( bOutStyles )
439         {
440             // We have to add hard attributes for any script dependent
441             // item that is not accessed by the style
442             static sal_uInt16 aWhichIds[3][4] =
443             {
444                 { RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
445                     RES_CHRATR_POSTURE, RES_CHRATR_WEIGHT },
446                 { RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE,
447                     RES_CHRATR_CJK_POSTURE, RES_CHRATR_CJK_WEIGHT },
448                 { RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE,
449                     RES_CHRATR_CTL_POSTURE, RES_CHRATR_CTL_WEIGHT }
450             };
451 
452             sal_uInt16 nRef = 0;
453             sal_uInt16 aSets[2] = {0,0};
454             switch( nCSS1Script )
455             {
456             case CSS1_OUTMODE_WESTERN:
457                 nRef = 0;
458                 aSets[0] = 1;
459                 aSets[1] = 2;
460                 break;
461             case CSS1_OUTMODE_CJK:
462                 nRef = 1;
463                 aSets[0] = 0;
464                 aSets[1] = 2;
465                 break;
466             case CSS1_OUTMODE_CTL:
467                 nRef = 2;
468                 aSets[0] = 0;
469                 aSets[1] = 1;
470                 break;
471             }
472             for( sal_uInt16 i=0; i<4; i++ )
473             {
474                 const SfxPoolItem& rRef = pFmt->GetFmtAttr( aWhichIds[nRef][i] );
475                 for( sal_uInt16 j=0; j<2; j++ )
476                 {
477                     const SfxPoolItem& rSet = pFmt->GetFmtAttr( aWhichIds[aSets[j]][i] );
478                     if( rSet != rRef )
479                     {
480                         if( !pItemSet )
481                             pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
482                                                        pFmt->GetAttrSet().GetRanges() );
483                         pItemSet->Put( rSet );
484                     }
485                 }
486             }
487         }
488 
489         // Ggf. noch ein DropCap-Attribut uebernehmen
490         if( bOutStyles && bHardDrop && nDeep != 0 )
491         {
492             const SfxPoolItem *pItem;
493             if( SFX_ITEM_SET==pFmt->GetAttrSet().GetItemState(
494                                     RES_PARATR_DROP, sal_True, &pItem ) )
495             {
496                 sal_Bool bPut = sal_True;
497                 if( pTemplate )
498                 {
499                     pReferenceFmt = SwHTMLWriter::GetTemplateFmt( nRefPoolId, pTemplate );
500                     const SfxPoolItem *pRefItem;
501                     sal_Bool bRefItemSet =
502                         SFX_ITEM_SET==pReferenceFmt->GetAttrSet().GetItemState(
503                                         RES_PARATR_DROP, sal_True, &pRefItem );
504                     bPut = !bRefItemSet || *pItem!=*pRefItem;
505                 }
506                 if( bPut )
507                 {
508                     if( !pItemSet )
509                         pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
510                                                    pFmt->GetAttrSet().GetRanges() );
511                     pItemSet->Put( *pItem );
512                 }
513             }
514         }
515 
516 
517         // Die diversen default-Abstaende aus der Vorlage oder der
518         // Vergleischs-Vorlage merken
519         const SvxLRSpaceItem &rLRSpace =
520             (pReferenceFmt ? pReferenceFmt : pFmt)->GetLRSpace();
521         nLeftMargin = rLRSpace.GetTxtLeft();
522         nRightMargin = rLRSpace.GetRight();
523         nFirstLineIndent = rLRSpace.GetTxtFirstLineOfst();
524 
525         const SvxULSpaceItem &rULSpace =
526             (pReferenceFmt ? pReferenceFmt : pFmt)->GetULSpace();
527         nTopMargin = rULSpace.GetUpper();
528         nBottomMargin = rULSpace.GetLower();
529 
530         // export language if it differs from the default language
531         sal_uInt16 nWhichId =
532             SwHTMLWriter::GetLangWhichIdFromScript( nCSS1Script );
533         const SvxLanguageItem& rLang =
534             (const SvxLanguageItem&)pFmt->GetFmtAttr( nWhichId );
535         LanguageType eLang = rLang.GetLanguage();
536         if( eLang != eDfltLang )
537         {
538             if( !pItemSet )
539                 pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
540                                            pFmt->GetAttrSet().GetRanges() );
541             pItemSet->Put( rLang );
542         }
543 
544         static sal_uInt16 aWhichIds[3] =
545             { RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
546                 RES_CHRATR_CTL_LANGUAGE };
547         for( sal_uInt16 i=0; i<3; i++ )
548         {
549             if( aWhichIds[i] != nWhichId )
550             {
551                 const SvxLanguageItem& rTmpLang =
552                     (const SvxLanguageItem&)pFmt->GetFmtAttr(aWhichIds[i]);
553                 if( rTmpLang.GetLanguage() != eLang )
554                 {
555                     if( !pItemSet )
556                         pItemSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
557                                                    pFmt->GetAttrSet().GetRanges() );
558                     pItemSet->Put( rTmpLang );
559                 }
560             }
561         }
562     }
563 }
564 
~SwHTMLFmtInfo()565 SwHTMLFmtInfo::~SwHTMLFmtInfo()
566 {
567     delete pItemSet;
568 }
569 
OutHTML_SwFmt(Writer & rWrt,const SwFmt & rFmt,const SfxItemSet * pNodeItemSet,SwHTMLTxtCollOutputInfo & rInfo)570 void OutHTML_SwFmt( Writer& rWrt, const SwFmt& rFmt,
571                     const SfxItemSet *pNodeItemSet,
572                     SwHTMLTxtCollOutputInfo& rInfo )
573 {
574     ASSERT( RES_CONDTXTFMTCOLL==rFmt.Which() || RES_TXTFMTCOLL==rFmt.Which(),
575             "keine Absatz-Vorlage" );
576 
577     SwHTMLWriter & rHWrt = (SwHTMLWriter&)rWrt;
578 
579     // Erstmal ein par Flags ...
580     sal_uInt16 nNewDefListLvl = 0;
581     sal_uInt16 nNumStart = USHRT_MAX;
582     sal_Bool bForceDL = sal_False;
583     sal_Bool bDT = sal_False;
584     rInfo.bInNumBulList = sal_False;    // Wir sind in einer Liste?
585     sal_Bool bNumbered = sal_False;         // Der aktuelle Absatz ist numeriert
586     sal_Bool bPara = sal_False;             // das aktuelle Token ist <P>
587     rInfo.bParaPossible = sal_False;    // ein <P> darf zusaetzlich ausgegeben werden
588     sal_Bool bNoEndTag = sal_False;         // kein End-Tag ausgeben
589 
590     rHWrt.bNoAlign = sal_False;         // kein ALIGN=... moeglich
591     sal_Bool bNoStyle = sal_False;          // kein STYLE=... moeglich
592     sal_uInt8 nBulletGrfLvl = 255;      // Die auszugebende Bullet-Grafik
593 
594     // Sind wir in einer Aufzaehlungs- oder Numerierungliste?
595     const SwTxtNode* pTxtNd = rWrt.pCurPam->GetNode()->GetTxtNode();
596 
597     SwHTMLNumRuleInfo aNumInfo;
598     if( rHWrt.GetNextNumInfo() )
599     {
600         aNumInfo = *rHWrt.GetNextNumInfo();
601         rHWrt.ClearNextNumInfo();
602     }
603     else
604     {
605         aNumInfo.Set( *pTxtNd );
606     }
607 
608     if( aNumInfo.GetNumRule() )
609     {
610         rInfo.bInNumBulList = sal_True;
611         nNewDefListLvl = 0;
612 
613         // ist der aktuelle Absatz numeriert?
614         bNumbered = aNumInfo.IsNumbered();
615         sal_uInt8 nLvl = aNumInfo.GetLevel();
616 
617         ASSERT( pTxtNd->GetActualListLevel() == nLvl,
618                 "Gemerkter Num-Level ist falsch" );
619         ASSERT( bNumbered == static_cast< sal_Bool >(pTxtNd->IsCountedInList()),
620                 "Gemerkter Numerierungs-Zustand ist falsch" );
621 
622         if( bNumbered )
623         {
624             nBulletGrfLvl = nLvl; // nur veruebergehend!!!
625             // --> OD 2005-11-15 #i57919#
626             // correction of re-factoring done by cws swnumtree:
627             // - <nNumStart> has to contain the restart value, if the
628             //   numbering is restarted at this text node. Value <USHRT_MAX>
629             //   indicates, that no additional restart value has to be written.
630             if ( pTxtNd->IsListRestart() )
631             {
632                 nNumStart = static_cast< sal_uInt16 >(pTxtNd->GetActualListStartValue());
633             }
634             // <--
635             DBG_ASSERT( rHWrt.nLastParaToken == 0,
636                 "<PRE> wurde nicht vor <LI> beendet." );
637         }
638     }
639 
640     // Jetzt holen wir das Token und ggf. die Klasse
641     SwHTMLFmtInfo aFmtInfo( &rFmt );
642     sal_uInt16 nArrayPos;
643     const SwHTMLFmtInfo *pFmtInfo;
644     if( rHWrt.aTxtCollInfos.Seek_Entry( &aFmtInfo, &nArrayPos ) )
645     {
646         pFmtInfo = rHWrt.aTxtCollInfos[nArrayPos];
647     }
648     else
649     {
650         pFmtInfo = new SwHTMLFmtInfo( &rFmt, rWrt.pDoc, rHWrt.pTemplate,
651                                       rHWrt.bCfgOutStyles, rHWrt.eLang,
652                                       rHWrt.nCSS1Script,
653                                       !rHWrt.IsHTMLMode(HTMLMODE_DROPCAPS) );
654         rHWrt.aTxtCollInfos.C40_PTR_INSERT( SwHTMLFmtInfo, pFmtInfo );
655         String aName( rFmt.GetName() );
656         if( rHWrt.aScriptParaStyles.Seek_Entry( &aName ) )
657             ((SwHTMLFmtInfo *)pFmtInfo)->bScriptDependent = sal_True;
658     }
659 
660     // Jetzt wird festgelegt, was aufgrund des Tokens so moeglich ist
661     sal_uInt16 nToken = 0;          // Token fuer Tag-Wechsel
662     sal_Bool bOutNewLine = sal_False;   // nur ein LF ausgeben?
663     if( pFmtInfo->aToken.Len() )
664     {
665         // Es ist eine HTML-Tag-Vorlage oder die Vorlage ist von einer
666         // solchen abgeleitet
667         rInfo.aToken = pFmtInfo->aToken;
668 
669         // der erste Buchstabe reicht meistens
670         switch( rInfo.aToken.GetChar( 0 ) )
671         {
672         case 'A':   ASSERT( rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_address),
673                             "Doch kein ADDRESS?" );
674                     rInfo.bParaPossible = sal_True;
675                     rHWrt.bNoAlign = sal_True;
676                     break;
677 
678         case 'B':   ASSERT( rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_blockquote),
679                             "Doch kein BLOCKQUOTE?" );
680                     rInfo.bParaPossible = sal_True;
681                     rHWrt.bNoAlign = sal_True;
682                     break;
683 
684         case 'P':   if( rInfo.aToken.Len() == 1 )
685                     {
686                         bPara = sal_True;
687                     }
688                     else
689                     {
690                         ASSERT( rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_preformtxt),
691                                 "Doch kein PRE?" );
692                         if( HTML_PREFORMTXT_ON == rHWrt.nLastParaToken )
693                         {
694                             bOutNewLine = sal_True;
695                         }
696                         else
697                         {
698                             nToken = HTML_PREFORMTXT_ON;
699                             rHWrt.bNoAlign = sal_True;
700                             bNoEndTag = sal_True;
701                         }
702                     }
703                     break;
704 
705         case 'D':   ASSERT( rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_dt) ||
706                             rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_dd),
707                             "Doch kein DD/DT?" );
708                     bDT = rInfo.aToken.Equals(OOO_STRING_SVTOOLS_HTML_dt);
709                     rInfo.bParaPossible = !bDT;
710                     rHWrt.bNoAlign = sal_True;
711                     bForceDL = sal_True;
712                     break;
713         }
714     }
715     else
716     {
717         // alle Vorlagen, die nicht einem HTML-Tag entsprechen oder von
718         // diesem abgeleitet sind, werden als <P> exportiert
719 
720         rInfo.aToken = OOO_STRING_SVTOOLS_HTML_parabreak;
721         bPara = sal_True;
722     }
723 
724     // Falls noetig, die harte Attributierung der Vorlage uebernehmen
725     if( pFmtInfo->pItemSet )
726     {
727         ASSERT( !rInfo.pItemSet, "Wo kommt der Item-Set her?" );
728         rInfo.pItemSet = new SfxItemSet( *pFmtInfo->pItemSet );
729     }
730 
731     // und noch die harte Attributierung des Absatzes dazunehmen
732     if( pNodeItemSet )
733     {
734         if( rInfo.pItemSet )
735             rInfo.pItemSet->Put( *pNodeItemSet );
736         else
737             rInfo.pItemSet = new SfxItemSet( *pNodeItemSet );
738     }
739 
740     // den unteren Absatz-Abstand brauchen wir noch
741     const SvxULSpaceItem& rULSpace =
742         pNodeItemSet ? ((const SvxULSpaceItem &)pNodeItemSet->Get(RES_UL_SPACE))
743                      : rFmt.GetULSpace();
744 
745 
746     if( (rHWrt.bOutHeader &&
747          rWrt.pCurPam->GetPoint()->nNode.GetIndex() ==
748             rWrt.pCurPam->GetMark()->nNode.GetIndex()) ||
749          rHWrt.bOutFooter )
750     {
751         if( rHWrt.bCfgOutStyles )
752         {
753             SvxULSpaceItem aULSpaceItem( rULSpace );
754             if( rHWrt.bOutHeader )
755                 aULSpaceItem.SetLower( rHWrt.nHeaderFooterSpace );
756             else
757                 aULSpaceItem.SetUpper( rHWrt.nHeaderFooterSpace );
758 
759             if( !rInfo.pItemSet )
760                 rInfo.pItemSet = new SfxItemSet(
761                                     *rFmt.GetAttrSet().GetPool(),
762                                     RES_UL_SPACE, RES_UL_SPACE );
763             rInfo.pItemSet->Put( aULSpaceItem );
764         }
765         rHWrt.bOutHeader = sal_False;
766         rHWrt.bOutFooter = sal_False;
767     }
768 
769     if( bOutNewLine )
770     {
771         // nur einen Zeilen-Umbruch (ohne Einrueckung) am Absatz-Anfang
772         // ausgeben
773         rInfo.aToken.Erase();   // kein End-Tag ausgeben
774         rWrt.Strm() << SwHTMLWriter::sNewLine;
775 
776         return;
777     }
778 
779 
780     // soll ein ALIGN=... geschrieben werden?
781     const SfxPoolItem* pAdjItem = 0;
782     const SfxPoolItem* pItem;
783 
784     if( rInfo.pItemSet &&
785         SFX_ITEM_SET == rInfo.pItemSet->GetItemState( RES_PARATR_ADJUST,
786                                                       sal_False, &pItem ) )
787     {
788         pAdjItem = pItem;
789     }
790 
791     // Unteren Absatz-Abstand beachten ? (nie im letzen Absatz von
792     // Tabellen)
793     sal_Bool bUseParSpace = !rHWrt.bOutTable ||
794                         (rWrt.pCurPam->GetPoint()->nNode.GetIndex() !=
795                          rWrt.pCurPam->GetMark()->nNode.GetIndex());
796     // Wenn Styles exportiert werden, wird aus eingerueckten Absaetzen
797     // eine Definitions-Liste
798     const SvxLRSpaceItem& rLRSpace =
799         pNodeItemSet ? ((const SvxLRSpaceItem &)pNodeItemSet->Get(RES_LR_SPACE))
800                      : rFmt.GetLRSpace();
801     if( (!rHWrt.bCfgOutStyles || bForceDL) && !rInfo.bInNumBulList )
802     {
803         sal_Int32 nLeftMargin;
804         if( bForceDL )
805             nLeftMargin = rLRSpace.GetTxtLeft();
806         else
807             nLeftMargin = rLRSpace.GetTxtLeft() > pFmtInfo->nLeftMargin
808                 ? rLRSpace.GetTxtLeft() - pFmtInfo->nLeftMargin
809                 : 0;
810 
811         if( nLeftMargin > 0 && rHWrt.nDefListMargin > 0 )
812         {
813             nNewDefListLvl = static_cast< sal_uInt16 >((nLeftMargin + (rHWrt.nDefListMargin/2)) /
814                                                     rHWrt.nDefListMargin);
815             if( nNewDefListLvl == 0 && bForceDL && !bDT )
816                 nNewDefListLvl = 1;
817         }
818         else
819         {
820             // If the left margin is 0 or negative, emulating indent
821             // with <dd> does not work. We then set a def list only if
822             // the dd style is used.
823             nNewDefListLvl = (bForceDL&& !bDT) ? 1 : 0;
824         }
825 
826         sal_Bool bIsNextTxtNode =
827             rWrt.pDoc->GetNodes()[rWrt.pCurPam->GetPoint()->nNode.GetIndex()+1]
828                      ->IsTxtNode();
829 
830         if( bForceDL && bDT )
831         {
832             // Statt eines DD muessen wir hier auch ein DT der Ebene
833             // darueber nehmen
834             nNewDefListLvl++;
835         }
836         else if( !nNewDefListLvl && !rHWrt.bCfgOutStyles && bPara &&
837                  rULSpace.GetLower()==0 &&
838                  ((bUseParSpace && bIsNextTxtNode) || rHWrt.nDefListLvl==1) &&
839                  (!pAdjItem || SVX_ADJUST_LEFT==
840                     ((const SvxAdjustItem *)pAdjItem)->GetAdjust()) )
841         {
842             // Absaetze ohne unteren Abstand als DT exportieren
843             nNewDefListLvl = 1;
844             bDT = sal_True;
845             rInfo.bParaPossible = sal_False;
846             rHWrt.bNoAlign = sal_True;
847         }
848     }
849 
850     if( nNewDefListLvl != rHWrt.nDefListLvl )
851         rHWrt.OutAndSetDefList( nNewDefListLvl );
852 
853     // ggf. eine Aufzaehlung- oder Numerierungsliste beginnen
854     if( rInfo.bInNumBulList )
855     {
856         ASSERT( !rHWrt.nDefListLvl, "DL in OL geht nicht!" );
857         OutHTML_NumBulListStart( rHWrt, aNumInfo );
858 
859         if( bNumbered )
860         {
861             if( rHWrt.aBulletGrfs[nBulletGrfLvl].Len()  )
862                 bNumbered = sal_False;
863             else
864                 nBulletGrfLvl = 255;
865         }
866     }
867 
868     // Die Defaults aus der Vorlage merken, denn sie muessen nicht
869     // exportiert werden
870     rHWrt.nDfltLeftMargin = pFmtInfo->nLeftMargin;
871     rHWrt.nDfltRightMargin = pFmtInfo->nRightMargin;
872     rHWrt.nDfltFirstLineIndent = pFmtInfo->nFirstLineIndent;
873 
874     if( rInfo.bInNumBulList )
875     {
876         if( !rHWrt.IsHTMLMode( HTMLMODE_LSPACE_IN_NUMBUL ) )
877             rHWrt.nDfltLeftMargin = rLRSpace.GetTxtLeft();
878 
879         // In Numerierungs-Listen keinen Ertzeilen-Einzug ausgeben.
880         rHWrt.nFirstLineIndent = rLRSpace.GetTxtFirstLineOfst();
881     }
882 
883     if( rInfo.bInNumBulList && bNumbered && bPara && !rHWrt.bCfgOutStyles )
884     {
885         // ein einzelnes LI hat keinen Abstand
886         rHWrt.nDfltTopMargin = 0;
887         rHWrt.nDfltBottomMargin = 0;
888     }
889     else if( rHWrt.nDefListLvl && bPara )
890     {
891         // ein einzelnes DD hat auch keinen Abstand
892         rHWrt.nDfltTopMargin = 0;
893         rHWrt.nDfltBottomMargin = 0;
894     }
895     else
896     {
897         rHWrt.nDfltTopMargin = pFmtInfo->nTopMargin;
898         // #60393#: Wenn im letzten Absatz einer Tabelle der
899         // untere Absatz-Abstand veraendert wird, vertut sich
900         // Netscape total. Deshalb exportieren wir hier erstmal
901         // nichts, indem wir den Abstand aus dem Absatz als Default
902         // setzen.
903         if( rHWrt.bCfgNetscape4 && !bUseParSpace )
904             rHWrt.nDfltBottomMargin = rULSpace.GetLower();
905         else
906             rHWrt.nDfltBottomMargin = pFmtInfo->nBottomMargin;
907     }
908 
909     if( rHWrt.nDefListLvl )
910     {
911         rHWrt.nLeftMargin =
912             (rHWrt.nDefListLvl-1) * rHWrt.nDefListMargin;
913     }
914 
915     if( rHWrt.bLFPossible )
916         rHWrt.OutNewLine(); // Absatz-Tag in neue Zeile
917     rInfo.bOutPara = sal_False;
918 
919     // das ist jetzt unser neues Token
920     rHWrt.ChangeParaToken( nToken );
921 
922     sal_Bool bHasParSpace = bUseParSpace && rULSpace.GetLower() > 0;
923 
924     // ggf ein List-Item aufmachen
925     if( rInfo.bInNumBulList && bNumbered )
926     {
927         ByteString sOut( '<' );
928         sOut += OOO_STRING_SVTOOLS_HTML_li;
929         if( USHRT_MAX != nNumStart )
930             (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_value) += '=')
931                 += ByteString::CreateFromInt32(nNumStart);
932         sOut += '>';
933         rWrt.Strm() << sOut.GetBuffer();
934     }
935 
936     if( rHWrt.nDefListLvl > 0 && !bForceDL )
937     {
938         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), bDT ? OOO_STRING_SVTOOLS_HTML_dt : OOO_STRING_SVTOOLS_HTML_dd );
939     }
940 
941     if( pAdjItem &&
942         rHWrt.IsHTMLMode( HTMLMODE_NO_CONTROL_CENTERING ) &&
943         rHWrt.HasControls() )
944     {
945         // #64687#: The align=... attribute does behave strange in netscape
946         // if there are controls in a paragraph, because the control and
947         // all text behind the control does not recognize this attribute.
948         ByteString sOut( '<' );
949         sOut += OOO_STRING_SVTOOLS_HTML_division;
950         rWrt.Strm() << sOut.GetBuffer();
951 
952         rHWrt.bTxtAttr = sal_False;
953         rHWrt.bOutOpts = sal_True;
954         OutHTML_SvxAdjust( rWrt, *pAdjItem );
955         rWrt.Strm() << '>';
956         pAdjItem = 0;
957         rHWrt.bNoAlign = sal_False;
958         rInfo.bOutDiv = sal_True;
959         rHWrt.IncIndentLevel();
960         rHWrt.bLFPossible = sal_True;
961             rHWrt.OutNewLine();
962     }
963 
964     // fuer BLOCKQUOTE, ADDRESS und DD wird noch ein Absatz-Token
965     // ausgegeben, wenn,
966     // - keine Styles geschrieben werden, und
967     // - ein untere Abstand oder eine Absatz-Ausrichtung existiert
968     ByteString aToken = rInfo.aToken;
969     if( !rHWrt.bCfgOutStyles && rInfo.bParaPossible && !bPara &&
970         (bHasParSpace || pAdjItem) )
971     {
972         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), rInfo.aToken.GetBuffer() );
973         aToken = OOO_STRING_SVTOOLS_HTML_parabreak;
974         bPara = sal_True;
975         rHWrt.bNoAlign = sal_False;
976         bNoStyle = sal_False;
977     }
978 
979     LanguageType eLang = rInfo.pItemSet
980         ? ((const SvxLanguageItem&)rInfo.pItemSet->Get(SwHTMLWriter::GetLangWhichIdFromScript(rHWrt.nCSS1Script))).GetLanguage()
981         : rHWrt.eLang;
982 
983     if( rInfo.pItemSet )
984     {
985         static sal_uInt16 aWhichIds[3] = { RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE };
986 
987         for( sal_uInt16 i=0; i<3; i++ )
988         {
989             // export language if it differs from the default language only.
990             const SfxPoolItem *pTmpItem;
991             if( SFX_ITEM_SET == rInfo.pItemSet->GetItemState( aWhichIds[i],
992                         sal_True, &pTmpItem ) &&
993                 ((const SvxLanguageItem *)pTmpItem)->GetLanguage() == eLang )
994                 rInfo.pItemSet->ClearItem( aWhichIds[i] );
995         }
996     }
997 
998     // and the text direction
999     sal_uInt16 nDir = rHWrt.GetHTMLDirection(
1000             (pNodeItemSet ? static_cast < const SvxFrameDirectionItem& >(
1001                                     pNodeItemSet->Get( RES_FRAMEDIR ) )
1002                           : rFmt.GetFrmDir() ).GetValue() );
1003 
1004     // Ein <P> wird nur geschrieben, wenn
1005     // - wir in keiner OL/UL/DL sind, oder
1006     // - der Absatz einer OL/UL nicht numeriert ist, oder
1007     // - keine Styles exportiert werden und
1008     //      - ein unterer Abstand oder
1009     //      - eine Absatz-Ausrichtung existiert, ode
1010     // - Styles exportiert werden und,
1011     //      - die Textkoerper-Vorlage geaendert wurde, oder
1012     //      - ein Benutzer-Format exportiert wird, oder
1013     //      - Absatz-Attribute existieren
1014     if( !bPara ||
1015         (!rInfo.bInNumBulList && !rHWrt.nDefListLvl) ||
1016         (rInfo.bInNumBulList && !bNumbered) ||
1017         (!rHWrt.bCfgOutStyles &&
1018          (bHasParSpace || pAdjItem ||
1019           (eLang != LANGUAGE_DONTKNOW && eLang != rHWrt.eLang))) ||
1020         nDir != rHWrt.nDirection ||
1021         rHWrt.bCfgOutStyles )
1022     {
1023         // jetzt werden Optionen ausgegeben
1024         rHWrt.bTxtAttr = sal_False;
1025         rHWrt.bOutOpts = sal_True;
1026 
1027         ByteString sOut( '<' );
1028         sOut += aToken;
1029 
1030         if( eLang != LANGUAGE_DONTKNOW && eLang != rHWrt.eLang )
1031         {
1032             rWrt.Strm() << sOut.GetBuffer();
1033             rHWrt.OutLanguage( eLang );
1034             sOut.Erase();
1035         }
1036 
1037         if( nDir != rHWrt.nDirection )
1038         {
1039             if( sOut.Len() )
1040             {
1041                 rWrt.Strm() << sOut.GetBuffer();
1042                 sOut.Erase();
1043             }
1044             rHWrt.OutDirection( nDir );
1045         }
1046 
1047         if( rHWrt.bCfgOutStyles &&
1048             (pFmtInfo->aClass.Len() || pFmtInfo->bScriptDependent) )
1049         {
1050             ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\"";
1051             rWrt.Strm() << sOut.GetBuffer();
1052             String aClass( pFmtInfo->aClass );
1053             if( pFmtInfo->bScriptDependent )
1054             {
1055                 if( aClass.Len() )
1056                    aClass += '-';
1057                 switch( rHWrt.nCSS1Script )
1058                 {
1059                 case CSS1_OUTMODE_WESTERN:
1060                     aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("western") );
1061                     break;
1062                 case CSS1_OUTMODE_CJK:
1063                     aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("cjk") );
1064                     break;
1065                 case CSS1_OUTMODE_CTL:
1066                     aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("ctl") );
1067                     break;
1068                 }
1069             }
1070             HTMLOutFuncs::Out_String( rWrt.Strm(), aClass,
1071                                       rHWrt.eDestEnc, &rHWrt.aNonConvertableCharacters );
1072             sOut = '\"';
1073         }
1074         rWrt.Strm() << sOut.GetBuffer();
1075 
1076         // ggf. Ausrichtung ausgeben.
1077         if( !rHWrt.bNoAlign && pAdjItem )
1078             OutHTML_SvxAdjust( rWrt, *pAdjItem );
1079 
1080         // und nun ggf. noch die STYLE-Option
1081         if( rHWrt.bCfgOutStyles && rInfo.pItemSet && !bNoStyle)
1082         {
1083             OutCSS1_ParaTagStyleOpt( rWrt, *rInfo.pItemSet );
1084         }
1085 
1086         rWrt.Strm() << '>';
1087 
1088         // Soll ein </P> geschrieben wenrden
1089         rInfo.bOutPara =
1090             bPara &&
1091             ( rHWrt.bCfgOutStyles ||
1092                 (!rHWrt.bCfgOutStyles && bHasParSpace) );
1093 
1094         // wenn kein End-Tag geschrieben werden soll, es loeschen
1095         if( bNoEndTag )
1096             rInfo.aToken.Erase();
1097     }
1098 
1099     // ??? Warum nicht ueber den Hint-Mechanismus ???
1100     if( rHWrt.IsHTMLMode(HTMLMODE_FIRSTLINE) )
1101     {
1102         const SvxLRSpaceItem& rLRSpaceTmp =
1103             pNodeItemSet ? ((const SvxLRSpaceItem &)pNodeItemSet->Get(RES_LR_SPACE))
1104                          : rFmt.GetLRSpace();
1105         if( rLRSpaceTmp.GetTxtFirstLineOfst() > 0 )
1106         {
1107             OutHTML_HoriSpacer( rWrt, rLRSpaceTmp.GetTxtFirstLineOfst() );
1108         }
1109     }
1110 
1111     if( nBulletGrfLvl != 255 )
1112     {
1113         ASSERT( aNumInfo.GetNumRule(), "Wo ist die Numerierung geblieben???" );
1114         ASSERT( nBulletGrfLvl < MAXLEVEL, "So viele Ebenen gibt's nicht" );
1115         const SwNumFmt& rNumFmt = aNumInfo.GetNumRule()->Get(nBulletGrfLvl);
1116 
1117         OutHTML_BulletImage( rWrt, OOO_STRING_SVTOOLS_HTML_image, 0,
1118                              rHWrt.aBulletGrfs[nBulletGrfLvl],
1119                              rNumFmt.GetGraphicSize(), rNumFmt.GetGraphicOrientation() );
1120     }
1121 
1122     rHWrt.GetNumInfo() = aNumInfo;
1123 
1124     // die Defaults zuruecksetzen
1125     rHWrt.nDfltLeftMargin = 0;
1126     rHWrt.nDfltRightMargin = 0;
1127     rHWrt.nDfltFirstLineIndent = 0;
1128     rHWrt.nDfltTopMargin = 0;
1129     rHWrt.nDfltBottomMargin = 0;
1130     rHWrt.nLeftMargin = 0;
1131     rHWrt.nFirstLineIndent = 0;
1132 }
1133 
OutHTML_SwFmtOff(Writer & rWrt,const SwHTMLTxtCollOutputInfo & rInfo)1134 void OutHTML_SwFmtOff( Writer& rWrt, const SwHTMLTxtCollOutputInfo& rInfo )
1135 {
1136     SwHTMLWriter & rHWrt = (SwHTMLWriter&)rWrt;
1137 
1138     // wenn es kein Token gibt haben wir auch nichts auszugeben
1139     if( !rInfo.aToken.Len() )
1140     {
1141         rHWrt.FillNextNumInfo();
1142         const SwHTMLNumRuleInfo& rNextInfo = *rHWrt.GetNextNumInfo();
1143         // Auch in PRE muss eine Bullet-Liste beendet werden
1144         if( rInfo.bInNumBulList )
1145         {
1146 
1147             const SwHTMLNumRuleInfo& rNRInfo = rHWrt.GetNumInfo();
1148             if( rNextInfo.GetNumRule() != rNRInfo.GetNumRule() ||
1149                 rNextInfo.GetDepth() != rNRInfo.GetDepth() ||
1150                 rNextInfo.IsNumbered() || rNextInfo.IsRestart() )
1151                 rHWrt.ChangeParaToken( 0 );
1152             OutHTML_NumBulListEnd( rHWrt, rNextInfo );
1153         }
1154         else if( rNextInfo.GetNumRule() != 0 )
1155             rHWrt.ChangeParaToken( 0 );
1156 
1157         return;
1158     }
1159 
1160     if( rInfo.ShouldOutputToken() )
1161     {
1162         if( rHWrt.bLFPossible )
1163             rHWrt.OutNewLine( sal_True );
1164 
1165         // fuer BLOCKQUOTE, ADDRESS und DD wird ggf noch ein
1166         // Absatz-Token ausgegeben, wenn
1167         // - keine Styles geschrieben werden, und
1168         // - ein untere Abstand existiert
1169         if( rInfo.bParaPossible && rInfo.bOutPara )
1170             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_parabreak, sal_False );
1171 
1172         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), rInfo.aToken.GetBuffer(),
1173                                     sal_False );
1174         rHWrt.bLFPossible = !rInfo.aToken.Equals( OOO_STRING_SVTOOLS_HTML_dt ) &&
1175                             !rInfo.aToken.Equals( OOO_STRING_SVTOOLS_HTML_dd ) &&
1176                             !rInfo.aToken.Equals( OOO_STRING_SVTOOLS_HTML_li );
1177     }
1178     if( rInfo.bOutDiv )
1179     {
1180         rHWrt.DecIndentLevel();
1181         if( rHWrt.bLFPossible )
1182             rHWrt.OutNewLine();
1183         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_division, sal_False );
1184         rHWrt.bLFPossible = sal_True;
1185     }
1186 
1187     // ggf. eine Aufzaehlung- oder Numerierungsliste beenden
1188     if( rInfo.bInNumBulList )
1189     {
1190         rHWrt.FillNextNumInfo();
1191         OutHTML_NumBulListEnd( rHWrt, *rHWrt.GetNextNumInfo() );
1192     }
1193 }
1194 
1195 
1196 class HTMLSttEndPos
1197 {
1198     xub_StrLen nStart;
1199     xub_StrLen nEnd;
1200     SfxPoolItem* pItem;
1201 
1202 public:
1203 
1204     HTMLSttEndPos( const SfxPoolItem& rItem, xub_StrLen nStt, xub_StrLen nE );
1205     ~HTMLSttEndPos();
1206 
GetItem() const1207     const SfxPoolItem *GetItem() const { return pItem; }
1208 
SetStart(xub_StrLen nStt)1209     void SetStart( xub_StrLen nStt ) { nStart = nStt; }
GetStart() const1210     xub_StrLen GetStart() const { return nStart; }
1211 
GetEnd() const1212     xub_StrLen GetEnd() const { return nEnd; }
SetEnd(xub_StrLen nE)1213     void SetEnd( xub_StrLen nE ) { nEnd = nE; }
1214 };
1215 
HTMLSttEndPos(const SfxPoolItem & rItem,xub_StrLen nStt,xub_StrLen nE)1216 HTMLSttEndPos::HTMLSttEndPos( const SfxPoolItem& rItem, xub_StrLen nStt,
1217                                                         xub_StrLen nE ) :
1218     nStart( nStt ),
1219     nEnd( nE ),
1220     pItem( rItem.Clone() )
1221 {}
1222 
~HTMLSttEndPos()1223 HTMLSttEndPos::~HTMLSttEndPos()
1224 {
1225     delete pItem;
1226 }
1227 
1228 typedef HTMLSttEndPos *HTMLSttEndPosPtr;
1229 SV_DECL_PTRARR( _HTMLEndLst, HTMLSttEndPosPtr, 5, 5 )
1230 
1231 enum HTMLOnOffState { HTML_NOT_SUPPORTED,   // nicht unterst. Attribut
1232                       HTML_REAL_VALUE,      // Attribut mit Wert
1233                       HTML_ON_VALUE,        // Attribut entspricht On-Tag
1234                       HTML_OFF_VALUE,       // Attribut entspricht Off-Tag
1235                       HTML_CHRFMT_VALUE,    // Attribut fuer Zeichenvorlage
1236                       HTML_COLOR_VALUE,     // Attribut fuer Vordergrundfarbe
1237                       HTML_STYLE_VALUE,     // Attribut muss als Style exp.
1238                       HTML_DROPCAP_VALUE,   // DropCap-Attributs
1239                       HTML_AUTOFMT_VALUE }; // Attribute for automatic character styles
1240 
1241 
1242 class HTMLEndPosLst
1243 {
1244     _HTMLEndLst aStartLst;  // nach Anfangs-Psoitionen sortierte Liste
1245     _HTMLEndLst aEndLst;    // nach End-Psotionen sortierte Liste
1246     SvXub_StrLens aScriptChgLst;    // positions where script changes
1247                                     // 0 is not contained in this list,
1248                                     // but the text length
1249     // the script that is valif up to the position
1250     // contained in aScriptChgList at the same index
1251     ::std::vector<sal_uInt16> aScriptLst;
1252 
1253     SwDoc *pDoc;            // das aktuelle Dokument
1254     SwDoc* pTemplate;       // die HTML-Vorlage (oder 0)
1255     const Color* pDfltColor;// die Default-Vordergrund-Farbe
1256     SvStringsSortDtor& rScriptTxtStyles;    //
1257 
1258     sal_uLong nHTMLMode;
1259     sal_Bool bOutStyles : 1;    // werden Styles exportiert
1260 
1261 
1262     // die Position eines Items in der Start-/Ende-Liste suchen
1263     sal_uInt16 _FindStartPos( const HTMLSttEndPos *pPos ) const;
1264     sal_uInt16 _FindEndPos( const HTMLSttEndPos *pPos ) const;
1265 
1266     // Eine SttEndPos in die Start- und Ende-Listen eintragen bzw. aus
1267     // ihnen loeschen, wobei die Ende-Position bekannt ist
1268     void _InsertItem( HTMLSttEndPos *pPos, sal_uInt16 nEndPos );
1269     void _RemoveItem( sal_uInt16 nEndPos );
1270 
1271     // die "Art" es Attributs ermitteln
1272     HTMLOnOffState GetHTMLItemState( const SfxPoolItem& rItem );
1273 
1274     // Existiert ein bestimmtes On-Tag-Item
1275     sal_Bool ExistsOnTagItem( sal_uInt16 nWhich, xub_StrLen nPos );
1276 
1277     // Existiert ein Item zum ausschalten eines Attributs, das genauso
1278     // exportiert wird wie das uebergebene Item im gleichen Bereich?
1279     sal_Bool ExistsOffTagItem( sal_uInt16 nWhich, xub_StrLen nStartPos,
1280                                           xub_StrLen nEndPos );
1281 
1282 
1283     // das Ende eines gesplitteten Items anpassen
1284     void FixSplittedItem( HTMLSttEndPos *pPos, sal_uInt16 nStartPos,
1285                           xub_StrLen nNewEnd );
1286 
1287     // Ein Attribut in die Listen eintragen und ggf. aufteilen
1288     void InsertItem( const SfxPoolItem& rItem, xub_StrLen nStart,
1289                                                xub_StrLen nEnd );
1290 
1291     // Ein bereits vorhandenes Attribut aufteilen
1292     void SplitItem( const SfxPoolItem& rItem, xub_StrLen nStart,
1293                                               xub_StrLen nEnd );
1294 
1295     // Insert without taking care of script
1296     void InsertNoScript( const SfxPoolItem& rItem, xub_StrLen nStart,
1297                          xub_StrLen nEnd, SwHTMLFmtInfos& rFmtInfos,
1298                          sal_Bool bParaAttrs=sal_False );
1299 
1300     const SwHTMLFmtInfo *GetFmtInfo( const SwFmt& rFmt,
1301                                      SwHTMLFmtInfos& rFmtInfos );
1302 
1303 public:
1304 
1305     HTMLEndPosLst( SwDoc *pDoc, SwDoc* pTemplate, const Color* pDfltColor,
1306                    sal_Bool bOutStyles, sal_uLong nHTMLMode,
1307                    const String& rText, SvStringsSortDtor& rStyles );
1308     ~HTMLEndPosLst();
1309 
1310     // Ein Attribut einfuegen
1311     void Insert( const SfxPoolItem& rItem, xub_StrLen nStart,  xub_StrLen nEnd,
1312                  SwHTMLFmtInfos& rFmtInfos, sal_Bool bParaAttrs=sal_False );
1313     void Insert( const SfxItemSet& rItemSet, xub_StrLen nStart, xub_StrLen nEnd,
1314                  SwHTMLFmtInfos& rFmtInfos, sal_Bool bDeep,
1315                  sal_Bool bParaAttrs=sal_False );
1316     void Insert( const SwDrawFrmFmt& rFmt, xub_StrLen nPos,
1317                  SwHTMLFmtInfos& rFmtInfos );
1318 
1319     sal_uInt16 GetScriptAtPos( xub_StrLen nPos,
1320                                sal_uInt16 nWeak=CSS1_OUTMODE_ANY_SCRIPT );
1321 
1322     void OutStartAttrs( SwHTMLWriter& rHWrt, xub_StrLen nPos,
1323                         HTMLOutContext *pContext = 0 );
1324     void OutEndAttrs( SwHTMLWriter& rHWrt, xub_StrLen nPos,
1325                       HTMLOutContext *pContext = 0 );
1326 
Count() const1327     sal_uInt16 Count() const { return aEndLst.Count(); }
1328 
IsHTMLMode(sal_uLong nMode) const1329     sal_Bool IsHTMLMode( sal_uLong nMode ) const { return (nHTMLMode & nMode) != 0; }
1330 };
1331 
1332 
_FindStartPos(const HTMLSttEndPos * pPos) const1333 sal_uInt16 HTMLEndPosLst::_FindStartPos( const HTMLSttEndPos *pPos ) const
1334 {
1335     sal_uInt16 i;
1336     for( i = 0; i < aStartLst.Count() && aStartLst[i] != pPos;  i++ )
1337         ;
1338 
1339     ASSERT( i != aStartLst.Count(), "Item nicht in Start-Liste gefunden!" );
1340 
1341     return i==aStartLst.Count() ? USHRT_MAX : i;
1342 }
1343 
_FindEndPos(const HTMLSttEndPos * pPos) const1344 sal_uInt16 HTMLEndPosLst::_FindEndPos( const HTMLSttEndPos *pPos ) const
1345 {
1346     sal_uInt16 i;
1347 
1348     for( i = 0; i < aEndLst.Count() && aEndLst[i] != pPos;  i++ )
1349         ;
1350 
1351     ASSERT( i != aEndLst.Count(), "Item nicht in Ende-Liste gefunden" );
1352 
1353     return i==aEndLst.Count() ? USHRT_MAX : i;
1354 }
1355 
1356 
_InsertItem(HTMLSttEndPos * pPos,sal_uInt16 nEndPos)1357 void HTMLEndPosLst::_InsertItem( HTMLSttEndPos *pPos, sal_uInt16 nEndPos )
1358 {
1359     // In der Start-Liste das Attribut hinter allen vorher und an
1360     // der gleichen Position gestarteten Attributen einfuegen
1361     xub_StrLen nStart = pPos->GetStart();
1362     sal_uInt16 i;
1363 
1364     for( i = 0; i < aStartLst.Count() &&
1365                      aStartLst[i]->GetStart() <= nStart; i++ )
1366         ;
1367     aStartLst.Insert( pPos, i );
1368 
1369     // die Position in der Ende-Liste wurde uebergeben
1370     aEndLst.Insert( pPos, nEndPos );
1371 }
1372 
_RemoveItem(sal_uInt16 nEndPos)1373 void HTMLEndPosLst::_RemoveItem( sal_uInt16 nEndPos )
1374 {
1375     HTMLSttEndPos *pPos = aEndLst[nEndPos];
1376 
1377     // jetzt Suchen wir es in der Start-Liste
1378     sal_uInt16 nStartPos = _FindStartPos( pPos );
1379     if( nStartPos != USHRT_MAX )
1380         aStartLst.Remove( nStartPos, 1 );
1381 
1382     aEndLst.Remove( nEndPos, 1 );
1383 
1384     delete pPos;
1385 }
1386 
GetHTMLItemState(const SfxPoolItem & rItem)1387 HTMLOnOffState HTMLEndPosLst::GetHTMLItemState( const SfxPoolItem& rItem )
1388 {
1389     HTMLOnOffState eState = HTML_NOT_SUPPORTED;
1390     switch( rItem.Which() )
1391     {
1392     case RES_CHRATR_POSTURE:
1393     case RES_CHRATR_CJK_POSTURE:
1394     case RES_CHRATR_CTL_POSTURE:
1395         switch( ((const SvxPostureItem&)rItem).GetPosture() )
1396         {
1397         case ITALIC_NORMAL:
1398             eState = HTML_ON_VALUE;
1399             break;
1400         case ITALIC_NONE:
1401             eState = HTML_OFF_VALUE;
1402             break;
1403         default:
1404             if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
1405                 eState = HTML_STYLE_VALUE;
1406             break;
1407         }
1408         break;
1409 
1410     case RES_CHRATR_CROSSEDOUT:
1411         switch( ((const SvxCrossedOutItem&)rItem).GetStrikeout() )
1412         {
1413         case STRIKEOUT_SINGLE:
1414         case STRIKEOUT_DOUBLE:
1415             eState = HTML_ON_VALUE;
1416             break;
1417         case STRIKEOUT_NONE:
1418             eState = HTML_OFF_VALUE;
1419             break;
1420         default:
1421             ;
1422         }
1423         break;
1424 
1425     case RES_CHRATR_ESCAPEMENT:
1426         switch( (const SvxEscapement)
1427                         ((const SvxEscapementItem&)rItem).GetEnumValue() )
1428         {
1429         case SVX_ESCAPEMENT_SUPERSCRIPT:
1430         case SVX_ESCAPEMENT_SUBSCRIPT:
1431             eState = HTML_ON_VALUE;
1432             break;
1433         case SVX_ESCAPEMENT_OFF:
1434             eState = HTML_OFF_VALUE;
1435             break;
1436         default:
1437             ;
1438         }
1439         break;
1440 
1441     case RES_CHRATR_UNDERLINE:
1442         switch( ((const SvxUnderlineItem&)rItem).GetLineStyle() )
1443         {
1444         case UNDERLINE_SINGLE:
1445             eState = HTML_ON_VALUE;
1446             break;
1447         case UNDERLINE_NONE:
1448             eState = HTML_OFF_VALUE;
1449             break;
1450         default:
1451             if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
1452                 eState = HTML_STYLE_VALUE;
1453             break;
1454         }
1455         break;
1456 
1457     case RES_CHRATR_OVERLINE:
1458         if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
1459             eState = HTML_STYLE_VALUE;
1460         break;
1461 
1462     case RES_CHRATR_WEIGHT:
1463     case RES_CHRATR_CJK_WEIGHT:
1464     case RES_CHRATR_CTL_WEIGHT:
1465         switch( ((const SvxWeightItem&)rItem).GetWeight() )
1466         {
1467         case WEIGHT_BOLD:
1468             eState = HTML_ON_VALUE;
1469             break;
1470         case WEIGHT_NORMAL:
1471             eState = HTML_OFF_VALUE;
1472             break;
1473         default:
1474             if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
1475                 eState = HTML_STYLE_VALUE;
1476             break;
1477         }
1478         break;
1479 
1480     case RES_CHRATR_BLINK:
1481         if( IsHTMLMode(HTMLMODE_BLINK) )
1482             eState = ((const SvxBlinkItem&)rItem).GetValue() ? HTML_ON_VALUE
1483                                                              : HTML_OFF_VALUE;
1484         break;
1485 
1486     case RES_CHRATR_COLOR:
1487         eState = HTML_COLOR_VALUE;
1488         break;
1489 
1490     case RES_CHRATR_FONT:
1491     case RES_CHRATR_FONTSIZE:
1492     case RES_CHRATR_LANGUAGE:
1493     case RES_CHRATR_CJK_FONT:
1494     case RES_CHRATR_CJK_FONTSIZE:
1495     case RES_CHRATR_CJK_LANGUAGE:
1496     case RES_CHRATR_CTL_FONT:
1497     case RES_CHRATR_CTL_FONTSIZE:
1498     case RES_CHRATR_CTL_LANGUAGE:
1499     case RES_TXTATR_INETFMT:
1500         eState = HTML_REAL_VALUE;
1501         break;
1502 
1503     case RES_TXTATR_CHARFMT:
1504         eState = HTML_CHRFMT_VALUE;
1505         break;
1506 
1507     case RES_TXTATR_AUTOFMT:
1508         eState = HTML_AUTOFMT_VALUE;
1509         break;
1510 
1511     case RES_CHRATR_CASEMAP:
1512         if( IsHTMLMode(HTMLMODE_SMALL_CAPS) )
1513             eState = HTML_STYLE_VALUE;
1514 
1515     case RES_CHRATR_KERNING:
1516         if( IsHTMLMode(HTMLMODE_FULL_STYLES) )
1517             eState = HTML_STYLE_VALUE;
1518         break;
1519 
1520     case RES_CHRATR_BACKGROUND:
1521         if( IsHTMLMode(HTMLMODE_SOME_STYLES) )
1522             eState = HTML_STYLE_VALUE;
1523         break;
1524 
1525     case RES_PARATR_DROP:
1526         eState = HTML_DROPCAP_VALUE;
1527         break;
1528 
1529 //  default:
1530 //      eState = HTML_NOT_SUPPORTED;
1531 //      break;
1532     }
1533 
1534     return eState;
1535 }
1536 
ExistsOnTagItem(sal_uInt16 nWhich,xub_StrLen nPos)1537 sal_Bool HTMLEndPosLst::ExistsOnTagItem( sal_uInt16 nWhich, xub_StrLen nPos )
1538 {
1539     for( sal_uInt16 i=0; i<aStartLst.Count(); i++ )
1540     {
1541         HTMLSttEndPos *pTest = aStartLst[i];
1542 
1543         if( pTest->GetStart() > nPos )
1544         {
1545             // dieses uns alle folgenden Attribute beginnen spaeter
1546             break;
1547         }
1548         else if( pTest->GetEnd() > nPos )
1549         {
1550             // das Attribut beginnt vor oder an der aktuellen Position
1551             // und endet hinter ihr
1552             const SfxPoolItem *pItem = pTest->GetItem();
1553             if( pItem->Which() == nWhich &&
1554                 HTML_ON_VALUE == GetHTMLItemState(*pItem) )
1555             {
1556                 // ein On-Tag-Attibut wurde gefunden
1557                 return sal_True;
1558             }
1559         }
1560     }
1561 
1562     return sal_False;
1563 }
1564 
ExistsOffTagItem(sal_uInt16 nWhich,xub_StrLen nStartPos,xub_StrLen nEndPos)1565 sal_Bool HTMLEndPosLst::ExistsOffTagItem( sal_uInt16 nWhich, xub_StrLen nStartPos,
1566                                       xub_StrLen nEndPos )
1567 {
1568     if( nWhich != RES_CHRATR_CROSSEDOUT &&
1569         nWhich != RES_CHRATR_UNDERLINE &&
1570         nWhich != RES_CHRATR_BLINK )
1571     {
1572         return sal_False;
1573     }
1574 
1575     for( sal_uInt16 i=0; i<aStartLst.Count(); i++ )
1576     {
1577         HTMLSttEndPos *pTest = aStartLst[i];
1578 
1579         if( pTest->GetStart() > nStartPos )
1580         {
1581             // dieses uns alle folgenden Attribute beginnen spaeter
1582             break;
1583         }
1584         else if( pTest->GetStart()==nStartPos &&
1585                  pTest->GetEnd()==nEndPos )
1586         {
1587             // das Attribut beginnt vor oder an der aktuellen Position
1588             // und endet hinter ihr
1589             const SfxPoolItem *pItem = pTest->GetItem();
1590             sal_uInt16 nTstWhich = pItem->Which() ;
1591             if( (nTstWhich == RES_CHRATR_CROSSEDOUT ||
1592                  nTstWhich == RES_CHRATR_UNDERLINE ||
1593                  nTstWhich == RES_CHRATR_BLINK) &&
1594                 HTML_OFF_VALUE == GetHTMLItemState(*pItem) )
1595             {
1596                 // Ein Off-Tag-Attibut wurde gefunden, das genauso
1597                 // exportiert wird, wie das aktuelle Item
1598                 return sal_True;
1599             }
1600         }
1601     }
1602 
1603     return sal_False;
1604 }
1605 
FixSplittedItem(HTMLSttEndPos * pPos,xub_StrLen nNewEnd,sal_uInt16 nStartPos)1606 void HTMLEndPosLst::FixSplittedItem( HTMLSttEndPos *pPos, xub_StrLen nNewEnd,
1607                                      sal_uInt16 nStartPos )
1608 {
1609     // die End-Position entsprechend fixen
1610     pPos->SetEnd( nNewEnd );
1611 
1612     // das Item aus der End-Liste entfernen
1613     sal_uInt16 nEndPos = _FindEndPos( pPos );
1614     if( nEndPos != USHRT_MAX )
1615         aEndLst.Remove( nEndPos, 1 );
1616 
1617     // es wird von nun an als letztes an der entsprechenden Position
1618     // beendet
1619     for( nEndPos=0; nEndPos < aEndLst.Count() &&
1620                     aEndLst[nEndPos]->GetEnd() <= nNewEnd; nEndPos++ )
1621         ;
1622     aEndLst.Insert( pPos, nEndPos );
1623 
1624     // jetzt noch die spaeter gestarteten Attribute anpassen
1625     for( sal_uInt16 i=nStartPos+1; i<aStartLst.Count(); i++ )
1626     {
1627         HTMLSttEndPos *pTest = aStartLst[i];
1628         xub_StrLen nTestEnd = pTest->GetEnd();
1629         if( pTest->GetStart() >= nNewEnd )
1630         {
1631             // das Test-Attribut und alle folgenden beginnen, nachdem das
1632             // gesplittete Attribut endet
1633             break;
1634         }
1635         else if( nTestEnd > nNewEnd )
1636         {
1637             // das Test-Attribut beginnt, bevor das gesplittete Attribut
1638             // endet und endet danach, muss also auch gesplittet werden
1639 
1640             // das neue Ende setzen
1641             pTest->SetEnd( nNewEnd );
1642 
1643             // das Attribut aus der End-Liste entfernen
1644             sal_uInt16 nEPos = _FindEndPos( pTest );
1645             if( nEPos != USHRT_MAX )
1646                 aEndLst.Remove( nEPos, 1 );
1647 
1648             // es endet jetzt als erstes Attribut an der entsprechenden
1649             // Position. Diese Position in der Ende-Liste kennen wir schon.
1650             aEndLst.Insert(pTest, nEndPos );
1651 
1652             // den "Rest" des Attributs neu einfuegen
1653             InsertItem( *pTest->GetItem(), nNewEnd, nTestEnd );
1654         }
1655     }
1656 }
1657 
1658 
InsertItem(const SfxPoolItem & rItem,xub_StrLen nStart,xub_StrLen nEnd)1659 void HTMLEndPosLst::InsertItem( const SfxPoolItem& rItem, xub_StrLen nStart,
1660                                                           xub_StrLen nEnd )
1661 {
1662     sal_uInt16 i;
1663     for( i = 0; i < aEndLst.Count(); i++ )
1664     {
1665         HTMLSttEndPos *pTest = aEndLst[i];
1666         xub_StrLen nTestEnd = pTest->GetEnd();
1667         if( nTestEnd <= nStart )
1668         {
1669             // das Test-Attribut endet, bevor das neue beginnt
1670             continue;
1671         }
1672         else if( nTestEnd < nEnd )
1673         {
1674             // das Test-Attribut endet, bevor das neue endet. Das
1675             // neue Attribut muss deshalb aufgesplittet werden
1676             _InsertItem( new HTMLSttEndPos( rItem, nStart, nTestEnd ), i );
1677             nStart = nTestEnd;
1678         }
1679         else
1680         {
1681             // das Test-Attribut (und alle folgenden) endet, bevor das neue
1682             // endet
1683             break;
1684         }
1685     }
1686 
1687     // ein Attribut muss noch eingefuegt werden
1688     _InsertItem( new HTMLSttEndPos( rItem, nStart, nEnd ), i );
1689 }
1690 
1691 
1692 
SplitItem(const SfxPoolItem & rItem,xub_StrLen nStart,xub_StrLen nEnd)1693 void HTMLEndPosLst::SplitItem( const SfxPoolItem& rItem, xub_StrLen nStart,
1694                                                          xub_StrLen nEnd )
1695 {
1696     sal_uInt16 nWhich = rItem.Which();
1697 
1698     // erstmal muessen wir die alten Items anhand der Startliste suchen
1699     // und die neuen Item-Bereiche festlegen
1700 
1701     for( sal_uInt16 i=0; i<aStartLst.Count(); i++ )
1702     {
1703         HTMLSttEndPos *pTest = aStartLst[i];
1704         xub_StrLen nTestStart = pTest->GetStart();
1705         xub_StrLen nTestEnd = pTest->GetEnd();
1706 
1707         if( nTestStart >= nEnd )
1708         {
1709             // dieses und alle nachfolgenden Attribute beginnen spaeter
1710             break;
1711         }
1712         else if( nTestEnd > nStart )
1713         {
1714             // das Test Attribut endet im zu loeschenenden Bereich
1715             const SfxPoolItem *pItem = pTest->GetItem();
1716 
1717             // nur entsprechende On-Tag Attribute muessen beruecksichtigt
1718             // werden
1719             if( pItem->Which() == nWhich &&
1720                 HTML_ON_VALUE == GetHTMLItemState( *pItem ) )
1721             {
1722                 sal_Bool bDelete = sal_True;
1723 
1724                 if( nTestStart < nStart )
1725                 {
1726                     // der Start des neuen Attribut entspricht
1727                     // dem neuen Ende des Attribts
1728                     FixSplittedItem( pTest, nStart, i );
1729                     bDelete = sal_False;
1730                 }
1731                 else
1732                 {
1733                     // das Test-Item beginnt erst hinter dem neuen
1734                     // Ende des Attribts und kann deshalb komplett
1735                     // geloescht werden
1736                     aStartLst.Remove( i, 1 );
1737                     i--;
1738 
1739                     sal_uInt16 nEndPos = _FindEndPos( pTest );
1740                     if( nEndPos != USHRT_MAX )
1741                         aEndLst.Remove( nEndPos, 1 );
1742                 }
1743 
1744                 // ggf den zweiten Teil des gesplitteten Attribts einfuegen
1745                 if( nTestEnd > nEnd )
1746                 {
1747                     InsertItem( *pTest->GetItem(), nEnd, nTestEnd );
1748                 }
1749 
1750                 if( bDelete )
1751                     delete pTest;
1752             }
1753         }
1754     }
1755 }
1756 
GetFmtInfo(const SwFmt & rFmt,SwHTMLFmtInfos & rFmtInfos)1757 const SwHTMLFmtInfo *HTMLEndPosLst::GetFmtInfo( const SwFmt& rFmt,
1758                                                 SwHTMLFmtInfos& rFmtInfos )
1759 {
1760     const SwHTMLFmtInfo *pFmtInfo;
1761     SwHTMLFmtInfo aFmtInfo( &rFmt );
1762     sal_uInt16 nPos;
1763     if( rFmtInfos.Seek_Entry( &aFmtInfo, &nPos ) )
1764     {
1765         pFmtInfo = rFmtInfos[nPos];
1766     }
1767     else
1768     {
1769         pFmtInfo = new SwHTMLFmtInfo( &rFmt, pDoc, pTemplate,
1770                                       bOutStyles );
1771         rFmtInfos.C40_PTR_INSERT( SwHTMLFmtInfo, pFmtInfo );
1772         String aName( rFmt.GetName() );
1773         if( rScriptTxtStyles.Seek_Entry( &aName ) )
1774             ((SwHTMLFmtInfo *)pFmtInfo)->bScriptDependent = sal_True;
1775     }
1776 
1777     return pFmtInfo;
1778 }
1779 
HTMLEndPosLst(SwDoc * pD,SwDoc * pTempl,const Color * pDfltCol,sal_Bool bStyles,sal_uLong nMode,const String & rText,SvStringsSortDtor & rStyles)1780 HTMLEndPosLst::HTMLEndPosLst( SwDoc *pD, SwDoc* pTempl,
1781                               const Color* pDfltCol, sal_Bool bStyles,
1782                               sal_uLong nMode, const String& rText,
1783                               SvStringsSortDtor& rStyles ):
1784     pDoc( pD ),
1785     pTemplate( pTempl ),
1786     pDfltColor( pDfltCol ),
1787     rScriptTxtStyles( rStyles ),
1788     nHTMLMode( nMode ),
1789     bOutStyles( bStyles )
1790 {
1791     xub_StrLen nEndPos = rText.Len();
1792     xub_StrLen nPos = 0;
1793     while( nPos < nEndPos )
1794     {
1795         sal_uInt16 nScript = pBreakIt->GetBreakIter()->getScriptType( rText, nPos );
1796         nPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfScript( rText, nPos, nScript );
1797         aScriptChgLst.push_back( nPos );
1798         aScriptLst.push_back( nScript );
1799     }
1800 }
1801 
~HTMLEndPosLst()1802 HTMLEndPosLst::~HTMLEndPosLst()
1803 {
1804     ASSERT( !aStartLst.Count(), "Start-Liste im Destruktor nicht leer" );
1805     ASSERT( !aEndLst.Count(), "End-Liste im Destruktor nicht leer" );
1806 }
1807 
1808 
1809 
InsertNoScript(const SfxPoolItem & rItem,xub_StrLen nStart,xub_StrLen nEnd,SwHTMLFmtInfos & rFmtInfos,sal_Bool bParaAttrs)1810 void HTMLEndPosLst::InsertNoScript( const SfxPoolItem& rItem,
1811                             xub_StrLen nStart, xub_StrLen nEnd,
1812                             SwHTMLFmtInfos& rFmtInfos, sal_Bool bParaAttrs )
1813 {
1814     // kein Bereich ?? dann nicht aufnehmen, wird nie wirksam !!
1815     if( nStart != nEnd )
1816     {
1817         sal_Bool bSet = sal_False, bSplit = sal_False;
1818         switch( GetHTMLItemState(rItem) )
1819         {
1820         case HTML_ON_VALUE:
1821             // das Attribut wird ausgegeben, wenn es nicht sowieso
1822             // schon an ist
1823             if( !ExistsOnTagItem( rItem.Which(), nStart ) )
1824                 bSet = sal_True;
1825             break;
1826 
1827         case HTML_OFF_VALUE:
1828             // wenn das entsprechne Attribut an ist, wird es gesplittet,
1829             // Zusaetlich wird es aber als Style ausgegeben, wenn es nicht
1830             // am ganzen Absatz gesetzt ist, weil es dann ja schon mit dem
1831             // ABsatz-Tag ausgegeben wurde.
1832             if( ExistsOnTagItem( rItem.Which(), nStart ) )
1833                 bSplit = sal_True;
1834             bSet = bOutStyles && !bParaAttrs &&
1835                    !ExistsOffTagItem( rItem.Which(), nStart, nEnd );
1836             break;
1837 
1838         case HTML_REAL_VALUE:
1839             // das Attribut kann immer ausgegeben werden
1840             bSet = sal_True;
1841             break;
1842 
1843         case HTML_STYLE_VALUE:
1844             // Das Attribut kann nur als CSS1 ausgegeben werden. Wenn
1845             // es am Absatz gesetzt ist, wurde es schon mit dem
1846             // Absatz-Tag ausgegeben. Einzige Ausnahme ist das
1847             // Zeichen-Hintergrund-Attribut. Es muss immer wie ein
1848             // Hint behandelt werden.
1849             bSet = bOutStyles &&
1850                    (!bParaAttrs
1851                   || rItem.Which()==RES_CHRATR_BACKGROUND
1852                   || rItem.Which()==RES_CHRATR_OVERLINE);
1853             break;
1854 
1855         case HTML_CHRFMT_VALUE:
1856             {
1857                 ASSERT( RES_TXTATR_CHARFMT == rItem.Which(),
1858                         "Doch keine Zeichen-Vorlage" );
1859                 const SwFmtCharFmt& rChrFmt = (const SwFmtCharFmt&)rItem;
1860                 const SwCharFmt* pFmt = rChrFmt.GetCharFmt();
1861 
1862                 const SwHTMLFmtInfo *pFmtInfo = GetFmtInfo( *pFmt, rFmtInfos );
1863                 if( pFmtInfo->aToken.Len() )
1864                 {
1865                     // das Zeichenvorlagen-Tag muss vor den harten
1866                     // Attributen ausgegeben werden
1867                     InsertItem( rItem, nStart, nEnd );
1868                 }
1869                 if( pFmtInfo->pItemSet )
1870                 {
1871                     Insert( *pFmtInfo->pItemSet, nStart, nEnd,
1872                             rFmtInfos, sal_True, bParaAttrs );
1873                 }
1874             }
1875             break;
1876 
1877         case HTML_AUTOFMT_VALUE:
1878             {
1879                 const SwFmtAutoFmt& rAutoFmt = (const SwFmtAutoFmt&)rItem;
1880                 const boost::shared_ptr<SfxItemSet> pSet = rAutoFmt.GetStyleHandle();
1881                 if( pSet.get() )
1882                     Insert( *pSet.get(), nStart, nEnd, rFmtInfos, sal_True, bParaAttrs );
1883             }
1884             break;
1885 
1886         case HTML_COLOR_VALUE:
1887             // Eine Vordergrund-Farbe als Absatz-Attribut wird nur
1888             // exportiert, wenn sie nicht der Default-Farbe entspricht.
1889             {
1890                 ASSERT( RES_CHRATR_COLOR == rItem.Which(),
1891                         "Doch keine Vordergrund-Farbe" );
1892                 Color aColor( ((const SvxColorItem&)rItem).GetValue() );
1893                 if( COL_AUTO == aColor.GetColor() )
1894                     aColor.SetColor( COL_BLACK );
1895                 bSet = !bParaAttrs || !pDfltColor ||
1896                        !pDfltColor->IsRGBEqual( aColor );
1897             }
1898             break;
1899 
1900         case HTML_DROPCAP_VALUE:
1901             {
1902                 ASSERT( RES_PARATR_DROP == rItem.Which(),
1903                         "Doch kein Drop-Cap" );
1904                 const SwFmtDrop& rDrop = (const SwFmtDrop&)rItem;
1905                 nEnd = nStart + rDrop.GetChars();
1906                 if( !bOutStyles )
1907                 {
1908                     // Zumindest die Attribute der Zeichenvorlage uebernehmen
1909                     const SwCharFmt *pCharFmt = rDrop.GetCharFmt();
1910                     if( pCharFmt )
1911                     {
1912                         Insert( pCharFmt->GetAttrSet(), nStart, nEnd,
1913                                 rFmtInfos, sal_True, bParaAttrs );
1914                     }
1915                 }
1916                 else
1917                 {
1918                     bSet = sal_True;
1919                 }
1920             }
1921             break;
1922         default:
1923             ;
1924         }
1925 
1926         if( bSet )
1927             InsertItem( rItem, nStart, nEnd );
1928         if( bSplit )
1929             SplitItem( rItem, nStart, nEnd );
1930     }
1931 }
1932 
Insert(const SfxPoolItem & rItem,xub_StrLen nStart,xub_StrLen nEnd,SwHTMLFmtInfos & rFmtInfos,sal_Bool bParaAttrs)1933 void HTMLEndPosLst::Insert( const SfxPoolItem& rItem,
1934                             xub_StrLen nStart, xub_StrLen nEnd,
1935                             SwHTMLFmtInfos& rFmtInfos, sal_Bool bParaAttrs )
1936 {
1937     sal_Bool bDependsOnScript = sal_False, bDependsOnAnyScript = sal_False;
1938     sal_uInt16 nScript = i18n::ScriptType::LATIN;
1939     switch( rItem.Which() )
1940     {
1941     case RES_CHRATR_FONT:
1942     case RES_CHRATR_FONTSIZE:
1943     case RES_CHRATR_LANGUAGE:
1944     case RES_CHRATR_POSTURE:
1945     case RES_CHRATR_WEIGHT:
1946         bDependsOnScript = sal_True;
1947         nScript = i18n::ScriptType::LATIN;
1948         break;
1949 
1950     case RES_CHRATR_CJK_FONT:
1951     case RES_CHRATR_CJK_FONTSIZE:
1952     case RES_CHRATR_CJK_LANGUAGE:
1953     case RES_CHRATR_CJK_POSTURE:
1954     case RES_CHRATR_CJK_WEIGHT:
1955         bDependsOnScript = sal_True;
1956         nScript = i18n::ScriptType::ASIAN;
1957         break;
1958 
1959     case RES_CHRATR_CTL_FONT:
1960     case RES_CHRATR_CTL_FONTSIZE:
1961     case RES_CHRATR_CTL_LANGUAGE:
1962     case RES_CHRATR_CTL_POSTURE:
1963     case RES_CHRATR_CTL_WEIGHT:
1964         bDependsOnScript = sal_True;
1965         nScript = i18n::ScriptType::COMPLEX;
1966         break;
1967     case RES_TXTATR_CHARFMT:
1968         {
1969             const SwFmtCharFmt& rChrFmt = (const SwFmtCharFmt&)rItem;
1970             const SwCharFmt* pFmt = rChrFmt.GetCharFmt();
1971             const SwHTMLFmtInfo *pFmtInfo = GetFmtInfo( *pFmt, rFmtInfos );
1972             if( pFmtInfo->bScriptDependent )
1973             {
1974                 bDependsOnScript = sal_True;
1975                 bDependsOnAnyScript = sal_True;
1976             }
1977         }
1978         break;
1979     case RES_TXTATR_INETFMT:
1980         {
1981             if( GetFmtInfo( *pDoc->GetCharFmtFromPool(
1982                      RES_POOLCHR_INET_NORMAL), rFmtInfos )->bScriptDependent ||
1983                 GetFmtInfo( *pDoc->GetCharFmtFromPool(
1984                      RES_POOLCHR_INET_VISIT), rFmtInfos )->bScriptDependent )
1985             {
1986                 bDependsOnScript = sal_True;
1987                 bDependsOnAnyScript = sal_True;
1988             }
1989         }
1990         break;
1991     }
1992 
1993     if( bDependsOnScript )
1994     {
1995         xub_StrLen nPos = nStart;
1996         for( size_t i=0; i < aScriptChgLst.size(); i++ )
1997         {
1998             xub_StrLen nChgPos = aScriptChgLst[i];
1999             if( nPos >= nChgPos )
2000             {
2001                 // the hint starts behind or at the next script change,
2002                 // so we may continue with this position.
2003                 continue;
2004             }
2005             if( nEnd <= nChgPos )
2006             {
2007                 // the (rest of) the hint ends before or at the next script
2008                 // change, so we can insert it, but only if it belongs
2009                 // to the current script.
2010                 if( bDependsOnAnyScript || nScript == aScriptLst[i] )
2011                     InsertNoScript( rItem, nPos, nEnd, rFmtInfos,
2012                                     bParaAttrs );
2013                 break;
2014             }
2015 
2016             // the hint starts before the next script change and ends behind
2017             // it, so we can insert a hint upto the next script change and
2018             // continue with the rest of the hint.
2019             if( bDependsOnAnyScript || nScript == aScriptLst[i] )
2020                 InsertNoScript( rItem, nPos, nChgPos, rFmtInfos, bParaAttrs );
2021             nPos = nChgPos;
2022         }
2023     }
2024     else
2025     {
2026         InsertNoScript( rItem, nStart, nEnd, rFmtInfos, bParaAttrs );
2027     }
2028 }
2029 
Insert(const SfxItemSet & rItemSet,xub_StrLen nStart,xub_StrLen nEnd,SwHTMLFmtInfos & rFmtInfos,sal_Bool bDeep,sal_Bool bParaAttrs)2030 void HTMLEndPosLst::Insert( const SfxItemSet& rItemSet,
2031                             xub_StrLen nStart, xub_StrLen nEnd,
2032                             SwHTMLFmtInfos& rFmtInfos,
2033                             sal_Bool bDeep, sal_Bool bParaAttrs )
2034 {
2035     SfxWhichIter aIter( rItemSet );
2036 
2037     sal_uInt16 nWhich = aIter.FirstWhich();
2038     while( nWhich )
2039     {
2040         const SfxPoolItem *pItem;
2041         if( SFX_ITEM_SET == rItemSet.GetItemState( nWhich, bDeep, &pItem ) )
2042         {
2043             Insert( *pItem, nStart, nEnd, rFmtInfos, bParaAttrs );
2044         }
2045 
2046         nWhich = aIter.NextWhich();
2047     }
2048 }
2049 
Insert(const SwDrawFrmFmt & rFmt,xub_StrLen nPos,SwHTMLFmtInfos & rFmtInfos)2050 void HTMLEndPosLst::Insert( const SwDrawFrmFmt& rFmt, xub_StrLen nPos,
2051                             SwHTMLFmtInfos& rFmtInfos )
2052 {
2053     // der Type-Cast ist nur noetig, um nicht seinetwegen
2054     // svdrwobt.hxx zu includem
2055     const SdrObject* pTextObj =
2056         (const SdrObject *)SwHTMLWriter::GetMarqueeTextObj( rFmt );
2057 
2058     if( pTextObj )
2059     {
2060         // die Edit-Engine-Attribute des Objekts als SW-Attribute holen
2061         // und als Hints einsortieren. Wegen der Menge der Hints werden
2062         // Styles hierbei nicht beruecksichtigt!
2063         const SfxItemSet& rFmtItemSet = rFmt.GetAttrSet();
2064         SfxItemSet aItemSet( *rFmtItemSet.GetPool(), RES_CHRATR_BEGIN,
2065                                                      RES_CHRATR_END );
2066         SwHTMLWriter::GetEEAttrsFromDrwObj( aItemSet, pTextObj, sal_True );
2067         sal_Bool bOutStylesOld = bOutStyles;
2068         bOutStyles = sal_False;
2069         Insert( aItemSet, nPos, nPos+1, rFmtInfos, sal_False, sal_False );
2070         bOutStyles = bOutStylesOld;
2071     }
2072 }
2073 
GetScriptAtPos(xub_StrLen nPos,sal_uInt16 nWeak)2074 sal_uInt16 HTMLEndPosLst::GetScriptAtPos( xub_StrLen nPos ,
2075                                           sal_uInt16 nWeak )
2076 {
2077     sal_uInt16 nRet = CSS1_OUTMODE_ANY_SCRIPT;
2078 
2079     size_t nScriptChgs = aScriptChgLst.size();
2080     size_t i=0;
2081     while( i < nScriptChgs && nPos >= aScriptChgLst[i] )
2082         i++;
2083     ASSERT( i < nScriptChgs, "script list is to short" );
2084     if( i < nScriptChgs )
2085     {
2086         if( i18n::ScriptType::WEAK == aScriptLst[i] )
2087             nRet = nWeak;
2088         else
2089             nRet = SwHTMLWriter::GetCSS1ScriptForScriptType( aScriptLst[i] );
2090     }
2091 
2092     return nRet;
2093 }
2094 
OutStartAttrs(SwHTMLWriter & rHWrt,xub_StrLen nPos,HTMLOutContext * pContext)2095 void HTMLEndPosLst::OutStartAttrs( SwHTMLWriter& rHWrt, xub_StrLen nPos,
2096                                    HTMLOutContext *pContext )
2097 {
2098     rHWrt.bTagOn = sal_True;
2099 
2100     // die Attribute in der Start-Liste sind aufsteigend sortiert
2101     for( sal_uInt16 i=0; i< aStartLst.Count(); i++ )
2102     {
2103         HTMLSttEndPos *pPos = aStartLst[i];
2104         xub_StrLen nStart = pPos->GetStart();
2105         if( nStart > nPos )
2106         {
2107             // dieses und alle folgenden Attribute werden erst noch geoeffnet
2108             break;
2109         }
2110         else if( nStart == nPos )
2111         {
2112             // das Attribut ausgeben
2113             sal_uInt16 nCSS1Script = rHWrt.nCSS1Script;
2114             sal_uInt16 nWhich = pPos->GetItem()->Which();
2115             if( RES_TXTATR_CHARFMT == nWhich ||
2116                 RES_TXTATR_INETFMT == nWhich ||
2117                 RES_PARATR_DROP == nWhich )
2118             {
2119                 rHWrt.nCSS1Script = GetScriptAtPos( nPos, nCSS1Script );
2120             }
2121             if( pContext )
2122             {
2123                 HTMLOutFuncs::FlushToAscii( rHWrt.Strm(), *pContext );
2124                 pContext = 0; // one time ony
2125             }
2126             Out( aHTMLAttrFnTab, *pPos->GetItem(), rHWrt );
2127             rHWrt.nCSS1Script = nCSS1Script;
2128         }
2129     }
2130 }
2131 
OutEndAttrs(SwHTMLWriter & rHWrt,xub_StrLen nPos,HTMLOutContext * pContext)2132 void HTMLEndPosLst::OutEndAttrs( SwHTMLWriter& rHWrt, xub_StrLen nPos,
2133                                  HTMLOutContext *pContext )
2134 {
2135     rHWrt.bTagOn = sal_False;
2136 
2137     // die Attribute in der End-Liste sind aufsteigend sortiert
2138     sal_uInt16 i=0;
2139     while( i < aEndLst.Count() )
2140     {
2141         HTMLSttEndPos *pPos = aEndLst[i];
2142         xub_StrLen nEnd = pPos->GetEnd();
2143 
2144         if( STRING_MAXLEN==nPos || nEnd == nPos )
2145         {
2146             if( pContext )
2147             {
2148                 HTMLOutFuncs::FlushToAscii( rHWrt.Strm(), *pContext );
2149                 pContext = 0; // one time ony
2150             }
2151             Out( aHTMLAttrFnTab, *pPos->GetItem(), rHWrt );
2152             _RemoveItem( i );
2153         }
2154         else if( nEnd > nPos )
2155         {
2156             // dieses und alle folgenden Attribute werden erst spaeter beendet
2157             break;
2158         }
2159         else
2160         {
2161             // Das Attribut wird vor der aktuellen Position beendet. Das
2162             // darf nicht sein, aber wie koennen trotzdem damit umgehen
2163             ASSERT( nEnd >= nPos,
2164                     "Das Attribut sollte schon laengst beendet sein" );
2165             i++;
2166         }
2167     }
2168 }
2169 
2170 
2171 /* Ausgabe der Nodes */
OutHTML_SwTxtNode(Writer & rWrt,const SwCntntNode & rNode)2172 Writer& OutHTML_SwTxtNode( Writer& rWrt, const SwCntntNode& rNode )
2173 {
2174     SwTxtNode * pNd = &((SwTxtNode&)rNode);
2175     SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt;
2176 
2177     const String& rStr = pNd->GetTxt();
2178     xub_StrLen nEnde = rStr.Len();
2179 
2180     // Besonderheit: leere Node und HR-Vorlage (horizontaler Strich)
2181     //              nur ein <HR> ausgeben
2182     sal_uInt16 nPoolId = pNd->GetAnyFmtColl().GetPoolFmtId();
2183 
2184     if( !nEnde && (RES_POOLCOLL_HTML_HR==nPoolId ||
2185                    pNd->GetAnyFmtColl().GetName().EqualsAscii( OOO_STRING_SVTOOLS_HTML_horzrule) ) )
2186     {
2187         // dann die absatz-gebundenen Grafiken/OLE-Objekte im Absatz
2188         // MIB 8.7.97: Ein <PRE> spannen wir um die Linie auf. Dann stimmen
2189         // zwar die Abstaende nicht, aber sonst bekommen wir einen leeren
2190         // Absatz hinter dem <HR> und das ist noch unschoener.
2191         rHTMLWrt.ChangeParaToken( 0 );
2192 
2193         // Alle an dem Node verankerten Rahmen ausgeben
2194         rHTMLWrt.OutFlyFrm( rNode.GetIndex(), 0, HTML_POS_ANY );
2195 
2196         if( rHTMLWrt.bLFPossible )
2197             rHTMLWrt.OutNewLine(); // Absatz-Tag in eine neue Zeile
2198 
2199         rHTMLWrt.bLFPossible = sal_True;
2200 
2201         ByteString sOut( '<' );
2202         sOut += OOO_STRING_SVTOOLS_HTML_horzrule;
2203 
2204         const SfxItemSet* pItemSet = pNd->GetpSwAttrSet();
2205         if( !pItemSet )
2206         {
2207             rWrt.Strm() << sOut.GetBuffer() << '>';
2208             return rHTMLWrt;
2209         }
2210         const SfxPoolItem* pItem;
2211         if( SFX_ITEM_SET == pItemSet->GetItemState( RES_LR_SPACE, sal_False, &pItem ))
2212         {
2213             sal_Int32 nLeft = ((SvxLRSpaceItem*)pItem)->GetLeft();
2214             sal_Int32 nRight = ((SvxLRSpaceItem*)pItem)->GetRight();
2215             if( nLeft || nRight )
2216             {
2217                 const SwFrmFmt& rPgFmt =
2218                     rHTMLWrt.pDoc->GetPageDescFromPool
2219                     ( RES_POOLPAGE_HTML, false )->GetMaster();
2220                 const SwFmtFrmSize& rSz   = rPgFmt.GetFrmSize();
2221                 const SvxLRSpaceItem& rLR = rPgFmt.GetLRSpace();
2222                 const SwFmtCol& rCol = rPgFmt.GetCol();
2223 
2224                 long nPageWidth = rSz.GetWidth() - rLR.GetLeft() - rLR.GetRight();
2225 
2226                 if( 1 < rCol.GetNumCols() )
2227                     nPageWidth /= rCol.GetNumCols();
2228 
2229                 const SwTableNode* pTblNd = pNd->FindTableNode();
2230                 if( pTblNd )
2231                 {
2232                     const SwTableBox* pBox = pTblNd->GetTable().GetTblBox(
2233                                     pNd->StartOfSectionIndex() );
2234                     if( pBox )
2235                         nPageWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
2236                 }
2237 
2238                 ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_width) += '=';
2239                 rWrt.Strm() << sOut.GetBuffer();
2240                 rWrt.OutULong( rHTMLWrt.ToPixel(nPageWidth-nLeft-nRight) );
2241 
2242                 ((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_align) += '=';
2243                 if( !nLeft )
2244                     sOut += OOO_STRING_SVTOOLS_HTML_AL_left;
2245                 else if( !nRight )
2246                     sOut += OOO_STRING_SVTOOLS_HTML_AL_right;
2247                 else
2248                     sOut += OOO_STRING_SVTOOLS_HTML_AL_center;
2249             }
2250         }
2251         rWrt.Strm() << sOut.GetBuffer();
2252         if( SFX_ITEM_SET == pItemSet->GetItemState( RES_BOX, sal_False, &pItem ))
2253         {
2254             const SvxBoxItem* pBoxItem = (const SvxBoxItem*)pItem;
2255             const SvxBorderLine* pBorderLine = pBoxItem->GetBottom();
2256             if( pBorderLine )
2257             {
2258                 sal_uInt16 nWidth = pBorderLine->GetOutWidth() +
2259                                 pBorderLine->GetInWidth() +
2260                                 pBorderLine->GetDistance();
2261                 ((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_size) += '=';
2262                 rWrt.Strm() << sOut.GetBuffer();
2263                 rWrt.OutULong( rHTMLWrt.ToPixel(nWidth) );
2264 
2265                 const Color& rBorderColor = pBorderLine->GetColor();
2266                 if( !rBorderColor.IsRGBEqual( Color(COL_GRAY) ) )
2267                 {
2268                     ((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_color) += '=';
2269                     rWrt.Strm() << sOut.GetBuffer();
2270                     HTMLOutFuncs::Out_Color( rWrt.Strm(), rBorderColor,
2271                                              rHTMLWrt.eDestEnc );
2272                 }
2273 
2274                 if( !pBorderLine->GetInWidth() )
2275                 {
2276                     (sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_noshade;
2277                     rWrt.Strm() << sOut.GetBuffer();
2278                 }
2279             }
2280         }
2281         rWrt.Strm() << '>';
2282         return rHTMLWrt;
2283     }
2284 
2285     // Die leeren Nodes mit 2pt Font-Hoehe und der Stand-Vorlage, die
2286     // vor Tabellen und Bereichen eingefuegt werden, nicht exportieren,
2287     // Bookmarks oder absatzgebundene Grafiken aber schon.
2288     // MIB 21.7.97: Ausserdem auch keine leeren Tabellen-Zellen exportieren.
2289     if( !nEnde && (nPoolId == RES_POOLCOLL_STANDARD ||
2290                    nPoolId == RES_POOLCOLL_TABLE ||
2291                    nPoolId == RES_POOLCOLL_TABLE_HDLN) )
2292     {
2293         // Der aktuelle Node ist leer und enthaelt Standard-Vorlage ...
2294         const SfxPoolItem* pItem;
2295         const SfxItemSet *pItemSet = pNd->GetpSwAttrSet();
2296         if( pItemSet && pItemSet->Count() &&
2297             SFX_ITEM_SET == pItemSet->GetItemState( RES_CHRATR_FONTSIZE, sal_False, &pItem ) &&
2298             40 == ((const SvxFontHeightItem *)pItem)->GetHeight() )
2299         {
2300             // ... ausserdem ist die 2pt Schrift eingestellt ...
2301             sal_uLong nNdPos = rWrt.pCurPam->GetPoint()->nNode.GetIndex();
2302             const SwNode *pNextNd = rWrt.pDoc->GetNodes()[nNdPos+1];
2303             const SwNode *pPrevNd = rWrt.pDoc->GetNodes()[nNdPos-1];
2304             sal_Bool bStdColl = nPoolId == RES_POOLCOLL_STANDARD;
2305             if( ( bStdColl && (pNextNd->IsTableNode() ||
2306                                pNextNd->IsSectionNode()) ) ||
2307                 ( !bStdColl && pNextNd->IsEndNode() &&
2308                                pPrevNd->IsStartNode() &&
2309                                SwTableBoxStartNode==
2310                                 pPrevNd->GetStartNode()->GetStartNodeType() ) )
2311             {
2312                 // ... und er steht vor einer Tabelle ohne einem Bereich
2313                 rHTMLWrt.OutBookmarks();
2314                 rHTMLWrt.bLFPossible = !rHTMLWrt.nLastParaToken;
2315 
2316                 // Alle an dem Node verankerten Rahmen ausgeben
2317                 rHTMLWrt.OutFlyFrm( rNode.GetIndex(), 0, HTML_POS_ANY );
2318                 rHTMLWrt.bLFPossible = sal_False;
2319 
2320                 return rWrt;
2321             }
2322         }
2323     }
2324 
2325     // PagePreaks uns PagDescs abfangen
2326     sal_Bool bPageBreakBehind = sal_False;
2327     if( rHTMLWrt.bCfgFormFeed &&
2328         !(rHTMLWrt.bOutTable || rHTMLWrt.bOutFlyFrame) &&
2329         rHTMLWrt.pStartNdIdx->GetIndex() !=
2330         rHTMLWrt.pCurPam->GetPoint()->nNode.GetIndex() )
2331     {
2332         sal_Bool bPageBreakBefore = sal_False;
2333         const SfxPoolItem* pItem;
2334         const SfxItemSet* pItemSet = pNd->GetpSwAttrSet();
2335 
2336         if( pItemSet )
2337         {
2338             if( SFX_ITEM_SET ==
2339                 pItemSet->GetItemState( RES_PAGEDESC, sal_True, &pItem ) &&
2340                 ((SwFmtPageDesc *)pItem)->GetPageDesc() )
2341                 bPageBreakBefore = sal_True;
2342             else if( SFX_ITEM_SET ==
2343                      pItemSet->GetItemState( RES_BREAK, sal_True, &pItem ) )
2344             {
2345                 switch( ((SvxFmtBreakItem *)pItem)->GetBreak() )
2346                 {
2347                 case SVX_BREAK_PAGE_BEFORE:
2348                     bPageBreakBefore = sal_True;
2349                     break;
2350                 case SVX_BREAK_PAGE_AFTER:
2351                     bPageBreakBehind = sal_True;
2352                     break;
2353                 case SVX_BREAK_PAGE_BOTH:
2354                     bPageBreakBefore = sal_True;
2355                     bPageBreakBehind = sal_True;
2356                     break;
2357                 default:
2358                     ;
2359                 }
2360             }
2361         }
2362 
2363         if( bPageBreakBefore )
2364             rWrt.Strm() << '\f';
2365     }
2366 
2367     // eventuell eine Form oeffnen
2368     rHTMLWrt.OutForm();
2369 
2370     // An dem Node "verankerte" Seitenegebunde Rahmen ausgeben
2371     sal_Bool bFlysLeft = rHTMLWrt.OutFlyFrm( rNode.GetIndex(),
2372                                          0, HTML_POS_PREFIX );
2373     // An dem Node verankerte Rahmen ausgeben, die vor dem
2374     // Absatz-Tag geschrieben werden sollen.
2375     if( bFlysLeft )
2376         bFlysLeft = rHTMLWrt.OutFlyFrm( rNode.GetIndex(),
2377                                         0, HTML_POS_BEFORE );
2378 
2379     if( rHTMLWrt.pCurPam->GetPoint()->nNode == rHTMLWrt.pCurPam->GetMark()->nNode )
2380         nEnde = rHTMLWrt.pCurPam->GetMark()->nContent.GetIndex();
2381 
2382     // gibt es harte Attribute, die als Optionen geschrieben werden muessen?
2383     rHTMLWrt.bTagOn = sal_True;
2384 
2385     // jetzt das Tag des Absatzes ausgeben
2386     const SwFmt& rFmt = pNd->GetAnyFmtColl();
2387     SwHTMLTxtCollOutputInfo aFmtInfo;
2388     sal_Bool bOldLFPossible = rHTMLWrt.bLFPossible;
2389     OutHTML_SwFmt( rWrt, rFmt, pNd->GetpSwAttrSet(), aFmtInfo );
2390 
2391     // Wenn vor dem Absatz-Tag keine neue Zeile aufgemacht wurde, dann
2392     // tun wir das jetzt
2393     rHTMLWrt.bLFPossible = !rHTMLWrt.nLastParaToken;
2394     if( !bOldLFPossible && rHTMLWrt.bLFPossible )
2395         rHTMLWrt.OutNewLine();
2396 
2397 
2398     // dann die Bookmarks (inkl. End-Tag)
2399     rHTMLWrt.bOutOpts = sal_False;
2400     rHTMLWrt.OutBookmarks();
2401 
2402     // jetzt ist noch mal eine gute Gelegenheit fuer ein LF, sofern es noch
2403     // erlaubt ist
2404     if( rHTMLWrt.bLFPossible &&
2405         rHTMLWrt.GetLineLen() >= rHTMLWrt.nWhishLineLen )
2406     {
2407         rHTMLWrt.OutNewLine();
2408     }
2409     rHTMLWrt.bLFPossible = sal_False;
2410 
2411     // Text, der aus einer Outline-Numerierung kommt ermitteln
2412     xub_StrLen nOffset = 0;
2413     String aOutlineTxt;
2414     String aFullText;
2415     // --> OD 2006-06-12 #b6435904#
2416     // export numbering string as plain text only for the outline numbering,
2417     // because the outline numbering isn't exported as a numbering - see <SwHTMLNumRuleInfo::Set(..)>
2418     if ( pNd->IsOutline() &&
2419          pNd->GetNumRule() == pNd->GetDoc()->GetOutlineNumRule() )
2420     // <--
2421     {
2422         aOutlineTxt = pNd->GetNumString();
2423         nOffset = nOffset + aOutlineTxt.Len();
2424         aFullText = aOutlineTxt;
2425     }
2426     String aFootEndNoteSym;
2427     if( rHTMLWrt.pFmtFtn )
2428     {
2429         aFootEndNoteSym = rHTMLWrt.GetFootEndNoteSym( *rHTMLWrt.pFmtFtn );
2430         nOffset = nOffset + aFootEndNoteSym.Len();
2431         aFullText += aFootEndNoteSym;
2432     }
2433 
2434     // gibt es harte Attribute, die als Tags geschrieben werden muessen?
2435     aFullText += rStr;
2436     HTMLEndPosLst aEndPosLst( rWrt.pDoc, rHTMLWrt.pTemplate,
2437                               rHTMLWrt.pDfltColor, rHTMLWrt.bCfgOutStyles,
2438                               rHTMLWrt.GetHTMLMode(), aFullText,
2439                               rHTMLWrt.aScriptTextStyles );
2440     if( aFmtInfo.pItemSet )
2441     {
2442         aEndPosLst.Insert( *aFmtInfo.pItemSet, 0, nEnde + nOffset,
2443                            rHTMLWrt.aChrFmtInfos, sal_False, sal_True );
2444     }
2445 
2446 
2447     if( aOutlineTxt.Len() || rHTMLWrt.pFmtFtn )
2448     {
2449         // Absatz-Attribute ausgeben, damit der Text die Attribute des
2450         // Absatzes bekommt.
2451         aEndPosLst.OutStartAttrs( rHTMLWrt, 0 );
2452 
2453         // Theoretisch muesste man hier die Zeichen-Vorlage der Numerierung
2454         // beachten. Da man die ueber die UI nicht setzen kann, ignorieren
2455         // wir sie erstmal.
2456 
2457         if( aOutlineTxt.Len() )
2458             HTMLOutFuncs::Out_String( rWrt.Strm(), aOutlineTxt,
2459                                       rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters);
2460 
2461         if( rHTMLWrt.pFmtFtn )
2462         {
2463             rHTMLWrt.OutFootEndNoteSym( *rHTMLWrt.pFmtFtn, aFootEndNoteSym,
2464                                         aEndPosLst.GetScriptAtPos( aOutlineTxt.Len(), rHTMLWrt.nCSS1Script ) );
2465             rHTMLWrt.pFmtFtn = 0;
2466         }
2467     }
2468 
2469     // erstmal den Start berichtigen. D.h. wird nur ein Teil vom Satz
2470     // ausgegeben, so muessen auch da die Attribute stimmen!!
2471     rHTMLWrt.bTxtAttr = sal_True;
2472 
2473 
2474     sal_uInt16 nAttrPos = 0;
2475     xub_StrLen nStrPos = rHTMLWrt.pCurPam->GetPoint()->nContent.GetIndex();
2476     const SwTxtAttr * pHt = 0;
2477     sal_uInt16 nCntAttr = pNd->HasHints() ? pNd->GetSwpHints().Count() : 0;
2478     if( nCntAttr && nStrPos > *( pHt = pNd->GetSwpHints()[ 0 ] )->GetStart() )
2479     {
2480         // Ok, es gibt vorher Attribute, die ausgegeben werden muessen
2481         do {
2482             aEndPosLst.OutEndAttrs( rHTMLWrt, nStrPos + nOffset );
2483 
2484             nAttrPos++;
2485             if( pHt->Which() == RES_TXTATR_FIELD
2486                 || pHt->Which() == RES_TXTATR_ANNOTATION )
2487                 continue;
2488 
2489             if ( pHt->End() && !pHt->HasDummyChar() )
2490             {
2491                 const xub_StrLen nHtEnd = *pHt->End(),
2492                        nHtStt = *pHt->GetStart();
2493                 if( !rHTMLWrt.bWriteAll && nHtEnd <= nStrPos )
2494                     continue;
2495 
2496                 // leere Hints am Anfang nicht beachten, oder ??
2497                 if( nHtEnd == nHtStt )
2498                     continue;
2499 
2500                 // Attribut in die Liste aufnehemen
2501                 if( rHTMLWrt.bWriteAll )
2502                     aEndPosLst.Insert( pHt->GetAttr(), nHtStt + nOffset,
2503                                        nHtEnd + nOffset,
2504                                        rHTMLWrt.aChrFmtInfos );
2505                 else
2506                 {
2507                     xub_StrLen nTmpStt = nHtStt < nStrPos ? nStrPos : nHtStt;
2508                     xub_StrLen nTmpEnd = nHtEnd < nEnde ? nHtEnd : nEnde;
2509                     aEndPosLst.Insert( pHt->GetAttr(), nTmpStt + nOffset,
2510                                        nTmpEnd + nOffset,
2511                                        rHTMLWrt.aChrFmtInfos );
2512                 }
2513                 continue;
2514                 // aber nicht ausgeben, das erfolgt spaeter !!
2515             }
2516 
2517         } while( nAttrPos < nCntAttr && nStrPos >
2518             *( pHt = pNd->GetSwpHints()[ nAttrPos ] )->GetStart() );
2519 
2520         // dann gebe mal alle gesammelten Attribute von der String-Pos aus
2521         aEndPosLst.OutEndAttrs( rHTMLWrt, nStrPos + nOffset );
2522         aEndPosLst.OutStartAttrs( rHTMLWrt, nStrPos + nOffset );
2523     }
2524 
2525     sal_Bool bWriteBreak = (HTML_PREFORMTXT_ON != rHTMLWrt.nLastParaToken);
2526     if( bWriteBreak && pNd->GetNumRule()  )
2527         bWriteBreak = sal_False;
2528 
2529     {
2530         HTMLOutContext aContext( rHTMLWrt.eDestEnc );
2531 
2532         xub_StrLen nPreSplitPos = 0;
2533         for( ; nStrPos < nEnde; nStrPos++ )
2534         {
2535             aEndPosLst.OutEndAttrs( rHTMLWrt, nStrPos + nOffset, &aContext );
2536 
2537             // Die an der aktuellen Position verankerten Rahmen ausgeben
2538             if( bFlysLeft )
2539                 bFlysLeft = rHTMLWrt.OutFlyFrm( rNode.GetIndex(),
2540                                                 nStrPos, HTML_POS_INSIDE,
2541                                                 &aContext );
2542 
2543             sal_Bool bOutChar = sal_True;
2544             const SwTxtAttr * pTxtHt = 0;
2545             if( nAttrPos < nCntAttr && *pHt->GetStart() == nStrPos
2546                 && nStrPos != nEnde )
2547             {
2548                 do {
2549                     if ( pHt->End() && !pHt->HasDummyChar() )
2550                     {
2551                         if( RES_CHRATR_KERNING == pHt->Which() &&
2552                             rHTMLWrt.IsHTMLMode(HTMLMODE_FIRSTLINE) &&
2553                             *pHt->End() - nStrPos == 1 &&
2554                             ' ' == rStr.GetChar(nStrPos) &&
2555                             ((const SvxKerningItem&)pHt->GetAttr()).GetValue() > 0 )
2556                         {
2557                             // Wenn erlaubt, wird das Ding als Spacer exportiert
2558 
2559                             bOutChar = sal_False;   // Space nicht ausgeben
2560                             bWriteBreak = sal_False;    // der Absatz ist aber auch nicht leer
2561                             HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
2562                             OutHTML_HoriSpacer( rWrt,
2563                                 ((const SvxKerningItem&)pHt->GetAttr()).GetValue() );
2564 
2565                             // Der Hint braucht nun doch nicht weiter
2566                             // beruecksichtigt werden.
2567                         }
2568                         else if( *pHt->End() != nStrPos )
2569                         {
2570                             // Hints mit Ende einsortieren, wenn sie keinen
2571                             // leeren Bereich aufspannen (Hints, die keinen
2572                             // Bereich aufspannen werden ignoriert
2573                             aEndPosLst.Insert( pHt->GetAttr(), nStrPos + nOffset,
2574                                                *pHt->End() + nOffset,
2575                                                rHTMLWrt.aChrFmtInfos );
2576                         }
2577                     }
2578                     else
2579                     {
2580                         // Hints ohne-Ende werden als letztes ausgebeben
2581                         ASSERT( !pTxtHt, "Wieso gibt es da schon ein Attribut ohne Ende?" );
2582                         if( rHTMLWrt.nTxtAttrsToIgnore>0 )
2583                         {
2584                             rHTMLWrt.nTxtAttrsToIgnore--;
2585                         }
2586                         else
2587                         {
2588                             pTxtHt = pHt;
2589                             sal_uInt16 nFldWhich;
2590                             if( RES_TXTATR_FIELD != pHt->Which()
2591                                 || ( RES_POSTITFLD != (nFldWhich = ((const SwFmtFld&)pHt->GetAttr()).GetField()->Which())
2592                                      && RES_SCRIPTFLD != nFldWhich ) )
2593                             {
2594                                 bWriteBreak = sal_False;
2595                             }
2596                         }
2597                         bOutChar = sal_False;       // keine 255 ausgeben
2598                     }
2599                 } while( ++nAttrPos < nCntAttr && nStrPos ==
2600                     *( pHt = pNd->GetSwpHints()[ nAttrPos ] )->GetStart() );
2601             }
2602 
2603             // Manche Draw-Formate koennen auch noch Attribute mitbringen
2604             if( pTxtHt && RES_TXTATR_FLYCNT == pTxtHt->Which() )
2605             {
2606                 const SwFrmFmt* pFrmFmt =
2607                     ((const SwFmtFlyCnt &)pTxtHt->GetAttr()).GetFrmFmt();
2608 
2609                 if( RES_DRAWFRMFMT == pFrmFmt->Which() )
2610                     aEndPosLst.Insert( *((const SwDrawFrmFmt *)pFrmFmt),
2611                                         nStrPos + nOffset,
2612                                         rHTMLWrt.aChrFmtInfos );
2613             }
2614 
2615             aEndPosLst.OutEndAttrs( rHTMLWrt, nStrPos + nOffset, &aContext );
2616             aEndPosLst.OutStartAttrs( rHTMLWrt, nStrPos + nOffset, &aContext );
2617 
2618             if( pTxtHt )
2619             {
2620                 rHTMLWrt.bLFPossible = !rHTMLWrt.nLastParaToken && nStrPos > 0 &&
2621                                        rStr.GetChar(nStrPos-1) == ' ';
2622                 sal_uInt16 nCSS1Script = rHTMLWrt.nCSS1Script;
2623                 rHTMLWrt.nCSS1Script = aEndPosLst.GetScriptAtPos(
2624                                                 nStrPos + nOffset, nCSS1Script );
2625                 HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
2626                 Out( aHTMLAttrFnTab, pTxtHt->GetAttr(), rHTMLWrt );
2627                 rHTMLWrt.nCSS1Script = nCSS1Script;
2628                 rHTMLWrt.bLFPossible = sal_False;
2629             }
2630 
2631             if( bOutChar )
2632             {
2633                 // #i120442#: get the UTF-32 codepoint by converting an eventual UTF-16 unicode surrogate pair
2634                 sal_uInt64 c = rStr.GetChar( nStrPos );
2635                 if( nStrPos < nEnde - 1 )
2636                 {
2637                     const sal_Unicode d = rStr.GetChar( nStrPos + 1 );
2638                     if( (c >= 0xd800 && c <= 0xdbff) && (d >= 0xdc00 && d <= 0xdfff) )
2639                     {
2640                         sal_uInt64 templow = d&0x03ff;
2641                         sal_uInt64 temphi = ((c&0x03ff) + 0x0040)<<10;
2642                         c = temphi|templow;
2643                         nStrPos++;
2644                     }
2645                 }
2646 
2647                 // try to split a line after about 255 characters
2648                 // at a space character unless in a PRE-context
2649                 if( ' '==c && !rHTMLWrt.nLastParaToken  )
2650                 {
2651                     xub_StrLen nLineLen;
2652                     if( rHTMLWrt.nLastParaToken )
2653                         nLineLen = nStrPos - nPreSplitPos;
2654                     else
2655                         nLineLen = rHTMLWrt.GetLineLen();
2656 
2657                     xub_StrLen nWordLen = rStr.Search( ' ', nStrPos+1 );
2658                     if( nWordLen == STRING_NOTFOUND )
2659                         nWordLen = nEnde;
2660                     nWordLen -= nStrPos;
2661 
2662                     if( nLineLen >= rHTMLWrt.nWhishLineLen ||
2663                         (nLineLen+nWordLen) >= rHTMLWrt.nWhishLineLen )
2664                     {
2665                         HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
2666                         rHTMLWrt.OutNewLine();
2667                         bOutChar = sal_False;
2668                         if( rHTMLWrt.nLastParaToken )
2669                             nPreSplitPos = nStrPos+1;
2670                     }
2671                 }
2672 
2673                 if( bOutChar )
2674                 {
2675                     if( 0x0a == c )
2676                     {
2677                         HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
2678                         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_linebreak );
2679                     }
2680                     // #i120442#: if c is outside the unicode base plane output it as "&#******;"
2681                     else if( c > 0xffff)
2682                     {
2683                         ByteString sOut("&#");
2684                         sOut += ByteString::CreateFromInt64( (sal_uInt64)c );
2685                         sOut += ';';
2686                         rWrt.Strm() << sOut.GetBuffer();
2687                     }
2688                     else
2689                         HTMLOutFuncs::Out_Char( rWrt.Strm(), (sal_Unicode)c, aContext, &rHTMLWrt.aNonConvertableCharacters );
2690 
2691                     // if a paragraph's last character is a hard line break
2692                     // then we need to add an extra <br>
2693                     // because browsers like Mozilla wouldn't add a line for the next paragraph
2694                     bWriteBreak = (0x0a == c) &&
2695                                   (HTML_PREFORMTXT_ON != rHTMLWrt.nLastParaToken);
2696                 }
2697             }
2698         }
2699         HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
2700     }
2701 
2702     aEndPosLst.OutEndAttrs( rHTMLWrt, STRING_MAXLEN );
2703 
2704     // Die an der letzten Position verankerten Rahmen ausgeben
2705     if( bFlysLeft )
2706         bFlysLeft = rHTMLWrt.OutFlyFrm( rNode.GetIndex(),
2707                                        nEnde, HTML_POS_INSIDE );
2708     ASSERT( !bFlysLeft, "Es wurden nicht alle Rahmen gespeichert!" );
2709 
2710     rHTMLWrt.bTxtAttr = sal_False;
2711 
2712     if( bWriteBreak )
2713     {
2714         sal_Bool bEndOfCell = rHTMLWrt.bOutTable &&
2715                          rWrt.pCurPam->GetPoint()->nNode.GetIndex() ==
2716                          rWrt.pCurPam->GetMark()->nNode.GetIndex();
2717 
2718         if( bEndOfCell && !nEnde &&
2719             rHTMLWrt.IsHTMLMode(HTMLMODE_NBSP_IN_TABLES) )
2720         {
2721             // Wenn der letzte Absatz einer Tabellezelle leer ist und
2722             // wir fuer den MS-IE exportieren, schreiben wir statt eines
2723             // <BR> ein &nbsp;
2724             rWrt.Strm() << '&' << OOO_STRING_SVTOOLS_HTML_S_nbsp << ';';
2725         }
2726         else
2727         {
2728             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_linebreak );
2729             const SvxULSpaceItem& rULSpace =
2730                 (const SvxULSpaceItem &)pNd->GetSwAttrSet().Get(RES_UL_SPACE);
2731             if( rULSpace.GetLower() > 0 && !bEndOfCell &&
2732                 !rHTMLWrt.IsHTMLMode(HTMLMODE_NO_BR_AT_PAREND) )
2733                 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_linebreak );
2734             rHTMLWrt.bLFPossible = sal_True;
2735         }
2736     }
2737 
2738     if( rHTMLWrt.bClearLeft || rHTMLWrt.bClearRight )
2739     {
2740         const sal_Char *pStr;
2741         if( rHTMLWrt.bClearLeft )
2742         {
2743             if( rHTMLWrt.bClearRight )
2744                 pStr = OOO_STRING_SVTOOLS_HTML_AL_all;
2745             else
2746                 pStr = OOO_STRING_SVTOOLS_HTML_AL_left;
2747         }
2748         else
2749             pStr = OOO_STRING_SVTOOLS_HTML_AL_right;
2750 
2751         ByteString sOut( OOO_STRING_SVTOOLS_HTML_linebreak );
2752         (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_clear) += '=') += pStr;
2753 
2754         HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), sOut.GetBuffer() );
2755         rHTMLWrt.bClearLeft = sal_False;
2756         rHTMLWrt.bClearRight = sal_False;
2757 
2758         rHTMLWrt.bLFPossible = sal_True;
2759     }
2760 
2761     // wenn ein LF nicht schon erlaubt ist wird es erlaubt, wenn der
2762     // Absatz mit einem ' ' endet
2763     if( !rHTMLWrt.bLFPossible && !rHTMLWrt.nLastParaToken &&
2764         nEnde > 0 && ' ' == rStr.GetChar(nEnde-1) )
2765         rHTMLWrt.bLFPossible = sal_True;
2766 
2767     rHTMLWrt.bTagOn = sal_False;
2768     OutHTML_SwFmtOff( rWrt, aFmtInfo );
2769 
2770     // eventuell eine Form schliessen
2771     rHTMLWrt.OutForm( sal_False );
2772 
2773     if( bPageBreakBehind )
2774         rWrt.Strm() << '\f';
2775 
2776     return rHTMLWrt;
2777 }
2778 
2779 
ToPixel(sal_uInt32 nVal) const2780 sal_uInt32 SwHTMLWriter::ToPixel( sal_uInt32 nVal ) const
2781 {
2782     if( Application::GetDefaultDevice() && nVal )
2783     {
2784         nVal = Application::GetDefaultDevice()->LogicToPixel(
2785                     Size( nVal, nVal ), MapMode( MAP_TWIP ) ).Width();
2786         if( !nVal )     // wo ein Twip ist sollte auch ein Pixel sein
2787             nVal = 1;
2788     }
2789     return nVal;
2790 }
2791 
2792 
OutHTML_CSS1Attr(Writer & rWrt,const SfxPoolItem & rHt)2793 static Writer& OutHTML_CSS1Attr( Writer& rWrt, const SfxPoolItem& rHt )
2794 {
2795     // wenn gerade Hints geschrieben werden versuchen wir den Hint als
2796     // CSS1-Attribut zu schreiben
2797 
2798     if( ((SwHTMLWriter&)rWrt).bCfgOutStyles && ((SwHTMLWriter&)rWrt).bTxtAttr )
2799         OutCSS1_HintSpanTag( rWrt, rHt );
2800 
2801     return rWrt;
2802 }
2803 
2804 
2805 /* File CHRATR.HXX: */
2806 
OutHTML_SvxColor(Writer & rWrt,const SfxPoolItem & rHt)2807 static Writer& OutHTML_SvxColor( Writer& rWrt, const SfxPoolItem& rHt )
2808 {
2809     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
2810     if( rHTMLWrt.bOutOpts )
2811         return rWrt;
2812 
2813     // die Default-Farbe nur Schreiben, wenn sie als Hint vorkommt
2814     //if( rHTMLWrt.bTagOn && !rHTMLWrt.bTxtAttr && rHTMLWrt.pDfltColor
2815     //  && rColor == *rHTMLWrt.pDfltColor )
2816     //  return rWrt;
2817 
2818     if( !rHTMLWrt.bTxtAttr && rHTMLWrt.bCfgOutStyles && rHTMLWrt.bCfgPreferStyles )
2819     {
2820         // Font-Farbe nicht als Tag schreiben, wenn Styles normalen Tags
2821         // vorgezogen werden
2822         return rWrt;
2823     }
2824 
2825     if( rHTMLWrt.bTagOn )
2826     {
2827         Color aColor( ((const SvxColorItem&)rHt).GetValue() );
2828         if( COL_AUTO == aColor.GetColor() )
2829             aColor.SetColor( COL_BLACK );
2830 
2831         ByteString sOut( '<' );
2832         (((sOut += OOO_STRING_SVTOOLS_HTML_font) += ' ') += OOO_STRING_SVTOOLS_HTML_O_color) += '=';
2833         rWrt.Strm() << sOut.GetBuffer();
2834         HTMLOutFuncs::Out_Color( rWrt.Strm(), aColor, rHTMLWrt.eDestEnc ) << '>';
2835     }
2836     else
2837         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_font, sal_False );
2838 
2839     return rWrt;
2840 }
2841 
2842 
OutHTML_SwPosture(Writer & rWrt,const SfxPoolItem & rHt)2843 static Writer& OutHTML_SwPosture( Writer& rWrt, const SfxPoolItem& rHt )
2844 {
2845     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
2846     if( rHTMLWrt.bOutOpts )
2847         return rWrt;
2848 
2849     const FontItalic nPosture = ((const SvxPostureItem&)rHt).GetPosture();
2850     if( ITALIC_NORMAL == nPosture )
2851     {
2852         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_italic, rHTMLWrt.bTagOn );
2853     }
2854     else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
2855     {
2856         // vielleicht als CSS1-Attribut ?
2857         OutCSS1_HintSpanTag( rWrt, rHt );
2858     }
2859 
2860     return rWrt;
2861 }
2862 
OutHTML_SvxFont(Writer & rWrt,const SfxPoolItem & rHt)2863 static Writer& OutHTML_SvxFont( Writer& rWrt, const SfxPoolItem& rHt )
2864 {
2865     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
2866     if( rHTMLWrt.bOutOpts )
2867         return rWrt;
2868 
2869     if( rHTMLWrt.bTagOn )
2870     {
2871         String aNames;
2872         SwHTMLWriter::PrepareFontList( ((const SvxFontItem&)rHt), aNames, 0,
2873                            rHTMLWrt.IsHTMLMode(HTMLMODE_FONT_GENERIC) );
2874         ByteString sOut( '<' );
2875         (((sOut += OOO_STRING_SVTOOLS_HTML_font) += ' ') += OOO_STRING_SVTOOLS_HTML_O_face) += "=\"";
2876         rWrt.Strm() << sOut.GetBuffer();
2877         HTMLOutFuncs::Out_String( rWrt.Strm(), aNames, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters )
2878             << "\">";
2879     }
2880     else
2881         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_font , sal_False );
2882 
2883     return rWrt;
2884 }
2885 
OutHTML_SvxFontHeight(Writer & rWrt,const SfxPoolItem & rHt)2886 static Writer& OutHTML_SvxFontHeight( Writer& rWrt, const SfxPoolItem& rHt )
2887 {
2888     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
2889     if( rHTMLWrt.bOutOpts )
2890         return rWrt;
2891 
2892     if( rHTMLWrt.bTagOn )
2893     {
2894         ByteString sOut( '<' );
2895         sOut += OOO_STRING_SVTOOLS_HTML_font;
2896 
2897         sal_uInt32 nHeight = ((const SvxFontHeightItem&)rHt).GetHeight();
2898         sal_uInt16 nSize = rHTMLWrt.GetHTMLFontSize( nHeight );
2899         (((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_size) += '=')
2900             += ByteString::CreateFromInt32( nSize );
2901         rWrt.Strm() << sOut.GetBuffer();
2902 
2903         if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr &&
2904             rHTMLWrt.aFontHeights[nSize-1] != nHeight )
2905         {
2906             // wenn die Groesse keiner HTML-Groesse entspricht,
2907             // wird sie noch zusatzlich als Style-Option exportiert
2908             OutCSS1_HintStyleOpt( rWrt, rHt );
2909         }
2910         rWrt.Strm() << '>';
2911     }
2912     else
2913     {
2914         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_font, sal_False );
2915     }
2916 
2917     return rWrt;
2918 }
2919 
OutHTML_SvxLanguage(Writer & rWrt,const SfxPoolItem & rHt)2920 static Writer& OutHTML_SvxLanguage( Writer& rWrt, const SfxPoolItem& rHt )
2921 {
2922     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
2923     if( rHTMLWrt.bOutOpts )
2924         return rWrt;
2925 
2926     LanguageType eLang = ((const SvxLanguageItem &)rHt).GetLanguage();
2927     if( LANGUAGE_DONTKNOW == eLang )
2928         return rWrt;
2929 
2930     if( rHTMLWrt.bTagOn )
2931     {
2932         ByteString sOut( '<' );
2933         sOut += OOO_STRING_SVTOOLS_HTML_span;
2934         rWrt.Strm() << sOut.GetBuffer();
2935         rHTMLWrt.OutLanguage( ((const SvxLanguageItem &)rHt).GetLanguage() );
2936         rWrt.Strm() << '>';
2937     }
2938     else
2939     {
2940         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_span, sal_False );
2941     }
2942 
2943     return rWrt;
2944 }
OutHTML_SwWeight(Writer & rWrt,const SfxPoolItem & rHt)2945 static Writer& OutHTML_SwWeight( Writer& rWrt, const SfxPoolItem& rHt )
2946 {
2947     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
2948     if( rHTMLWrt.bOutOpts )
2949         return rWrt;
2950 
2951     const FontWeight nBold = ((const SvxWeightItem&)rHt).GetWeight();
2952     if( WEIGHT_BOLD == nBold )
2953     {
2954         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_bold, rHTMLWrt.bTagOn );
2955     }
2956     else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
2957     {
2958         // vielleicht als CSS1-Attribut ?
2959         OutCSS1_HintSpanTag( rWrt, rHt );
2960     }
2961 
2962     return rWrt;
2963 }
2964 
2965 
OutHTML_SwCrossedOut(Writer & rWrt,const SfxPoolItem & rHt)2966 static Writer& OutHTML_SwCrossedOut( Writer& rWrt, const SfxPoolItem& rHt )
2967 {
2968     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
2969     if( rHTMLWrt.bOutOpts )
2970         return rWrt;
2971 
2972     // Wegen Netscape schrieben wir hier STRIKE und nicht S raus!
2973     const FontStrikeout nStrike = ((const SvxCrossedOutItem&)rHt).GetStrikeout();
2974     if( STRIKEOUT_NONE != nStrike )
2975     {
2976         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_strike, rHTMLWrt.bTagOn );
2977     }
2978     else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
2979     {
2980         // vielleicht als CSS1-Attribut ?
2981         OutCSS1_HintSpanTag( rWrt, rHt );
2982     }
2983 
2984     return rWrt;
2985 }
2986 
2987 
OutHTML_SvxEscapement(Writer & rWrt,const SfxPoolItem & rHt)2988 static Writer& OutHTML_SvxEscapement( Writer& rWrt, const SfxPoolItem& rHt )
2989 {
2990     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
2991     if( rHTMLWrt.bOutOpts )
2992         return rWrt;
2993 
2994     const SvxEscapement eEscape =
2995         (const SvxEscapement)((const SvxEscapementItem&)rHt).GetEnumValue();
2996     const sal_Char *pStr = 0;
2997     switch( eEscape )
2998     {
2999     case SVX_ESCAPEMENT_SUPERSCRIPT: pStr = OOO_STRING_SVTOOLS_HTML_superscript; break;
3000     case SVX_ESCAPEMENT_SUBSCRIPT: pStr = OOO_STRING_SVTOOLS_HTML_subscript; break;
3001     default:
3002         ;
3003     }
3004 
3005     if( pStr )
3006     {
3007         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), pStr, rHTMLWrt.bTagOn );
3008     }
3009     else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
3010     {
3011         // vielleicht als CSS1-Attribut ?
3012         OutCSS1_HintSpanTag( rWrt, rHt );
3013     }
3014 
3015     return rWrt;
3016 }
3017 
3018 
3019 
OutHTML_SwUnderline(Writer & rWrt,const SfxPoolItem & rHt)3020 static Writer& OutHTML_SwUnderline( Writer& rWrt, const SfxPoolItem& rHt )
3021 {
3022     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
3023     if( rHTMLWrt.bOutOpts )
3024         return rWrt;
3025 
3026     const FontUnderline eUnder = ((const SvxUnderlineItem&)rHt).GetLineStyle();
3027     if( UNDERLINE_NONE != eUnder )
3028     {
3029         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_underline, rHTMLWrt.bTagOn );
3030     }
3031     else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
3032     {
3033         // vielleicht als CSS1-Attribut ?
3034         OutCSS1_HintSpanTag( rWrt, rHt );
3035     }
3036 
3037     return rWrt;
3038 }
3039 
3040 
OutHTML_SwFlyCnt(Writer & rWrt,const SfxPoolItem & rHt)3041 static Writer& OutHTML_SwFlyCnt( Writer& rWrt, const SfxPoolItem& rHt )
3042 {
3043     SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt;
3044     SwFmtFlyCnt& rFlyCnt = (SwFmtFlyCnt&)rHt;
3045 
3046     const SwFrmFmt& rFmt = *rFlyCnt.GetFrmFmt();
3047     const SdrObject *pSdrObj = 0;
3048 
3049     SwHTMLFrmType eType =
3050         (SwHTMLFrmType)rHTMLWrt.GuessFrmType( rFmt, pSdrObj );
3051     sal_uInt8 nMode = aHTMLOutFrmAsCharTable[eType][rHTMLWrt.nExportMode];
3052     rHTMLWrt.OutFrmFmt( nMode, rFmt, pSdrObj );
3053     return rWrt;
3054 }
3055 
3056 
3057 // Das ist jetzt unser Blink-Item. Blinkend wird eingeschaltet, indem man
3058 // das Item auf sal_True setzt!
OutHTML_SwBlink(Writer & rWrt,const SfxPoolItem & rHt)3059 static Writer& OutHTML_SwBlink( Writer& rWrt, const SfxPoolItem& rHt )
3060 {
3061     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
3062     if( rHTMLWrt.bOutOpts || !rHTMLWrt.IsHTMLMode(HTMLMODE_BLINK) )
3063         return rWrt;
3064 
3065     if( ((const SvxBlinkItem&)rHt).GetValue() )
3066     {
3067         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_blink, rHTMLWrt.bTagOn );
3068     }
3069     else if( rHTMLWrt.bCfgOutStyles && rHTMLWrt.bTxtAttr )
3070     {
3071         // vielleicht als CSS1-Attribut ?
3072         OutCSS1_HintSpanTag( rWrt, rHt );
3073     }
3074 
3075     return rWrt;
3076 }
3077 
OutHTML_INetFmt(Writer & rWrt,const SwFmtINetFmt & rINetFmt,sal_Bool bOn)3078 Writer& OutHTML_INetFmt( Writer& rWrt, const SwFmtINetFmt& rINetFmt, sal_Bool bOn )
3079 {
3080     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
3081 
3082     String aURL( rINetFmt.GetValue() );
3083     const SvxMacroTableDtor *pMacTable = rINetFmt.GetMacroTbl();
3084     sal_Bool bEvents = pMacTable != 0 && pMacTable->Count() > 0;
3085 
3086     // Gibt es ueberhaupt etwas auszugeben?
3087     if( !aURL.Len() && !bEvents && !rINetFmt.GetName().Len() )
3088         return rWrt;
3089 
3090     // Tag aus? Dann nur ein </A> ausgeben.
3091     if( !bOn )
3092     {
3093         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OOO_STRING_SVTOOLS_HTML_anchor, sal_False );
3094         return rWrt;
3095     }
3096 
3097     ByteString sOut( '<' );
3098     sOut += OOO_STRING_SVTOOLS_HTML_anchor;
3099 
3100     sal_Bool bScriptDependent = sal_False;
3101     {
3102         const SwCharFmt* pFmt = rWrt.pDoc->GetCharFmtFromPool(
3103                  RES_POOLCHR_INET_NORMAL );
3104         SwHTMLFmtInfo aFmtInfo( pFmt );
3105         sal_uInt16 nPos;
3106         if( rHTMLWrt.aChrFmtInfos.Seek_Entry( &aFmtInfo, &nPos ) )
3107         {
3108             bScriptDependent = rHTMLWrt.aChrFmtInfos[nPos]->bScriptDependent;
3109         }
3110     }
3111     if( !bScriptDependent )
3112     {
3113         const SwCharFmt* pFmt = rWrt.pDoc->GetCharFmtFromPool(
3114                  RES_POOLCHR_INET_VISIT );
3115         SwHTMLFmtInfo aFmtInfo( pFmt );
3116         sal_uInt16 nPos;
3117         if( rHTMLWrt.aChrFmtInfos.Seek_Entry( &aFmtInfo, &nPos ) )
3118         {
3119             bScriptDependent = rHTMLWrt.aChrFmtInfos[nPos]->bScriptDependent;
3120         }
3121     }
3122 
3123     if( bScriptDependent )
3124     {
3125         ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\"";
3126         switch( rHTMLWrt.nCSS1Script )
3127         {
3128         case CSS1_OUTMODE_WESTERN:
3129             sOut += "western";
3130             break;
3131         case CSS1_OUTMODE_CJK:
3132             sOut += "cjk";
3133             break;
3134         case CSS1_OUTMODE_CTL:
3135             sOut += "ctl";
3136             break;
3137         }
3138         sOut += '\"';
3139     }
3140 
3141     rWrt.Strm() << sOut.GetBuffer();
3142 
3143 #define REL_HACK
3144 #ifdef REL_HACK
3145     String sRel;
3146 #endif
3147 
3148     if( aURL.Len() || bEvents )
3149     {
3150 #ifdef REL_HACK
3151         String sTmp( aURL );
3152         sTmp.ToUpperAscii();
3153         xub_StrLen nPos = sTmp.SearchAscii( "\" REL=" );
3154         if( nPos!=STRING_NOTFOUND )
3155         {
3156             sRel = aURL.Copy( nPos+1 );
3157             aURL.Erase( nPos );
3158         }
3159 #endif
3160         aURL.EraseLeadingChars().EraseTrailingChars();
3161 
3162         ((sOut = ' ') += OOO_STRING_SVTOOLS_HTML_O_href) += "=\"";
3163         rWrt.Strm() << sOut.GetBuffer();
3164         rHTMLWrt.OutHyperlinkHRefValue( aURL );
3165         sOut = '\"';
3166     }
3167     else
3168         sOut.Erase();
3169 
3170     if( rINetFmt.GetName().Len() )
3171     {
3172         ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) += "=\"";
3173         rWrt.Strm() << sOut.GetBuffer();
3174         HTMLOutFuncs::Out_String( rWrt.Strm(), rINetFmt.GetName(),
3175                                   rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
3176         sOut = '\"';
3177     }
3178 
3179     const String& rTarget = rINetFmt.GetTargetFrame();
3180     if( rTarget.Len() )
3181     {
3182         ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_target) += "=\"";
3183         rWrt.Strm() << sOut.GetBuffer();
3184         HTMLOutFuncs::Out_String( rWrt.Strm(), rTarget, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
3185         sOut = '\"';
3186     }
3187 
3188 #ifdef REL_HACK
3189     if( sRel.Len() )
3190         sOut += ByteString( sRel, RTL_TEXTENCODING_ASCII_US );
3191 #endif
3192     if( sOut.Len() )
3193         rWrt.Strm() << sOut.GetBuffer();
3194 
3195     if( bEvents )
3196         HTMLOutFuncs::Out_Events( rWrt.Strm(), *pMacTable, aAnchorEventTable,
3197                                   rHTMLWrt.bCfgStarBasic, rHTMLWrt.eDestEnc,
3198                                   &rHTMLWrt.aNonConvertableCharacters   );
3199     rWrt.Strm() << ">";
3200 
3201     return rWrt;
3202 }
3203 
OutHTML_SwFmtINetFmt(Writer & rWrt,const SfxPoolItem & rHt)3204 static Writer& OutHTML_SwFmtINetFmt( Writer& rWrt, const SfxPoolItem& rHt )
3205 {
3206     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
3207 
3208     if( rHTMLWrt.bOutOpts )
3209         return rWrt;
3210 
3211     const SwFmtINetFmt& rINetFmt = (const SwFmtINetFmt&)rHt;
3212 
3213     if( rHTMLWrt.bTagOn )
3214     {
3215         // ggf. ein noch offenes Attribut voruebergehend beenden
3216         if( rHTMLWrt.aINetFmts.Count() )
3217         {
3218             SwFmtINetFmt *pINetFmt =
3219                 rHTMLWrt.aINetFmts[ rHTMLWrt.aINetFmts.Count()-1 ];
3220             OutHTML_INetFmt( rWrt, *pINetFmt, sal_False );
3221         }
3222 
3223         // jetzt das neue aufmachen
3224         OutHTML_INetFmt( rWrt, rINetFmt, sal_True );
3225 
3226         // und merken
3227         const SwFmtINetFmt *pINetFmt = new SwFmtINetFmt( rINetFmt );
3228         rHTMLWrt.aINetFmts.C40_INSERT( SwFmtINetFmt, pINetFmt,
3229                                        rHTMLWrt.aINetFmts.Count() );
3230     }
3231     else
3232     {
3233         // das
3234         OutHTML_INetFmt( rWrt, rINetFmt, sal_False );
3235 
3236         ASSERT( rHTMLWrt.aINetFmts.Count(), "da fehlt doch ein URL-Attribut" );
3237         if( rHTMLWrt.aINetFmts.Count() )
3238         {
3239             // das eigene Attribut vom Stack holen
3240             SwFmtINetFmt *pINetFmt =
3241                 rHTMLWrt.aINetFmts[ rHTMLWrt.aINetFmts.Count()-1 ];
3242 
3243             rHTMLWrt.aINetFmts.Remove( rHTMLWrt.aINetFmts.Count()-1, 1 );
3244             delete pINetFmt;
3245         }
3246 
3247         if( rHTMLWrt.aINetFmts.Count() )
3248         {
3249             // es ist noch ein Attribut auf dem Stack, das wieder geoeffnet
3250             // werden muss
3251             SwFmtINetFmt *pINetFmt =
3252                 rHTMLWrt.aINetFmts[ rHTMLWrt.aINetFmts.Count()-1 ];
3253             OutHTML_INetFmt( rWrt, *pINetFmt, sal_True );
3254         }
3255     }
3256 
3257     return rWrt;
3258 }
3259 
OutHTML_SwTxtCharFmt(Writer & rWrt,const SfxPoolItem & rHt)3260 static Writer& OutHTML_SwTxtCharFmt( Writer& rWrt, const SfxPoolItem& rHt )
3261 {
3262     SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
3263     if( rHTMLWrt.bOutOpts )
3264         return rWrt;
3265 
3266     const SwFmtCharFmt& rChrFmt = (const SwFmtCharFmt&)rHt;
3267     const SwCharFmt* pFmt = rChrFmt.GetCharFmt();
3268 
3269     if( !pFmt )
3270     {
3271         return rWrt;
3272     }
3273 
3274     SwHTMLFmtInfo aFmtInfo( pFmt );
3275     sal_uInt16 nPos;
3276     if( !rHTMLWrt.aChrFmtInfos.Seek_Entry( &aFmtInfo, &nPos ) )
3277         return rWrt;
3278 
3279     const SwHTMLFmtInfo *pFmtInfo = rHTMLWrt.aChrFmtInfos[nPos];
3280     ASSERT( pFmtInfo, "Wieso gint es keine Infos ueber die Zeichenvorlage?" );
3281 
3282     if( rHTMLWrt.bTagOn )
3283     {
3284         ByteString sOut( '<' );
3285         if( pFmtInfo->aToken.Len() > 0 )
3286             sOut += pFmtInfo->aToken;
3287         else
3288             sOut += OOO_STRING_SVTOOLS_HTML_span;
3289         if( rHTMLWrt.bCfgOutStyles &&
3290             (pFmtInfo->aClass.Len() || pFmtInfo->bScriptDependent) )
3291         {
3292             ((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_class) += "=\"";
3293             rWrt.Strm() << sOut.GetBuffer();
3294             String aClass( pFmtInfo->aClass );
3295             if( pFmtInfo->bScriptDependent )
3296             {
3297                 if( aClass.Len() )
3298                    aClass += '-';
3299                 switch( rHTMLWrt.nCSS1Script )
3300                 {
3301                 case CSS1_OUTMODE_WESTERN:
3302                     aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("western") );
3303                     break;
3304                 case CSS1_OUTMODE_CJK:
3305                     aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("cjk") );
3306                     break;
3307                 case CSS1_OUTMODE_CTL:
3308                     aClass.AppendAscii( RTL_CONSTASCII_STRINGPARAM("ctl") );
3309                     break;
3310                 }
3311             }
3312             HTMLOutFuncs::Out_String( rWrt.Strm(), aClass,
3313                                       rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
3314             sOut = '\"';
3315         }
3316         sOut += '>';
3317         rWrt.Strm() << sOut.GetBuffer();
3318     }
3319     else
3320     {
3321         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(),
3322                 pFmtInfo->aToken.Len() ? pFmtInfo->aToken.GetBuffer()
3323                                        : OOO_STRING_SVTOOLS_HTML_span,
3324                 sal_False );
3325     }
3326 
3327     return rWrt;
3328 }
3329 
OutHTML_SvxAdjust(Writer & rWrt,const SfxPoolItem & rHt)3330 static Writer& OutHTML_SvxAdjust( Writer& rWrt, const SfxPoolItem& rHt )
3331 {
3332     SwHTMLWriter & rHTMLWrt = (SwHTMLWriter&)rWrt;
3333     if( !rHTMLWrt.bOutOpts || !rHTMLWrt.bTagOn )
3334         return  rWrt;
3335 
3336     SvxAdjustItem& rAdjust = (SvxAdjustItem&)rHt;
3337     const sal_Char* pStr = 0;
3338     switch( rAdjust.GetAdjust() )
3339     {
3340     case SVX_ADJUST_CENTER: pStr = OOO_STRING_SVTOOLS_HTML_AL_center; break;
3341     case SVX_ADJUST_LEFT: pStr = OOO_STRING_SVTOOLS_HTML_AL_left; break;
3342     case SVX_ADJUST_RIGHT: pStr = OOO_STRING_SVTOOLS_HTML_AL_right; break;
3343     case SVX_ADJUST_BLOCK: pStr = OOO_STRING_SVTOOLS_HTML_AL_justify; break;
3344     default:
3345         ;
3346     }
3347     if( pStr )
3348     {
3349         ByteString sOut( ' ' );
3350         ((sOut += OOO_STRING_SVTOOLS_HTML_O_align) += '=') += pStr;
3351         rWrt.Strm() << sOut.GetBuffer();
3352     }
3353 
3354     return rWrt;
3355 }
3356 
3357 /*
3358  * lege hier die Tabellen fuer die HTML-Funktions-Pointer auf
3359  * die Ausgabe-Funktionen an.
3360  * Es sind lokale Strukturen, die nur innerhalb der HTML-DLL
3361  * bekannt sein muessen.
3362  */
3363 
3364 
3365 SwAttrFnTab aHTMLAttrFnTab = {
3366 /* RES_CHRATR_CASEMAP   */          OutHTML_CSS1Attr,
3367 /* RES_CHRATR_CHARSETCOLOR  */      0,
3368 /* RES_CHRATR_COLOR */              OutHTML_SvxColor,
3369 /* RES_CHRATR_CONTOUR   */          0,
3370 /* RES_CHRATR_CROSSEDOUT    */      OutHTML_SwCrossedOut,
3371 /* RES_CHRATR_ESCAPEMENT    */      OutHTML_SvxEscapement,
3372 /* RES_CHRATR_FONT  */              OutHTML_SvxFont,
3373 /* RES_CHRATR_FONTSIZE  */          OutHTML_SvxFontHeight,
3374 /* RES_CHRATR_KERNING   */          OutHTML_CSS1Attr,
3375 /* RES_CHRATR_LANGUAGE  */          OutHTML_SvxLanguage,
3376 /* RES_CHRATR_POSTURE   */          OutHTML_SwPosture,
3377 /* RES_CHRATR_PROPORTIONALFONTSIZE*/0,
3378 /* RES_CHRATR_SHADOWED  */          0,
3379 /* RES_CHRATR_UNDERLINE */          OutHTML_SwUnderline,
3380 /* RES_CHRATR_WEIGHT    */          OutHTML_SwWeight,
3381 /* RES_CHRATR_WORDLINEMODE  */      0,
3382 /* RES_CHRATR_AUTOKERN  */          0,
3383 /* RES_CHRATR_BLINK */              OutHTML_SwBlink,
3384 /* RES_CHRATR_NOHYPHEN  */          0, // Neu: nicht trennen
3385 /* RES_CHRATR_NOLINEBREAK */        0, // Neu: nicht umbrechen
3386 /* RES_CHRATR_BACKGROUND */         OutHTML_CSS1Attr, // Neu: Zeichenhintergrund
3387 /* RES_CHRATR_CJK_FONT */           OutHTML_SvxFont,
3388 /* RES_CHRATR_CJK_FONTSIZE */       OutHTML_SvxFontHeight,
3389 /* RES_CHRATR_CJK_LANGUAGE */       OutHTML_SvxLanguage,
3390 /* RES_CHRATR_CJK_POSTURE */        OutHTML_SwPosture,
3391 /* RES_CHRATR_CJK_WEIGHT */         OutHTML_SwWeight,
3392 /* RES_CHRATR_CTL_FONT */           OutHTML_SvxFont,
3393 /* RES_CHRATR_CTL_FONTSIZE */       OutHTML_SvxFontHeight,
3394 /* RES_CHRATR_CTL_LANGUAGE */       OutHTML_SvxLanguage,
3395 /* RES_CHRATR_CTL_POSTURE */        OutHTML_SwPosture,
3396 /* RES_CHRATR_CTL_WEIGHT */         OutHTML_SwWeight,
3397 /* RES_CHRATR_ROTATE */             0,
3398 /* RES_CHRATR_EMPHASIS_MARK */      0,
3399 /* RES_CHRATR_TWO_LINES */          0,
3400 /* RES_CHRATR_SCALEW */             0,
3401 /* RES_CHRATR_RELIEF */             0,
3402 /* RES_CHRATR_HIDDEN */             0,
3403 /* RES_CHRATR_OVERLINE */           OutHTML_CSS1Attr,
3404 /* RES_CHRATR_DUMMY1 */             0,
3405 /* RES_CHRATR_DUMMY2 */             0,
3406 //For i120935, Insert blank entry for RES_CHRATR_BIDITRL and RES_CHRATR_IDCTHINT, for keep the identical res order
3407 /*RES_CHRATR_BIDIRTL*/          0,
3408 /*RES_CHRATR_IDCTHINT*/     0,
3409 /* RES_TXTATR_REFMARK */            0,
3410 /* RES_TXTATR_TOXMARK */            0,
3411 /* RES_TXTATR_META */               0,
3412 /* RES_TXTATR_METAFIELD */          0,
3413 /* RES_TXTATR_AUTOFMT */            0,
3414 /* RES_TXTATR_INETFMT */            OutHTML_SwFmtINetFmt,
3415 /* RES_TXTATR_CHARFMT */            OutHTML_SwTxtCharFmt,
3416 /* RES_TXTATR_CJK_RUBY */           0,
3417 /* RES_TXTATR_UNKNOWN_CONTAINER */  0,
3418 /* RES_TXTATR_INPUTFIELD */         OutHTML_SwFmtFld,
3419 
3420 /* RES_TXTATR_FIELD */              OutHTML_SwFmtFld,
3421 /* RES_TXTATR_FLYCNT */             OutHTML_SwFlyCnt,
3422 /* RES_TXTATR_FTN */                OutHTML_SwFmtFtn,
3423 /* RES_TXTATR_ANNOTATION */         OutHTML_SwFmtFld,
3424 /* RES_TXTATR_DUMMY3 */             0,
3425 /* RES_TXTATR_DUMMY1 */             0, // Dummy:
3426 /* RES_TXTATR_DUMMY2 */             0, // Dummy:
3427 
3428 /* RES_PARATR_LINESPACING   */      0,
3429 /* RES_PARATR_ADJUST    */          OutHTML_SvxAdjust,
3430 /* RES_PARATR_SPLIT */              0,
3431 /* RES_PARATR_WIDOWS    */          0,
3432 /* RES_PARATR_ORPHANS   */          0,
3433 /* RES_PARATR_TABSTOP   */          0,
3434 /* RES_PARATR_HYPHENZONE*/          0,
3435 /* RES_PARATR_DROP */               OutHTML_CSS1Attr,
3436 /* RES_PARATR_REGISTER */           0, // neu:  Registerhaltigkeit
3437 /* RES_PARATR_NUMRULE */            0, // Dummy:
3438 /* RES_PARATR_SCRIPTSPACE */        0, // Dummy:
3439 /* RES_PARATR_HANGINGPUNCTUATION */ 0, // Dummy:
3440 /* RES_PARATR_FORBIDDEN_RULES */    0, // new
3441 /* RES_PARATR_VERTALIGN */          0, // new
3442 /* RES_PARATR_SNAPTOGRID*/          0, // new
3443 /* RES_PARATR_CONNECT_TO_BORDER */  0, // new
3444 
3445 /* RES_PARATR_LIST_ID */            0, // new
3446 /* RES_PARATR_LIST_LEVEL */         0, // new
3447 /* RES_PARATR_LIST_ISRESTART */     0, // new
3448 /* RES_PARATR_LIST_RESTARTVALUE */  0, // new
3449 /* RES_PARATR_LIST_ISCOUNTED */     0, // new
3450 
3451 /* RES_FILL_ORDER   */              0,
3452 /* RES_FRM_SIZE */                  0,
3453 /* RES_PAPER_BIN    */              0,
3454 /* RES_LR_SPACE */                  0,
3455 /* RES_UL_SPACE */                  0,
3456 /* RES_PAGEDESC */                  0,
3457 /* RES_BREAK */                     0,
3458 /* RES_CNTNT */                     0,
3459 /* RES_HEADER */                    0,
3460 /* RES_FOOTER */                    0,
3461 /* RES_PRINT */                     0,
3462 /* RES_OPAQUE */                    0,
3463 /* RES_PROTECT */                   0,
3464 /* RES_SURROUND */                  0,
3465 /* RES_VERT_ORIENT */               0,
3466 /* RES_HORI_ORIENT */               0,
3467 /* RES_ANCHOR */                    0,
3468 /* RES_BACKGROUND */                0,
3469 /* RES_BOX  */                      0,
3470 /* RES_SHADOW */                    0,
3471 /* RES_FRMMACRO */                  0,
3472 /* RES_COL */                       0,
3473 /* RES_KEEP */                      0,
3474 /* RES_URL */                       0,
3475 /* RES_EDIT_IN_READONLY */          0,
3476 /* RES_LAYOUT_SPLIT */              0,
3477 /* RES_FRMATR_DUMMY1 */             0, // Dummy:
3478 /* RES_FRMATR_DUMMY2 */             0, // Dummy:
3479 /* RES_AUTO_STYLE */                0, // Dummy:
3480 /* RES_FRMATR_DUMMY4 */             0, // Dummy:
3481 /* RES_FRMATR_DUMMY5 */             0, // Dummy:
3482 /* RES_FRMATR_DUMMY6 */             0, // Dummy:
3483 /* RES_FRMATR_DUMMY7 */             0, // Dummy:
3484 /* RES_FRMATR_DUMMY8 */             0, // Dummy:
3485 /* RES_FRMATR_DUMMY9 */             0, // Dummy:
3486 /* RES_FOLLOW_TEXT_FLOW */          0,
3487 /* RES_WRAP_INFLUENCE_ON_OBJPOS */  0,
3488 /* RES_FRMATR_DUMMY2 */             0, // Dummy:
3489 /* RES_AUTO_STYLE */                0, // Dummy:
3490 /* RES_FRMATR_DUMMY4 */             0, // Dummy:
3491 /* RES_FRMATR_DUMMY5 */             0, // Dummy:
3492 
3493 /* RES_GRFATR_MIRRORGRF */          0,
3494 /* RES_GRFATR_CROPGRF   */          0,
3495 /* RES_GRFATR_ROTATION */           0,
3496 /* RES_GRFATR_LUMINANCE */          0,
3497 /* RES_GRFATR_CONTRAST */           0,
3498 /* RES_GRFATR_CHANNELR */           0,
3499 /* RES_GRFATR_CHANNELG */           0,
3500 /* RES_GRFATR_CHANNELB */           0,
3501 /* RES_GRFATR_GAMMA */              0,
3502 /* RES_GRFATR_INVERT */             0,
3503 /* RES_GRFATR_TRANSPARENCY */       0,
3504 /* RES_GRFATR_DRWAMODE */           0,
3505 /* RES_GRFATR_DUMMY1 */             0,
3506 /* RES_GRFATR_DUMMY2 */             0,
3507 /* RES_GRFATR_DUMMY3 */             0,
3508 /* RES_GRFATR_DUMMY4 */             0,
3509 /* RES_GRFATR_DUMMY5 */             0,
3510 
3511 /* RES_BOXATR_FORMAT */             0,
3512 /* RES_BOXATR_FORMULA */            0,
3513 /* RES_BOXATR_VALUE */              0
3514 };
3515