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
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