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