xref: /aoo41x/main/sw/source/filter/html/wrthtml.cxx (revision efeef26f)
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 <stdlib.h>
29 #include <hintids.hxx>
30 #include <svl/urihelper.hxx>
31 #include <rtl/tencinfo.h>
32 #include <vcl/wrkwin.hxx>
33 #include <sfx2/linkmgr.hxx>
34 
35 #include <svtools/htmlcfg.hxx>
36 #include <vcl/svapp.hxx>
37 #include <i18npool/mslangid.hxx>
38 #include <sfx2/frmhtmlw.hxx>
39 #include <svx/xoutbmp.hxx>
40 #include <svx/htmlmode.hxx>
41 #include <editeng/lrspitem.hxx>
42 #include <editeng/colritem.hxx>
43 #include <editeng/brshitem.hxx>
44 #include <editeng/fontitem.hxx>
45 #include <editeng/scripttypeitem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <svl/stritem.hxx>
48 #include <editeng/frmdiritem.hxx>
49 
50 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
51 #include <com/sun/star/document/XDocumentProperties.hpp>
52 #include <com/sun/star/form/XFormsSupplier.hpp>
53 #include <com/sun/star/form/XForm.hpp>
54 #include <com/sun/star/form/XImageProducerSupplier.hpp>
55 #include <com/sun/star/form/XFormController.hpp>
56 #include <com/sun/star/container/XContainer.hpp>
57 #include <com/sun/star/container/XIndexContainer.hpp>
58 #include <com/sun/star/container/XSet.hpp>
59 #include <fmthdft.hxx>
60 #include <fmtfld.hxx>
61 #include <fmtpdsc.hxx>
62 #include <txatbase.hxx>
63 #include <frmatr.hxx>
64 #include <charfmt.hxx>
65 #include <docary.hxx>
66 #include <pam.hxx>
67 #include <doc.hxx>
68 #include <ndtxt.hxx>
69 #include <mdiexp.hxx>		// ...Percent()
70 #include <fltini.hxx>
71 #include <viewopt.hxx>
72 #include <IMark.hxx>		// fuer SwBookmark ...
73 #include <poolfmt.hxx>
74 #include <pagedesc.hxx>
75 #include <section.hxx>
76 #include <swtable.hxx>
77 #include <fldbas.hxx>
78 #include <fmtclds.hxx>
79 #ifndef _DOCSH_HXX
80 #include <docsh.hxx>
81 #endif
82 #include <wrthtml.hxx>
83 #include <htmlnum.hxx>
84 #include <htmlfly.hxx>
85 #include <swmodule.hxx>
86 
87 #ifndef _STATSTR_HRC
88 #include <statstr.hrc>		// ResId fuer Statusleiste
89 #endif
90 #include <swerror.h>
91 
92 #define MAX_INDENT_LEVEL 20
93 
94 #if defined(UNX)
95 const sal_Char SwHTMLWriter::sNewLine = '\012';
96 #else
97 const sal_Char __FAR_DATA SwHTMLWriter::sNewLine[] = "\015\012";
98 #endif
99 
100 static sal_Char __FAR_DATA sIndentTabs[MAX_INDENT_LEVEL+2] =
101 	"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
102 
103 SwHTMLWriter::SwHTMLWriter( const String& rBaseURL )
104 {
105     SetBaseURL( rBaseURL );
106 	bFirstLine = sal_True;
107 	nBkmkTabPos = -1;
108 	pDfltColor = 0;
109 	nImgMapCnt = 1;
110 	pStartNdIdx = 0;
111 	pTemplate = 0;
112 	pNumRuleInfo = new SwHTMLNumRuleInfo;
113 	pNextNumRuleInfo = 0;
114 	pFootEndNotes = 0;
115 	pFmtFtn = 0;
116 	eDestEnc = RTL_TEXTENCODING_MS_1252;
117 	nDirection = FRMDIR_HORI_LEFT_TOP;
118 }
119 
120 
121 __EXPORT SwHTMLWriter::~SwHTMLWriter()
122 {
123 	delete pNumRuleInfo;
124 }
125 
126 sal_uLong SwHTMLWriter::WriteStream()
127 {
128 	// neue Konfiguration setzen
129 	SvxHtmlOptions* pHtmlOptions = SvxHtmlOptions::Get();
130 
131 	// die Fontgroessen 1-7
132 	aFontHeights[0] = pHtmlOptions->GetFontSize( 0 ) * 20;
133 	aFontHeights[1] = pHtmlOptions->GetFontSize( 1 ) * 20;
134 	aFontHeights[2] = pHtmlOptions->GetFontSize( 2 ) * 20;
135 	aFontHeights[3] = pHtmlOptions->GetFontSize( 3 ) * 20;
136 	aFontHeights[4] = pHtmlOptions->GetFontSize( 4 ) * 20;
137 	aFontHeights[5] = pHtmlOptions->GetFontSize( 5 ) * 20;
138 	aFontHeights[6] = pHtmlOptions->GetFontSize( 6 ) * 20;
139 
140 	// ueberhaupt Styles ausgeben
141 	// (dann auch obere und untere Absatz-Abstaende)
142 	nExportMode = pHtmlOptions->GetExportMode();
143 	nHTMLMode = GetHtmlMode(0);
144     if( HTML_CFG_WRITER==nExportMode ||
145 		HTML_CFG_NS40==nExportMode )
146 		nHTMLMode |= HTMLMODE_BLOCK_SPACER;
147 
148 	if( HTML_CFG_WRITER==nExportMode || HTML_CFG_MSIE==nExportMode )
149 		nHTMLMode |= (HTMLMODE_FLOAT_FRAME | HTMLMODE_LSPACE_IN_NUMBUL);
150 
151 	if( HTML_CFG_MSIE==nExportMode )
152 		nHTMLMode |= HTMLMODE_NBSP_IN_TABLES;
153 
154 	if( HTML_CFG_WRITER==nExportMode || HTML_CFG_NS40==nExportMode ||
155 		HTML_CFG_MSIE==nExportMode )
156 		nHTMLMode |= HTMLMODE_ABS_POS_FLY|HTMLMODE_ABS_POS_DRAW;
157 
158 	if( HTML_CFG_WRITER==nExportMode )
159 //		nHTMLMode |= HTMLMODE_FLY_MARGINS | HTMLMODE_FRSTLINE_IN_NUMBUL;
160 		nHTMLMode |= HTMLMODE_FLY_MARGINS;
161 
162 	if( HTML_CFG_NS40==nExportMode )
163 		nHTMLMode |= HTMLMODE_BORDER_NONE;
164 
165 	if( HTML_CFG_HTML32!=nExportMode )
166 		nHTMLMode |= HTMLMODE_FONT_GENERIC;
167 
168     if( HTML_CFG_NS40==nExportMode )
169 		nHTMLMode |= HTMLMODE_NO_CONTROL_CENTERING;
170 
171 	bCfgOutStyles = IsHTMLMode(HTMLMODE_SOME_STYLES |
172 							   HTMLMODE_FULL_STYLES);
173 	bCfgNetscape4 = (HTML_CFG_NS40==nExportMode);
174 
175 	if( IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES) )
176 		nHTMLMode |= HTMLMODE_PRINT_EXT;
177 
178 	const sal_Char *pHelpHack = getenv( "HelpEx" );
179 	if( pHelpHack )
180 	{
181 		ByteString aTmp( pHelpHack );
182 		if( aTmp.EqualsIgnoreCaseAscii( "Hilfe" ) )
183 			nHTMLMode |= HTMLMODE_NO_BR_AT_PAREND;
184 	}
185 
186 	eCSS1Unit = (FieldUnit)SW_MOD()->GetMetric( pDoc->get(IDocumentSettingAccess::HTML_MODE) );
187 
188 	sal_Bool bWriteUTF8 = bWriteClipboardDoc;
189 	eDestEnc = bWriteUTF8 ? RTL_TEXTENCODING_UTF8
190 						  : pHtmlOptions->GetTextEncoding();
191 	const sal_Char *pCharSet =
192 		rtl_getBestMimeCharsetFromTextEncoding( eDestEnc );
193 	eDestEnc = rtl_getTextEncodingFromMimeCharset( pCharSet );
194 
195 	// fuer Netscape optimieren heisst Spacer- und Multicol ausgeben
196 //	bCfgMultiCol = pHtmlOptions->IsNetscape3();
197 //	bCfgSpacer = pHtmlOptions->IsNetscape3();
198 
199 	// wenn Styles exportiert werden, wird ein Style einem HTML-Tag manchmal
200 	// vorgezogen, wenn nicht fuer Netscape exportiert wird
201 	// bCfgPreferStyles = bCfgOutStyles; // && !pHtmlOptions->IsNetscape3();
202 
203 	// Nur noch fuer den MS-IE ziehen wir den Export von Styles vor.
204 	bCfgPreferStyles = HTML_CFG_MSIE==nExportMode;
205 
206 	bCfgStarBasic = pHtmlOptions->IsStarBasic();
207 
208 	bCfgFormFeed = !IsHTMLMode(HTMLMODE_PRINT_EXT);
209 	bCfgCpyLinkedGrfs = pHtmlOptions->IsSaveGraphicsLocal();
210 
211 	// die HTML-Vorlage holen
212 	sal_Bool bOldHTMLMode = sal_False;
213 	sal_uInt16 nOldTxtFmtCollCnt = 0, nOldCharFmtCnt = 0;
214 
215 	ASSERT( !pTemplate, "Wo kommt denn die HTML-Vorlage hier her?" );
216 	pTemplate = ((HTMLReader*)ReadHTML)->GetTemplateDoc();
217 	if( pTemplate )
218 	{
219 		pTemplate->acquire();
220 		bOldHTMLMode = pTemplate->get(IDocumentSettingAccess::HTML_MODE);
221 		pTemplate->set(IDocumentSettingAccess::HTML_MODE, true);
222 
223 		nOldTxtFmtCollCnt = pTemplate->GetTxtFmtColls()->Count();
224 		nOldCharFmtCnt = pTemplate->GetCharFmts()->Count();
225 	}
226 
227 	if( bShowProgress )
228 		::StartProgress( STR_STATSTR_W4WWRITE, 0, pDoc->GetNodes().Count(),
229 						 pDoc->GetDocShell());
230 
231 	pDfltColor = 0;
232 	pFootEndNotes = 0;
233 	pFmtFtn = 0;
234 	bOutTable = bOutHeader = bOutFooter = bOutFlyFrame = sal_False;
235 	pxFormComps = 0;
236 	nFormCntrlCnt = 0;
237 	bPreserveForm = sal_False;
238 	bClearLeft = bClearRight = sal_False;
239 	bLFPossible = sal_False;
240 
241 	nLeftMargin = nDfltLeftMargin = nDfltRightMargin = 0;
242 	nDfltTopMargin = nDfltBottomMargin = 0;
243 	nFirstLineIndent = nDfltFirstLineIndent = 0;
244 	bPoolCollTextModified = sal_False;
245 	bFirstCSS1Property = bFirstCSS1Rule = sal_False;
246 	bCSS1IgnoreFirstPageDesc = sal_False;
247 	nIndentLvl = 0;
248 	nWhishLineLen = 70;
249 	nLastLFPos = 0;
250 	nDefListLvl = 0;
251 	nDefListMargin = ((pTemplate && !bCfgOutStyles) ? pTemplate : pDoc)
252         ->GetTxtCollFromPool( RES_POOLCOLL_HTML_DD, false )
253 		->GetLRSpace().GetTxtLeft();
254 	nHeaderFooterSpace = 0;
255 	nTxtAttrsToIgnore = 0;
256 	nCSS1OutMode = 0;
257 	sal_uInt16 nScript = SvtLanguageOptions::GetScriptTypeOfLanguage(
258 			static_cast< LanguageType >( GetAppLanguage() ) );
259 	switch( nScript )
260 	{
261 	case SCRIPTTYPE_ASIAN:
262 		nCSS1Script = CSS1_OUTMODE_CJK;
263 		break;
264 	case SCRIPTTYPE_COMPLEX:
265 		nCSS1Script = CSS1_OUTMODE_CTL;
266 		break;
267 	default:
268 		nCSS1Script = CSS1_OUTMODE_WESTERN;
269 		break;
270 	}
271 	eLang = ((const SvxLanguageItem&)pDoc
272 			->GetDefault(GetLangWhichIdFromScript(nCSS1Script))).GetLanguage();
273 
274 	nFootNote = nEndNote = 0;
275 
276 	nWarn = 0;
277 	GetNumInfo().Clear();
278 	pNextNumRuleInfo = 0;
279 
280 	ByteString aStartTags;
281 
282 	// Tabellen und Bereiche am Doc.-Anfang beachten
283 	{
284 		SwTableNode * pTNd = pCurPam->GetNode()->FindTableNode();
285 		if( pTNd && bWriteAll )
286 		{
287 			// mit dem Tabellen-Node anfangen !!
288 			pCurPam->GetPoint()->nNode = *pTNd;
289 
290 			if( bWriteOnlyFirstTable )
291 				pCurPam->GetMark()->nNode = *pTNd->EndOfSectionNode();
292 		}
293 
294 		// erster Node (der einen Seitenumbruch enthalten darf)
295 		pStartNdIdx = new SwNodeIndex( pCurPam->GetPoint()->nNode );
296 
297 		SwSectionNode * pSNd = pCurPam->GetNode()->FindSectionNode();
298 		while( pSNd )
299 		{
300 			if( bWriteAll )
301 			{
302 				// mit dem Section-Node anfangen !!
303 				pCurPam->GetPoint()->nNode = *pSNd;
304 			}
305 			else
306 			{
307 				ASSERT( FILE_LINK_SECTION != pSNd->GetSection().GetType(),
308 						"Export gelinkter Bereiche am Dok-Anfang ist nicht implemntiert" );
309 
310 				// nur das Tag fuer die Section merken
311 				ByteString aName;
312                 HTMLOutFuncs::ConvertStringToHTML(
313                     pSNd->GetSection().GetSectionName(),
314 												   aName, eDestEnc, &aNonConvertableCharacters );
315 
316 				ByteString sOut( '<' );
317 				(((((((sOut += OOO_STRING_SVTOOLS_HTML_division)
318 					+= ' ') += OOO_STRING_SVTOOLS_HTML_O_id) += "=\"")
319 				    += aName) += '\"')
320 					+= '>')	+= aStartTags;
321 
322 				aStartTags = sOut;
323 			}
324 			// FindSectionNode() an einem SectionNode liefert den selben!
325             pSNd = pSNd->StartOfSectionNode()->FindSectionNode();
326 		}
327 	}
328 
329 
330 	// Tabelle fuer die freifliegenden Rahmen erzeugen, aber nur wenn
331 	// das gesamte Dokument geschrieben wird
332 	pHTMLPosFlyFrms = 0;
333 	CollectFlyFrms();
334 	nLastParaToken = 0;
335 	GetControls();
336 	CollectLinkTargets();
337 
338 	sal_uInt16 nHeaderAttrs = 0;
339 	pCurrPageDesc = MakeHeader( nHeaderAttrs );
340 
341 	bLFPossible = sal_True;
342 
343 	// Formulare, die nur HiddenControls enthalten ausgeben.
344 	OutHiddenForms();
345 
346 	if( aStartTags.Len() )
347 		Strm() << aStartTags.GetBuffer();
348 
349 	const SfxPoolItem *pItem;
350 	const SfxItemSet& rPageItemSet = pCurrPageDesc->GetMaster().GetAttrSet();
351 	if( !bWriteClipboardDoc && pDoc->GetDocShell() &&
352          (!pDoc->get(IDocumentSettingAccess::HTML_MODE) &&
353           !pDoc->get(IDocumentSettingAccess::BROWSE_MODE)) &&
354 		SFX_ITEM_SET == rPageItemSet.GetItemState( RES_HEADER, sal_True, &pItem) )
355 	{
356 		const SwFrmFmt *pHeaderFmt =
357 			((const SwFmtHeader *)pItem)->GetHeaderFmt();
358 		if( pHeaderFmt )
359 			OutHTML_HeaderFooter( *this, *pHeaderFmt, sal_True );
360 	}
361 
362 	nTxtAttrsToIgnore = nHeaderAttrs;
363 	Out_SwDoc( pOrigPam );
364 	nTxtAttrsToIgnore = 0;
365 
366 	if( pxFormComps && pxFormComps->is() )
367 		OutForm( sal_False, *pxFormComps );
368 
369 	if( pFootEndNotes )
370 		OutFootEndNotes();
371 
372 	if( !bWriteClipboardDoc && pDoc->GetDocShell() &&
373         (!pDoc->get(IDocumentSettingAccess::HTML_MODE) && !pDoc->get(IDocumentSettingAccess::BROWSE_MODE))  &&
374 		SFX_ITEM_SET == rPageItemSet.GetItemState( RES_FOOTER, sal_True, &pItem) )
375 	{
376 		const SwFrmFmt *pFooterFmt =
377 			((const SwFmtFooter *)pItem)->GetFooterFmt();
378 		if( pFooterFmt )
379 			OutHTML_HeaderFooter( *this, *pFooterFmt, sal_False );
380 	}
381 
382 	if( bLFPossible )
383 		OutNewLine();
384 	HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_body, sal_False );
385 	OutNewLine();
386 	HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html, sal_False );
387 
388 	// loesche die Tabelle mit den freifliegenden Rahmen
389 	sal_uInt16 i;
390 	ASSERT( !pHTMLPosFlyFrms, "Wurden nicht alle Rahmen ausgegeben" );
391 	if( pHTMLPosFlyFrms )
392 	{
393 		pHTMLPosFlyFrms->DeleteAndDestroy( 0, pHTMLPosFlyFrms->Count() );
394 		delete pHTMLPosFlyFrms;
395 		pHTMLPosFlyFrms = 0;
396 	}
397 
398 	if( aHTMLControls.Count() )
399 		aHTMLControls.DeleteAndDestroy( sal_uInt16(0), aHTMLControls.Count() );
400 
401 	if( aChrFmtInfos.Count() )
402 		aChrFmtInfos.DeleteAndDestroy( sal_uInt16(0), aChrFmtInfos.Count() );
403 
404 	if( aTxtCollInfos.Count() )
405 		aTxtCollInfos.DeleteAndDestroy( sal_uInt16(0), aTxtCollInfos.Count() );
406 
407 	if( aImgMapNames.Count() )
408 		aImgMapNames.DeleteAndDestroy( sal_uInt16(0), aImgMapNames.Count() );
409 
410 	if( aImplicitMarks.Count() )
411 		aImplicitMarks.DeleteAndDestroy( sal_uInt16(0), aImplicitMarks.Count() );
412 
413 	if( aOutlineMarks.Count() )
414 		aOutlineMarks.DeleteAndDestroy( sal_uInt16(0), aOutlineMarks.Count() );
415 
416 	if( aOutlineMarkPoss.Count() )
417 		aOutlineMarkPoss.Remove( sal_uInt16(0), aOutlineMarkPoss.Count() );
418 
419 	if( aNumRuleNames.Count() )
420 		aNumRuleNames.DeleteAndDestroy( sal_uInt16(0), aNumRuleNames.Count() );
421 
422 	if( aScriptParaStyles.Count() )
423 		aScriptParaStyles.DeleteAndDestroy( sal_uInt16(0), aScriptParaStyles.Count() );
424 	if( aScriptTextStyles.Count() )
425 		aScriptTextStyles.DeleteAndDestroy( sal_uInt16(0), aScriptTextStyles.Count() );
426 
427 	delete pDfltColor;
428 	pDfltColor = 0;
429 
430 	delete pStartNdIdx;
431 	pStartNdIdx = 0;
432 
433 	delete pxFormComps;
434 	pxFormComps = 0;
435 
436 	ASSERT( !pFootEndNotes,
437 			"SwHTMLWriter::Write: Ftns nicht durch OutFootEndNotes geloescht" );
438 
439 	pCurrPageDesc = 0;
440 
441 	ClearNextNumInfo();
442 
443 	for( i=0; i<MAXLEVEL; i++ )
444 		aBulletGrfs[i].Erase();
445 
446 	aNonConvertableCharacters.Erase();
447 
448 	if( bShowProgress )
449 		::EndProgress( pDoc->GetDocShell() );
450 
451 	if( pTemplate )
452 	{
453 		// Waehrend des Exports angelegte Zeichen- und Abastzvorlagen
454 		// loeschen
455 		sal_uInt16 nTxtFmtCollCnt = pTemplate->GetTxtFmtColls()->Count();
456 		while( nTxtFmtCollCnt > nOldTxtFmtCollCnt )
457 			pTemplate->DelTxtFmtColl( --nTxtFmtCollCnt );
458 		ASSERT( pTemplate->GetTxtFmtColls()->Count() == nOldTxtFmtCollCnt,
459 				"falsche Anzahl TxtFmtColls geloescht" );
460 
461 		sal_uInt16 nCharFmtCnt = pTemplate->GetCharFmts()->Count();
462 		while( nCharFmtCnt > nOldCharFmtCnt )
463 			pTemplate->DelCharFmt( --nCharFmtCnt );
464 		ASSERT( pTemplate->GetCharFmts()->Count() == nOldCharFmtCnt,
465 				"falsche Anzahl CharFmts geloescht" );
466 
467 		// HTML-Modus wieder restaurieren
468 		pTemplate->set(IDocumentSettingAccess::HTML_MODE, bOldHTMLMode);
469 
470 		if( 0 == pTemplate->release() )
471 			delete pTemplate;
472 
473 		pTemplate = 0;
474 	}
475 
476 	return nWarn;
477 }
478 
479 const SwFmtCol *lcl_html_GetFmtCol( const SwHTMLWriter& rHTMLWrt,
480 							   		const SwSection& rSection,
481 							   		const SwSectionFmt& rFmt )
482 {
483 	const SwFmtCol *pCol = 0;
484 
485 	const SfxPoolItem* pItem;
486 	if( rHTMLWrt.IsHTMLMode( HTMLMODE_FRM_COLUMNS ) &&
487 		FILE_LINK_SECTION != rSection.GetType() &&
488 		SFX_ITEM_SET == rFmt.GetAttrSet().GetItemState(RES_COL,sal_False,&pItem) &&
489 		((const SwFmtCol *)pItem)->GetNumCols() > 1 )
490 	{
491 		pCol = (const SwFmtCol *)pItem;
492 	}
493 
494 	return pCol;
495 }
496 
497 sal_Bool lcl_html_IsMultiColStart( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
498 {
499 	sal_Bool bRet = sal_False;
500 	const SwSectionNode *pSectNd =
501 		rHTMLWrt.pDoc->GetNodes()[nIndex]->GetSectionNode();
502 	if( pSectNd )
503 	{
504 		const SwSection& rSection = pSectNd->GetSection();
505 		const SwSectionFmt *pFmt = rSection.GetFmt();
506 		if( pFmt && lcl_html_GetFmtCol( rHTMLWrt, rSection, *pFmt ) )
507 			bRet = sal_True;
508 	}
509 
510 	return bRet;
511 }
512 
513 sal_Bool lcl_html_IsMultiColEnd( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
514 {
515 	sal_Bool bRet = sal_False;
516 	const SwEndNode *pEndNd = rHTMLWrt.pDoc->GetNodes()[nIndex]->GetEndNode();
517 	if( pEndNd )
518 		bRet = lcl_html_IsMultiColStart( rHTMLWrt,
519 										 pEndNd->StartOfSectionIndex() );
520 
521 	return bRet;
522 }
523 
524 
525 void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt,
526 							   	  const SwSection& rSection,
527 							   	  const SwSectionFmt& rFmt,
528 								  const SwFmtCol *pCol,
529 								  sal_Bool bContinued=sal_False )
530 {
531 	ASSERT( pCol || !bContinued, "Continuation of DIV" );
532 
533 	if( rHTMLWrt.bLFPossible )
534 		rHTMLWrt.OutNewLine();
535 
536 	const sal_Char *pTag = pCol ? OOO_STRING_SVTOOLS_HTML_multicol : OOO_STRING_SVTOOLS_HTML_division;
537 
538 	ByteString sOut( '<' );
539 	sOut += pTag;
540 
541     const String& rName = rSection.GetSectionName();
542 	if( rName.Len() && !bContinued )
543 	{
544 		((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_id) += "=\"";
545 		rHTMLWrt.Strm() << sOut.GetBuffer();
546 		HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), rName, rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
547 		sOut = '\"';
548 	}
549 
550 	sal_uInt16 nDir = rHTMLWrt.GetHTMLDirection( rFmt.GetAttrSet() );
551 	rHTMLWrt.Strm() << sOut.GetBuffer();
552 	sOut.Erase();
553 	rHTMLWrt.OutDirection( nDir );
554 
555 	if( FILE_LINK_SECTION == rSection.GetType() )
556 	{
557 		((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_href) += "=\"";
558 		rHTMLWrt.Strm() << sOut.GetBuffer();
559 
560 		const String& aFName = rSection.GetLinkFileName();
561         String aURL( aFName.GetToken(0,sfx2::cTokenSeperator) );
562         String aFilter( aFName.GetToken(1,sfx2::cTokenSeperator) );
563         String aSection( aFName.GetToken(2,sfx2::cTokenSeperator) );
564 
565         String aEncURL( URIHelper::simpleNormalizedMakeRelative(rHTMLWrt.GetBaseURL(), aURL ) );
566 		sal_Unicode cDelim = 255U;
567 		sal_Bool bURLContainsDelim =
568 			(STRING_NOTFOUND != aEncURL.Search( cDelim ) );
569 
570 		HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aEncURL,
571 								  rHTMLWrt.eDestEnc,
572 								  &rHTMLWrt.aNonConvertableCharacters );
573 		const sal_Char *pDelim = "&#255;";
574 		if( aFilter.Len() || aSection.Len() || bURLContainsDelim )
575 			rHTMLWrt.Strm() << pDelim;
576 		if( aFilter.Len() )
577 			HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aFilter,
578 									  rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
579 		if( aSection.Len() || bURLContainsDelim  )
580 				rHTMLWrt.Strm() << pDelim;
581 		if( aSection.Len() )
582 		{
583 			xub_StrLen nPos = aSection.Search( '%' );
584 			while( STRING_NOTFOUND != nPos )
585 			{
586 				aSection.Erase( nPos, 1 );
587 				aSection.InsertAscii( "%25", nPos );
588 				nPos = aSection.Search( '%', nPos+3 );
589 			}
590 			nPos = aSection.Search( cDelim );
591 			while( STRING_NOTFOUND != nPos )
592 			{
593 				aSection.Erase( nPos, 1 );
594 				aSection.InsertAscii( "%FF", nPos );
595 				nPos = aSection.Search( cDelim, nPos+3 );
596 			}
597 			HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aSection,
598 									  rHTMLWrt.eDestEnc, &rHTMLWrt.aNonConvertableCharacters );
599 		}
600 		sOut = '\"';
601 	}
602 	else if( pCol )
603 	{
604 		(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_cols) += '=')
605 			+= ByteString::CreateFromInt32( pCol->GetNumCols() );
606 
607 		// minumum gutter width
608 		sal_uInt16 nGutter = pCol->GetGutterWidth( sal_True );
609 		if( nGutter!=USHRT_MAX )
610 		{
611 			if( nGutter && Application::GetDefaultDevice() )
612 			{
613 				nGutter = (sal_uInt16)Application::GetDefaultDevice()
614 								->LogicToPixel( Size(nGutter,0),
615 												MapMode(MAP_TWIP) ).Width();
616 			}
617 			(((sOut += ' ') += OOO_STRING_SVTOOLS_HTML_O_gutter) += '=')
618 				+= ByteString::CreateFromInt32( nGutter );
619 		}
620 	}
621 
622 	rHTMLWrt.Strm() << sOut.GetBuffer();
623 	if( rHTMLWrt.IsHTMLMode( rHTMLWrt.bCfgOutStyles ) )
624 		rHTMLWrt.OutCSS1_SectionFmtOptions( rFmt );
625 
626 	rHTMLWrt.Strm() << '>';
627 
628 	rHTMLWrt.bLFPossible = sal_True;
629 	if( rName.Len() && !bContinued )
630 		rHTMLWrt.OutImplicitMark( rName, pMarkToRegion );
631 
632 	rHTMLWrt.IncIndentLevel();
633 }
634 
635 void lcl_html_OutSectionEndTag( SwHTMLWriter& rHTMLWrt,
636 								const SwFmtCol *pCol )
637 {
638 	const sal_Char *pTag = pCol ? OOO_STRING_SVTOOLS_HTML_multicol : OOO_STRING_SVTOOLS_HTML_division;
639 
640 	rHTMLWrt.DecIndentLevel();
641 	if( rHTMLWrt.bLFPossible )
642 		rHTMLWrt.OutNewLine();
643 	HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), pTag, sal_False );
644 	rHTMLWrt.bLFPossible = sal_True;
645 }
646 
647 static Writer& OutHTML_Section( Writer& rWrt, const SwSectionNode& rSectNd )
648 {
649 	SwHTMLWriter& rHTMLWrt = (SwHTMLWriter&)rWrt;
650 
651 	// End <PRE> and any <DL>, because a definition list's level may
652 	// change inside the section.
653 	rHTMLWrt.ChangeParaToken( 0 );
654 	rHTMLWrt.OutAndSetDefList( 0 );
655 
656 	const SwSection& rSection = rSectNd.GetSection();
657 	const SwSectionFmt *pFmt = rSection.GetFmt();
658 	ASSERT( pFmt, "Section without a format?" );
659 
660 	sal_Bool bStartTag = sal_True;
661 	sal_Bool bEndTag = sal_True;
662 	const SwSectionFmt *pSurrFmt = 0;
663 	const SwSectionNode *pSurrSectNd = 0;
664 	const SwSection *pSurrSection = 0;
665 	const SwFmtCol *pSurrCol = 0;
666 
667 	sal_uInt32 nSectSttIdx = rSectNd.GetIndex();
668 	sal_uInt32 nSectEndIdx = rSectNd.EndOfSectionIndex();
669 	const SwFmtCol *pCol = lcl_html_GetFmtCol( rHTMLWrt, rSection, *pFmt );
670 	if( pCol )
671 	{
672 		// If the next node is a columned section node, too, don't export
673 		// an empty section.
674 		if( lcl_html_IsMultiColStart( rHTMLWrt, nSectSttIdx+1 ) )
675 			bStartTag = sal_False;
676 
677 		// The same applies if the section end with another columned section.
678 		if( lcl_html_IsMultiColEnd( rHTMLWrt, nSectEndIdx-1 ) )
679 			bEndTag = sal_False;
680 
681 		//.is there a columned section arround this one?
682         const SwStartNode *pSttNd = rSectNd.StartOfSectionNode();
683 		if( pSttNd )
684 		{
685 			pSurrSectNd = pSttNd->FindSectionNode();
686 			if( pSurrSectNd )
687 			{
688 				const SwStartNode *pBoxSttNd = pSttNd->FindTableBoxStartNode();
689 				if( !pBoxSttNd ||
690 					pBoxSttNd->GetIndex() < pSurrSectNd->GetIndex() )
691 				{
692 					pSurrSection = &pSurrSectNd->GetSection();
693 					pSurrFmt = pSurrSection->GetFmt();
694 					if( pSurrFmt )
695 						pSurrCol = lcl_html_GetFmtCol( rHTMLWrt, *pSurrSection,
696 													   *pSurrFmt );
697 				}
698 			}
699 		}
700 	}
701 
702 	// The surrounding section must be closed before the current one is
703 	// opended, except that it start immediatly before the current one or
704 	// another end immediately before the current one
705 	if( pSurrCol && nSectSttIdx - pSurrSectNd->GetIndex() > 1 &&
706 		!lcl_html_IsMultiColEnd( rHTMLWrt, nSectSttIdx-1 ) )
707 		lcl_html_OutSectionEndTag( rHTMLWrt, pSurrCol );
708 
709 	if( bStartTag )
710 		lcl_html_OutSectionStartTag( rHTMLWrt, rSection, *pFmt, pCol );
711 
712 	{
713 		HTMLSaveData aSaveData( rHTMLWrt,
714 			rHTMLWrt.pCurPam->GetPoint()->nNode.GetIndex()+1,
715 			rSectNd.EndOfSectionIndex(),
716 			sal_False, pFmt );
717 		rHTMLWrt.Out_SwDoc( rHTMLWrt.pCurPam );
718 	}
719 
720 	rHTMLWrt.pCurPam->GetPoint()->nNode = *rSectNd.EndOfSectionNode();
721 
722 	if( bEndTag )
723 		lcl_html_OutSectionEndTag( rHTMLWrt, pCol );
724 
725 	// The surrounding section must be started again, except that it ends
726 	// immeditaly behind the current one.
727 	if( pSurrCol &&
728 		pSurrSectNd->EndOfSectionIndex() - nSectEndIdx > 1 &&
729 		!lcl_html_IsMultiColStart( rHTMLWrt, nSectEndIdx+1 ) )
730 		lcl_html_OutSectionStartTag( rHTMLWrt, *pSurrSection, *pSurrFmt,
731 									 pSurrCol, sal_True );
732 
733 	return rWrt;
734 }
735 
736 void SwHTMLWriter::Out_SwDoc( SwPaM* pPam )
737 {
738 	sal_Bool bSaveWriteAll = bWriteAll;		// sichern
739 
740     // suche die naechste text::Bookmark-Position aus der text::Bookmark-Tabelle
741 	nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
742 
743 	// gebe alle Bereiche des Pams in das HTML-File aus.
744 	do {
745 		bWriteAll = bSaveWriteAll;
746 		bFirstLine = sal_True;
747 
748 		// suche den ersten am Pam-auszugebenen FlyFrame
749 		// fehlt noch:
750 
751 		while( pCurPam->GetPoint()->nNode.GetIndex() < pCurPam->GetMark()->nNode.GetIndex() ||
752 			  (pCurPam->GetPoint()->nNode.GetIndex() == pCurPam->GetMark()->nNode.GetIndex() &&
753 			   pCurPam->GetPoint()->nContent.GetIndex() <= pCurPam->GetMark()->nContent.GetIndex()) )
754 		{
755 			SwNode * pNd = pCurPam->GetNode();
756 
757 			ASSERT( !(pNd->IsGrfNode() || pNd->IsOLENode()),
758 					"Grf- oder OLE-Node hier unerwartet" );
759 			if( pNd->IsTxtNode() )
760 			{
761 				SwTxtNode* pTxtNd = pNd->GetTxtNode();
762 
763 				if( !bFirstLine )
764 					pCurPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
765 
766 				OutHTML_SwTxtNode( *this, *pTxtNd );
767 			}
768 			else if( pNd->IsTableNode() )
769 			{
770 				OutHTML_SwTblNode( *this, *pNd->GetTableNode(), 0 );
771                 nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
772 			}
773 			else if( pNd->IsSectionNode() )
774 			{
775 				OutHTML_Section( *this, *pNd->GetSectionNode() );
776                 nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
777 			}
778 			else if( pNd == &pDoc->GetNodes().GetEndOfContent() )
779 				break;
780 
781 			pCurPam->GetPoint()->nNode++; 	// Bewegen
782 			sal_uInt32 nPos = pCurPam->GetPoint()->nNode.GetIndex();
783 
784 			if( bShowProgress )
785 				::SetProgressState( nPos, pDoc->GetDocShell() );   // Wie weit ?
786 
787 			/* sollen nur die Selectierten Bereiche gesichert werden, so
788 			 * duerfen nur die vollstaendigen Nodes gespeichert werde,
789 			 * d.H. der 1. und n. Node teilweise, der 2. bis n-1. Node
790 			 * vollstaendig. (vollstaendig heisst mit allen Formaten! )
791 			 */
792 			bWriteAll = bSaveWriteAll ||
793 						nPos != pCurPam->GetMark()->nNode.GetIndex();
794 			bFirstLine = sal_False;
795 			bOutFooter = sal_False; // Nach einem Node keine Fusszeile mehr
796 		}
797 
798 		ChangeParaToken( 0 ); // MIB 8.7.97: Machen wir jetzt hier und nicht
799 							  // beim Aufrufer
800 		OutAndSetDefList( 0 );
801 
802 	} while( CopyNextPam( &pPam ) );		// bis alle PaM's bearbeitet
803 
804 	bWriteAll = bSaveWriteAll;			// wieder auf alten Wert zurueck
805 }
806 
807 
808 // schreibe die StyleTabelle, algemeine Angaben,Header/Footer/Footnotes
809 static void OutBodyColor( const sal_Char *pTag, const SwFmt *pFmt,
810 						  SwHTMLWriter& rHWrt )
811 {
812 	const SwFmt *pRefFmt = 0;
813 
814 	if( rHWrt.pTemplate )
815 		pRefFmt = SwHTMLWriter::GetTemplateFmt( pFmt->GetPoolFmtId(),
816 												rHWrt.pTemplate );
817 
818 	const SvxColorItem *pColorItem = 0;
819 
820 	const SfxItemSet& rItemSet = pFmt->GetAttrSet();
821     const SfxPoolItem *pRefItem = 0, *pItem = 0;
822 	sal_Bool bItemSet = SFX_ITEM_SET == rItemSet.GetItemState( RES_CHRATR_COLOR,
823 														   sal_True, &pItem);
824 	sal_Bool bRefItemSet = pRefFmt &&
825 		SFX_ITEM_SET == pRefFmt->GetAttrSet().GetItemState( RES_CHRATR_COLOR,
826 															sal_True, &pRefItem);
827 	if( bItemSet )
828 	{
829 		// wenn das Item nur in der Vorlage des aktuellen Doks gesetzt
830 		// ist oder einen anderen Wert hat, als in der HTML-Vorlage,
831 		// wird es gesetzt
832 		const SvxColorItem *pCItem = (const SvxColorItem*)pItem;
833 
834 		if( !bRefItemSet )
835 		{
836 			pColorItem = pCItem;
837 		}
838 		else
839 		{
840 			Color aColor( pCItem->GetValue() );
841 			if( COL_AUTO == aColor.GetColor() )
842 				aColor.SetColor( COL_BLACK );
843 
844 			Color aRefColor( ((const SvxColorItem*)pRefItem)->GetValue() );
845 			if( COL_AUTO == aRefColor.GetColor() )
846 				aRefColor.SetColor( COL_BLACK );
847 
848 			if( !aColor.IsRGBEqual( aRefColor ) )
849 				pColorItem = pCItem;
850 		}
851 	}
852 	else if( bRefItemSet )
853 	{
854 		// Das Item war in der HTML-Vorlage noch gesetzt, also geben wir
855 		// das Default aus
856 		pColorItem = (const SvxColorItem*)&rItemSet.GetPool()
857 										->GetDefaultItem( RES_CHRATR_COLOR );
858 	}
859 
860 	if( pColorItem )
861 	{
862 		ByteString sOut( ' ' );
863 		(sOut += pTag) += '=';
864 		rHWrt.Strm() << sOut.GetBuffer();
865 		Color aColor( pColorItem->GetValue() );
866 		if( COL_AUTO == aColor.GetColor() )
867 			aColor.SetColor( COL_BLACK );
868 		HTMLOutFuncs::Out_Color( rHWrt.Strm(), aColor, rHWrt.eDestEnc );
869 		if( RES_POOLCOLL_STANDARD==pFmt->GetPoolFmtId() )
870 			rHWrt.pDfltColor = new Color( aColor );
871 	}
872 }
873 
874 sal_uInt16 SwHTMLWriter::OutHeaderAttrs()
875 {
876 	sal_uLong nIdx = pCurPam->GetPoint()->nNode.GetIndex();
877 	sal_uLong nEndIdx = pCurPam->GetMark()->nNode.GetIndex();
878 
879 	SwTxtNode *pTxtNd = 0;
880 	while( nIdx<=nEndIdx &&
881 			0==(pTxtNd=pDoc->GetNodes()[nIdx]->GetTxtNode()) )
882 		nIdx++;
883 
884 	ASSERT( pTxtNd, "Kein Text-Node gefunden" );
885 	if( !pTxtNd || !pTxtNd->HasHints() )
886 		return 0;
887 
888 	sal_uInt16 nAttrs = 0;
889 	sal_uInt16 nCntAttr = pTxtNd->GetSwpHints().Count();
890 	xub_StrLen nOldPos = 0;
891 	for( sal_uInt16 i=0; i<nCntAttr; i++ )
892 	{
893 		const SwTxtAttr *pHt = pTxtNd->GetSwpHints()[i];
894 		if( !pHt->GetEnd() )
895 		{
896 			xub_StrLen nPos = *pHt->GetStart();
897 			if( nPos-nOldPos > 1 || RES_TXTATR_FIELD != pHt->Which() )
898 				break;
899 
900 			sal_uInt16 nFldWhich = ((const SwFmtFld&)pHt->GetAttr()).GetFld()
901 													 ->GetTyp()->Which();
902 			if( RES_POSTITFLD!=nFldWhich &&
903 				RES_SCRIPTFLD!=nFldWhich )
904 				break;
905 
906 			OutNewLine();
907 			OutHTML_SwFmtFld( *this, pHt->GetAttr() );
908 			nOldPos = nPos;
909 			nAttrs++;
910 		}
911 	}
912 
913 	return nAttrs;
914 }
915 
916 const SwPageDesc *SwHTMLWriter::MakeHeader( sal_uInt16 &rHeaderAttrs )
917 {
918 	ByteString sOut( OOO_STRING_SVTOOLS_HTML_doctype );
919 	(sOut += ' ') +=
920 		(HTML_CFG_HTML32==nExportMode ? OOO_STRING_SVTOOLS_HTML_doctype32
921 		 							  : OOO_STRING_SVTOOLS_HTML_doctype40);
922 	HTMLOutFuncs::Out_AsciiTag( Strm(), sOut.GetBuffer() );
923 
924 	// baue den Vorspann
925 	OutNewLine();
926 	HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html );
927 
928 	OutNewLine();
929 	HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head );
930 
931 	IncIndentLevel();	// Inhalt von <HEAD> einruecken
932 
933 	// DokumentInfo
934 	ByteString sIndent;
935 	GetIndentString( sIndent );
936 //	OutNewLine();
937     using namespace ::com::sun::star;
938     uno::Reference<document::XDocumentProperties> xDocProps;
939     SwDocShell *pDocShell(pDoc->GetDocShell());
940     if (pDocShell) {
941         uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
942             pDocShell->GetModel(), uno::UNO_QUERY_THROW);
943         xDocProps.set(xDPS->getDocumentProperties());
944     }
945 
946     // xDocProps may be null here (when copying)
947     SfxFrameHTMLWriter::Out_DocInfo( Strm(), GetBaseURL(), xDocProps,
948                                      sIndent.GetBuffer(), eDestEnc,
949                                      &aNonConvertableCharacters );
950 
951 	// Kommentare und Meta-Tags des ersten Absatzes
952 	rHeaderAttrs = OutHeaderAttrs();
953 
954 	OutFootEndNoteInfo();
955 
956 	const SwPageDesc *pPageDesc = 0;
957 	//if( !pDoc->IsHTMLMode() )
958 	//{
959 		// In Nicht-HTML-Dokumenten wird die erste gesetzte Seitenvorlage
960 		// exportiert und wenn keine gesetzt ist die Standard-Vorlage
961 		sal_uLong nNodeIdx = pCurPam->GetPoint()->nNode.GetIndex();
962 
963 		while( nNodeIdx < pDoc->GetNodes().Count() )
964 		{
965 			SwNode *pNd = pDoc->GetNodes()[ nNodeIdx ];
966 			if( pNd->IsCntntNode() )
967 			{
968 				pPageDesc = ((const SwFmtPageDesc &)pNd->GetCntntNode()
969 					->GetAttr(RES_PAGEDESC)).GetPageDesc();
970 				break;
971 			}
972 			else if( pNd->IsTableNode() )
973 			{
974 				pPageDesc = pNd->GetTableNode()->GetTable().GetFrmFmt()
975 							   ->GetPageDesc().GetPageDesc();
976 				break;
977 			}
978 
979 			nNodeIdx++;
980 		}
981 
982 		if( !pPageDesc )
983 			pPageDesc = &const_cast<const SwDoc *>(pDoc)->GetPageDesc( 0 );
984 	//}
985 	//else
986 	//{
987 		// In HTML-Dokumenten nehmen wir immer die HTML-Vorlage
988 	//	pPageDesc = pDoc->GetPageDescFromPool( RES_POOLPAGE_HTML );
989 	//}
990 
991 	// und nun ... das Style-Sheet!!!
992 	if( bCfgOutStyles )
993 	{
994 		OutStyleSheet( *pPageDesc );
995 	}
996 
997 	// und nun ... das BASIC und JavaScript!
998 	if( pDoc->GetDocShell() )	// nur mit DocShell ist Basic moeglich
999 		OutBasic();
1000 
1001 	DecIndentLevel();	// Inhalt von <HEAD> einruecken
1002 	OutNewLine();
1003 	HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head, sal_False );
1004 
1005 	// der Body wird nicht eingerueckt, weil sonst alles eingerueckt waere!
1006 	OutNewLine();
1007 	sOut = '<';
1008 	sOut += OOO_STRING_SVTOOLS_HTML_body;
1009 	Strm() << sOut.GetBuffer();
1010 	sOut.Erase();
1011 
1012 	// language
1013 	OutLanguage( eLang );
1014 
1015 	// Textfarbe ausgeben, wenn sie an der Standard-Vorlage gesetzt ist
1016 	// und sich geaendert hat.
1017 	OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_text,
1018                   pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false ),
1019 				  *this );
1020 
1021 	// Farben fuer (un)besuchte Links
1022 	OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_link,
1023 				  pDoc->GetCharFmtFromPool( RES_POOLCHR_INET_NORMAL ),
1024 				  *this );
1025 	OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_vlink,
1026 				  pDoc->GetCharFmtFromPool( RES_POOLCHR_INET_VISIT ),
1027 				  *this );
1028 
1029 	const SfxItemSet& rItemSet = pPageDesc->GetMaster().GetAttrSet();
1030 
1031 	String aEmbGrfName;
1032 	OutBackground( rItemSet, aEmbGrfName, sal_True );
1033 
1034 	nDirection = GetHTMLDirection( rItemSet );
1035 	OutDirection( nDirection );
1036 
1037 	if( bCfgOutStyles )
1038 		OutCSS1_BodyTagStyleOpt( *this, rItemSet, aEmbGrfName );
1039 
1040 	// Events anhaengen
1041 	if( pDoc->GetDocShell() )	// nur mit DocShell ist Basic moeglich
1042 		OutBasicBodyEvents();
1043 
1044 	Strm() << '>';
1045 
1046 	return pPageDesc;
1047 }
1048 
1049 void SwHTMLWriter::OutAnchor( const String& rName )
1050 {
1051 	ByteString sOut( '<' );
1052 	(((sOut += OOO_STRING_SVTOOLS_HTML_anchor) += ' ') += OOO_STRING_SVTOOLS_HTML_O_name) += "=\"";
1053 	Strm() << sOut.GetBuffer();
1054 	HTMLOutFuncs::Out_String( Strm(), rName, eDestEnc, &aNonConvertableCharacters ) << "\">";
1055 	HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_anchor, sal_False );
1056 }
1057 
1058 void SwHTMLWriter::OutBookmarks()
1059 {
1060     // hole das aktuelle Bookmark
1061     const ::sw::mark::IMark* pBookmark = NULL;
1062     IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1063     if(nBkmkTabPos != -1)
1064         pBookmark = (pMarkAccess->getMarksBegin() + nBkmkTabPos)->get();
1065     // Ausgabe aller Bookmarks in diesem Absatz. Die Content-Position
1066     // wird vorerst nicht beruecksichtigt!
1067     sal_uInt32 nNode = pCurPam->GetPoint()->nNode.GetIndex();
1068     while( nBkmkTabPos != -1 &&
1069         pBookmark->GetMarkPos().nNode.GetIndex() == nNode )
1070     {
1071         // Der Bereich derBookmark wird erstam ignoriert, da er von uns
1072         // auch nicht eingelesen wird.
1073 
1074         // erst die SWG spezifischen Daten:
1075         if(dynamic_cast< const ::sw::mark::IBookmark* >(pBookmark) && pBookmark->GetName().getLength() )
1076             OutAnchor( pBookmark->GetName() );
1077 
1078         if( ++nBkmkTabPos >= pMarkAccess->getMarksCount() )
1079             nBkmkTabPos = -1;
1080         else
1081             pBookmark = (pMarkAccess->getMarksBegin() + nBkmkTabPos)->get();
1082     }
1083 
1084     sal_uInt16 nPos;
1085     for( nPos = 0; nPos < aOutlineMarkPoss.Count() &&
1086                    aOutlineMarkPoss[nPos] < nNode; nPos++ )
1087         ;
1088 
1089     while( nPos < aOutlineMarkPoss.Count() && aOutlineMarkPoss[nPos] == nNode )
1090     {
1091         String sMark( *aOutlineMarks[nPos] );
1092         sMark.SearchAndReplaceAll( '?', '_' );  // '?' causes problems in IE/Netscape 5
1093         OutAnchor( sMark );
1094         aOutlineMarkPoss.Remove( nPos, 1 );
1095         aOutlineMarks.DeleteAndDestroy( nPos, 1 );
1096     }
1097 }
1098 
1099 void SwHTMLWriter::OutImplicitMark( const String& rMark,
1100 									const sal_Char *pMarkType )
1101 {
1102 	if( rMark.Len() && aImplicitMarks.Count() )
1103 	{
1104 		String sMark( rMark );
1105 		sMark.Append( cMarkSeperator );
1106 		sMark.AppendAscii( pMarkType );
1107 		sal_uInt16 nPos;
1108 		if( aImplicitMarks.Seek_Entry( &sMark, &nPos ) )
1109 		{
1110 			sMark.SearchAndReplaceAll( '?', '_' );	// '?' causes problems in IE/Netscape 5
1111 			OutAnchor( sMark );
1112 			aImplicitMarks.DeleteAndDestroy( nPos, 1 );
1113 		}
1114 	}
1115 }
1116 
1117 void SwHTMLWriter::OutHyperlinkHRefValue( const String& rURL )
1118 {
1119 	String sURL( rURL );
1120 	xub_StrLen nPos = sURL.SearchBackward( cMarkSeperator );
1121 	if( STRING_NOTFOUND != nPos )
1122 	{
1123 		String sCmp( sURL.Copy( nPos+1 ) );
1124 		sCmp.EraseAllChars();
1125 		if( sCmp.Len() )
1126 		{
1127 			sCmp.ToLowerAscii();
1128 			if( sCmp.EqualsAscii( pMarkToRegion ) ||
1129 				sCmp.EqualsAscii( pMarkToFrame ) ||
1130 				sCmp.EqualsAscii( pMarkToGraphic ) ||
1131 				sCmp.EqualsAscii( pMarkToOLE ) ||
1132 				sCmp.EqualsAscii( pMarkToTable ) ||
1133 				sCmp.EqualsAscii( pMarkToOutline ) ||
1134 				sCmp.EqualsAscii( pMarkToText ) )
1135 			{
1136 				sURL.SearchAndReplaceAll( '?', '_' );	// '?' causes problems in IE/Netscape 5
1137 			}
1138 		}
1139 	}
1140 
1141     sURL = URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), sURL);
1142 	HTMLOutFuncs::Out_String( Strm(), sURL, eDestEnc,
1143 							  &aNonConvertableCharacters );
1144 }
1145 
1146 void SwHTMLWriter::OutBackground( const SvxBrushItem *pBrushItem,
1147 								  String& rEmbGrfNm, sal_Bool bGraphic )
1148 {
1149 	const Color &rBackColor = pBrushItem->GetColor();
1150     /// OD 02.09.2002 #99657#
1151     /// check, if background color is not "no fill"/"auto fill", instead of
1152     /// only checking, if transparency is not set.
1153     if( rBackColor.GetColor() != COL_TRANSPARENT )
1154 	{
1155 		ByteString sOut( ' ' );
1156 		(sOut += OOO_STRING_SVTOOLS_HTML_O_bgcolor) += '=';
1157 		Strm() << sOut.GetBuffer();
1158 		HTMLOutFuncs::Out_Color( Strm(), rBackColor, eDestEnc);
1159 	}
1160 
1161 	if( !bGraphic )
1162 		return;
1163 
1164 	const String *pLink = pBrushItem->GetGraphicLink();
1165 
1166 	// embeddete Grafik -> WriteEmbedded schreiben
1167 	if( !pLink )
1168 	{
1169 		const Graphic* pGrf = pBrushItem->GetGraphic();
1170 		if( pGrf )
1171 		{
1172 			// Grafik als (JPG-)File speichern
1173 			const String* pTempFileName = GetOrigFileName();
1174 			if(pTempFileName)
1175 				rEmbGrfNm = *pTempFileName;
1176 			sal_uInt16 nErr = XOutBitmap::WriteGraphic( *pGrf, rEmbGrfNm,
1177 					String::CreateFromAscii( "JPG" ),
1178 					XOUTBMP_USE_NATIVE_IF_POSSIBLE );
1179 			if( !nErr )		// fehlerhaft, da ist nichts auszugeben
1180 			{
1181                 rEmbGrfNm = URIHelper::SmartRel2Abs(
1182                     INetURLObject( GetBaseURL() ), rEmbGrfNm,
1183                     URIHelper::GetMaybeFileHdl() );
1184 				pLink = &rEmbGrfNm;
1185 			}
1186 			else
1187 			{
1188 				nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE;
1189 			}
1190 		}
1191 	}
1192 	else
1193 	{
1194 		rEmbGrfNm = *pLink;
1195 		if( bCfgCpyLinkedGrfs )
1196 		{
1197 			CopyLocalFileToINet( rEmbGrfNm  );
1198 			pLink = &rEmbGrfNm;
1199 		}
1200 	}
1201 
1202 	if( pLink )
1203 	{
1204 		ByteString sOut( ' ' );
1205         String s( URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), *pLink));
1206 		(sOut += OOO_STRING_SVTOOLS_HTML_O_background) += "=\"";
1207 		Strm() << sOut.GetBuffer();
1208 		HTMLOutFuncs::Out_String( Strm(), s, eDestEnc, &aNonConvertableCharacters ) << '\"';
1209 	}
1210 }
1211 
1212 void SwHTMLWriter::OutBackground( const SfxItemSet& rItemSet,
1213 								  String& rEmbGrfNm, sal_Bool bGraphic )
1214 {
1215 	const SfxPoolItem* pItem;
1216 	if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False,
1217 											   &pItem ))
1218 	{
1219 		OutBackground( ((const SvxBrushItem*)pItem), rEmbGrfNm, bGraphic );
1220 	}
1221 }
1222 
1223 sal_uInt16 SwHTMLWriter::GetLangWhichIdFromScript( sal_uInt16 nScript )
1224 {
1225 	sal_uInt16 nWhichId;
1226 	switch( nScript )
1227 	{
1228 	case CSS1_OUTMODE_CJK:
1229 		nWhichId = RES_CHRATR_CJK_LANGUAGE;
1230 		break;
1231 	case CSS1_OUTMODE_CTL:
1232 		nWhichId = RES_CHRATR_CJK_LANGUAGE;
1233 		break;
1234 	default:
1235 		nWhichId = RES_CHRATR_LANGUAGE;
1236 		break;
1237 	}
1238 	return nWhichId;
1239 }
1240 
1241 void SwHTMLWriter::OutLanguage( LanguageType nLang )
1242 {
1243 	if( LANGUAGE_DONTKNOW != nLang )
1244 	{
1245 		ByteString sOut( ' ' );
1246 		(sOut += OOO_STRING_SVTOOLS_HTML_O_lang) += "=\"";
1247 		Strm() << sOut.GetBuffer();
1248 		HTMLOutFuncs::Out_String( Strm(), MsLangId::convertLanguageToIsoString(nLang),
1249 								  eDestEnc, &aNonConvertableCharacters ) << '"';
1250 	}
1251 }
1252 
1253 sal_uInt16 SwHTMLWriter::GetHTMLDirection( const SfxItemSet& rItemSet ) const
1254 {
1255 	return GetHTMLDirection(
1256 		static_cast < const SvxFrameDirectionItem& >( rItemSet.Get( RES_FRAMEDIR ) )
1257 			.GetValue() );
1258 }
1259 
1260 sal_uInt16 SwHTMLWriter::GetHTMLDirection( sal_uInt16 nDir ) const
1261 {
1262 	switch( nDir )
1263 	{
1264 	case FRMDIR_VERT_TOP_LEFT:
1265 		nDir = FRMDIR_HORI_LEFT_TOP;
1266 		break;
1267 	case FRMDIR_VERT_TOP_RIGHT:
1268 		nDir = FRMDIR_HORI_RIGHT_TOP;
1269 		break;
1270 	case FRMDIR_ENVIRONMENT:
1271 		nDir = nDirection;
1272 	}
1273 
1274 	return nDir;
1275 }
1276 
1277 void SwHTMLWriter::OutDirection( sal_uInt16 nDir )
1278 {
1279 	const sal_Char *pValue = 0;
1280 	switch( nDir )
1281 	{
1282 	case FRMDIR_HORI_LEFT_TOP:
1283 	case FRMDIR_VERT_TOP_LEFT:
1284 		pValue = "LTR";
1285 		break;
1286 	case FRMDIR_HORI_RIGHT_TOP:
1287 	case FRMDIR_VERT_TOP_RIGHT:
1288 		pValue = "RTL";
1289 		break;
1290 	}
1291 	if( pValue != 0 )
1292 	{
1293 		ByteString sOut( ' ' );
1294 		(((sOut += OOO_STRING_SVTOOLS_HTML_O_dir) += "=\"") += pValue) += '\"';
1295 		Strm() << sOut.GetBuffer();
1296 	}
1297 }
1298 
1299 void SwHTMLWriter::GetIndentString( ByteString& rStr, sal_uInt16 nIncLvl )
1300 {
1301 	// etwas umstaendlich, aber wir haben nur einen Indent-String!
1302 	sal_uInt16 nLevel = nIndentLvl + nIncLvl;
1303 
1304 	if( nLevel && nLevel <= MAX_INDENT_LEVEL)
1305 	{
1306 		sIndentTabs[nLevel] = 0;
1307 		rStr = sIndentTabs;
1308 		sIndentTabs[nLevel] = '\t';
1309 	}
1310 }
1311 
1312 void SwHTMLWriter::OutNewLine( sal_Bool bCheck )
1313 {
1314 	if( !bCheck || (Strm().Tell()-nLastLFPos) > nIndentLvl )
1315 	{
1316 		Strm() << sNewLine;
1317 		nLastLFPos = Strm().Tell();
1318 	}
1319 
1320 	if( nIndentLvl && nIndentLvl <= MAX_INDENT_LEVEL)
1321 	{
1322 		sIndentTabs[nIndentLvl] = 0;
1323 		Strm() << sIndentTabs;
1324 		sIndentTabs[nIndentLvl] = '\t';
1325 	}
1326 }
1327 
1328 sal_uInt16 SwHTMLWriter::GetHTMLFontSize( sal_uInt32 nHeight ) const
1329 {
1330 	sal_uInt16 nSize = 1;
1331 	for( sal_uInt16 i=6; i>0; i-- )
1332 	{
1333 		if( nHeight > (aFontHeights[i] + aFontHeights[i-1])/2 )
1334 		{
1335 			nSize = i+1;
1336 			break;
1337 		}
1338 	}
1339 
1340 	return nSize;
1341 }
1342 
1343 // Struktur speichert die aktuellen Daten des Writers zwischen, um
1344 // einen anderen Dokument-Teil auszugeben, wie z.B. Header/Footer
1345 HTMLSaveData::HTMLSaveData( SwHTMLWriter& rWriter, sal_uLong nStt,
1346 							sal_uLong nEnd, sal_Bool bSaveNum,
1347 	   					 	const SwFrmFmt *pFrmFmt	) :
1348 	rWrt( rWriter ),
1349 	pOldPam( rWrt.pCurPam ),
1350 	pOldEnd( rWrt.GetEndPaM() ),
1351 	pOldNumRuleInfo( 0 ),
1352 	pOldNextNumRuleInfo( 0 ),
1353 	nOldDefListLvl( rWrt.nDefListLvl ),
1354 	nOldDirection( rWrt.nDirection ),
1355 	bOldOutHeader( rWrt.bOutHeader ),
1356 	bOldOutFooter( rWrt.bOutFooter ),
1357 	bOldOutFlyFrame( rWrt.bOutFlyFrame )
1358 {
1359 	bOldWriteAll = rWrt.bWriteAll;
1360 
1361 	rWrt.pCurPam = rWrt.NewSwPaM( *rWrt.pDoc, nStt, nEnd );
1362 
1363 	// Tabelle in Sonderbereichen erkennen
1364 	if( nStt != rWrt.pCurPam->GetMark()->nNode.GetIndex() )
1365 	{
1366 		const SwNode *pNd = rWrt.pDoc->GetNodes()[ nStt ];
1367 		if( pNd->IsTableNode() || pNd->IsSectionNode() )
1368 			rWrt.pCurPam->GetMark()->nNode = nStt;
1369 	}
1370 
1371 	rWrt.SetEndPaM( rWrt.pCurPam );
1372 	rWrt.pCurPam->Exchange( );
1373 	rWrt.bWriteAll = sal_True;
1374 	rWrt.nDefListLvl = 0;
1375 	rWrt.bOutHeader = rWrt.bOutFooter = sal_False;
1376 
1377 	// Ggf. die aktuelle Numerierungs-Info merken, damit sie wieder
1378 	// neu aufgenommen werden kann. Nur dann belibt auch die Numerierungs-
1379 	// Info des nachsten Absatz gueltig.
1380 	if( bSaveNum )
1381 	{
1382 		pOldNumRuleInfo = new SwHTMLNumRuleInfo( rWrt.GetNumInfo() );
1383 		pOldNextNumRuleInfo = rWrt.GetNextNumInfo();
1384 		rWrt.SetNextNumInfo( 0 );
1385 	}
1386 	else
1387 	{
1388 		rWrt.ClearNextNumInfo();
1389 	}
1390 
1391 	// Die Numerierung wird in jedem Fall unterbrochen.
1392 	rWrt.GetNumInfo().Clear();
1393 
1394 	if( pFrmFmt )
1395 		rWrt.nDirection = rWrt.GetHTMLDirection( pFrmFmt->GetAttrSet() );
1396 }
1397 
1398 
1399 HTMLSaveData::~HTMLSaveData()
1400 {
1401 	delete rWrt.pCurPam;					// Pam wieder loeschen
1402 
1403 	rWrt.pCurPam = pOldPam;
1404 	rWrt.SetEndPaM( pOldEnd );
1405 	rWrt.bWriteAll = bOldWriteAll;
1406     rWrt.nBkmkTabPos = bOldWriteAll ? rWrt.FindPos_Bkmk( *pOldPam->GetPoint() ) : -1;
1407 	rWrt.nLastParaToken = 0;
1408 	rWrt.nDefListLvl = nOldDefListLvl;
1409 	rWrt.nDirection = nOldDirection;
1410 	rWrt.bOutHeader = bOldOutHeader;
1411 	rWrt.bOutFooter = bOldOutFooter;
1412 	rWrt.bOutFlyFrame = bOldOutFlyFrame;
1413 
1414 	// Ggf. die Numerierung von vor der Section fortsetzen. Die Numerierung
1415 	// des naecshten Absatz wird in jedem Fall ungueltig.
1416 	if( pOldNumRuleInfo )
1417 	{
1418 		rWrt.GetNumInfo().Set( *pOldNumRuleInfo );
1419 		delete pOldNumRuleInfo;
1420 		rWrt.SetNextNumInfo( pOldNextNumRuleInfo );
1421 	}
1422 	else
1423 	{
1424 		rWrt.GetNumInfo().Clear();
1425 		rWrt.ClearNextNumInfo();
1426 	}
1427 }
1428 
1429 
1430 void GetHTMLWriter( const String&, const String& rBaseURL, WriterRef& xRet )
1431 {
1432     xRet = new SwHTMLWriter( rBaseURL );
1433 }
1434 
1435 
1436