1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <stdlib.h>
21 #include <hintids.hxx>
22 #include <comphelper/string.hxx>
23 #include <svl/urihelper.hxx>
24 #include <svl/languageoptions.hxx>
25 #include <rtl/tencinfo.h>
26 #include <sfx2/linkmgr.hxx>
27 #include <sfx2/docfile.hxx>
28
29 #include <svtools/htmlcfg.hxx>
30 #include <svtools/htmltokn.h>
31 #include <svtools/htmlkywd.hxx>
32 #include <vcl/svapp.hxx>
33 #include <i18nlangtag/languagetag.hxx>
34 #include <sfx2/frmhtmlw.hxx>
35 #include <svx/xoutbmp.hxx>
36 #include <svx/unobrushitemhelper.hxx>
37 #include <sfx2/htmlmode.hxx>
38 #include <editeng/lrspitem.hxx>
39 #include <editeng/colritem.hxx>
40 #include <editeng/brushitem.hxx>
41 #include <editeng/langitem.hxx>
42 #include <svl/stritem.hxx>
43 #include <editeng/frmdiritem.hxx>
44
45 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
46 #include <com/sun/star/document/XDocumentProperties.hpp>
47 #include <com/sun/star/frame/XModel.hpp>
48 #include <fmthdft.hxx>
49 #include <fmtfld.hxx>
50 #include <fmtpdsc.hxx>
51 #include <txatbase.hxx>
52 #include <frmatr.hxx>
53 #include <charfmt.hxx>
54 #include <docary.hxx>
55 #include <pam.hxx>
56 #include <doc.hxx>
57 #include <ndtxt.hxx>
58 #include <mdiexp.hxx>
59 #include <fltini.hxx>
60 #include <viewopt.hxx>
61 #include <IMark.hxx>
62 #include <poolfmt.hxx>
63 #include <pagedesc.hxx>
64 #include <section.hxx>
65 #include <swtable.hxx>
66 #include <fldbas.hxx>
67 #include <fmtclds.hxx>
68 #include <docsh.hxx>
69 #include "wrthtml.hxx"
70 #include "htmlnum.hxx"
71 #include "htmlfly.hxx"
72 #include <swmodule.hxx>
73 #include <strings.hrc>
74 #include <swerror.h>
75 #include <rtl/strbuf.hxx>
76 #include <IDocumentSettingAccess.hxx>
77 #include <IDocumentStylePoolAccess.hxx>
78 #include <IDocumentMarkAccess.hxx>
79 #include <xmloff/odffields.hxx>
80 #include <tools/urlobj.hxx>
81 #include <osl/file.hxx>
82 #include <tools/stream.hxx>
83 #include <comphelper/scopeguard.hxx>
84 #include <unotools/tempfile.hxx>
85 #include <comphelper/sequenceashashmap.hxx>
86
87 #define MAX_INDENT_LEVEL 20
88
89 using namespace css;
90
91 static char sIndentTabs[MAX_INDENT_LEVEL+2] =
92 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
93
SwHTMLWriter(const OUString & rBaseURL,const OUString & rFilterOptions)94 SwHTMLWriter::SwHTMLWriter( const OUString& rBaseURL, const OUString& rFilterOptions )
95 : m_pNumRuleInfo(new SwHTMLNumRuleInfo)
96 , m_nHTMLMode(0)
97 , m_eCSS1Unit(FieldUnit::NONE)
98 , mxFormComps()
99 , m_pStartNdIdx(nullptr)
100 , m_pCurrPageDesc(nullptr)
101 , m_pFormatFootnote(nullptr)
102 , m_nWarn(0)
103 , m_nLastLFPos(0)
104 , m_nLastParaToken(HtmlTokenId::NONE)
105 , m_nBkmkTabPos(-1)
106 , m_nImgMapCnt(1)
107 , m_nFormCntrlCnt(0)
108 , m_nEndNote(0)
109 , m_nFootNote(0)
110 , m_nLeftMargin(0)
111 , m_nDfltLeftMargin(0)
112 , m_nDfltRightMargin(0)
113 , m_nFirstLineIndent(0)
114 , m_nDfltFirstLineIndent(0)
115 , m_nDfltTopMargin(0)
116 , m_nDfltBottomMargin(0)
117 , m_nIndentLvl(0)
118 , m_nWishLineLen(0)
119 , m_nDefListLvl(0)
120 , m_nDefListMargin(0)
121 , m_nHeaderFooterSpace(0)
122 , m_nTextAttrsToIgnore(0)
123 , m_nExportMode(0)
124 , m_nCSS1OutMode(0)
125 , m_nCSS1Script(CSS1_OUTMODE_WESTERN)
126 , m_nDirection(SvxFrameDirection::Horizontal_LR_TB)
127 , m_eDestEnc(RTL_TEXTENCODING_MS_1252)
128 , m_eLang(LANGUAGE_DONTKNOW)
129 , m_bCfgOutStyles( false )
130 , m_bCfgPreferStyles( false )
131 , m_bCfgFormFeed( false )
132 , m_bCfgStarBasic( false )
133 , m_bCfgCpyLinkedGrfs( false )
134 , m_bFirstLine(true)
135 , m_bTagOn( false )
136 , m_bTextAttr( false )
137 , m_bOutOpts( false )
138 , m_bOutTable( false )
139 , m_bOutHeader( false )
140 , m_bOutFooter( false )
141 , m_bOutFlyFrame( false )
142 , m_bFirstCSS1Rule( false )
143 , m_bFirstCSS1Property( false )
144 , m_bCSS1IgnoreFirstPageDesc( false )
145 , m_bNoAlign( false )
146 , m_bClearLeft( false )
147 , m_bClearRight( false )
148 , m_bLFPossible( false )
149 , m_bPreserveForm( false )
150 , m_bCfgNetscape4( false )
151 , mbSkipImages(false)
152 , mbSkipHeaderFooter(false)
153 , mbEmbedImages(false)
154 , mbIndexingOutput(false)
155 , m_bCfgPrintLayout( false )
156 , m_bParaDotLeaders( false )
157 {
158 SetBaseURL(rBaseURL);
159
160 if (rBaseURL.isEmpty())
161 {
162 // Paste: set base URL to a tempfile, so images are not lost.
163 mpTempBaseURL.reset(new utl::TempFile());
164 mpTempBaseURL->EnableKillingFile();
165 SetBaseURL(mpTempBaseURL->GetURL());
166 }
167
168 SetupFilterOptions(rFilterOptions);
169
170 if (mbXHTML)
171 {
172 m_bNoAlign = true;
173 }
174 }
175
~SwHTMLWriter()176 SwHTMLWriter::~SwHTMLWriter()
177 {
178 }
179
ReleaseNextNumInfo()180 std::unique_ptr<SwHTMLNumRuleInfo> SwHTMLWriter::ReleaseNextNumInfo()
181 {
182 return std::move(m_pNextNumRuleInfo);
183 }
184
SetupFilterOptions(SfxMedium & rMedium)185 void SwHTMLWriter::SetupFilterOptions(SfxMedium& rMedium)
186 {
187 const SfxItemSet* pSet = rMedium.GetItemSet();
188 if (pSet == nullptr)
189 return;
190
191 const SfxPoolItem* pItem;
192 if (pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) != SfxItemState::SET)
193 return;
194
195
196 const OUString sFilterOptions = static_cast<const SfxStringItem*>(pItem)->GetValue();
197 SetupFilterOptions(sFilterOptions);
198
199 comphelper::SequenceAsHashMap aStoreMap(rMedium.GetArgs());
200 auto it = aStoreMap.find("RTFOLEMimeType");
201 if (it != aStoreMap.end())
202 {
203 it->second >>= m_aRTFOLEMimeType;
204 }
205
206 it = aStoreMap.find("ExportImagesAsOLE");
207 if (it != aStoreMap.end())
208 {
209 it->second >>= m_bExportImagesAsOLE;
210 }
211
212 it = aStoreMap.find("ShapeDPI");
213 if (it != aStoreMap.end())
214 {
215 sal_Int32 nVal{};
216 it->second >>= nVal;
217 m_nShapeDPI.emplace(nVal);
218 }
219 }
220
SetupFilterOptions(const OUString & rFilterOptions)221 void SwHTMLWriter::SetupFilterOptions(const OUString& rFilterOptions)
222 {
223 if (rFilterOptions == "SkipImages")
224 {
225 mbSkipImages = true;
226 }
227 else if (rFilterOptions == "SkipHeaderFooter")
228 {
229 mbSkipHeaderFooter = true;
230 }
231 else if (rFilterOptions == "EmbedImages")
232 {
233 mbEmbedImages = true;
234 }
235 else if (rFilterOptions == "IndexingOutput")
236 {
237 mbIndexingOutput = true;
238 mbSkipHeaderFooter = true;
239 mbSkipImages = true;
240 mbXHTML = true;
241 }
242
243 const uno::Sequence<OUString> aOptionSeq = comphelper::string::convertCommaSeparated(rFilterOptions);
244 static const OUStringLiteral aXhtmlNsKey(u"xhtmlns=");
245 for (const auto& rOption : aOptionSeq)
246 {
247 if (rOption == "XHTML")
248 mbXHTML = true;
249 else if (rOption.startsWith(aXhtmlNsKey))
250 {
251 maNamespace = rOption.copy(aXhtmlNsKey.getLength()).toUtf8();
252 if (maNamespace == "reqif-xhtml")
253 {
254 mbReqIF = true;
255 // XHTML is always just a fragment inside ReqIF.
256 mbSkipHeaderFooter = true;
257 }
258 // XHTML namespace implies XHTML.
259 mbXHTML = true;
260 }
261 }
262 }
263
WriteStream()264 ErrCode SwHTMLWriter::WriteStream()
265 {
266 if (!SW_MOD())
267 return ERRCODE_ABORT;
268 // Intercept paste output if requested.
269 char* pPasteEnv = getenv("SW_DEBUG_HTML_PASTE_TO");
270 std::unique_ptr<SvStream> pPasteStream;
271 SvStream* pOldPasteStream = nullptr;
272 if (pPasteEnv)
273 {
274 OUString aPasteStr;
275 if (osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pPasteEnv), aPasteStr)
276 == osl::FileBase::E_None)
277 {
278 pPasteStream.reset(new SvFileStream(aPasteStr, StreamMode::WRITE));
279 pOldPasteStream = &Strm();
280 SetStream(pPasteStream.get());
281 }
282 }
283 comphelper::ScopeGuard g([this, pOldPasteStream] { this->SetStream(pOldPasteStream); });
284
285 HtmlWriter aHtmlWriter(Strm(), GetNamespace());
286
287 SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
288
289 // font heights 1-7
290 m_aFontHeights[0] = rHtmlOptions.GetFontSize( 0 ) * 20;
291 m_aFontHeights[1] = rHtmlOptions.GetFontSize( 1 ) * 20;
292 m_aFontHeights[2] = rHtmlOptions.GetFontSize( 2 ) * 20;
293 m_aFontHeights[3] = rHtmlOptions.GetFontSize( 3 ) * 20;
294 m_aFontHeights[4] = rHtmlOptions.GetFontSize( 4 ) * 20;
295 m_aFontHeights[5] = rHtmlOptions.GetFontSize( 5 ) * 20;
296 m_aFontHeights[6] = rHtmlOptions.GetFontSize( 6 ) * 20;
297
298 // output styles anyway
299 // (then also top and bottom paragraph spacing)
300 m_nExportMode = rHtmlOptions.GetExportMode();
301 m_nHTMLMode = GetHtmlMode(nullptr);
302
303 if( HTML_CFG_WRITER == m_nExportMode || HTML_CFG_NS40 == m_nExportMode )
304 m_nHTMLMode |= HTMLMODE_BLOCK_SPACER;
305
306 if( HTML_CFG_WRITER == m_nExportMode || HTML_CFG_MSIE == m_nExportMode )
307 m_nHTMLMode |= (HTMLMODE_FLOAT_FRAME | HTMLMODE_LSPACE_IN_NUMBER_BULLET);
308
309 if( HTML_CFG_MSIE == m_nExportMode )
310 m_nHTMLMode |= HTMLMODE_NBSP_IN_TABLES;
311
312 if( HTML_CFG_WRITER == m_nExportMode || HTML_CFG_NS40 == m_nExportMode || HTML_CFG_MSIE == m_nExportMode )
313 m_nHTMLMode |= HTMLMODE_ABS_POS_FLY | HTMLMODE_ABS_POS_DRAW;
314
315 if( HTML_CFG_WRITER == m_nExportMode )
316 m_nHTMLMode |= HTMLMODE_FLY_MARGINS;
317
318 if( HTML_CFG_NS40 == m_nExportMode )
319 m_nHTMLMode |= HTMLMODE_BORDER_NONE;
320
321 m_nHTMLMode |= HTMLMODE_FONT_GENERIC;
322
323 if( HTML_CFG_NS40==m_nExportMode )
324 m_nHTMLMode |= HTMLMODE_NO_CONTROL_CENTERING;
325
326 m_bCfgOutStyles = IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES);
327 m_bCfgNetscape4 = (HTML_CFG_NS40 == m_nExportMode);
328
329 if( IsHTMLMode(HTMLMODE_SOME_STYLES | HTMLMODE_FULL_STYLES) )
330 m_nHTMLMode |= HTMLMODE_PRINT_EXT;
331
332 m_eCSS1Unit = SW_MOD()->GetMetric( m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) );
333
334 bool bWriteUTF8 = m_bWriteClipboardDoc;
335 m_eDestEnc = bWriteUTF8 ? RTL_TEXTENCODING_UTF8 : rHtmlOptions.GetTextEncoding();
336 const char *pCharSet = rtl_getBestMimeCharsetFromTextEncoding( m_eDestEnc );
337 m_eDestEnc = rtl_getTextEncodingFromMimeCharset( pCharSet );
338
339 // Only for the MS-IE we favour the export of styles.
340 m_bCfgPreferStyles = HTML_CFG_MSIE == m_nExportMode;
341
342 m_bCfgStarBasic = rHtmlOptions.IsStarBasic();
343
344 m_bCfgFormFeed = !IsHTMLMode(HTMLMODE_PRINT_EXT);
345 m_bCfgCpyLinkedGrfs = rHtmlOptions.IsSaveGraphicsLocal();
346
347 m_bCfgPrintLayout = rHtmlOptions.IsPrintLayoutExtension();
348
349 // get HTML template
350 bool bOldHTMLMode = false;
351 SwTextFormatColls::size_type nOldTextFormatCollCnt = 0;
352 SwCharFormats::size_type nOldCharFormatCnt = 0;
353
354 OSL_ENSURE( !m_xTemplate.is(), "Where is the HTML template coming from?" );
355 m_xTemplate = static_cast<HTMLReader*>(ReadHTML)->GetTemplateDoc(*m_pDoc);
356 if( m_xTemplate.is() )
357 {
358 bOldHTMLMode = m_xTemplate->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE);
359 m_xTemplate->getIDocumentSettingAccess().set(DocumentSettingId::HTML_MODE, true);
360
361 nOldTextFormatCollCnt = m_xTemplate->GetTextFormatColls()->size();
362 nOldCharFormatCnt = m_xTemplate->GetCharFormats()->size();
363 }
364
365 if( m_bShowProgress )
366 ::StartProgress( STR_STATSTR_W4WWRITE, 0, m_pDoc->GetNodes().Count(),
367 m_pDoc->GetDocShell());
368
369 m_xDfltColor.reset();
370 m_xFootEndNotes.reset();
371 m_pFormatFootnote = nullptr;
372 m_bOutTable = m_bOutHeader = m_bOutFooter = m_bOutFlyFrame = false;
373 mxFormComps.clear();
374 m_nFormCntrlCnt = 0;
375 m_bPreserveForm = false;
376 m_bClearLeft = m_bClearRight = false;
377 m_bLFPossible = false;
378
379 m_nLeftMargin = m_nDfltLeftMargin = m_nDfltRightMargin = 0;
380 m_nDfltTopMargin = m_nDfltBottomMargin = 0;
381 m_nFirstLineIndent = m_nDfltFirstLineIndent = 0;
382 m_bFirstCSS1Property = m_bFirstCSS1Rule = false;
383 m_bCSS1IgnoreFirstPageDesc = false;
384 m_nIndentLvl = 0;
385 m_nWishLineLen = 70;
386 m_nLastLFPos = 0;
387 m_nDefListLvl = 0;
388 m_nDefListMargin = ((m_xTemplate.is() && !m_bCfgOutStyles) ? m_xTemplate.get() : m_pDoc)
389 ->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_HTML_DD, false )
390 ->GetLRSpace().GetTextLeft();
391 m_nHeaderFooterSpace = 0;
392 m_nTextAttrsToIgnore = 0;
393 m_nCSS1OutMode = 0;
394 SvtScriptType nScript = SvtLanguageOptions::GetScriptTypeOfLanguage( GetAppLanguage() );
395 switch( nScript )
396 {
397 case SvtScriptType::ASIAN:
398 m_nCSS1Script = CSS1_OUTMODE_CJK;
399 break;
400 case SvtScriptType::COMPLEX:
401 m_nCSS1Script = CSS1_OUTMODE_CTL;
402 break;
403 default:
404 m_nCSS1Script = CSS1_OUTMODE_WESTERN;
405 break;
406 }
407 m_eLang = static_cast<const SvxLanguageItem&>(m_pDoc
408 ->GetDefault(GetLangWhichIdFromScript(m_nCSS1Script))).GetLanguage();
409
410 m_nFootNote = m_nEndNote = 0;
411
412 m_nWarn = ERRCODE_NONE;
413 GetNumInfo().Clear();
414 m_pNextNumRuleInfo = nullptr;
415
416 OString aStartTags;
417
418 // respect table and section at document beginning
419 {
420 SwTableNode * pTNd = m_pCurrentPam->GetNode().FindTableNode();
421 if( pTNd && m_bWriteAll )
422 {
423 // start with table node !!
424 m_pCurrentPam->GetPoint()->nNode = *pTNd;
425
426 if( m_bWriteOnlyFirstTable )
427 m_pCurrentPam->GetMark()->nNode = *pTNd->EndOfSectionNode();
428 }
429
430 // first node (with can contain a page break)
431 m_pStartNdIdx = new SwNodeIndex( m_pCurrentPam->GetPoint()->nNode );
432
433 SwSectionNode * pSNd = m_pCurrentPam->GetNode().FindSectionNode();
434 while( pSNd )
435 {
436 if( m_bWriteAll )
437 {
438 // start with section node !!
439 m_pCurrentPam->GetPoint()->nNode = *pSNd;
440 }
441 else
442 {
443 OSL_ENSURE( SectionType::FileLink != pSNd->GetSection().GetType(),
444 "Export linked areas at document beginning is not implemented" );
445
446 // save only the tag of section
447 OString aName = HTMLOutFuncs::ConvertStringToHTML(
448 pSNd->GetSection().GetSectionName(), m_eDestEnc,
449 &m_aNonConvertableCharacters );
450
451 aStartTags =
452 "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_division
453 " " OOO_STRING_SVTOOLS_HTML_O_id
454 "=\"" + aName + "\">" +
455 aStartTags;
456 }
457 // FindSectionNode() on a SectionNode return the same!
458 pSNd = pSNd->StartOfSectionNode()->FindSectionNode();
459 }
460 }
461
462 // create table of the floating frames, but only when the whole
463 // document is saved
464 m_pHTMLPosFlyFrames = nullptr;
465 CollectFlyFrames();
466 m_nLastParaToken = HtmlTokenId::NONE;
467 GetControls();
468 CollectLinkTargets();
469
470 sal_uInt16 nHeaderAttrs = 0;
471 m_pCurrPageDesc = MakeHeader(aHtmlWriter, nHeaderAttrs);
472
473 m_bLFPossible = true;
474
475 // output forms which contain only HiddenControls
476 OutHiddenForms();
477
478 if( !aStartTags.isEmpty() )
479 Strm().WriteOString( aStartTags );
480
481 const SfxPoolItem *pItem;
482 const SfxItemSet& rPageItemSet = m_pCurrPageDesc->GetMaster().GetAttrSet();
483 if( !m_bWriteClipboardDoc && m_pDoc->GetDocShell() &&
484 (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) &&
485 !m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)) &&
486 SfxItemState::SET == rPageItemSet.GetItemState( RES_HEADER, true, &pItem) )
487 {
488 const SwFrameFormat *pHeaderFormat =
489 static_cast<const SwFormatHeader *>(pItem)->GetHeaderFormat();
490 if( pHeaderFormat )
491 OutHTML_HeaderFooter( *this, *pHeaderFormat, true );
492 }
493
494 m_nTextAttrsToIgnore = nHeaderAttrs;
495 Out_SwDoc( m_pOrigPam );
496 m_nTextAttrsToIgnore = 0;
497
498 if( mxFormComps.is() )
499 OutForm( false, mxFormComps );
500
501 if( m_xFootEndNotes )
502 OutFootEndNotes();
503
504 if( !m_bWriteClipboardDoc && m_pDoc->GetDocShell() &&
505 (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) && !m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)) &&
506 SfxItemState::SET == rPageItemSet.GetItemState( RES_FOOTER, true, &pItem) )
507 {
508 const SwFrameFormat *pFooterFormat =
509 static_cast<const SwFormatFooter *>(pItem)->GetFooterFormat();
510 if( pFooterFormat )
511 OutHTML_HeaderFooter( *this, *pFooterFormat, false );
512 }
513
514 if( m_bLFPossible )
515 OutNewLine();
516 if (!mbSkipHeaderFooter)
517 {
518 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_body), false );
519 OutNewLine();
520 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_html), false );
521 }
522 else if (mbReqIF)
523 {
524 // ReqIF: end xhtml.BlkStruct.class.
525 HTMLOutFuncs::Out_AsciiTag(Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false);
526 }
527 else if (mbIndexingOutput)
528 {
529 aHtmlWriter.end("indexing");
530 }
531
532 // delete the table with floating frames
533 OSL_ENSURE( !m_pHTMLPosFlyFrames, "Were not all frames output?" );
534 m_pHTMLPosFlyFrames.reset();
535
536 m_aHTMLControls.clear();
537
538 m_CharFormatInfos.clear();
539 m_TextCollInfos.clear();
540 m_aImgMapNames.clear();
541 m_aImplicitMarks.clear();
542 m_aOutlineMarks.clear();
543 m_aOutlineMarkPoss.clear();
544 m_aNumRuleNames.clear();
545 m_aScriptParaStyles.clear();
546 m_aScriptTextStyles.clear();
547
548 m_xDfltColor.reset();
549
550 delete m_pStartNdIdx;
551 m_pStartNdIdx = nullptr;
552
553 mxFormComps.clear();
554
555 OSL_ENSURE( !m_xFootEndNotes,
556 "SwHTMLWriter::Write: Footnotes not deleted by OutFootEndNotes" );
557
558 m_pCurrPageDesc = nullptr;
559
560 ClearNextNumInfo();
561
562 for(OUString & s : m_aBulletGrfs)
563 s.clear();
564
565 m_aNonConvertableCharacters.clear();
566
567 if( m_bShowProgress )
568 ::EndProgress( m_pDoc->GetDocShell() );
569
570 if( m_xTemplate.is() )
571 {
572 // delete character and paragraph templates created during export
573 auto nTextFormatCollCnt = m_xTemplate->GetTextFormatColls()->size();
574 while( nTextFormatCollCnt > nOldTextFormatCollCnt )
575 m_xTemplate->DelTextFormatColl( --nTextFormatCollCnt );
576 OSL_ENSURE( m_xTemplate->GetTextFormatColls()->size() == nOldTextFormatCollCnt,
577 "wrong number of TextFormatColls deleted" );
578
579 auto nCharFormatCnt = m_xTemplate->GetCharFormats()->size();
580 while( nCharFormatCnt > nOldCharFormatCnt )
581 m_xTemplate->DelCharFormat( --nCharFormatCnt );
582 OSL_ENSURE( m_xTemplate->GetCharFormats()->size() == nOldCharFormatCnt,
583 "wrong number of CharFormats deleted" );
584
585 // restore HTML mode
586 m_xTemplate->getIDocumentSettingAccess().set(DocumentSettingId::HTML_MODE, bOldHTMLMode);
587
588 m_xTemplate.clear();
589 }
590
591 return m_nWarn;
592 }
593
lcl_html_GetFormatCol(const SwSection & rSection,const SwSectionFormat & rFormat)594 static const SwFormatCol *lcl_html_GetFormatCol( const SwSection& rSection,
595 const SwSectionFormat& rFormat )
596 {
597 const SwFormatCol *pCol = nullptr;
598
599 const SfxPoolItem* pItem;
600 if( SectionType::FileLink != rSection.GetType() &&
601 SfxItemState::SET == rFormat.GetAttrSet().GetItemState(RES_COL,false,&pItem) &&
602 static_cast<const SwFormatCol *>(pItem)->GetNumCols() > 1 )
603 {
604 pCol = static_cast<const SwFormatCol *>(pItem);
605 }
606
607 return pCol;
608 }
609
lcl_html_IsMultiColStart(const SwHTMLWriter & rHTMLWrt,sal_uLong nIndex)610 static bool lcl_html_IsMultiColStart( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
611 {
612 bool bRet = false;
613 const SwSectionNode *pSectNd =
614 rHTMLWrt.m_pDoc->GetNodes()[nIndex]->GetSectionNode();
615 if( pSectNd )
616 {
617 const SwSection& rSection = pSectNd->GetSection();
618 const SwSectionFormat *pFormat = rSection.GetFormat();
619 if( pFormat && lcl_html_GetFormatCol( rSection, *pFormat ) )
620 bRet = true;
621 }
622
623 return bRet;
624 }
625
lcl_html_IsMultiColEnd(const SwHTMLWriter & rHTMLWrt,sal_uLong nIndex)626 static bool lcl_html_IsMultiColEnd( const SwHTMLWriter& rHTMLWrt, sal_uLong nIndex )
627 {
628 bool bRet = false;
629 const SwEndNode *pEndNd = rHTMLWrt.m_pDoc->GetNodes()[nIndex]->GetEndNode();
630 if( pEndNd )
631 bRet = lcl_html_IsMultiColStart( rHTMLWrt,
632 pEndNd->StartOfSectionIndex() );
633
634 return bRet;
635 }
636
lcl_html_OutSectionStartTag(SwHTMLWriter & rHTMLWrt,const SwSection & rSection,const SwSectionFormat & rFormat,const SwFormatCol * pCol,bool bContinued=false)637 static void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt,
638 const SwSection& rSection,
639 const SwSectionFormat& rFormat,
640 const SwFormatCol *pCol,
641 bool bContinued=false )
642 {
643 OSL_ENSURE( pCol || !bContinued, "Continuation of DIV" );
644
645 if( rHTMLWrt.m_bLFPossible )
646 rHTMLWrt.OutNewLine();
647
648 OStringBuffer sOut;
649 sOut.append('<').append(OOO_STRING_SVTOOLS_HTML_division);
650
651 const OUString& rName = rSection.GetSectionName();
652 if( !rName.isEmpty() && !bContinued )
653 {
654 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_id "=\"");
655 rHTMLWrt.Strm().WriteOString( sOut.makeStringAndClear() );
656 HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), rName, rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
657 sOut.append('\"');
658 }
659
660 SvxFrameDirection nDir = rHTMLWrt.GetHTMLDirection( rFormat.GetAttrSet() );
661 rHTMLWrt.Strm().WriteOString( sOut.makeStringAndClear() );
662 rHTMLWrt.OutDirection( nDir );
663
664 if( SectionType::FileLink == rSection.GetType() )
665 {
666 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_href "=\"");
667 rHTMLWrt.Strm().WriteOString( sOut.makeStringAndClear() );
668
669 const OUString& aFName = rSection.GetLinkFileName();
670 sal_Int32 nIdx{ 0 };
671 OUString aURL( aFName.getToken(0, sfx2::cTokenSeparator, nIdx) );
672 OUString aFilter( aFName.getToken(0, sfx2::cTokenSeparator, nIdx) );
673 OUString aSection( aFName.getToken(0, sfx2::cTokenSeparator, nIdx) );
674
675 OUString aEncURL( URIHelper::simpleNormalizedMakeRelative(rHTMLWrt.GetBaseURL(), aURL ) );
676 sal_Unicode cDelim = 255U;
677 bool bURLContainsDelim = (-1 != aEncURL.indexOf( cDelim ) );
678
679 HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aEncURL,
680 rHTMLWrt.m_eDestEnc,
681 &rHTMLWrt.m_aNonConvertableCharacters );
682 const char* const pDelim = "ÿ";
683 if( !aFilter.isEmpty() || !aSection.isEmpty() || bURLContainsDelim )
684 rHTMLWrt.Strm().WriteCharPtr( pDelim );
685 if( !aFilter.isEmpty() )
686 HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aFilter, rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
687 if( !aSection.isEmpty() || bURLContainsDelim )
688 rHTMLWrt.Strm().WriteCharPtr( pDelim );
689 if( !aSection.isEmpty() )
690 {
691 sal_Int32 nPos = aSection.indexOf( '%' );
692 while( nPos != -1 )
693 {
694 aSection = aSection.replaceAt(nPos, 1, "%25");
695 nPos = aSection.indexOf( '%', nPos+3 );
696 }
697 nPos = aSection.indexOf( cDelim );
698 while( nPos != -1 )
699 {
700 aSection = aSection.replaceAt(nPos, 1, "%FF" );
701 nPos = aSection.indexOf( cDelim, nPos+3 );
702 }
703 HTMLOutFuncs::Out_String( rHTMLWrt.Strm(), aSection,
704 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
705 }
706 sOut.append('\"');
707 }
708 else if( pCol )
709 {
710 // minimum gutter width
711 sal_uInt16 nGutter = pCol->GetGutterWidth( true );
712 if( nGutter!=USHRT_MAX )
713 {
714 if( nGutter && Application::GetDefaultDevice() )
715 {
716 nGutter = o3tl::narrowing<sal_uInt16>(Application::GetDefaultDevice()
717 ->LogicToPixel( Size(nGutter, 0), MapMode(MapUnit::MapTwip) ).Width());
718 }
719 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_gutter "=\"" + OString::number(nGutter) + "\"");
720 }
721 }
722
723 rHTMLWrt.Strm().WriteOString( sOut.makeStringAndClear() );
724 if( rHTMLWrt.IsHTMLMode( rHTMLWrt.m_bCfgOutStyles ? HTMLMODE_ON : 0 ) )
725 rHTMLWrt.OutCSS1_SectionFormatOptions( rFormat, pCol );
726
727 rHTMLWrt.Strm().WriteChar( '>' );
728
729 rHTMLWrt.m_bLFPossible = true;
730 if( !rName.isEmpty() && !bContinued )
731 rHTMLWrt.OutImplicitMark( rName, "region" );
732
733 rHTMLWrt.IncIndentLevel();
734 }
735
lcl_html_OutSectionEndTag(SwHTMLWriter & rHTMLWrt)736 static void lcl_html_OutSectionEndTag( SwHTMLWriter& rHTMLWrt )
737 {
738 rHTMLWrt.DecIndentLevel();
739 if( rHTMLWrt.m_bLFPossible )
740 rHTMLWrt.OutNewLine();
741 HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
742 rHTMLWrt.m_bLFPossible = true;
743 }
744
OutHTML_Section(Writer & rWrt,const SwSectionNode & rSectNd)745 static Writer& OutHTML_Section( Writer& rWrt, const SwSectionNode& rSectNd )
746 {
747 SwHTMLWriter& rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
748
749 // End <PRE> and any <DL>, because a definition list's level may
750 // change inside the section.
751 rHTMLWrt.ChangeParaToken( HtmlTokenId::NONE );
752 rHTMLWrt.OutAndSetDefList( 0 );
753
754 const SwSection& rSection = rSectNd.GetSection();
755 const SwSectionFormat *pFormat = rSection.GetFormat();
756 OSL_ENSURE( pFormat, "Section without a format?" );
757
758 bool bStartTag = true;
759 bool bEndTag = true;
760 const SwSectionFormat *pSurrFormat = nullptr;
761 const SwSectionNode *pSurrSectNd = nullptr;
762 const SwSection *pSurrSection = nullptr;
763 const SwFormatCol *pSurrCol = nullptr;
764
765 sal_uInt32 nSectSttIdx = rSectNd.GetIndex();
766 sal_uInt32 nSectEndIdx = rSectNd.EndOfSectionIndex();
767 const SwFormatCol *pCol = lcl_html_GetFormatCol( rSection, *pFormat );
768 if( pCol )
769 {
770 // If the next node is a columned section node, too, don't export
771 // an empty section.
772 if( lcl_html_IsMultiColStart( rHTMLWrt, nSectSttIdx+1 ) )
773 bStartTag = false;
774
775 // The same applies if the section end with another columned section.
776 if( lcl_html_IsMultiColEnd( rHTMLWrt, nSectEndIdx-1 ) )
777 bEndTag = false;
778
779 // is there a columned section around this one?
780 const SwStartNode *pSttNd = rSectNd.StartOfSectionNode();
781 if( pSttNd )
782 {
783 pSurrSectNd = pSttNd->FindSectionNode();
784 if( pSurrSectNd )
785 {
786 const SwStartNode *pBoxSttNd = pSttNd->FindTableBoxStartNode();
787 if( !pBoxSttNd ||
788 pBoxSttNd->GetIndex() < pSurrSectNd->GetIndex() )
789 {
790 pSurrSection = &pSurrSectNd->GetSection();
791 pSurrFormat = pSurrSection->GetFormat();
792 if( pSurrFormat )
793 pSurrCol = lcl_html_GetFormatCol( *pSurrSection,
794 *pSurrFormat );
795 }
796 }
797 }
798 }
799
800 // The surrounding section must be closed before the current one is
801 // opened, except that it start immediately before the current one or
802 // another end immediately before the current one
803 if( pSurrCol && nSectSttIdx - pSurrSectNd->GetIndex() > 1 &&
804 !lcl_html_IsMultiColEnd( rHTMLWrt, nSectSttIdx-1 ) )
805 lcl_html_OutSectionEndTag( rHTMLWrt );
806
807 if( bStartTag )
808 lcl_html_OutSectionStartTag( rHTMLWrt, rSection, *pFormat, pCol );
809
810 {
811 HTMLSaveData aSaveData( rHTMLWrt,
812 rHTMLWrt.m_pCurrentPam->GetPoint()->nNode.GetIndex()+1,
813 rSectNd.EndOfSectionIndex(),
814 false, pFormat );
815 rHTMLWrt.Out_SwDoc( rHTMLWrt.m_pCurrentPam.get() );
816 }
817
818 rHTMLWrt.m_pCurrentPam->GetPoint()->nNode = *rSectNd.EndOfSectionNode();
819
820 if( bEndTag )
821 lcl_html_OutSectionEndTag( rHTMLWrt );
822
823 // The surrounding section must be started again, except that it ends
824 // immediately behind the current one.
825 if( pSurrCol &&
826 pSurrSectNd->EndOfSectionIndex() - nSectEndIdx > 1 &&
827 !lcl_html_IsMultiColStart( rHTMLWrt, nSectEndIdx+1 ) )
828 lcl_html_OutSectionStartTag( rHTMLWrt, *pSurrSection, *pSurrFormat,
829 pSurrCol, true );
830
831 return rWrt;
832 }
833
Out_SwDoc(SwPaM * pPam)834 void SwHTMLWriter::Out_SwDoc( SwPaM* pPam )
835 {
836 bool bSaveWriteAll = m_bWriteAll; // save
837
838 // search next text::Bookmark position from text::Bookmark table
839 m_nBkmkTabPos = m_bWriteAll ? FindPos_Bkmk( *m_pCurrentPam->GetPoint() ) : -1;
840
841 // output all areas of PaM's in the HTML file
842 do {
843 m_bWriteAll = bSaveWriteAll;
844 m_bFirstLine = true;
845
846 // search for first on PaM created FlyFrame
847 // still missing:
848
849 while( m_pCurrentPam->GetPoint()->nNode.GetIndex() < m_pCurrentPam->GetMark()->nNode.GetIndex() ||
850 (m_pCurrentPam->GetPoint()->nNode.GetIndex() == m_pCurrentPam->GetMark()->nNode.GetIndex() &&
851 m_pCurrentPam->GetPoint()->nContent.GetIndex() <= m_pCurrentPam->GetMark()->nContent.GetIndex()) )
852 {
853 SwNode& rNd = m_pCurrentPam->GetNode();
854
855 OSL_ENSURE( !(rNd.IsGrfNode() || rNd.IsOLENode()),
856 "Unexpected Grf- or OLE-Node here" );
857 if( rNd.IsTextNode() )
858 {
859 SwTextNode* pTextNd = rNd.GetTextNode();
860
861 if( !m_bFirstLine )
862 m_pCurrentPam->GetPoint()->nContent.Assign( pTextNd, 0 );
863
864 OutHTML_SwTextNode( *this, *pTextNd );
865 }
866 else if( rNd.IsTableNode() )
867 {
868 OutHTML_SwTableNode( *this, *rNd.GetTableNode(), nullptr );
869 m_nBkmkTabPos = m_bWriteAll ? FindPos_Bkmk( *m_pCurrentPam->GetPoint() ) : -1;
870 }
871 else if( rNd.IsSectionNode() )
872 {
873 OutHTML_Section( *this, *rNd.GetSectionNode() );
874 m_nBkmkTabPos = m_bWriteAll ? FindPos_Bkmk( *m_pCurrentPam->GetPoint() ) : -1;
875 }
876 else if( &rNd == &m_pDoc->GetNodes().GetEndOfContent() )
877 break;
878
879 ++m_pCurrentPam->GetPoint()->nNode; // move
880 sal_uInt32 nPos = m_pCurrentPam->GetPoint()->nNode.GetIndex();
881
882 if( m_bShowProgress )
883 ::SetProgressState( nPos, m_pDoc->GetDocShell() ); // How far ?
884
885 /* If only the selected area should be saved, so only the complete
886 * nodes should be saved, this means the first and n-th node
887 * partly, the 2nd till n-1 node complete. (complete means with
888 * all formats!)
889 */
890 m_bWriteAll = bSaveWriteAll ||
891 nPos != m_pCurrentPam->GetMark()->nNode.GetIndex();
892 m_bFirstLine = false;
893 m_bOutFooter = false; // after one node no footer anymore
894 }
895
896 ChangeParaToken( HtmlTokenId::NONE ); // MIB 8.7.97: We're doing it here and not at the caller
897 OutAndSetDefList( 0 );
898
899 } while( CopyNextPam( &pPam ) ); // until all PaM's processed
900
901 m_bWriteAll = bSaveWriteAll; // reset to old values
902 }
903
904 // write the StyleTable, general data, header/footer/footnotes
OutBodyColor(const char * pTag,const SwFormat * pFormat,SwHTMLWriter & rHWrt)905 static void OutBodyColor( const char* pTag, const SwFormat *pFormat,
906 SwHTMLWriter& rHWrt )
907 {
908 const SwFormat *pRefFormat = nullptr;
909
910 if( rHWrt.m_xTemplate.is() )
911 pRefFormat = SwHTMLWriter::GetTemplateFormat( pFormat->GetPoolFormatId(),
912 &rHWrt.m_xTemplate->getIDocumentStylePoolAccess() );
913
914 const SvxColorItem *pColorItem = nullptr;
915
916 const SfxItemSet& rItemSet = pFormat->GetAttrSet();
917 const SfxPoolItem *pRefItem = nullptr, *pItem = nullptr;
918 bool bItemSet = SfxItemState::SET == rItemSet.GetItemState( RES_CHRATR_COLOR,
919 true, &pItem);
920 bool bRefItemSet = pRefFormat &&
921 SfxItemState::SET == pRefFormat->GetAttrSet().GetItemState( RES_CHRATR_COLOR,
922 true, &pRefItem);
923 if( bItemSet )
924 {
925 // only when the item is set in the template of the current document
926 // or has a different value as the in HTML template, it will be set
927 const SvxColorItem *pCItem = static_cast<const SvxColorItem*>(pItem);
928
929 if( !bRefItemSet )
930 {
931 pColorItem = pCItem;
932 }
933 else
934 {
935 Color aColor( pCItem->GetValue() );
936 if( COL_AUTO == aColor )
937 aColor = COL_BLACK;
938
939 Color aRefColor( static_cast<const SvxColorItem*>(pRefItem)->GetValue() );
940 if( COL_AUTO == aRefColor )
941 aRefColor = COL_BLACK;
942
943 if( !aColor.IsRGBEqual( aRefColor ) )
944 pColorItem = pCItem;
945 }
946 }
947 else if( bRefItemSet )
948 {
949 // The item was still set in the HTML template so we output the default
950 pColorItem = &rItemSet.GetPool()->GetDefaultItem( RES_CHRATR_COLOR );
951 }
952
953 if( pColorItem )
954 {
955 OString sOut = OString::Concat(" ") + pTag + "=";
956 rHWrt.Strm().WriteOString( sOut );
957 Color aColor( pColorItem->GetValue() );
958 if( COL_AUTO == aColor )
959 aColor = COL_BLACK;
960 HTMLOutFuncs::Out_Color( rHWrt.Strm(), aColor );
961 if( RES_POOLCOLL_STANDARD==pFormat->GetPoolFormatId() )
962 rHWrt.m_xDfltColor = aColor;
963 }
964 }
965
OutHeaderAttrs()966 sal_uInt16 SwHTMLWriter::OutHeaderAttrs()
967 {
968 sal_uLong nIdx = m_pCurrentPam->GetPoint()->nNode.GetIndex();
969 sal_uLong nEndIdx = m_pCurrentPam->GetMark()->nNode.GetIndex();
970
971 SwTextNode *pTextNd = nullptr;
972 while( nIdx<=nEndIdx &&
973 nullptr==(pTextNd=m_pDoc->GetNodes()[nIdx]->GetTextNode()) )
974 nIdx++;
975
976 OSL_ENSURE( pTextNd, "No Text-Node found" );
977 if( !pTextNd || !pTextNd->HasHints() )
978 return 0;
979
980 sal_uInt16 nAttrs = 0;
981 const size_t nCntAttr = pTextNd->GetSwpHints().Count();
982 sal_Int32 nOldPos = 0;
983 for( size_t i=0; i<nCntAttr; ++i )
984 {
985 const SwTextAttr *pHt = pTextNd->GetSwpHints().Get(i);
986 if( !pHt->End() )
987 {
988 sal_Int32 nPos = pHt->GetStart();
989 if( nPos-nOldPos > 1
990 || ( pHt->Which() != RES_TXTATR_FIELD
991 && pHt->Which() != RES_TXTATR_ANNOTATION ) )
992 break;
993
994 const SwFieldIds nFieldWhich =
995 static_cast<const SwFormatField&>(pHt->GetAttr()).GetField()->GetTyp()->Which();
996 if( SwFieldIds::Postit!=nFieldWhich &&
997 SwFieldIds::Script!=nFieldWhich )
998 break;
999
1000 OutNewLine();
1001 OutHTML_SwFormatField( *this, pHt->GetAttr() );
1002 nOldPos = nPos;
1003 OSL_ENSURE( nAttrs<SAL_MAX_UINT16, "Too many attributes" );
1004 nAttrs++;
1005 }
1006 }
1007
1008 return nAttrs;
1009 }
1010
MakeHeader(HtmlWriter & rHtmlWriter,sal_uInt16 & rHeaderAttrs)1011 const SwPageDesc* SwHTMLWriter::MakeHeader(HtmlWriter & rHtmlWriter, sal_uInt16 &rHeaderAttrs )
1012 {
1013 OStringBuffer sOut;
1014 if (!mbSkipHeaderFooter)
1015 {
1016 if (mbXHTML)
1017 sOut.append(OOO_STRING_SVTOOLS_HTML_doctype " " OOO_STRING_SVTOOLS_XHTML_doctype11);
1018 else
1019 sOut.append(OOO_STRING_SVTOOLS_HTML_doctype " " OOO_STRING_SVTOOLS_HTML_doctype40);
1020 HTMLOutFuncs::Out_AsciiTag( Strm(), sOut.makeStringAndClear().getStr() ); // No GetNamespace() here.
1021
1022 // build prelude
1023 OutNewLine();
1024 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_html) );
1025
1026 OutNewLine();
1027
1028 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_head) );
1029
1030 IncIndentLevel(); // indent content of <HEAD>
1031
1032 // DocumentInfo
1033 OString sIndent = GetIndentString();
1034
1035 uno::Reference<document::XDocumentProperties> xDocProps;
1036 SwDocShell *pDocShell(m_pDoc->GetDocShell());
1037 if (pDocShell)
1038 {
1039 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1040 pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1041 xDocProps.set(xDPS->getDocumentProperties());
1042 }
1043
1044 // xDocProps may be null here (when copying)
1045 SfxFrameHTMLWriter::Out_DocInfo( Strm(), GetBaseURL(), xDocProps,
1046 sIndent.getStr(), m_eDestEnc,
1047 &m_aNonConvertableCharacters );
1048
1049 // comments and meta-tags of first paragraph
1050 rHeaderAttrs = OutHeaderAttrs();
1051
1052 OutFootEndNoteInfo();
1053 }
1054 else if (mbIndexingOutput)
1055 {
1056 Strm().WriteCharPtr("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
1057 Strm().WriteCharPtr(SAL_NEWLINE_STRING);
1058 rHtmlWriter.start("indexing");
1059 rHtmlWriter.characters("");
1060 Strm().WriteCharPtr(SAL_NEWLINE_STRING);
1061 }
1062
1063 const SwPageDesc *pPageDesc = nullptr;
1064
1065 // In none HTML documents the first set template will be exported
1066 // and if none is set the default template
1067 sal_uLong nNodeIdx = m_pCurrentPam->GetPoint()->nNode.GetIndex();
1068
1069 while( nNodeIdx < m_pDoc->GetNodes().Count() )
1070 {
1071 SwNode *pNd = m_pDoc->GetNodes()[ nNodeIdx ];
1072 if( pNd->IsContentNode() )
1073 {
1074 pPageDesc = static_cast<const SwFormatPageDesc &>(pNd->GetContentNode()
1075 ->GetAttr(RES_PAGEDESC)).GetPageDesc();
1076 break;
1077 }
1078 else if( pNd->IsTableNode() )
1079 {
1080 pPageDesc = pNd->GetTableNode()->GetTable().GetFrameFormat()
1081 ->GetPageDesc().GetPageDesc();
1082 break;
1083 }
1084
1085 nNodeIdx++;
1086 }
1087
1088 if( !pPageDesc )
1089 pPageDesc = &m_pDoc->GetPageDesc( 0 );
1090
1091 if (!mbSkipHeaderFooter)
1092 {
1093 // and now ... the style sheet!!!
1094 if( m_bCfgOutStyles )
1095 {
1096 OutStyleSheet( *pPageDesc );
1097 }
1098
1099 // and now ... the BASIC and JavaScript!
1100 if( m_pDoc->GetDocShell() ) // BASIC is possible only in case we have a DocShell
1101 OutBasic(*this);
1102
1103 DecIndentLevel(); // indent content of <HEAD>
1104 OutNewLine();
1105
1106 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_head), false );
1107
1108 // the body won't be indented, because then everything would be indented!
1109 OutNewLine();
1110 sOut.append("<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_body);
1111 Strm().WriteOString( sOut.makeStringAndClear() );
1112
1113 // language
1114 OutLanguage( m_eLang );
1115
1116 // output text colour, when it was set in the default template or was changed
1117 OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_text,
1118 m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD, false ),
1119 *this );
1120
1121 // colour of (un)visited links
1122 OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_link,
1123 m_pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( RES_POOLCHR_INET_NORMAL ),
1124 *this );
1125 OutBodyColor( OOO_STRING_SVTOOLS_HTML_O_vlink,
1126 m_pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( RES_POOLCHR_INET_VISIT ),
1127 *this );
1128
1129 const SfxItemSet& rItemSet = pPageDesc->GetMaster().GetAttrSet();
1130
1131 // fdo#86857 page styles now contain the XATTR_*, not RES_BACKGROUND
1132 std::unique_ptr<SvxBrushItem> const aBrushItem(getSvxBrushItemFromSourceSet(rItemSet, RES_BACKGROUND));
1133 OutBackground(aBrushItem.get(), true);
1134
1135 m_nDirection = GetHTMLDirection( rItemSet );
1136 OutDirection( m_nDirection );
1137
1138 if( m_bCfgOutStyles )
1139 {
1140 OutCSS1_BodyTagStyleOpt( *this, rItemSet );
1141 }
1142 // append events
1143 if( m_pDoc->GetDocShell() ) // BASIC is possible only in case we have a DocShell
1144 OutBasicBodyEvents();
1145
1146 Strm().WriteChar( '>' );
1147 }
1148 else if (mbReqIF)
1149 // ReqIF: start xhtml.BlkStruct.class.
1150 HTMLOutFuncs::Out_AsciiTag(Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division));
1151
1152 return pPageDesc;
1153 }
1154
OutAnchor(const OUString & rName)1155 void SwHTMLWriter::OutAnchor( const OUString& rName )
1156 {
1157 OStringBuffer sOut;
1158 sOut.append("<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor " ");
1159 if (!mbXHTML)
1160 {
1161 sOut.append(OOO_STRING_SVTOOLS_HTML_O_name "=\"");
1162 Strm().WriteOString( sOut.makeStringAndClear() );
1163 HTMLOutFuncs::Out_String( Strm(), rName, m_eDestEnc, &m_aNonConvertableCharacters ).WriteCharPtr( "\">" );
1164 }
1165 else
1166 {
1167 // XHTML wants 'id' instead of 'name', also the value can't contain
1168 // spaces.
1169 sOut.append(OOO_STRING_SVTOOLS_HTML_O_id "=\"");
1170 Strm().WriteOString( sOut.makeStringAndClear() );
1171 HTMLOutFuncs::Out_String( Strm(), rName.replace(' ', '_'), m_eDestEnc, &m_aNonConvertableCharacters ).WriteCharPtr( "\">" );
1172 }
1173 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor), false );
1174 }
1175
OutBookmarks()1176 void SwHTMLWriter::OutBookmarks()
1177 {
1178 // fetch current bookmark
1179 const ::sw::mark::IMark* pBookmark = nullptr;
1180 IDocumentMarkAccess* const pMarkAccess = m_pDoc->getIDocumentMarkAccess();
1181 if(m_nBkmkTabPos != -1)
1182 pBookmark = pMarkAccess->getAllMarksBegin()[m_nBkmkTabPos];
1183 // Output all bookmarks in this paragraph. The content position
1184 // for the moment isn't considered!
1185 sal_uInt32 nNode = m_pCurrentPam->GetPoint()->nNode.GetIndex();
1186 while( m_nBkmkTabPos != -1
1187 && pBookmark->GetMarkPos().nNode.GetIndex() == nNode )
1188 {
1189 // The area of bookmarks is first ignored, because it's not read.
1190
1191 // first the SWG specific data:
1192 if ( dynamic_cast< const ::sw::mark::IBookmark* >(pBookmark) && !pBookmark->GetName().isEmpty() )
1193 {
1194 OutAnchor( pBookmark->GetName() );
1195 }
1196
1197 if( ++m_nBkmkTabPos >= pMarkAccess->getAllMarksCount() )
1198 m_nBkmkTabPos = -1;
1199 else
1200 pBookmark = pMarkAccess->getAllMarksBegin()[m_nBkmkTabPos];
1201 }
1202
1203 decltype(m_aOutlineMarkPoss)::size_type nPos;
1204 for( nPos = 0; nPos < m_aOutlineMarkPoss.size() &&
1205 m_aOutlineMarkPoss[nPos] < nNode; nPos++ )
1206 ;
1207
1208 while( nPos < m_aOutlineMarkPoss.size() && m_aOutlineMarkPoss[nPos] == nNode )
1209 {
1210 OUString sMark( m_aOutlineMarks[nPos] );
1211 OutAnchor( sMark.replace('?', '_') ); // '?' causes problems in IE/Netscape 5
1212 m_aOutlineMarkPoss.erase( m_aOutlineMarkPoss.begin()+nPos );
1213 m_aOutlineMarks.erase( m_aOutlineMarks.begin() + nPos );
1214 }
1215 }
1216
OutPointFieldmarks(const SwPosition & rPos)1217 void SwHTMLWriter::OutPointFieldmarks( const SwPosition& rPos )
1218 {
1219 // "point" fieldmarks that occupy single character space, as opposed to
1220 // range fieldmarks that are associated with start and end points.
1221
1222 const IDocumentMarkAccess* pMarkAccess = m_pDoc->getIDocumentMarkAccess();
1223 if (!pMarkAccess)
1224 return;
1225
1226 const sw::mark::IFieldmark* pMark = pMarkAccess->getFieldmarkAt(rPos);
1227 if (!pMark)
1228 return;
1229
1230 if (pMark->GetFieldname() != ODF_FORMCHECKBOX)
1231 return;
1232
1233 const sw::mark::ICheckboxFieldmark* pCheckBox =
1234 dynamic_cast<const sw::mark::ICheckboxFieldmark*>(pMark);
1235
1236 if (!pCheckBox)
1237 return;
1238
1239 OString aOut("<"
1240 OOO_STRING_SVTOOLS_HTML_input
1241 " "
1242 OOO_STRING_SVTOOLS_HTML_O_type
1243 "=\""
1244 OOO_STRING_SVTOOLS_HTML_IT_checkbox
1245 "\"");
1246
1247 if (pCheckBox->IsChecked())
1248 {
1249 aOut += " "
1250 OOO_STRING_SVTOOLS_HTML_O_checked
1251 "=\""
1252 OOO_STRING_SVTOOLS_HTML_O_checked
1253 "\"";
1254 }
1255
1256 aOut += "/>";
1257 Strm().WriteOString(aOut);
1258
1259 // TODO : Handle other single-point fieldmark types here (if any).
1260 }
1261
OutImplicitMark(std::u16string_view rMark,const char * pMarkType)1262 void SwHTMLWriter::OutImplicitMark( std::u16string_view rMark,
1263 const char *pMarkType )
1264 {
1265 if( !rMark.empty() && !m_aImplicitMarks.empty() )
1266 {
1267 OUString sMark(rMark + OUStringChar(cMarkSeparator) + OUString::createFromAscii(pMarkType));
1268 if( 0 != m_aImplicitMarks.erase( sMark ) )
1269 {
1270 OutAnchor(sMark.replace('?', '_')); // '?' causes problems in IE/Netscape 5
1271 }
1272 }
1273 }
1274
convertHyperlinkHRefValue(const OUString & rURL)1275 OUString SwHTMLWriter::convertHyperlinkHRefValue(const OUString& rURL)
1276 {
1277 OUString sURL(rURL);
1278 sal_Int32 nPos = sURL.lastIndexOf(cMarkSeparator);
1279 if (nPos != -1)
1280 {
1281 OUString sCompare = sURL.copy(nPos + 1).replaceAll(" ", "");
1282 if (!sCompare.isEmpty())
1283 {
1284 sCompare = sCompare.toAsciiLowerCase();
1285 if( sCompare == "region" || sCompare == "frame" ||
1286 sCompare == "graphic" || sCompare == "ole" ||
1287 sCompare == "table" || sCompare == "outline" ||
1288 sCompare == "text" )
1289 {
1290 sURL = sURL.replace( '?', '_' ); // '?' causes problems in IE/Netscape 5
1291 }
1292 }
1293 }
1294 else if (!sURL.isEmpty() && sURL[0] != '#')
1295 {
1296 // Link is not started from "#", so looks like external link. Encode this URL.
1297 INetURLObject aURL(sURL);
1298 sURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
1299 }
1300 return URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), sURL );
1301 }
1302
OutHyperlinkHRefValue(const OUString & rURL)1303 void SwHTMLWriter::OutHyperlinkHRefValue( const OUString& rURL )
1304 {
1305 OUString sURL = convertHyperlinkHRefValue(rURL);
1306 HTMLOutFuncs::Out_String( Strm(), sURL, m_eDestEnc, &m_aNonConvertableCharacters );
1307 }
1308
OutBackground(const SvxBrushItem * pBrushItem,bool bGraphic)1309 void SwHTMLWriter::OutBackground( const SvxBrushItem *pBrushItem, bool bGraphic )
1310 {
1311 const Color &rBackColor = pBrushItem->GetColor();
1312 /// check, if background color is not "no fill"/"auto fill", instead of
1313 /// only checking, if transparency is not set.
1314 if( rBackColor != COL_TRANSPARENT )
1315 {
1316 Strm().WriteOString( " " OOO_STRING_SVTOOLS_HTML_O_bgcolor "=" );
1317 HTMLOutFuncs::Out_Color( Strm(), rBackColor);
1318 }
1319
1320 if( !bGraphic )
1321 return;
1322
1323 const Graphic* pGrf = pBrushItem->GetGraphic();
1324 OUString GraphicURL = pBrushItem->GetGraphicLink();
1325 if( mbEmbedImages || GraphicURL.isEmpty())
1326 {
1327 if( pGrf )
1328 {
1329 OUString aGraphicInBase64;
1330 if( !XOutBitmap::GraphicToBase64(*pGrf, aGraphicInBase64) )
1331 {
1332 m_nWarn = WARN_SWG_POOR_LOAD;
1333 }
1334 Strm().WriteCharPtr( " " OOO_STRING_SVTOOLS_HTML_O_background "=\"" );
1335 Strm().WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_data ":" );
1336 HTMLOutFuncs::Out_String( Strm(), aGraphicInBase64, m_eDestEnc, &m_aNonConvertableCharacters ).WriteChar( '\"' );
1337 }
1338 }
1339 else
1340 {
1341 if( m_bCfgCpyLinkedGrfs )
1342 {
1343 CopyLocalFileToINet( GraphicURL );
1344 }
1345 OUString s( URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), GraphicURL));
1346 Strm().WriteCharPtr(" " OOO_STRING_SVTOOLS_HTML_O_background "=\"" );
1347 HTMLOutFuncs::Out_String( Strm(), s, m_eDestEnc, &m_aNonConvertableCharacters );
1348 Strm().WriteCharPtr("\"");
1349
1350 }
1351 }
1352
OutBackground(const SfxItemSet & rItemSet,bool bGraphic)1353 void SwHTMLWriter::OutBackground( const SfxItemSet& rItemSet, bool bGraphic )
1354 {
1355 const SfxPoolItem* pItem;
1356 if( SfxItemState::SET == rItemSet.GetItemState( RES_BACKGROUND, false,
1357 &pItem ))
1358 {
1359 OutBackground( static_cast<const SvxBrushItem*>(pItem), bGraphic );
1360 }
1361 }
1362
GetLangWhichIdFromScript(sal_uInt16 nScript)1363 sal_uInt16 SwHTMLWriter::GetLangWhichIdFromScript( sal_uInt16 nScript )
1364 {
1365 sal_uInt16 nWhichId;
1366 switch( nScript )
1367 {
1368 case CSS1_OUTMODE_CJK:
1369 nWhichId = RES_CHRATR_CJK_LANGUAGE;
1370 break;
1371 case CSS1_OUTMODE_CTL:
1372 nWhichId = RES_CHRATR_CJK_LANGUAGE;
1373 break;
1374 default:
1375 nWhichId = RES_CHRATR_LANGUAGE;
1376 break;
1377 }
1378 return nWhichId;
1379 }
1380
OutLanguage(LanguageType nLang)1381 void SwHTMLWriter::OutLanguage( LanguageType nLang )
1382 {
1383 // ReqIF mode: consumers would ignore language anyway.
1384 if (!(LANGUAGE_DONTKNOW != nLang && !mbReqIF))
1385 return;
1386
1387 OStringBuffer sOut;
1388 sOut.append(' ');
1389 if (mbXHTML)
1390 sOut.append(OOO_STRING_SVTOOLS_XHTML_O_lang);
1391 else
1392 sOut.append(OOO_STRING_SVTOOLS_HTML_O_lang);
1393 sOut.append("=\"");
1394 Strm().WriteOString( sOut.makeStringAndClear() );
1395 HTMLOutFuncs::Out_String( Strm(), LanguageTag::convertToBcp47(nLang),
1396 m_eDestEnc, &m_aNonConvertableCharacters ).WriteChar( '"' );
1397 }
1398
GetHTMLDirection(const SfxItemSet & rItemSet) const1399 SvxFrameDirection SwHTMLWriter::GetHTMLDirection( const SfxItemSet& rItemSet ) const
1400 {
1401 return GetHTMLDirection( rItemSet.Get( RES_FRAMEDIR ).GetValue() );
1402 }
1403
GetHTMLDirection(SvxFrameDirection nDir) const1404 SvxFrameDirection SwHTMLWriter::GetHTMLDirection( SvxFrameDirection nDir ) const
1405 {
1406 switch( nDir )
1407 {
1408 case SvxFrameDirection::Vertical_LR_TB:
1409 nDir = SvxFrameDirection::Horizontal_LR_TB;
1410 break;
1411 case SvxFrameDirection::Vertical_RL_TB:
1412 nDir = SvxFrameDirection::Horizontal_RL_TB;
1413 break;
1414 case SvxFrameDirection::Environment:
1415 nDir = m_nDirection;
1416 break;
1417 default: break;
1418 }
1419
1420 return nDir;
1421 }
1422
OutDirection(SvxFrameDirection nDir)1423 void SwHTMLWriter::OutDirection( SvxFrameDirection nDir )
1424 {
1425 OString sConverted = convertDirection(nDir);
1426 if (!sConverted.isEmpty())
1427 {
1428 OString sOut =
1429 " " OOO_STRING_SVTOOLS_HTML_O_dir
1430 "=\"" + sConverted + "\"";
1431 Strm().WriteOString( sOut );
1432 }
1433 }
1434
convertDirection(SvxFrameDirection nDir)1435 OString SwHTMLWriter::convertDirection(SvxFrameDirection nDir)
1436 {
1437 OString sConverted;
1438 switch (nDir)
1439 {
1440 case SvxFrameDirection::Horizontal_LR_TB:
1441 case SvxFrameDirection::Vertical_LR_TB:
1442 sConverted = "ltr";
1443 break;
1444 case SvxFrameDirection::Horizontal_RL_TB:
1445 case SvxFrameDirection::Vertical_RL_TB:
1446 sConverted = "rtl";
1447 break;
1448 default: break;
1449 }
1450 return sConverted;
1451 }
1452
GetIndentString(sal_uInt16 nIncLvl)1453 OString SwHTMLWriter::GetIndentString(sal_uInt16 nIncLvl)
1454 {
1455 OString sRet;
1456
1457 // somewhat cumbersome, but we have only one indent string!
1458 sal_uInt16 nLevel = m_nIndentLvl + nIncLvl;
1459
1460 if( nLevel && nLevel <= MAX_INDENT_LEVEL)
1461 {
1462 sIndentTabs[nLevel] = 0;
1463 sRet = sIndentTabs;
1464 sIndentTabs[nLevel] = '\t';
1465 }
1466
1467 return sRet;
1468 }
1469
OutNewLine(bool bCheck)1470 void SwHTMLWriter::OutNewLine( bool bCheck )
1471 {
1472 if( !bCheck || (Strm().Tell()-m_nLastLFPos) > m_nIndentLvl )
1473 {
1474 Strm().WriteCharPtr( SAL_NEWLINE_STRING );
1475 m_nLastLFPos = Strm().Tell();
1476 }
1477
1478 if( m_nIndentLvl && m_nIndentLvl <= MAX_INDENT_LEVEL)
1479 {
1480 sIndentTabs[m_nIndentLvl] = 0;
1481 Strm().WriteCharPtr( sIndentTabs );
1482 sIndentTabs[m_nIndentLvl] = '\t';
1483 }
1484 }
1485
GetHTMLFontSize(sal_uInt32 nHeight) const1486 sal_uInt16 SwHTMLWriter::GetHTMLFontSize( sal_uInt32 nHeight ) const
1487 {
1488 sal_uInt16 nSize = 1;
1489 for( sal_uInt16 i=6; i>0; i-- )
1490 {
1491 if( nHeight > (m_aFontHeights[i] + m_aFontHeights[i-1])/2 )
1492 {
1493 nSize = i+1;
1494 break;
1495 }
1496 }
1497
1498 return nSize;
1499 }
1500
1501 // Paragraphs with Table of Contents and other index styles will be typeset with
1502 // dot leaders at the position of the last tabulator in PrintLayout (CSS2) mode
indexOfDotLeaders(sal_uInt16 nPoolId,const OUString & rStr)1503 sal_Int32 SwHTMLWriter::indexOfDotLeaders( sal_uInt16 nPoolId, const OUString& rStr )
1504 {
1505 if (m_bCfgPrintLayout && ((nPoolId >= RES_POOLCOLL_TOX_CNTNT1 && nPoolId <= RES_POOLCOLL_TOX_CNTNT5) ||
1506 (nPoolId >= RES_POOLCOLL_TOX_IDX1 && nPoolId <= RES_POOLCOLL_TOX_IDX3) ||
1507 (nPoolId >= RES_POOLCOLL_TOX_USER1 && nPoolId <= RES_POOLCOLL_TOX_CNTNT10) ||
1508 nPoolId == RES_POOLCOLL_TOX_ILLUS1 || nPoolId == RES_POOLCOLL_TOX_TABLES1 ||
1509 nPoolId == RES_POOLCOLL_TOX_OBJECT1 ||
1510 (nPoolId >= RES_POOLCOLL_TOX_AUTHORITIES1 && nPoolId <= RES_POOLCOLL_TOX_USER10))) {
1511 sal_Int32 i = rStr.lastIndexOf('\t');
1512 // there are only ASCII (Latin-1) characters after the tabulator
1513 if (i > -1 && OUStringToOString(rStr.subView(i + 1), RTL_TEXTENCODING_ASCII_US).indexOf('?') == -1)
1514 return i;
1515 }
1516 return -1;
1517 }
1518
GetNamespace() const1519 OString SwHTMLWriter::GetNamespace() const
1520 {
1521 if (maNamespace.isEmpty())
1522 return OString();
1523
1524 return maNamespace + ":";
1525 }
1526
1527 // Structure caches the current data of the writer to output a
1528 // other part of the document, like e.g. header/footer
HTMLSaveData(SwHTMLWriter & rWriter,sal_uLong nStt,sal_uLong nEnd,bool bSaveNum,const SwFrameFormat * pFrameFormat)1529 HTMLSaveData::HTMLSaveData(SwHTMLWriter& rWriter, sal_uLong nStt,
1530 sal_uLong nEnd, bool bSaveNum,
1531 const SwFrameFormat *pFrameFormat)
1532 : rWrt(rWriter)
1533 , pOldPam(rWrt.m_pCurrentPam)
1534 , pOldEnd(rWrt.GetEndPaM())
1535 , nOldDefListLvl(rWrt.m_nDefListLvl)
1536 , nOldDirection(rWrt.m_nDirection)
1537 , bOldOutHeader(rWrt.m_bOutHeader)
1538 , bOldOutFooter(rWrt.m_bOutFooter)
1539 , bOldOutFlyFrame(rWrt.m_bOutFlyFrame)
1540 {
1541 bOldWriteAll = rWrt.m_bWriteAll;
1542
1543 rWrt.m_pCurrentPam = Writer::NewUnoCursor(*rWrt.m_pDoc, nStt, nEnd);
1544
1545 // recognize table in special areas
1546 if( nStt != rWrt.m_pCurrentPam->GetMark()->nNode.GetIndex() )
1547 {
1548 const SwNode *pNd = rWrt.m_pDoc->GetNodes()[ nStt ];
1549 if( pNd->IsTableNode() || pNd->IsSectionNode() )
1550 rWrt.m_pCurrentPam->GetMark()->nNode = nStt;
1551 }
1552
1553 rWrt.SetEndPaM( rWrt.m_pCurrentPam.get() );
1554 rWrt.m_pCurrentPam->Exchange( );
1555 rWrt.m_bWriteAll = true;
1556 rWrt.m_nDefListLvl = 0;
1557 rWrt.m_bOutHeader = rWrt.m_bOutFooter = false;
1558
1559 // Maybe save the current numbering information, so that it can be started again.
1560 // Only then also the numbering information of the next paragraph will be valid.
1561 if( bSaveNum )
1562 {
1563 pOldNumRuleInfo.reset( new SwHTMLNumRuleInfo( rWrt.GetNumInfo() ) );
1564 pOldNextNumRuleInfo = rWrt.ReleaseNextNumInfo();
1565 }
1566 else
1567 {
1568 rWrt.ClearNextNumInfo();
1569 }
1570
1571 // The numbering will be in any case interrupted.
1572 rWrt.GetNumInfo().Clear();
1573
1574 if( pFrameFormat )
1575 rWrt.m_nDirection = rWrt.GetHTMLDirection( pFrameFormat->GetAttrSet() );
1576 }
1577
~HTMLSaveData()1578 HTMLSaveData::~HTMLSaveData()
1579 {
1580 rWrt.m_pCurrentPam.reset(); // delete PaM again
1581
1582 rWrt.m_pCurrentPam = pOldPam;
1583 rWrt.SetEndPaM( pOldEnd );
1584 rWrt.m_bWriteAll = bOldWriteAll;
1585 rWrt.m_nBkmkTabPos = bOldWriteAll ? rWrt.FindPos_Bkmk( *pOldPam->GetPoint() ) : -1;
1586 rWrt.m_nLastParaToken = HtmlTokenId::NONE;
1587 rWrt.m_nDefListLvl = nOldDefListLvl;
1588 rWrt.m_nDirection = nOldDirection;
1589 rWrt.m_bOutHeader = bOldOutHeader;
1590 rWrt.m_bOutFooter = bOldOutFooter;
1591 rWrt.m_bOutFlyFrame = bOldOutFlyFrame;
1592
1593 // Maybe continue the numbering from before section. The numbering
1594 // of the next paragraph will be invalid in any case.
1595 if( pOldNumRuleInfo )
1596 {
1597 rWrt.GetNumInfo().Set( *pOldNumRuleInfo );
1598 pOldNumRuleInfo.reset();
1599 rWrt.SetNextNumInfo( std::move(pOldNextNumRuleInfo) );
1600 }
1601 else
1602 {
1603 rWrt.GetNumInfo().Clear();
1604 rWrt.ClearNextNumInfo();
1605 }
1606 }
1607
GetHTMLWriter(const OUString & rFilterOptions,const OUString & rBaseURL,WriterRef & xRet)1608 void GetHTMLWriter( const OUString& rFilterOptions, const OUString& rBaseURL, WriterRef& xRet )
1609 {
1610 xRet = new SwHTMLWriter( rBaseURL, rFilterOptions );
1611 }
1612
1613 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1614