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