build fix
[LibreOffice.git] / sw / source / filter / html / wrthtml.cxx
blob09627bdf89853d4c257ec6695c7a490f8cb00705
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <stdlib.h>
21 #include <hintids.hxx>
22 #include <comphelper/string.hxx>
23 #include <svl/urihelper.hxx>
24 #include <rtl/tencinfo.h>
25 #include <vcl/wrkwin.hxx>
26 #include <sfx2/linkmgr.hxx>
28 #include <svtools/htmlcfg.hxx>
29 #include <vcl/svapp.hxx>
30 #include <i18nlangtag/languagetag.hxx>
31 #include <sfx2/frmhtmlw.hxx>
32 #include <svx/xoutbmp.hxx>
33 #include <svx/unobrushitemhelper.hxx>
34 #include <sfx2/htmlmode.hxx>
35 #include <editeng/lrspitem.hxx>
36 #include <editeng/colritem.hxx>
37 #include <editeng/brushitem.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <editeng/scripttypeitem.hxx>
40 #include <editeng/langitem.hxx>
41 #include <svl/stritem.hxx>
42 #include <editeng/frmdiritem.hxx>
44 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
45 #include <com/sun/star/document/XDocumentProperties.hpp>
46 #include <com/sun/star/form/XFormsSupplier.hpp>
47 #include <com/sun/star/form/XForm.hpp>
48 #include <com/sun/star/form/XImageProducerSupplier.hpp>
49 #include <com/sun/star/form/XFormController.hpp>
50 #include <com/sun/star/container/XContainer.hpp>
51 #include <com/sun/star/container/XIndexContainer.hpp>
52 #include <com/sun/star/container/XSet.hpp>
53 #include <fmthdft.hxx>
54 #include <fmtfld.hxx>
55 #include <fmtpdsc.hxx>
56 #include <txatbase.hxx>
57 #include <frmatr.hxx>
58 #include <charfmt.hxx>
59 #include <docary.hxx>
60 #include <pam.hxx>
61 #include <doc.hxx>
62 #include <ndtxt.hxx>
63 #include <mdiexp.hxx>
64 #include <fltini.hxx>
65 #include <viewopt.hxx>
66 #include <IMark.hxx>
67 #include <poolfmt.hxx>
68 #include <pagedesc.hxx>
69 #include <section.hxx>
70 #include <swtable.hxx>
71 #include <fldbas.hxx>
72 #include <fmtclds.hxx>
73 #include <docsh.hxx>
74 #include <wrthtml.hxx>
75 #include <htmlnum.hxx>
76 #include <htmlfly.hxx>
77 #include <swmodule.hxx>
78 #include <statstr.hrc>
79 #include <swerror.h>
80 #include <rtl/strbuf.hxx>
81 #include <IDocumentSettingAccess.hxx>
82 #include <IDocumentStylePoolAccess.hxx>
83 #include <xmloff/odffields.hxx>
84 #include <tools/urlobj.hxx>
86 #define MAX_INDENT_LEVEL 20
88 using namespace css;
90 static sal_Char sIndentTabs[MAX_INDENT_LEVEL+2] =
91 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
93 SwHTMLWriter::SwHTMLWriter( const OUString& rBaseURL )
94 : m_pHTMLPosFlyFrames(nullptr)
95 , m_pNumRuleInfo(new SwHTMLNumRuleInfo)
96 , m_pNextNumRuleInfo(nullptr)
97 , m_nHTMLMode(0)
98 , m_eCSS1Unit(FUNIT_NONE)
99 , m_pFootEndNotes(nullptr)
100 , mxFormComps()
101 , m_pTemplate(nullptr)
102 , m_pDfltColor(nullptr)
103 , m_pStartNdIdx(nullptr)
104 , m_pCurrPageDesc(nullptr)
105 , m_pFormatFootnote(nullptr)
106 , m_nWarn(0)
107 , m_nLastLFPos(0)
108 , m_nLastParaToken(0)
109 , m_nBkmkTabPos(-1)
110 , m_nImgMapCnt(1)
111 , m_nFormCntrlCnt(0)
112 , m_nEndNote(0)
113 , m_nFootNote(0)
114 , m_nLeftMargin(0)
115 , m_nDfltLeftMargin(0)
116 , m_nDfltRightMargin(0)
117 , m_nFirstLineIndent(0)
118 , m_nDfltFirstLineIndent(0)
119 , m_nDfltTopMargin(0)
120 , m_nDfltBottomMargin(0)
121 , m_nIndentLvl(0)
122 , m_nWhishLineLen(0)
123 , m_nDefListLvl(0)
124 , m_nDefListMargin(0)
125 , m_nHeaderFooterSpace(0)
126 , m_nTextAttrsToIgnore(0)
127 , m_nExportMode(0)
128 , m_nCSS1OutMode(0)
129 , m_nCSS1Script(CSS1_OUTMODE_WESTERN)
130 , m_nDirection(FRMDIR_HORI_LEFT_TOP)
131 , m_eDestEnc(RTL_TEXTENCODING_MS_1252)
132 , m_eLang(LANGUAGE_DONTKNOW)
133 , m_bCfgOutStyles( false )
134 , m_bCfgPreferStyles( false )
135 , m_bCfgFormFeed( false )
136 , m_bCfgStarBasic( false )
137 , m_bCfgCpyLinkedGrfs( false )
138 , m_bFirstLine(true)
139 , m_bTagOn( false )
140 , m_bTextAttr( false )
141 , m_bOutOpts( false )
142 , m_bOutTable( false )
143 , m_bOutHeader( false )
144 , m_bOutFooter( false )
145 , m_bOutFlyFrame( false )
146 , m_bFirstCSS1Rule( false )
147 , m_bFirstCSS1Property( false )
148 , m_bPoolCollTextModified( false )
149 , m_bCSS1IgnoreFirstPageDesc( false )
150 , m_bNoAlign( false )
151 , m_bClearLeft( false )
152 , m_bClearRight( false )
153 , m_bLFPossible( false )
154 , m_bPreserveForm( false )
155 , m_bCfgNetscape4( false )
156 , mbSkipImages(false)
157 , mbSkipHeaderFooter(false)
158 , mbEmbedImages(false)
159 , m_bCfgPrintLayout( false )
160 , m_bParaDotLeaders( false )
162 SetBaseURL(rBaseURL);
165 SwHTMLWriter::~SwHTMLWriter()
167 delete m_pNumRuleInfo;
170 void SwHTMLWriter::SetupFilterOptions(SfxMedium& rMedium)
172 const SfxItemSet* pSet = rMedium.GetItemSet();
173 if (pSet == nullptr)
174 return;
176 const SfxPoolItem* pItem;
177 if (pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) != SfxItemState::SET)
178 return;
181 OUString sFilterOptions = static_cast<const SfxStringItem*>(pItem)->GetValue();
182 if (sFilterOptions == "SkipImages")
184 mbSkipImages = true;
186 else if (sFilterOptions == "SkipHeaderFooter")
188 mbSkipHeaderFooter = true;
190 else if (sFilterOptions == "EmbedImages" )
192 mbEmbedImages = true;
196 sal_uLong SwHTMLWriter::WriteStream()
198 SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
200 // font heights 1-7
201 m_aFontHeights[0] = rHtmlOptions.GetFontSize( 0 ) * 20;
202 m_aFontHeights[1] = rHtmlOptions.GetFontSize( 1 ) * 20;
203 m_aFontHeights[2] = rHtmlOptions.GetFontSize( 2 ) * 20;
204 m_aFontHeights[3] = rHtmlOptions.GetFontSize( 3 ) * 20;
205 m_aFontHeights[4] = rHtmlOptions.GetFontSize( 4 ) * 20;
206 m_aFontHeights[5] = rHtmlOptions.GetFontSize( 5 ) * 20;
207 m_aFontHeights[6] = rHtmlOptions.GetFontSize( 6 ) * 20;
209 // ueberhaupt Styles ausgeben
210 // (dann auch obere und untere Absatz-Abstaende)
211 m_nExportMode = rHtmlOptions.GetExportMode();
212 m_nHTMLMode = GetHtmlMode(nullptr);
214 if( HTML_CFG_WRITER == m_nExportMode || HTML_CFG_NS40 == m_nExportMode )
215 m_nHTMLMode |= HTMLMODE_BLOCK_SPACER;
217 if( HTML_CFG_WRITER == m_nExportMode || HTML_CFG_MSIE == m_nExportMode )
218 m_nHTMLMode |= (HTMLMODE_FLOAT_FRAME | HTMLMODE_LSPACE_IN_NUMBUL);
220 if( HTML_CFG_MSIE == m_nExportMode )
221 m_nHTMLMode |= HTMLMODE_NBSP_IN_TABLES;
223 if( HTML_CFG_WRITER == m_nExportMode || HTML_CFG_NS40 == m_nExportMode || HTML_CFG_MSIE == m_nExportMode )
224 m_nHTMLMode |= HTMLMODE_ABS_POS_FLY | HTMLMODE_ABS_POS_DRAW;
226 if( HTML_CFG_WRITER == m_nExportMode )
227 m_nHTMLMode |= HTMLMODE_FLY_MARGINS;
229 if( HTML_CFG_NS40 == m_nExportMode )
230 m_nHTMLMode |= HTMLMODE_BORDER_NONE;
232 m_nHTMLMode |= HTMLMODE_FONT_GENERIC;
234 if( HTML_CFG_NS40==m_nExportMode )
235 m_nHTMLMode |= HTMLMODE_NO_CONTROL_CENTERING;
237 m_bCfgOutStyles = IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES);
238 m_bCfgNetscape4 = (HTML_CFG_NS40 == m_nExportMode);
240 if( IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES) )
241 m_nHTMLMode |= HTMLMODE_PRINT_EXT;
243 const sal_Char *pHelpHack = getenv( "HelpEx" );
244 if( pHelpHack )
246 OString aTmp(pHelpHack);
247 if (aTmp.equalsIgnoreAsciiCase("Hilfe"))
248 m_nHTMLMode |= HTMLMODE_NO_BR_AT_PAREND;
251 m_eCSS1Unit = (FieldUnit)SW_MOD()->GetMetric( pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) );
253 bool bWriteUTF8 = bWriteClipboardDoc;
254 m_eDestEnc = bWriteUTF8 ? RTL_TEXTENCODING_UTF8 : rHtmlOptions.GetTextEncoding();
255 const sal_Char *pCharSet = rtl_getBestMimeCharsetFromTextEncoding( m_eDestEnc );
256 m_eDestEnc = rtl_getTextEncodingFromMimeCharset( pCharSet );
258 // Nur noch fuer den MS-IE ziehen wir den Export von Styles vor.
259 m_bCfgPreferStyles = HTML_CFG_MSIE == m_nExportMode;
261 m_bCfgStarBasic = rHtmlOptions.IsStarBasic();
263 m_bCfgFormFeed = !IsHTMLMode(HTMLMODE_PRINT_EXT);
264 m_bCfgCpyLinkedGrfs = rHtmlOptions.IsSaveGraphicsLocal();
266 m_bCfgPrintLayout = rHtmlOptions.IsPrintLayoutExtension();
268 // die HTML-Vorlage holen
269 bool bOldHTMLMode = false;
270 SwTextFormatColls::size_type nOldTextFormatCollCnt = 0;
271 SwCharFormats::size_type nOldCharFormatCnt = 0;
273 OSL_ENSURE( !m_pTemplate, "Wo kommt denn die HTML-Vorlage hier her?" );
274 m_pTemplate = static_cast<HTMLReader*>(ReadHTML)->GetTemplateDoc();
275 if( m_pTemplate )
277 m_pTemplate->acquire();
278 bOldHTMLMode = m_pTemplate->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE);
279 m_pTemplate->getIDocumentSettingAccess().set(DocumentSettingId::HTML_MODE, true);
281 nOldTextFormatCollCnt = m_pTemplate->GetTextFormatColls()->size();
282 nOldCharFormatCnt = m_pTemplate->GetCharFormats()->size();
285 if( bShowProgress )
286 ::StartProgress( STR_STATSTR_W4WWRITE, 0, pDoc->GetNodes().Count(),
287 pDoc->GetDocShell());
289 m_pDfltColor = nullptr;
290 m_pFootEndNotes = nullptr;
291 m_pFormatFootnote = nullptr;
292 m_bOutTable = m_bOutHeader = m_bOutFooter = m_bOutFlyFrame = false;
293 mxFormComps.clear();
294 m_nFormCntrlCnt = 0;
295 m_bPreserveForm = false;
296 m_bClearLeft = m_bClearRight = false;
297 m_bLFPossible = false;
299 m_nLeftMargin = m_nDfltLeftMargin = m_nDfltRightMargin = 0;
300 m_nDfltTopMargin = m_nDfltBottomMargin = 0;
301 m_nFirstLineIndent = m_nDfltFirstLineIndent = 0;
302 m_bPoolCollTextModified = false;
303 m_bFirstCSS1Property = m_bFirstCSS1Rule = false;
304 m_bCSS1IgnoreFirstPageDesc = false;
305 m_nIndentLvl = 0;
306 m_nWhishLineLen = 70;
307 m_nLastLFPos = 0;
308 m_nDefListLvl = 0;
309 m_nDefListMargin = ((m_pTemplate && !m_bCfgOutStyles) ? m_pTemplate : pDoc)
310 ->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_HTML_DD, false )
311 ->GetLRSpace().GetTextLeft();
312 m_nHeaderFooterSpace = 0;
313 m_nTextAttrsToIgnore = 0;
314 m_nCSS1OutMode = 0;
315 SvtScriptType nScript = SvtLanguageOptions::GetScriptTypeOfLanguage( GetAppLanguage() );
316 switch( nScript )
318 case SvtScriptType::ASIAN:
319 m_nCSS1Script = CSS1_OUTMODE_CJK;
320 break;
321 case SvtScriptType::COMPLEX:
322 m_nCSS1Script = CSS1_OUTMODE_CTL;
323 break;
324 default:
325 m_nCSS1Script = CSS1_OUTMODE_WESTERN;
326 break;
328 m_eLang = static_cast<const SvxLanguageItem&>(pDoc
329 ->GetDefault(GetLangWhichIdFromScript(m_nCSS1Script))).GetLanguage();
331 m_nFootNote = m_nEndNote = 0;
333 m_nWarn = 0;
334 GetNumInfo().Clear();
335 m_pNextNumRuleInfo = nullptr;
337 OString aStartTags;
339 // respect table and section at document beginning
341 SwTableNode * pTNd = pCurPam->GetNode().FindTableNode();
342 if( pTNd && bWriteAll )
344 // mit dem Tabellen-Node anfangen !!
345 pCurPam->GetPoint()->nNode = *pTNd;
347 if( bWriteOnlyFirstTable )
348 pCurPam->GetMark()->nNode = *pTNd->EndOfSectionNode();
351 // erster Node (der einen Seitenumbruch enthalten darf)
352 m_pStartNdIdx = new SwNodeIndex( pCurPam->GetPoint()->nNode );
354 SwSectionNode * pSNd = pCurPam->GetNode().FindSectionNode();
355 while( pSNd )
357 if( bWriteAll )
359 // mit dem Section-Node anfangen !!
360 pCurPam->GetPoint()->nNode = *pSNd;
362 else
364 OSL_ENSURE( FILE_LINK_SECTION != pSNd->GetSection().GetType(),
365 "Export gelinkter Bereiche am Dok-Anfang ist nicht implemntiert" );
367 // nur das Tag fuer die Section merken
368 OString aName = HTMLOutFuncs::ConvertStringToHTML(
369 pSNd->GetSection().GetSectionName(), m_eDestEnc,
370 &m_aNonConvertableCharacters );
372 OStringBuffer sOut;
373 sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_division)
374 .append(' ').append(OOO_STRING_SVTOOLS_HTML_O_id)
375 .append("=\"").append(aName).append('\"').append('>')
376 .append(aStartTags);
377 aStartTags = sOut.makeStringAndClear();
379 // FindSectionNode() an einem SectionNode liefert den selben!
380 pSNd = pSNd->StartOfSectionNode()->FindSectionNode();
384 // Tabelle fuer die freifliegenden Rahmen erzeugen, aber nur wenn
385 // das gesamte Dokument geschrieben wird
386 m_pHTMLPosFlyFrames = nullptr;
387 CollectFlyFrames();
388 m_nLastParaToken = 0;
389 GetControls();
390 CollectLinkTargets();
392 sal_uInt16 nHeaderAttrs = 0;
393 m_pCurrPageDesc = MakeHeader( nHeaderAttrs );
395 m_bLFPossible = true;
397 // Formulare, die nur HiddenControls enthalten ausgeben.
398 OutHiddenForms();
400 if( !aStartTags.isEmpty() )
401 Strm().WriteCharPtr( aStartTags.getStr() );
403 const SfxPoolItem *pItem;
404 const SfxItemSet& rPageItemSet = m_pCurrPageDesc->GetMaster().GetAttrSet();
405 if( !bWriteClipboardDoc && pDoc->GetDocShell() &&
406 (!pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) &&
407 !pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)) &&
408 SfxItemState::SET == rPageItemSet.GetItemState( RES_HEADER, true, &pItem) )
410 const SwFrameFormat *pHeaderFormat =
411 static_cast<const SwFormatHeader *>(pItem)->GetHeaderFormat();
412 if( pHeaderFormat )
413 OutHTML_HeaderFooter( *this, *pHeaderFormat, true );
416 m_nTextAttrsToIgnore = nHeaderAttrs;
417 Out_SwDoc( pOrigPam );
418 m_nTextAttrsToIgnore = 0;
420 if( mxFormComps.is() )
421 OutForm( false, mxFormComps );
423 if( m_pFootEndNotes )
424 OutFootEndNotes();
426 if( !bWriteClipboardDoc && pDoc->GetDocShell() &&
427 (!pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) && !pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)) &&
428 SfxItemState::SET == rPageItemSet.GetItemState( RES_FOOTER, true, &pItem) )
430 const SwFrameFormat *pFooterFormat =
431 static_cast<const SwFormatFooter *>(pItem)->GetFooterFormat();
432 if( pFooterFormat )
433 OutHTML_HeaderFooter( *this, *pFooterFormat, false );
436 if( m_bLFPossible )
437 OutNewLine();
438 if (!mbSkipHeaderFooter)
440 HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_body, false );
441 OutNewLine();
442 HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html, false );
445 // loesche die Tabelle mit den freifliegenden Rahmen
446 OSL_ENSURE( !m_pHTMLPosFlyFrames, "Wurden nicht alle Rahmen ausgegeben" );
447 if( m_pHTMLPosFlyFrames )
449 m_pHTMLPosFlyFrames->DeleteAndDestroyAll();
450 delete m_pHTMLPosFlyFrames;
451 m_pHTMLPosFlyFrames = nullptr;
454 m_aHTMLControls.DeleteAndDestroyAll();
456 if (!m_CharFormatInfos.empty())
457 m_CharFormatInfos.clear();
459 if (!m_TextCollInfos.empty())
460 m_TextCollInfos.clear();
462 if(!m_aImgMapNames.empty())
463 m_aImgMapNames.clear();
465 m_aImplicitMarks.clear();
467 m_aOutlineMarks.clear();
469 m_aOutlineMarkPoss.clear();
471 m_aNumRuleNames.clear();
473 m_aScriptParaStyles.clear();
474 m_aScriptTextStyles.clear();
476 delete m_pDfltColor;
477 m_pDfltColor = nullptr;
479 delete m_pStartNdIdx;
480 m_pStartNdIdx = nullptr;
482 mxFormComps.clear();
484 OSL_ENSURE( !m_pFootEndNotes,
485 "SwHTMLWriter::Write: Footnotes nicht durch OutFootEndNotes geloescht" );
487 m_pCurrPageDesc = nullptr;
489 ClearNextNumInfo();
491 for(OUString & s : m_aBulletGrfs)
492 s.clear();
494 m_aNonConvertableCharacters.clear();
496 if( bShowProgress )
497 ::EndProgress( pDoc->GetDocShell() );
499 if( m_pTemplate )
501 // Waehrend des Exports angelegte Zeichen- und Abastzvorlagen
502 // loeschen
503 auto nTextFormatCollCnt = m_pTemplate->GetTextFormatColls()->size();
504 while( nTextFormatCollCnt > nOldTextFormatCollCnt )
505 m_pTemplate->DelTextFormatColl( --nTextFormatCollCnt );
506 OSL_ENSURE( m_pTemplate->GetTextFormatColls()->size() == nOldTextFormatCollCnt,
507 "falsche Anzahl TextFormatColls geloescht" );
509 auto nCharFormatCnt = m_pTemplate->GetCharFormats()->size();
510 while( nCharFormatCnt > nOldCharFormatCnt )
511 m_pTemplate->DelCharFormat( --nCharFormatCnt );
512 OSL_ENSURE( m_pTemplate->GetCharFormats()->size() == nOldCharFormatCnt,
513 "falsche Anzahl CharFormats geloescht" );
515 // HTML-Modus wieder restaurieren
516 m_pTemplate->getIDocumentSettingAccess().set(DocumentSettingId::HTML_MODE, bOldHTMLMode);
518 if( 0 == m_pTemplate->release() )
519 delete m_pTemplate;
521 m_pTemplate = nullptr;
524 return m_nWarn;
527 static const SwFormatCol *lcl_html_GetFormatCol( const SwSection& rSection,
528 const SwSectionFormat& rFormat )
530 const SwFormatCol *pCol = nullptr;
532 const SfxPoolItem* pItem;
533 if( FILE_LINK_SECTION != rSection.GetType() &&
534 SfxItemState::SET == rFormat.GetAttrSet().GetItemState(RES_COL,false,&pItem) &&
535 static_cast<const SwFormatCol *>(pItem)->GetNumCols() > 1 )
537 pCol = static_cast<const SwFormatCol *>(pItem);
540 return pCol;
543 static bool lcl_html_IsMultiColStart( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
545 bool bRet = false;
546 const SwSectionNode *pSectNd =
547 rHTMLWrt.pDoc->GetNodes()[nIndex]->GetSectionNode();
548 if( pSectNd )
550 const SwSection& rSection = pSectNd->GetSection();
551 const SwSectionFormat *pFormat = rSection.GetFormat();
552 if( pFormat && lcl_html_GetFormatCol( rSection, *pFormat ) )
553 bRet = true;
556 return bRet;
559 static bool lcl_html_IsMultiColEnd( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
561 bool bRet = false;
562 const SwEndNode *pEndNd = rHTMLWrt.pDoc->GetNodes()[nIndex]->GetEndNode();
563 if( pEndNd )
564 bRet = lcl_html_IsMultiColStart( rHTMLWrt,
565 pEndNd->StartOfSectionIndex() );
567 return bRet;
570 static void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt,
571 const SwSection& rSection,
572 const SwSectionFormat& rFormat,
573 const SwFormatCol *pCol,
574 bool bContinued=false )
576 OSL_ENSURE( pCol || !bContinued, "Continuation of DIV" );
578 if( rHTMLWrt.m_bLFPossible )
579 rHTMLWrt.OutNewLine();
581 OStringBuffer sOut;
582 sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_division);
584 const OUString& rName = rSection.GetSectionName();
585 if( !rName.isEmpty() && !bContinued )
587 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_id "=\"");
588 rHTMLWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
589 HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), rName, rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
590 sOut.append('\"');
593 sal_uInt16 nDir = rHTMLWrt.GetHTMLDirection( rFormat.GetAttrSet() );
594 rHTMLWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
595 rHTMLWrt.OutDirection( nDir );
597 if( FILE_LINK_SECTION == rSection.GetType() )
599 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_href "=\"");
600 rHTMLWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
602 const OUString& aFName = rSection.GetLinkFileName();
603 OUString aURL( aFName.getToken(0,sfx2::cTokenSeparator) );
604 OUString aFilter( aFName.getToken(1,sfx2::cTokenSeparator) );
605 OUString aSection( aFName.getToken(2,sfx2::cTokenSeparator) );
607 OUString aEncURL( URIHelper::simpleNormalizedMakeRelative(rHTMLWrt.GetBaseURL(), aURL ) );
608 sal_Unicode cDelim = 255U;
609 bool bURLContainsDelim = (-1 != aEncURL.indexOf( cDelim ) );
611 HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aEncURL,
612 rHTMLWrt.m_eDestEnc,
613 &rHTMLWrt.m_aNonConvertableCharacters );
614 const sal_Char* pDelim = "&#255;";
615 if( !aFilter.isEmpty() || !aSection.isEmpty() || bURLContainsDelim )
616 rHTMLWrt.Strm().WriteCharPtr( pDelim );
617 if( !aFilter.isEmpty() )
618 HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aFilter, rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
619 if( !aSection.isEmpty() || bURLContainsDelim )
620 rHTMLWrt.Strm().WriteCharPtr( pDelim );
621 if( !aSection.isEmpty() )
623 sal_Int32 nPos = aSection.indexOf( '%' );
624 while( nPos != -1 )
626 aSection = aSection.replaceAt(nPos, 1, "%25");
627 nPos = aSection.indexOf( '%', nPos+3 );
629 nPos = aSection.indexOf( cDelim );
630 while( nPos != -1 )
632 aSection = aSection.replaceAt(nPos, 1, "%FF" );
633 nPos = aSection.indexOf( cDelim, nPos+3 );
635 HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aSection,
636 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
638 sOut.append('\"');
640 else if( pCol )
642 // minimum gutter width
643 sal_uInt16 nGutter = pCol->GetGutterWidth( true );
644 if( nGutter!=USHRT_MAX )
646 if( nGutter && Application::GetDefaultDevice() )
648 nGutter = (sal_uInt16)Application::GetDefaultDevice()
649 ->LogicToPixel( Size(nGutter, 0), MapMode(MapUnit::MapTwip) ).Width();
651 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_gutter "=\"" + OString::number(nGutter) + "\"");
655 rHTMLWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
656 if( rHTMLWrt.IsHTMLMode( rHTMLWrt.m_bCfgOutStyles ? HTMLMODE_ON : 0 ) )
657 rHTMLWrt.OutCSS1_SectionFormatOptions( rFormat, pCol );
659 rHTMLWrt.Strm().WriteChar( '>' );
661 rHTMLWrt.m_bLFPossible = true;
662 if( !rName.isEmpty() && !bContinued )
663 rHTMLWrt.OutImplicitMark( rName, "region" );
665 rHTMLWrt.IncIndentLevel();
668 static void lcl_html_OutSectionEndTag( SwHTMLWriter& rHTMLWrt )
670 rHTMLWrt.DecIndentLevel();
671 if( rHTMLWrt.m_bLFPossible )
672 rHTMLWrt.OutNewLine();
673 HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), OOO_STRING_SVTOOLS_HTML_division, false );
674 rHTMLWrt.m_bLFPossible = true;
677 static Writer& OutHTML_Section( Writer& rWrt, const SwSectionNode& rSectNd )
679 SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
681 // End <PRE> and any <DL>, because a definition list's level may
682 // change inside the section.
683 rHTMLWrt.ChangeParaToken( 0 );
684 rHTMLWrt.OutAndSetDefList( 0 );
686 const SwSection& rSection = rSectNd.GetSection();
687 const SwSectionFormat *pFormat = rSection.GetFormat();
688 OSL_ENSURE( pFormat, "Section without a format?" );
690 bool bStartTag = true;
691 bool bEndTag = true;
692 const SwSectionFormat *pSurrFormat = nullptr;
693 const SwSectionNode *pSurrSectNd = nullptr;
694 const SwSection *pSurrSection = nullptr;
695 const SwFormatCol *pSurrCol = nullptr;
697 sal_uInt32 nSectSttIdx = rSectNd.GetIndex();
698 sal_uInt32 nSectEndIdx = rSectNd.EndOfSectionIndex();
699 const SwFormatCol *pCol = lcl_html_GetFormatCol( rSection, *pFormat );
700 if( pCol )
702 // If the next node is a columned section node, too, don't export
703 // an empty section.
704 if( lcl_html_IsMultiColStart( rHTMLWrt, nSectSttIdx+1 ) )
705 bStartTag = false;
707 // The same applies if the section end with another columned section.
708 if( lcl_html_IsMultiColEnd( rHTMLWrt, nSectEndIdx-1 ) )
709 bEndTag = false;
711 //.is there a columned section around this one?
712 const SwStartNode *pSttNd = rSectNd.StartOfSectionNode();
713 if( pSttNd )
715 pSurrSectNd = pSttNd->FindSectionNode();
716 if( pSurrSectNd )
718 const SwStartNode *pBoxSttNd = pSttNd->FindTableBoxStartNode();
719 if( !pBoxSttNd ||
720 pBoxSttNd->GetIndex() < pSurrSectNd->GetIndex() )
722 pSurrSection = &pSurrSectNd->GetSection();
723 pSurrFormat = pSurrSection->GetFormat();
724 if( pSurrFormat )
725 pSurrCol = lcl_html_GetFormatCol( *pSurrSection,
726 *pSurrFormat );
732 // The surrounding section must be closed before the current one is
733 // opended, except that it start immediately before the current one or
734 // another end immediately before the current one
735 if( pSurrCol && nSectSttIdx - pSurrSectNd->GetIndex() > 1 &&
736 !lcl_html_IsMultiColEnd( rHTMLWrt, nSectSttIdx-1 ) )
737 lcl_html_OutSectionEndTag( rHTMLWrt );
739 if( bStartTag )
740 lcl_html_OutSectionStartTag( rHTMLWrt, rSection, *pFormat, pCol );
743 HTMLSaveData aSaveData( rHTMLWrt,
744 rHTMLWrt.pCurPam->GetPoint()->nNode.GetIndex()+1,
745 rSectNd.EndOfSectionIndex(),
746 false, pFormat );
747 rHTMLWrt.Out_SwDoc( rHTMLWrt.pCurPam );
750 rHTMLWrt.pCurPam->GetPoint()->nNode = *rSectNd.EndOfSectionNode();
752 if( bEndTag )
753 lcl_html_OutSectionEndTag( rHTMLWrt );
755 // The surrounding section must be started again, except that it ends
756 // immeditaly behind the current one.
757 if( pSurrCol &&
758 pSurrSectNd->EndOfSectionIndex() - nSectEndIdx > 1 &&
759 !lcl_html_IsMultiColStart( rHTMLWrt, nSectEndIdx+1 ) )
760 lcl_html_OutSectionStartTag( rHTMLWrt, *pSurrSection, *pSurrFormat,
761 pSurrCol, true );
763 return rWrt;
766 void SwHTMLWriter::Out_SwDoc( SwPaM* pPam )
768 bool bSaveWriteAll = bWriteAll; // sichern
770 // suche die naechste text::Bookmark-Position aus der text::Bookmark-Tabelle
771 m_nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
773 // gebe alle Bereiche des Pams in das HTML-File aus.
774 do {
775 bWriteAll = bSaveWriteAll;
776 m_bFirstLine = true;
778 // suche den ersten am Pam-auszugebenen FlyFrame
779 // fehlt noch:
781 while( pCurPam->GetPoint()->nNode.GetIndex() < pCurPam->GetMark()->nNode.GetIndex() ||
782 (pCurPam->GetPoint()->nNode.GetIndex() == pCurPam->GetMark()->nNode.GetIndex() &&
783 pCurPam->GetPoint()->nContent.GetIndex() <= pCurPam->GetMark()->nContent.GetIndex()) )
785 SwNode& rNd = pCurPam->GetNode();
787 OSL_ENSURE( !(rNd.IsGrfNode() || rNd.IsOLENode()),
788 "Grf- oder OLE-Node hier unerwartet" );
789 if( rNd.IsTextNode() )
791 SwTextNode* pTextNd = rNd.GetTextNode();
793 if( !m_bFirstLine )
794 pCurPam->GetPoint()->nContent.Assign( pTextNd, 0 );
796 OutHTML_SwTextNode( *this, *pTextNd );
798 else if( rNd.IsTableNode() )
800 OutHTML_SwTableNode( *this, *rNd.GetTableNode(), nullptr );
801 m_nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
803 else if( rNd.IsSectionNode() )
805 OutHTML_Section( *this, *rNd.GetSectionNode() );
806 m_nBkmkTabPos = bWriteAll ? FindPos_Bkmk( *pCurPam->GetPoint() ) : -1;
808 else if( &rNd == &pDoc->GetNodes().GetEndOfContent() )
809 break;
811 ++pCurPam->GetPoint()->nNode; // Bewegen
812 sal_uInt32 nPos = pCurPam->GetPoint()->nNode.GetIndex();
814 if( bShowProgress )
815 ::SetProgressState( nPos, pDoc->GetDocShell() ); // Wie weit ?
817 /* sollen nur die Selectierten Bereiche gesichert werden, so
818 * duerfen nur die vollstaendigen Nodes gespeichert werde,
819 * d.H. der 1. und n. Node teilweise, der 2. bis n-1. Node
820 * vollstaendig. (vollstaendig heisst mit allen Formaten! )
822 bWriteAll = bSaveWriteAll ||
823 nPos != pCurPam->GetMark()->nNode.GetIndex();
824 m_bFirstLine = false;
825 m_bOutFooter = false; // Nach einem Node keine Fusszeile mehr
828 ChangeParaToken( 0 ); // MIB 8.7.97: Machen wir jetzt hier und nicht
829 // beim Aufrufer
830 OutAndSetDefList( 0 );
832 } while( CopyNextPam( &pPam ) ); // bis alle PaM's bearbeitet
834 bWriteAll = bSaveWriteAll; // wieder auf alten Wert zurueck
837 // schreibe die StyleTabelle, algemeine Angaben,Header/Footer/Footnotes
838 static void OutBodyColor( const sal_Char* pTag, const SwFormat *pFormat,
839 SwHTMLWriter& rHWrt )
841 const SwFormat *pRefFormat = nullptr;
843 if( rHWrt.m_pTemplate )
844 pRefFormat = SwHTMLWriter::GetTemplateFormat( pFormat->GetPoolFormatId(),
845 &rHWrt.m_pTemplate->getIDocumentStylePoolAccess() );
847 const SvxColorItem *pColorItem = nullptr;
849 const SfxItemSet& rItemSet = pFormat->GetAttrSet();
850 const SfxPoolItem *pRefItem = nullptr, *pItem = nullptr;
851 bool bItemSet = SfxItemState::SET == rItemSet.GetItemState( RES_CHRATR_COLOR,
852 true, &pItem);
853 bool bRefItemSet = pRefFormat &&
854 SfxItemState::SET == pRefFormat->GetAttrSet().GetItemState( RES_CHRATR_COLOR,
855 true, &pRefItem);
856 if( bItemSet )
858 // wenn das Item nur in der Vorlage des aktuellen Doks gesetzt
859 // ist oder einen anderen Wert hat, als in der HTML-Vorlage,
860 // wird es gesetzt
861 const SvxColorItem *pCItem = static_cast<const SvxColorItem*>(pItem);
863 if( !bRefItemSet )
865 pColorItem = pCItem;
867 else
869 Color aColor( pCItem->GetValue() );
870 if( COL_AUTO == aColor.GetColor() )
871 aColor.SetColor( COL_BLACK );
873 Color aRefColor( static_cast<const SvxColorItem*>(pRefItem)->GetValue() );
874 if( COL_AUTO == aRefColor.GetColor() )
875 aRefColor.SetColor( COL_BLACK );
877 if( !aColor.IsRGBEqual( aRefColor ) )
878 pColorItem = pCItem;
881 else if( bRefItemSet )
883 // Das Item war in der HTML-Vorlage noch gesetzt, also geben wir
884 // das Default aus
885 pColorItem = static_cast<const SvxColorItem*>(&rItemSet.GetPool()
886 ->GetDefaultItem( RES_CHRATR_COLOR ));
889 if( pColorItem )
891 OStringBuffer sOut;
892 sOut.append(" " + OString(pTag) + "=");
893 rHWrt.Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
894 Color aColor( pColorItem->GetValue() );
895 if( COL_AUTO == aColor.GetColor() )
896 aColor.SetColor( COL_BLACK );
897 HTMLOutFuncs::Out_Color( rHWrt.Strm(), aColor, rHWrt.m_eDestEnc );
898 if( RES_POOLCOLL_STANDARD==pFormat->GetPoolFormatId() )
899 rHWrt.m_pDfltColor = new Color( aColor );
903 sal_uInt16 SwHTMLWriter::OutHeaderAttrs()
905 sal_uLong nIdx = pCurPam->GetPoint()->nNode.GetIndex();
906 sal_uLong nEndIdx = pCurPam->GetMark()->nNode.GetIndex();
908 SwTextNode *pTextNd = nullptr;
909 while( nIdx<=nEndIdx &&
910 nullptr==(pTextNd=pDoc->GetNodes()[nIdx]->GetTextNode()) )
911 nIdx++;
913 OSL_ENSURE( pTextNd, "Kein Text-Node gefunden" );
914 if( !pTextNd || !pTextNd->HasHints() )
915 return 0;
917 sal_uInt16 nAttrs = 0;
918 const size_t nCntAttr = pTextNd->GetSwpHints().Count();
919 sal_Int32 nOldPos = 0;
920 for( size_t i=0; i<nCntAttr; ++i )
922 const SwTextAttr *pHt = pTextNd->GetSwpHints().Get(i);
923 if( !pHt->End() )
925 sal_Int32 nPos = pHt->GetStart();
926 if( nPos-nOldPos > 1
927 || ( pHt->Which() != RES_TXTATR_FIELD
928 && pHt->Which() != RES_TXTATR_ANNOTATION ) )
929 break;
931 const sal_uInt16 nFieldWhich =
932 static_cast<const SwFormatField&>(pHt->GetAttr()).GetField()->GetTyp()->Which();
933 if( RES_POSTITFLD!=nFieldWhich &&
934 RES_SCRIPTFLD!=nFieldWhich )
935 break;
937 OutNewLine();
938 OutHTML_SwFormatField( *this, pHt->GetAttr() );
939 nOldPos = nPos;
940 OSL_ENSURE( nAttrs<SAL_MAX_UINT16, "Too many attributes" );
941 nAttrs++;
945 return nAttrs;
948 const SwPageDesc *SwHTMLWriter::MakeHeader( sal_uInt16 &rHeaderAttrs )
950 OStringBuffer sOut;
951 if (!mbSkipHeaderFooter)
953 sOut.append(OOO_STRING_SVTOOLS_HTML_doctype " " OOO_STRING_SVTOOLS_HTML_doctype40);
954 HTMLOutFuncs::Out_AsciiTag( Strm(), sOut.makeStringAndClear().getStr() );
956 // baue den Vorspann
957 OutNewLine();
958 HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_html );
960 OutNewLine();
961 HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head );
963 IncIndentLevel(); // Inhalt von <HEAD> einruecken
965 // DokumentInfo
966 OString sIndent = GetIndentString();
968 uno::Reference<document::XDocumentProperties> xDocProps;
969 SwDocShell *pDocShell(pDoc->GetDocShell());
970 if (pDocShell)
972 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
973 pDocShell->GetModel(), uno::UNO_QUERY_THROW);
974 xDocProps.set(xDPS->getDocumentProperties());
977 // xDocProps may be null here (when copying)
978 SfxFrameHTMLWriter::Out_DocInfo( Strm(), GetBaseURL(), xDocProps,
979 sIndent.getStr(), m_eDestEnc,
980 &m_aNonConvertableCharacters );
982 // Kommentare und Meta-Tags des ersten Absatzes
983 rHeaderAttrs = OutHeaderAttrs();
985 OutFootEndNoteInfo();
988 const SwPageDesc *pPageDesc = nullptr;
990 // In Nicht-HTML-Dokumenten wird die erste gesetzte Seitenvorlage
991 // exportiert und wenn keine gesetzt ist die Standard-Vorlage
992 sal_uLong nNodeIdx = pCurPam->GetPoint()->nNode.GetIndex();
994 while( nNodeIdx < pDoc->GetNodes().Count() )
996 SwNode *pNd = pDoc->GetNodes()[ nNodeIdx ];
997 if( pNd->IsContentNode() )
999 pPageDesc = static_cast<const SwFormatPageDesc &>(pNd->GetContentNode()
1000 ->GetAttr(RES_PAGEDESC)).GetPageDesc();
1001 break;
1003 else if( pNd->IsTableNode() )
1005 pPageDesc = pNd->GetTableNode()->GetTable().GetFrameFormat()
1006 ->GetPageDesc().GetPageDesc();
1007 break;
1010 nNodeIdx++;
1013 if( !pPageDesc )
1014 pPageDesc = &pDoc->GetPageDesc( 0 );
1016 if (!mbSkipHeaderFooter)
1018 // und nun ... das Style-Sheet!!!
1019 if( m_bCfgOutStyles )
1021 OutStyleSheet( *pPageDesc );
1024 // und nun ... das BASIC und JavaScript!
1025 if( pDoc->GetDocShell() ) // nur mit DocShell ist Basic moeglich
1026 OutBasic();
1028 DecIndentLevel(); // Inhalt von <HEAD> einruecken
1029 OutNewLine();
1030 HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_head, false );
1032 // der Body wird nicht eingerueckt, weil sonst alles eingerueckt waere!
1033 OutNewLine();
1034 sOut.append("<" OOO_STRING_SVTOOLS_HTML_body);
1035 Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1037 // language
1038 OutLanguage( m_eLang );
1040 // Textfarbe ausgeben, wenn sie an der Standard-Vorlage gesetzt ist
1041 // und sich geaendert hat.
1042 OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_text,
1043 pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD, false ),
1044 *this );
1046 // Farben fuer (un)besuchte Links
1047 OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_link,
1048 pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( RES_POOLCHR_INET_NORMAL ),
1049 *this );
1050 OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_vlink,
1051 pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( RES_POOLCHR_INET_VISIT ),
1052 *this );
1054 const SfxItemSet& rItemSet = pPageDesc->GetMaster().GetAttrSet();
1056 // fdo#86857 page styles now contain the XATTR_*, not RES_BACKGROUND
1057 SvxBrushItem const aBrushItem(
1058 getSvxBrushItemFromSourceSet(rItemSet, RES_BACKGROUND));
1059 OutBackground(&aBrushItem, true);
1061 m_nDirection = GetHTMLDirection( rItemSet );
1062 OutDirection( m_nDirection );
1064 if( m_bCfgOutStyles )
1066 OUString dummy;
1067 OutCSS1_BodyTagStyleOpt( *this, rItemSet, dummy );
1069 // Events anhaengen
1070 if( pDoc->GetDocShell() ) // nur mit DocShell ist Basic moeglich
1071 OutBasicBodyEvents();
1073 Strm().WriteChar( '>' );
1076 return pPageDesc;
1079 void SwHTMLWriter::OutAnchor( const OUString& rName )
1081 OStringBuffer sOut;
1082 sOut.append("<" OOO_STRING_SVTOOLS_HTML_anchor " " OOO_STRING_SVTOOLS_HTML_O_name "=\"");
1083 Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1084 HTMLOutFuncs::Out_String( Strm(), rName, m_eDestEnc, &m_aNonConvertableCharacters ).WriteCharPtr( "\">" );
1085 HTMLOutFuncs::Out_AsciiTag( Strm(), OOO_STRING_SVTOOLS_HTML_anchor, false );
1088 void SwHTMLWriter::OutBookmarks()
1090 // hole das aktuelle Bookmark
1091 const ::sw::mark::IMark* pBookmark = nullptr;
1092 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1093 if(m_nBkmkTabPos != -1)
1094 pBookmark = (pMarkAccess->getAllMarksBegin() + m_nBkmkTabPos)->get();
1095 // Ausgabe aller Bookmarks in diesem Absatz. Die Content-Position
1096 // wird vorerst nicht beruecksichtigt!
1097 sal_uInt32 nNode = pCurPam->GetPoint()->nNode.GetIndex();
1098 while( m_nBkmkTabPos != -1
1099 && pBookmark->GetMarkPos().nNode.GetIndex() == nNode )
1101 // Der Bereich derBookmark wird erstam ignoriert, da er von uns
1102 // auch nicht eingelesen wird.
1104 // erst die SWG spezifischen Daten:
1105 if ( dynamic_cast< const ::sw::mark::IBookmark* >(pBookmark) && !pBookmark->GetName().isEmpty() )
1107 OutAnchor( pBookmark->GetName() );
1110 if( ++m_nBkmkTabPos >= pMarkAccess->getAllMarksCount() )
1111 m_nBkmkTabPos = -1;
1112 else
1113 pBookmark = (pMarkAccess->getAllMarksBegin() + m_nBkmkTabPos)->get();
1116 sal_uInt32 nPos;
1117 for( nPos = 0; nPos < m_aOutlineMarkPoss.size() &&
1118 m_aOutlineMarkPoss[nPos] < nNode; nPos++ )
1121 while( nPos < m_aOutlineMarkPoss.size() && m_aOutlineMarkPoss[nPos] == nNode )
1123 OUString sMark( m_aOutlineMarks[nPos] );
1124 OutAnchor( sMark.replace('?', '_') ); // '?' causes problems in IE/Netscape 5
1125 m_aOutlineMarkPoss.erase( m_aOutlineMarkPoss.begin()+nPos );
1126 m_aOutlineMarks.erase( m_aOutlineMarks.begin() + nPos );
1130 void SwHTMLWriter::OutPointFieldmarks( const SwPosition& rPos )
1132 // "point" fieldmarks that occupy single character space, as opposed to
1133 // range fieldmarks that are associated with start and end points.
1135 const IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
1136 if (!pMarkAccess)
1137 return;
1139 const sw::mark::IFieldmark* pMark = pMarkAccess->getFieldmarkFor(rPos);
1140 if (!pMark)
1141 return;
1143 if (pMark->GetFieldname() == ODF_FORMCHECKBOX)
1145 const sw::mark::ICheckboxFieldmark* pCheckBox =
1146 dynamic_cast<const sw::mark::ICheckboxFieldmark*>(pMark);
1148 if (pCheckBox)
1150 OString aOut("<");
1151 aOut += OOO_STRING_SVTOOLS_HTML_input;
1152 aOut += " ";
1153 aOut += OOO_STRING_SVTOOLS_HTML_O_type;
1154 aOut += "=\"";
1155 aOut += OOO_STRING_SVTOOLS_HTML_IT_checkbox;
1156 aOut += "\"";
1158 if (pCheckBox->IsChecked())
1160 aOut += " ";
1161 aOut += OOO_STRING_SVTOOLS_HTML_O_checked;
1162 aOut += "=\"";
1163 aOut += OOO_STRING_SVTOOLS_HTML_O_checked;
1164 aOut += "\"";
1167 aOut += "/>";
1168 Strm().WriteCharPtr(aOut.getStr());
1172 // TODO : Handle other single-point fieldmark types here (if any).
1175 void SwHTMLWriter::OutImplicitMark( const OUString& rMark,
1176 const sal_Char *pMarkType )
1178 if( !rMark.isEmpty() && !m_aImplicitMarks.empty() )
1180 OUString sMark(rMark + OUStringLiteral1(cMarkSeparator) + OUString::createFromAscii(pMarkType));
1181 if( 0 != m_aImplicitMarks.erase( sMark ) )
1183 OutAnchor(sMark.replace('?', '_')); // '?' causes problems in IE/Netscape 5
1188 OUString SwHTMLWriter::convertHyperlinkHRefValue(const OUString& rURL)
1190 OUString sURL(rURL);
1191 sal_Int32 nPos = sURL.lastIndexOf(cMarkSeparator);
1192 if (nPos != -1)
1194 OUString sCompare = sURL.copy(nPos + 1).replaceAll(" ", "");
1195 if (!sCompare.isEmpty())
1197 sCompare = sCompare.toAsciiLowerCase();
1198 if( sCompare == "region" || sCompare == "frame" ||
1199 sCompare == "graphic" || sCompare == "ole" ||
1200 sCompare == "table" || sCompare == "outline" ||
1201 sCompare == "text" )
1203 sURL = sURL.replace( '?', '_' ); // '?' causes problems in IE/Netscape 5
1207 else if (!sURL.isEmpty() && sURL[0] != '#')
1209 // Link is not started from "#", so looks like external link. Encode this URL.
1210 INetURLObject aURL(sURL);
1211 sURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
1213 return URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), sURL );
1216 void SwHTMLWriter::OutHyperlinkHRefValue( const OUString& rURL )
1218 OUString sURL = convertHyperlinkHRefValue(rURL);
1219 HTMLOutFuncs::Out_String( Strm(), sURL, m_eDestEnc, &m_aNonConvertableCharacters );
1222 void SwHTMLWriter::OutBackground( const SvxBrushItem *pBrushItem, bool bGraphic )
1224 const Color &rBackColor = pBrushItem->GetColor();
1225 /// check, if background color is not "no fill"/"auto fill", instead of
1226 /// only checking, if transparency is not set.
1227 if( rBackColor.GetColor() != COL_TRANSPARENT )
1229 OStringBuffer sOut;
1230 sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_bgcolor).append('=');
1231 Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1232 HTMLOutFuncs::Out_Color( Strm(), rBackColor, m_eDestEnc);
1235 if( !bGraphic )
1236 return;
1238 OUString aGraphicInBase64;
1239 const Graphic* pGrf = pBrushItem->GetGraphic();
1240 OUString GraphicURL = pBrushItem->GetGraphicLink();
1241 if( mbEmbedImages || GraphicURL.isEmpty())
1243 if( pGrf )
1245 if( !XOutBitmap::GraphicToBase64(*pGrf, aGraphicInBase64) )
1247 m_nWarn = WARN_SWG_POOR_LOAD | WARN_SW_WRITE_BASE;
1249 Strm().WriteCharPtr( " " OOO_STRING_SVTOOLS_HTML_O_background "=\"" );
1250 Strm().WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_data ":" );
1251 HTMLOutFuncs::Out_String( Strm(), aGraphicInBase64, m_eDestEnc, &m_aNonConvertableCharacters ).WriteChar( '\"' );
1254 else
1256 if( m_bCfgCpyLinkedGrfs )
1258 CopyLocalFileToINet( GraphicURL );
1260 OUString s( URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), GraphicURL));
1261 Strm().WriteCharPtr(" " OOO_STRING_SVTOOLS_HTML_O_background "=\"" );
1262 HTMLOutFuncs::Out_String( Strm(), s, m_eDestEnc, &m_aNonConvertableCharacters );
1263 Strm().WriteCharPtr("\"");
1268 void SwHTMLWriter::OutBackground( const SfxItemSet& rItemSet, bool bGraphic )
1270 const SfxPoolItem* pItem;
1271 if( SfxItemState::SET == rItemSet.GetItemState( RES_BACKGROUND, false,
1272 &pItem ))
1274 OutBackground( static_cast<const SvxBrushItem*>(pItem), bGraphic );
1278 sal_uInt16 SwHTMLWriter::GetLangWhichIdFromScript( sal_uInt16 nScript )
1280 sal_uInt16 nWhichId;
1281 switch( nScript )
1283 case CSS1_OUTMODE_CJK:
1284 nWhichId = RES_CHRATR_CJK_LANGUAGE;
1285 break;
1286 case CSS1_OUTMODE_CTL:
1287 nWhichId = RES_CHRATR_CJK_LANGUAGE;
1288 break;
1289 default:
1290 nWhichId = RES_CHRATR_LANGUAGE;
1291 break;
1293 return nWhichId;
1296 void SwHTMLWriter::OutLanguage( LanguageType nLang )
1298 if( LANGUAGE_DONTKNOW != nLang )
1300 OStringBuffer sOut;
1301 sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_lang)
1302 .append("=\"");
1303 Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1304 HTMLOutFuncs::Out_String( Strm(), LanguageTag::convertToBcp47(nLang),
1305 m_eDestEnc, &m_aNonConvertableCharacters ).WriteChar( '"' );
1309 sal_uInt16 SwHTMLWriter::GetHTMLDirection( const SfxItemSet& rItemSet ) const
1311 return GetHTMLDirection(
1312 static_cast < const SvxFrameDirectionItem& >( rItemSet.Get( RES_FRAMEDIR ) )
1313 .GetValue() );
1316 sal_uInt16 SwHTMLWriter::GetHTMLDirection( sal_uInt16 nDir ) const
1318 switch( nDir )
1320 case FRMDIR_VERT_TOP_LEFT:
1321 nDir = FRMDIR_HORI_LEFT_TOP;
1322 break;
1323 case FRMDIR_VERT_TOP_RIGHT:
1324 nDir = FRMDIR_HORI_RIGHT_TOP;
1325 break;
1326 case FRMDIR_ENVIRONMENT:
1327 nDir = m_nDirection;
1330 return nDir;
1333 void SwHTMLWriter::OutDirection( sal_uInt16 nDir )
1335 OString sConverted = convertDirection(nDir);
1336 if (!sConverted.isEmpty())
1338 OStringBuffer sOut;
1339 sOut.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_dir)
1340 .append("=\"").append(sConverted).append('\"');
1341 Strm().WriteCharPtr( sOut.makeStringAndClear().getStr() );
1345 OString SwHTMLWriter::convertDirection(sal_uInt16 nDir)
1347 OString sConverted;
1348 switch (nDir)
1350 case FRMDIR_HORI_LEFT_TOP:
1351 case FRMDIR_VERT_TOP_LEFT:
1352 sConverted = "ltr";
1353 break;
1354 case FRMDIR_HORI_RIGHT_TOP:
1355 case FRMDIR_VERT_TOP_RIGHT:
1356 sConverted = "rtl";
1357 break;
1359 return sConverted;
1362 OString SwHTMLWriter::GetIndentString(sal_uInt16 nIncLvl)
1364 OString sRet;
1366 // etwas umstaendlich, aber wir haben nur einen Indent-String!
1367 sal_uInt16 nLevel = m_nIndentLvl + nIncLvl;
1369 if( nLevel && nLevel <= MAX_INDENT_LEVEL)
1371 sIndentTabs[nLevel] = 0;
1372 sRet = sIndentTabs;
1373 sIndentTabs[nLevel] = '\t';
1376 return sRet;
1379 void SwHTMLWriter::OutNewLine( bool bCheck )
1381 if( !bCheck || (Strm().Tell()-m_nLastLFPos) > m_nIndentLvl )
1383 Strm().WriteCharPtr( SAL_NEWLINE_STRING );
1384 m_nLastLFPos = Strm().Tell();
1387 if( m_nIndentLvl && m_nIndentLvl <= MAX_INDENT_LEVEL)
1389 sIndentTabs[m_nIndentLvl] = 0;
1390 Strm().WriteCharPtr( sIndentTabs );
1391 sIndentTabs[m_nIndentLvl] = '\t';
1395 sal_uInt16 SwHTMLWriter::GetHTMLFontSize( sal_uInt32 nHeight ) const
1397 sal_uInt16 nSize = 1;
1398 for( sal_uInt16 i=6; i>0; i-- )
1400 if( nHeight > (m_aFontHeights[i] + m_aFontHeights[i-1])/2 )
1402 nSize = i+1;
1403 break;
1407 return nSize;
1410 // Paragraphs with Table of Contents and other index styles will be typeset with
1411 // dot leaders at the position of the last tabulator in PrintLayout (CSS2) mode
1412 sal_Int32 SwHTMLWriter::indexOfDotLeaders( sal_uInt16 nPoolId, const OUString& rStr )
1414 if (m_bCfgPrintLayout && ((nPoolId >= RES_POOLCOLL_TOX_CNTNT1 && nPoolId <= RES_POOLCOLL_TOX_CNTNT5) ||
1415 (nPoolId >= RES_POOLCOLL_TOX_IDX1 && nPoolId <= RES_POOLCOLL_TOX_IDX3) ||
1416 (nPoolId >= RES_POOLCOLL_TOX_USER1 && nPoolId <= RES_POOLCOLL_TOX_CNTNT10) ||
1417 nPoolId == RES_POOLCOLL_TOX_ILLUS1 || nPoolId == RES_POOLCOLL_TOX_TABLES1 ||
1418 nPoolId == RES_POOLCOLL_TOX_OBJECT1 ||
1419 (nPoolId >= RES_POOLCOLL_TOX_AUTHORITIES1 && nPoolId <= RES_POOLCOLL_TOX_USER10))) {
1420 sal_Int32 i = rStr.lastIndexOf('\t');
1421 // there are only ASCII (Latin-1) characters after the tabulator
1422 if (i > -1 && OUStringToOString(rStr.copy(i + 1), RTL_TEXTENCODING_ASCII_US).indexOf('?') == -1)
1423 return i;
1425 return -1;
1428 // Struktur speichert die aktuellen Daten des Writers zwischen, um
1429 // einen anderen Dokument-Teil auszugeben, wie z.B. Header/Footer
1430 HTMLSaveData::HTMLSaveData(SwHTMLWriter& rWriter, sal_uLong nStt,
1431 sal_uLong nEnd, bool bSaveNum,
1432 const SwFrameFormat *pFrameFormat)
1433 : rWrt(rWriter)
1434 , pOldPam(rWrt.pCurPam)
1435 , pOldEnd(rWrt.GetEndPaM())
1436 , pOldNumRuleInfo(nullptr)
1437 , pOldNextNumRuleInfo(nullptr)
1438 , nOldDefListLvl(rWrt.m_nDefListLvl)
1439 , nOldDirection(rWrt.m_nDirection)
1440 , bOldOutHeader(rWrt.m_bOutHeader)
1441 , bOldOutFooter(rWrt.m_bOutFooter)
1442 , bOldOutFlyFrame(rWrt.m_bOutFlyFrame)
1444 bOldWriteAll = rWrt.bWriteAll;
1446 rWrt.pCurPam = Writer::NewSwPaM( *rWrt.pDoc, nStt, nEnd );
1448 // Tabelle in Sonderbereichen erkennen
1449 if( nStt != rWrt.pCurPam->GetMark()->nNode.GetIndex() )
1451 const SwNode *pNd = rWrt.pDoc->GetNodes()[ nStt ];
1452 if( pNd->IsTableNode() || pNd->IsSectionNode() )
1453 rWrt.pCurPam->GetMark()->nNode = nStt;
1456 rWrt.SetEndPaM( rWrt.pCurPam );
1457 rWrt.pCurPam->Exchange( );
1458 rWrt.bWriteAll = true;
1459 rWrt.m_nDefListLvl = 0;
1460 rWrt.m_bOutHeader = rWrt.m_bOutFooter = false;
1462 // Ggf. die aktuelle Numerierungs-Info merken, damit sie wieder
1463 // neu aufgenommen werden kann. Nur dann belibt auch die Numerierungs-
1464 // Info des nachsten Absatz gueltig.
1465 if( bSaveNum )
1467 pOldNumRuleInfo = new SwHTMLNumRuleInfo( rWrt.GetNumInfo() );
1468 pOldNextNumRuleInfo = rWrt.GetNextNumInfo();
1469 rWrt.SetNextNumInfo( nullptr );
1471 else
1473 rWrt.ClearNextNumInfo();
1476 // Die Numerierung wird in jedem Fall unterbrochen.
1477 rWrt.GetNumInfo().Clear();
1479 if( pFrameFormat )
1480 rWrt.m_nDirection = rWrt.GetHTMLDirection( pFrameFormat->GetAttrSet() );
1483 HTMLSaveData::~HTMLSaveData()
1485 delete rWrt.pCurPam; // Pam wieder loeschen
1487 rWrt.pCurPam = pOldPam;
1488 rWrt.SetEndPaM( pOldEnd );
1489 rWrt.bWriteAll = bOldWriteAll;
1490 rWrt.m_nBkmkTabPos = bOldWriteAll ? rWrt.FindPos_Bkmk( *pOldPam->GetPoint() ) : -1;
1491 rWrt.m_nLastParaToken = 0;
1492 rWrt.m_nDefListLvl = nOldDefListLvl;
1493 rWrt.m_nDirection = nOldDirection;
1494 rWrt.m_bOutHeader = bOldOutHeader;
1495 rWrt.m_bOutFooter = bOldOutFooter;
1496 rWrt.m_bOutFlyFrame = bOldOutFlyFrame;
1498 // Ggf. die Numerierung von vor der Section fortsetzen. Die Numerierung
1499 // des naecshten Absatz wird in jedem Fall ungueltig.
1500 if( pOldNumRuleInfo )
1502 rWrt.GetNumInfo().Set( *pOldNumRuleInfo );
1503 delete pOldNumRuleInfo;
1504 rWrt.SetNextNumInfo( pOldNextNumRuleInfo );
1506 else
1508 rWrt.GetNumInfo().Clear();
1509 rWrt.ClearNextNumInfo();
1513 void GetHTMLWriter( const OUString&, const OUString& rBaseURL, WriterRef& xRet )
1515 xRet = new SwHTMLWriter( rBaseURL );
1518 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */