crashtesting: assert on reimport of docx export of ooo102874-2.doc
[LibreOffice.git] / sw / source / filter / html / css1atr.cxx
blob6010dba6464bbe0d56fb85a5f8542d24cbfb3e9f
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 <sal/config.h>
22 #include <string_view>
24 #include <hintids.hxx>
25 #include <comphelper/string.hxx>
26 #include <comphelper/xmlencode.hxx>
27 #include <vcl/svapp.hxx>
28 #include <svl/whiter.hxx>
29 #include <editeng/boxitem.hxx>
30 #include <editeng/ulspitem.hxx>
31 #include <editeng/udlnitem.hxx>
32 #include <editeng/crossedoutitem.hxx>
33 #include <editeng/blinkitem.hxx>
34 #include <editeng/cmapitem.hxx>
35 #include <editeng/colritem.hxx>
36 #include <editeng/fontitem.hxx>
37 #include <editeng/fhgtitem.hxx>
38 #include <editeng/postitem.hxx>
39 #include <editeng/kernitem.hxx>
40 #include <editeng/wghtitem.hxx>
41 #include <editeng/lspcitem.hxx>
42 #include <editeng/adjustitem.hxx>
43 #include <editeng/lrspitem.hxx>
44 #include <editeng/brushitem.hxx>
45 #include <editeng/formatbreakitem.hxx>
46 #include <editeng/keepitem.hxx>
47 #include <editeng/widwitem.hxx>
48 #include <editeng/spltitem.hxx>
49 #include <editeng/orphitem.hxx>
50 #include <editeng/charhiddenitem.hxx>
51 #include <svx/xoutbmp.hxx>
52 #include <svx/svdobj.hxx>
53 #include <editeng/langitem.hxx>
54 #include <editeng/frmdiritem.hxx>
55 #include <svtools/htmlout.hxx>
56 #include <svtools/htmlkywd.hxx>
57 #include <svl/urihelper.hxx>
58 #include <unotools/charclass.hxx>
59 #include <i18nlangtag/languagetag.hxx>
60 #include <charfmt.hxx>
61 #include <fmtclds.hxx>
62 #include <fmtcol.hxx>
63 #include <fmtfsize.hxx>
64 #include <fmtornt.hxx>
65 #include <fmtpdsc.hxx>
66 #include <fmtlsplt.hxx>
67 #include <pagedesc.hxx>
68 #include <fmtanchr.hxx>
69 #include <docary.hxx>
70 #include <pam.hxx>
71 #include <viewsh.hxx>
72 #include <viewopt.hxx>
73 #include <swtable.hxx>
74 // NOTES
75 #include <ftninfo.hxx>
76 #include <ftnidx.hxx>
77 #include <txtftn.hxx>
78 #include <fmtftn.hxx>
79 // FOOTNOTES
80 #include <doc.hxx>
81 #include <IDocumentSettingAccess.hxx>
82 #include <IDocumentLayoutAccess.hxx>
83 #include <swerror.h>
84 #include <paratr.hxx>
85 #include <frmatr.hxx>
86 #include <poolfmt.hxx>
87 #include "css1kywd.hxx"
88 #include "wrthtml.hxx"
89 #include "htmlnum.hxx"
90 #include "css1atr.hxx"
92 #include <IDocumentStylePoolAccess.hxx>
93 #include <numrule.hxx>
94 #include <o3tl/typed_flags_set.hxx>
95 #include <o3tl/unit_conversion.hxx>
97 #include <rtl/strbuf.hxx>
98 #include <osl/diagnose.h>
100 using namespace css;
101 using editeng::SvxBorderLine;
103 #define HTML_HEADSPACE (12*20)
105 namespace {
107 enum class Css1FrameSize {
108 NONE = 0x00,
109 Width = 0x01,
110 MinHeight = 0x02,
111 FixHeight = 0x04,
112 Pixel = 0x10,
117 namespace o3tl {
118 template<> struct typed_flags<Css1FrameSize> : is_typed_flags<Css1FrameSize, 0x17> {};
121 constexpr int DOT_LEADERS_MAX_WIDTH = 18; // cm
123 static SwHTMLWriter& OutCSS1_SwFormat( SwHTMLWriter& rWrt, const SwFormat& rFormat,
124 IDocumentStylePoolAccess /*SwDoc*/ *pDoc, SwDoc *pTemplate );
125 static SwHTMLWriter& OutCSS1_SwPageDesc( SwHTMLWriter& rWrt, const SwPageDesc& rFormat,
126 IDocumentStylePoolAccess /*SwDoc*/ *pDoc, SwDoc *pTemplate,
127 sal_uInt16 nRefPoolId, bool bExtRef,
128 bool bPseudo=true );
129 static SwHTMLWriter& OutCSS1_SwFootnoteInfo( SwHTMLWriter& rWrt, const SwEndNoteInfo& rInfo,
130 SwDoc *pDoc, bool bHasNotes, bool bEndNote );
131 static void OutCSS1_SwFormatDropAttrs( SwHTMLWriter& rHWrt,
132 const SwFormatDrop& rDrop,
133 const SfxItemSet *pCharFormatItemSet=nullptr );
134 static SwHTMLWriter& OutCSS1_SvxTextLn_SvxCrOut_SvxBlink( SwHTMLWriter& rWrt,
135 const SvxUnderlineItem *pUItem,
136 const SvxOverlineItem *pOItem,
137 const SvxCrossedOutItem *pCOItem,
138 const SvxBlinkItem *pBItem );
139 static SwHTMLWriter& OutCSS1_SvxFontWeight( SwHTMLWriter& rWrt, const SfxPoolItem& rHt );
140 static SwHTMLWriter& OutCSS1_SvxPosture( SwHTMLWriter& rWrt, const SfxPoolItem& rHt );
141 static SwHTMLWriter& OutCSS1_SvxULSpace( SwHTMLWriter& rWrt, const SfxPoolItem& rHt );
142 static SwHTMLWriter& OutCSS1_SvxFirstLineIndent(SwHTMLWriter& rWrt, const SfxPoolItem& rHt);
143 static SwHTMLWriter& OutCSS1_SvxTextLeftMargin(SwHTMLWriter& rWrt, const SfxPoolItem& rHt);
144 static SwHTMLWriter& OutCSS1_SvxRightMargin(SwHTMLWriter& rWrt, const SfxPoolItem& rHt);
145 static SwHTMLWriter& OutCSS1_SvxLRSpace( SwHTMLWriter& rWrt, const SfxPoolItem& rHt );
146 static SwHTMLWriter& OutCSS1_SvxULSpace_SvxLRSpace( SwHTMLWriter& rWrt,
147 const SvxULSpaceItem *pULSpace,
148 const SvxLRSpaceItem *pLRSpace );
149 static SwHTMLWriter& OutCSS1_SvxULSpace_SvxLRSpace( SwHTMLWriter& rWrt,
150 const SfxItemSet& rItemSet );
151 static SwHTMLWriter& OutCSS1_SvxBrush( SwHTMLWriter& rWrt, const SfxPoolItem& rHt,
152 sw::Css1Background nMode,
153 const OUString *pGraphicName );
154 static SwHTMLWriter& OutCSS1_SvxBrush( SwHTMLWriter& rWrt, const SfxPoolItem& rHt );
155 static SwHTMLWriter& OutCSS1_SwFormatFrameSize( SwHTMLWriter& rWrt, const SfxPoolItem& rHt,
156 Css1FrameSize nMode );
157 static SwHTMLWriter& OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( SwHTMLWriter& rWrt,
158 const SfxItemSet& rItemSet,
159 bool bDeep );
160 static SwHTMLWriter& OutCSS1_SwFormatLayoutSplit( SwHTMLWriter& rWrt, const SfxPoolItem& rHt );
162 namespace
165 const char sCSS1_rule_end[] = " }";
166 const char sCSS1_span_tag_end[] = "\">";
167 const char cCSS1_style_opt_end = '\"';
169 const char* const sHTML_FTN_fontheight = "57%";
171 OString lclConvToHex(sal_uInt16 nHex)
173 char aNToABuf[] = "00";
175 // set pointer to end of buffer
176 char *pStr = aNToABuf + (sizeof(aNToABuf)-1);
177 for( sal_uInt8 n = 0; n < 2; ++n )
179 *(--pStr) = static_cast<char>(nHex & 0xf ) + 48;
180 if( *pStr > '9' )
181 *pStr += 39;
182 nHex >>= 4;
185 return OString(aNToABuf, 2);
189 bool IgnorePropertyForReqIF(bool bReqIF, std::string_view rProperty, std::string_view rValue,
190 std::optional<sw::Css1Background> oMode)
192 if (!bReqIF)
193 return false;
195 if (oMode.has_value() && *oMode != sw::Css1Background::TableCell)
197 // Table or row.
198 if (rProperty == sCSS1_P_background && rValue == "transparent")
200 // This is the default already.
201 return true;
204 return false;
207 // Only allow these two keys, nothing else in ReqIF mode.
208 if (rProperty == sCSS1_P_text_decoration)
210 // Deny other text-decoration values (e.g. "none").
211 if (rValue == "underline" || rValue == "line-through")
213 return false;
216 return true;
219 if (rProperty == sCSS1_P_color)
220 return false;
222 return true;
225 OString GetCSS1_Color(const Color& rColor)
227 return "#" + lclConvToHex(rColor.GetRed()) + lclConvToHex(rColor.GetGreen()) + lclConvToHex(rColor.GetBlue());
230 namespace {
232 class SwCSS1OutMode
234 SwHTMLWriter& rWrt;
235 sal_uInt16 nOldMode;
237 public:
239 SwCSS1OutMode( SwHTMLWriter& rHWrt, sal_uInt16 nMode,
240 const OUString *pSelector ) :
241 rWrt( rHWrt ),
242 nOldMode( rHWrt.m_nCSS1OutMode )
244 rWrt.m_nCSS1OutMode = nMode;
245 rWrt.m_bFirstCSS1Property = true;
246 if( pSelector )
247 rWrt.m_aCSS1Selector = *pSelector;
250 ~SwCSS1OutMode()
252 rWrt.m_nCSS1OutMode = nOldMode;
258 void SwHTMLWriter::OutCSS1_Property( std::string_view pProp,
259 std::string_view sVal,
260 const OUString *pSVal,
261 std::optional<sw::Css1Background> oMode )
263 OString aPropertyValue(sVal);
264 if (aPropertyValue.isEmpty() && pSVal)
266 aPropertyValue = OUStringToOString(*pSVal, RTL_TEXTENCODING_UTF8);
268 if (IgnorePropertyForReqIF(mbReqIF, pProp, aPropertyValue, oMode))
269 return;
271 OStringBuffer sOut;
273 if( m_bFirstCSS1Rule && (m_nCSS1OutMode & CSS1_OUTMODE_RULE_ON)!=0 )
275 m_bFirstCSS1Rule = false;
276 OutNewLine();
277 sOut.append("<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_style " "
278 OOO_STRING_SVTOOLS_HTML_O_type "=\"text/css\">");
279 // Optional CSS2 code for dot leaders (dotted line between the Table of Contents titles and page numbers):
280 // (More information: http://www.w3.org/Style/Examples/007/leaders.en.html)
282 // p.leaders {
283 // /* FIXME:
284 // (1) dots line up vertically only in the paragraphs with the same alignment/level
285 // (2) max-width = 18 cm instead of 80em; possible improvement with the new CSS3 calc() */
286 // max-width: 18cm; /* note: need to overwrite max-width with max-width - border-left_of_the_actual_paragraph */
287 // padding: 0;
288 // overflow-x: hidden;
289 // line-height: 120%; /* note: avoid HTML scrollbars and missing descenders of the letters */
290 // }
291 // p.leaders:after {
292 // float: left;
293 // width: 0;
294 // white-space: nowrap;
295 // content: ". . . . . . . . . . . . . . . . . . ...";
296 // }
297 // p.leaders span:first-child {
298 // padding-right: 0.33em;
299 // background: white;
300 // }
301 // p.leaders span + span {
302 // float: right;
303 // padding-left: 0.33em;
304 // background: white;
305 // position: relative;
306 // z-index: 1
307 // }
309 if (m_bCfgPrintLayout) {
310 sOut.append(
311 "p." sCSS2_P_CLASS_leaders "{max-width:" + OString::number(DOT_LEADERS_MAX_WIDTH) +
312 "cm;padding:0;overflow-x:hidden;line-height:120%}"
313 "p." sCSS2_P_CLASS_leaders ":after{float:left;width:0;white-space:nowrap;content:\"");
314 for (int i = 0; i < 100; i++ )
315 sOut.append(". ");
316 sOut.append(
317 "\"}p." sCSS2_P_CLASS_leaders " span:first-child{padding-right:0.33em;background:white}"
318 "p." sCSS2_P_CLASS_leaders " span+span{float:right;padding-left:0.33em;"
319 "background:white;position:relative;z-index:1}");
321 Strm().WriteOString( sOut );
322 sOut.setLength(0);
324 IncIndentLevel();
327 if( m_bFirstCSS1Property )
329 switch( m_nCSS1OutMode & CSS1_OUTMODE_ANY_ON )
331 case CSS1_OUTMODE_SPAN_TAG_ON:
332 case CSS1_OUTMODE_SPAN_TAG1_ON:
333 if( m_bTagOn )
335 sOut.append("<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
336 " " OOO_STRING_SVTOOLS_HTML_O_style "=\"");
338 else
340 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false );
341 return;
343 break;
345 case CSS1_OUTMODE_RULE_ON:
347 OutNewLine();
348 sOut.append(OUStringToOString(m_aCSS1Selector, RTL_TEXTENCODING_UTF8) + " { ");
350 break;
352 case CSS1_OUTMODE_STYLE_OPT_ON:
353 sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_style "=\"");
354 break;
356 m_bFirstCSS1Property = false;
358 else
360 sOut.append("; ");
363 sOut.append(pProp + OString::Concat(": "));
364 if( m_nCSS1OutMode & CSS1_OUTMODE_ENCODE )
366 // for STYLE-Option encode string
367 Strm().WriteOString( sOut );
368 sOut.setLength(0);
369 if( !sVal.empty() )
370 HTMLOutFuncs::Out_String( Strm(), OUString::createFromAscii(sVal) );
371 else if( pSVal )
372 HTMLOutFuncs::Out_String( Strm(), *pSVal );
374 else
376 // for STYLE-Tag print string directly
377 sOut.append(aPropertyValue);
380 if (!sOut.isEmpty())
381 Strm().WriteOString( sOut );
384 static void AddUnitPropertyValue(OStringBuffer &rOut, tools::Long nVal,
385 FieldUnit eUnit)
387 if( nVal < 0 )
389 // special-case sign symbol
390 nVal = -nVal;
391 rOut.append('-');
394 o3tl::Length eTo;
395 int nFac; // used to get specific number of decimals
396 std::string_view pUnit;
397 switch( eUnit )
399 case FieldUnit::MM_100TH:
400 OSL_ENSURE( FieldUnit::MM == eUnit, "Measuring unit not supported" );
401 [[fallthrough]];
402 case FieldUnit::MM:
403 eTo = o3tl::Length::mm;
404 nFac = 100;
405 pUnit = sCSS1_UNIT_mm;
406 break;
408 case FieldUnit::M:
409 case FieldUnit::KM:
410 OSL_ENSURE( FieldUnit::CM == eUnit, "Measuring unit not supported" );
411 [[fallthrough]];
412 case FieldUnit::CM:
413 eTo = o3tl::Length::cm;
414 nFac = 100;
415 pUnit = sCSS1_UNIT_cm;
416 break;
418 case FieldUnit::TWIP:
419 OSL_ENSURE( FieldUnit::POINT == eUnit, "Measuring unit not supported" );
420 [[fallthrough]];
421 case FieldUnit::POINT:
422 eTo = o3tl::Length::pt;
423 nFac = 10;
424 pUnit = sCSS1_UNIT_pt;
425 break;
427 case FieldUnit::PICA:
428 eTo = o3tl::Length::pc;
429 nFac = 100;
430 pUnit = sCSS1_UNIT_pc;
431 break;
433 case FieldUnit::NONE:
434 case FieldUnit::FOOT:
435 case FieldUnit::MILE:
436 case FieldUnit::CUSTOM:
437 case FieldUnit::PERCENT:
438 case FieldUnit::INCH:
439 default:
440 OSL_ENSURE( FieldUnit::INCH == eUnit, "Measuring unit not supported" );
441 eTo = o3tl::Length::in;
442 nFac = 100;
443 pUnit = sCSS1_UNIT_inch;
444 break;
447 sal_Int64 nResult = o3tl::convert(nVal * nFac, o3tl::Length::twip, eTo);
448 rOut.append(nResult/nFac);
449 if ((nResult % nFac) != 0)
451 rOut.append('.');
452 while (nFac > 1 && (nResult % nFac) != 0)
454 nFac /= 10;
455 rOut.append((nResult / nFac) % 10);
459 rOut.append(pUnit);
462 void SwHTMLWriter::OutCSS1_UnitProperty( std::string_view pProp, tools::Long nVal )
464 OStringBuffer sOut;
465 AddUnitPropertyValue(sOut, nVal, m_eCSS1Unit);
466 OutCSS1_PropertyAscii(pProp, sOut);
469 void SwHTMLWriter::OutCSS1_PixelProperty( std::string_view pProp, tools::Long nTwips )
471 OString sOut(OString::number(ToPixel(nTwips)) + sCSS1_UNIT_px);
472 OutCSS1_PropertyAscii(pProp, sOut);
475 void SwHTMLWriter::OutStyleSheet( const SwPageDesc& rPageDesc )
477 m_bFirstCSS1Rule = true;
479 // Feature: PrintExt
480 if( IsHTMLMode(HTMLMODE_PRINT_EXT) )
482 const SwPageDesc *pFirstPageDesc = nullptr;
483 sal_uInt16 nFirstRefPoolId = RES_POOLPAGE_HTML;
484 m_bCSS1IgnoreFirstPageDesc = true;
486 // First we try to guess how the document is constructed.
487 // Allowed are only the templates: HTML, 1st page, left page, and right page.
488 // A first page is only exported, if it matches the template "1st page".
489 // Left and right pages are only exported, if their templates are linked.
490 // If other templates are used, only very simple cases are exported.
491 const SwPageDesc *pPageDesc = &rPageDesc;
492 const SwPageDesc *pFollow = rPageDesc.GetFollow();
493 if( RES_POOLPAGE_FIRST == pPageDesc->GetPoolFormatId() &&
494 pFollow != pPageDesc &&
495 !IsPoolUserFormat( pFollow->GetPoolFormatId() ) )
497 // the document has a first page
498 pFirstPageDesc = pPageDesc;
499 pPageDesc = pFollow;
500 pFollow = pPageDesc->GetFollow();
503 IDocumentStylePoolAccess* pStylePoolAccess = &getIDocumentStylePoolAccess();
504 if( pPageDesc == pFollow )
506 // The document is one-sided; no matter what page, we do not create a 2-sided doc.
507 // The attribute is exported relative to the HTML page template.
508 OutCSS1_SwPageDesc( *this, *pPageDesc, pStylePoolAccess, m_xTemplate.get(),
509 RES_POOLPAGE_HTML, true, false );
510 nFirstRefPoolId = pFollow->GetPoolFormatId();
512 else if( (RES_POOLPAGE_LEFT == pPageDesc->GetPoolFormatId() &&
513 RES_POOLPAGE_RIGHT == pFollow->GetPoolFormatId()) ||
514 (RES_POOLPAGE_RIGHT == pPageDesc->GetPoolFormatId() &&
515 RES_POOLPAGE_LEFT == pFollow->GetPoolFormatId()) )
517 // the document is double-sided
518 OutCSS1_SwPageDesc( *this, *pPageDesc, pStylePoolAccess, m_xTemplate.get(),
519 RES_POOLPAGE_HTML, true );
520 OutCSS1_SwPageDesc( *this, *pFollow, pStylePoolAccess, m_xTemplate.get(),
521 RES_POOLPAGE_HTML, true );
522 nFirstRefPoolId = RES_POOLPAGE_RIGHT;
523 m_bCSS1IgnoreFirstPageDesc = false;
525 // other cases we miss
527 if( pFirstPageDesc )
528 OutCSS1_SwPageDesc( *this, *pFirstPageDesc, pStylePoolAccess, m_xTemplate.get(),
529 nFirstRefPoolId, false );
532 // The text body style has to be exported always (if it is changed compared
533 // to the template), because it is used as reference for any style
534 // that maps to <P>, and that's especially the standard style
535 getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT, false );
537 // the Default-TextStyle is not also exported !!
538 // 0-Style is the Default; is never exported !!
539 const size_t nTextFormats = m_pDoc->GetTextFormatColls()->size();
540 for( size_t i = 1; i < nTextFormats; ++i )
542 const SwTextFormatColl* pColl = (*m_pDoc->GetTextFormatColls())[i];
543 sal_uInt16 nPoolId = pColl->GetPoolFormatId();
544 if( nPoolId == RES_POOLCOLL_TEXT || m_pDoc->IsUsed( *pColl ) )
545 OutCSS1_SwFormat( *this, *pColl, &m_pDoc->getIDocumentStylePoolAccess(), m_xTemplate.get() );
548 // the Default-TextStyle is not also exported !!
549 const size_t nCharFormats = m_pDoc->GetCharFormats()->size();
550 for( size_t i = 1; i < nCharFormats; ++i )
552 const SwCharFormat *pCFormat = (*m_pDoc->GetCharFormats())[i];
553 sal_uInt16 nPoolId = pCFormat->GetPoolFormatId();
554 if( nPoolId == RES_POOLCHR_INET_NORMAL ||
555 nPoolId == RES_POOLCHR_INET_VISIT ||
556 m_pDoc->IsUsed( *pCFormat ) )
557 OutCSS1_SwFormat( *this, *pCFormat, &m_pDoc->getIDocumentStylePoolAccess(), m_xTemplate.get() );
560 bool bHasEndNotes {false};
561 bool bHasFootNotes {false};
562 const SwFootnoteIdxs& rIdxs = m_pDoc->GetFootnoteIdxs();
563 for( auto pIdx : rIdxs )
565 if( pIdx->GetFootnote().IsEndNote() )
567 bHasEndNotes = true;
568 if (bHasFootNotes)
569 break;
571 else
573 bHasFootNotes = true;
574 if (bHasEndNotes)
575 break;
578 OutCSS1_SwFootnoteInfo( *this, m_pDoc->GetFootnoteInfo(), m_pDoc, bHasFootNotes, false );
579 OutCSS1_SwFootnoteInfo( *this, m_pDoc->GetEndNoteInfo(), m_pDoc, bHasEndNotes, true );
581 if( !m_bFirstCSS1Rule )
583 DecIndentLevel();
585 OutNewLine();
586 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_style), false );
588 else
590 m_bFirstCSS1Rule = false;
593 m_nDfltTopMargin = 0;
594 m_nDfltBottomMargin = 0;
597 // if pPseudo is set, Styles-Sheets will be exported;
598 // otherwise we only search for Token and Class for a Format
599 sal_uInt16 SwHTMLWriter::GetCSS1Selector( const SwFormat *pFormat, OString& rToken,
600 OUString& rClass, sal_uInt16& rRefPoolId,
601 OUString *pPseudo )
603 sal_uInt16 nDeep = 0;
604 rToken.clear();
605 rClass.clear();
606 rRefPoolId = 0;
607 if( pPseudo )
608 pPseudo->clear();
610 bool bChrFormat = RES_CHRFMT==pFormat->Which();
612 // search formats above for the nearest standard or HTML-Tag template
613 const SwFormat *pPFormat = pFormat;
614 while( pPFormat && !pPFormat->IsDefault() )
616 bool bStop = false;
617 sal_uInt16 nPoolId = pPFormat->GetPoolFormatId();
618 if( USER_FMT & nPoolId )
620 // user templates
621 const OUString& aNm(pPFormat->GetName());
623 if (!bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_blockquote)
625 rRefPoolId = RES_POOLCOLL_HTML_BLOCKQUOTE;
626 rToken = OOO_STRING_SVTOOLS_HTML_blockquote ""_ostr;
628 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_citation)
630 rRefPoolId = RES_POOLCHR_HTML_CITATION;
631 rToken = OOO_STRING_SVTOOLS_HTML_citation ""_ostr;
633 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_code)
635 rRefPoolId = RES_POOLCHR_HTML_CODE;
636 rToken = OOO_STRING_SVTOOLS_HTML_code ""_ostr;
638 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_definstance)
640 rRefPoolId = RES_POOLCHR_HTML_DEFINSTANCE;
641 rToken = OOO_STRING_SVTOOLS_HTML_definstance ""_ostr;
643 else if (!bChrFormat && (aNm == OOO_STRING_SVTOOLS_HTML_dd ||
644 aNm == OOO_STRING_SVTOOLS_HTML_dt))
646 sal_uInt16 nDefListLvl = GetDefListLvl(aNm, nPoolId);
647 // Export the templates DD 1/DT 1,
648 // but none of their derived templates,
649 // also not DD 2/DT 2 etc.
650 if (nDefListLvl)
652 if (pPseudo && (nDeep || (nDefListLvl & 0x0fff) > 1))
654 bStop = true;
656 else if (nDefListLvl & HTML_DLCOLL_DD)
658 rRefPoolId = RES_POOLCOLL_HTML_DD;
659 rToken = OOO_STRING_SVTOOLS_HTML_dd ""_ostr;
661 else
663 rRefPoolId = RES_POOLCOLL_HTML_DT;
664 rToken = OOO_STRING_SVTOOLS_HTML_dt ""_ostr;
668 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_emphasis)
670 rRefPoolId = RES_POOLCHR_HTML_EMPHASIS;
671 rToken = OOO_STRING_SVTOOLS_HTML_emphasis ""_ostr;
673 else if (!bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_horzrule)
675 // do not export HR !
676 bStop = (nDeep==0);
678 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_keyboard)
680 rRefPoolId = RES_POOLCHR_HTML_KEYBOARD;
681 rToken = OOO_STRING_SVTOOLS_HTML_keyboard ""_ostr;
683 else if (!bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_listing)
685 // Export Listings as PRE or PRE-derived template
686 rToken = OOO_STRING_SVTOOLS_HTML_preformtxt ""_ostr;
687 rRefPoolId = RES_POOLCOLL_HTML_PRE;
688 nDeep = CSS1_FMT_CMPREF;
690 else if (!bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_preformtxt)
692 rRefPoolId = RES_POOLCOLL_HTML_PRE;
693 rToken = OOO_STRING_SVTOOLS_HTML_preformtxt ""_ostr;
695 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_sample)
697 rRefPoolId = RES_POOLCHR_HTML_SAMPLE;
698 rToken = OOO_STRING_SVTOOLS_HTML_sample ""_ostr;
700 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_strong)
702 rRefPoolId = RES_POOLCHR_HTML_STRONG;
703 rToken = OOO_STRING_SVTOOLS_HTML_strong ""_ostr;
705 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_teletype)
707 rRefPoolId = RES_POOLCHR_HTML_TELETYPE;
708 rToken = OOO_STRING_SVTOOLS_HTML_teletype ""_ostr;
710 else if (bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_variable)
712 rRefPoolId = RES_POOLCHR_HTML_VARIABLE;
713 rToken = OOO_STRING_SVTOOLS_HTML_variable ""_ostr;
715 else if (!bChrFormat && aNm == OOO_STRING_SVTOOLS_HTML_xmp)
717 // export XMP as PRE (but not the template as Style)
718 rToken = OOO_STRING_SVTOOLS_HTML_preformtxt ""_ostr;
719 rRefPoolId = RES_POOLCOLL_HTML_PRE;
720 nDeep = CSS1_FMT_CMPREF;
723 // if a PoolId is set, the Name of the template is that of the related Token
724 OSL_ENSURE( (rRefPoolId != 0) == (!rToken.isEmpty()),
725 "Token missing" );
727 else
729 // Pool templates
730 switch( nPoolId )
732 // paragraph templates
733 case RES_POOLCOLL_HEADLINE_BASE:
734 case RES_POOLCOLL_STANDARD:
735 // do not export this template
736 case RES_POOLCOLL_HTML_HR:
737 // do not export HR !
738 bStop = (nDeep==0);
739 break;
740 case RES_POOLCOLL_TEXT:
741 rToken = OOO_STRING_SVTOOLS_HTML_parabreak ""_ostr;
742 break;
743 case RES_POOLCOLL_HEADLINE1:
744 rToken = OOO_STRING_SVTOOLS_HTML_head1 ""_ostr;
745 break;
746 case RES_POOLCOLL_HEADLINE2:
747 rToken = OOO_STRING_SVTOOLS_HTML_head2 ""_ostr;
748 break;
749 case RES_POOLCOLL_HEADLINE3:
750 rToken = OOO_STRING_SVTOOLS_HTML_head3 ""_ostr;
751 break;
752 case RES_POOLCOLL_HEADLINE4:
753 rToken = OOO_STRING_SVTOOLS_HTML_head4 ""_ostr;
754 break;
755 case RES_POOLCOLL_HEADLINE5:
756 rToken = OOO_STRING_SVTOOLS_HTML_head5 ""_ostr;
757 break;
758 case RES_POOLCOLL_HEADLINE6:
759 rToken = OOO_STRING_SVTOOLS_HTML_head6 ""_ostr;
760 break;
761 case RES_POOLCOLL_SEND_ADDRESS:
762 rToken = OOO_STRING_SVTOOLS_HTML_address ""_ostr;
763 break;
764 case RES_POOLCOLL_HTML_BLOCKQUOTE:
765 rToken = OOO_STRING_SVTOOLS_HTML_blockquote ""_ostr;
766 break;
767 case RES_POOLCOLL_HTML_PRE:
768 rToken = OOO_STRING_SVTOOLS_HTML_preformtxt ""_ostr;
769 break;
771 case RES_POOLCOLL_HTML_DD:
772 rToken = OOO_STRING_SVTOOLS_HTML_dd ""_ostr;
773 break;
774 case RES_POOLCOLL_HTML_DT:
775 rToken = OOO_STRING_SVTOOLS_HTML_dt ""_ostr;
776 break;
778 case RES_POOLCOLL_TABLE:
779 if( pPseudo )
781 rToken = OOO_STRING_SVTOOLS_HTML_tabledata " "
782 OOO_STRING_SVTOOLS_HTML_parabreak ""_ostr;
784 else
785 rToken = OOO_STRING_SVTOOLS_HTML_parabreak ""_ostr;
786 break;
787 case RES_POOLCOLL_TABLE_HDLN:
788 if( pPseudo )
790 rToken = OOO_STRING_SVTOOLS_HTML_tableheader " "
791 OOO_STRING_SVTOOLS_HTML_parabreak ""_ostr;
793 else
794 rToken = OOO_STRING_SVTOOLS_HTML_parabreak ""_ostr;
795 break;
796 case RES_POOLCOLL_FOOTNOTE:
797 if( !nDeep )
799 rToken = OOO_STRING_SVTOOLS_HTML_parabreak ""_ostr;
800 rClass = OOO_STRING_SVTOOLS_HTML_sdfootnote;
801 rRefPoolId = RES_POOLCOLL_TEXT;
802 nDeep = CSS1_FMT_CMPREF;
804 break;
805 case RES_POOLCOLL_ENDNOTE:
806 if( !nDeep )
808 rToken = OOO_STRING_SVTOOLS_HTML_parabreak ""_ostr;
809 rClass = OOO_STRING_SVTOOLS_HTML_sdendnote;
810 rRefPoolId = RES_POOLCOLL_TEXT;
811 nDeep = CSS1_FMT_CMPREF;
813 break;
815 // character templates
816 case RES_POOLCHR_HTML_EMPHASIS:
817 rToken = OOO_STRING_SVTOOLS_HTML_emphasis ""_ostr;
818 break;
819 case RES_POOLCHR_HTML_CITATION:
820 rToken = OOO_STRING_SVTOOLS_HTML_citation ""_ostr;
821 break;
822 case RES_POOLCHR_HTML_STRONG:
823 rToken = OOO_STRING_SVTOOLS_HTML_strong ""_ostr;
824 break;
825 case RES_POOLCHR_HTML_CODE:
826 rToken = OOO_STRING_SVTOOLS_HTML_code ""_ostr;
827 break;
828 case RES_POOLCHR_HTML_SAMPLE:
829 rToken = OOO_STRING_SVTOOLS_HTML_sample ""_ostr;
830 break;
831 case RES_POOLCHR_HTML_KEYBOARD:
832 rToken = OOO_STRING_SVTOOLS_HTML_keyboard ""_ostr;
833 break;
834 case RES_POOLCHR_HTML_VARIABLE:
835 rToken = OOO_STRING_SVTOOLS_HTML_variable ""_ostr;
836 break;
837 case RES_POOLCHR_HTML_DEFINSTANCE:
838 rToken = OOO_STRING_SVTOOLS_HTML_definstance ""_ostr;
839 break;
840 case RES_POOLCHR_HTML_TELETYPE:
841 rToken = OOO_STRING_SVTOOLS_HTML_teletype ""_ostr;
842 break;
844 case RES_POOLCHR_INET_NORMAL:
845 if( pPseudo )
847 rToken = OOO_STRING_SVTOOLS_HTML_anchor ""_ostr;
848 *pPseudo = sCSS1_link;
850 break;
851 case RES_POOLCHR_INET_VISIT:
852 if( pPseudo )
854 rToken = OOO_STRING_SVTOOLS_HTML_anchor ""_ostr;
855 *pPseudo = sCSS1_visited;
857 break;
860 // if a token is set, PoolId contains the related template
861 if( !rToken.isEmpty() && !rRefPoolId )
862 rRefPoolId = nPoolId;
865 if( !rToken.isEmpty() || bStop )
867 // stop if a HTML-Tag template was found
868 break;
870 else
872 // continue otherwise
873 nDeep++;
874 pPFormat = pPFormat->DerivedFrom();
878 if( !rToken.isEmpty() )
880 // this is a HTML-Tag template
881 if( !nDeep )
882 nDeep = CSS1_FMT_ISTAG;
884 else
886 // this is not a HTML-Tag template nor derived from one
887 nDeep = 0;
889 if( nDeep > 0 && nDeep < CSS1_FMT_SPECIAL )
891 // If the template is derived from a HTML template,
892 // we export it as <TOKEN>.<CLASS>, otherwise as .<CLASS>.
893 // <CLASS> is the name of the template after removing all characters
894 // before and including the first '.'
895 rClass = pFormat->GetName();
896 sal_Int32 nPos = rClass.indexOf( '.' );
897 if( nPos >= 0 && rClass.getLength() > nPos+1 )
899 rClass = rClass.replaceAt( 0, nPos+1, u"" );
902 rClass = GetAppCharClass().lowercase( rClass );
903 rClass = rClass.replaceAll( ".", "-" );
904 rClass = rClass.replaceAll( " ", "-" );
905 rClass = rClass.replaceAll( "_", "-" );
908 return nDeep;
911 static sal_uInt16 GetCSS1Selector( const SwFormat *pFormat, OUString& rSelector,
912 sal_uInt16& rRefPoolId )
914 OString aToken;
915 OUString aClass;
916 OUString aPseudo;
918 sal_uInt16 nDeep = SwHTMLWriter::GetCSS1Selector( pFormat, aToken, aClass,
919 rRefPoolId, &aPseudo );
920 if( nDeep )
922 if( !aToken.isEmpty() )
923 rSelector = OStringToOUString(aToken, RTL_TEXTENCODING_ASCII_US);
924 else
925 rSelector.clear();
927 if( !aClass.isEmpty() )
928 rSelector += "." + aClass;
929 if( !aPseudo.isEmpty() )
930 rSelector += ":" + aPseudo;
933 return nDeep;
936 const SwFormat *SwHTMLWriter::GetTemplateFormat( sal_uInt16 nPoolFormatId,
937 IDocumentStylePoolAccess* pTemplate /*SwDoc *pTemplate*/)
939 const SwFormat *pRefFormat = nullptr;
941 if( pTemplate )
943 OSL_ENSURE( !(USER_FMT & nPoolFormatId),
944 "No user templates found" );
945 if( POOLGRP_NOCOLLID & nPoolFormatId )
946 pRefFormat = pTemplate->GetCharFormatFromPool( nPoolFormatId );
947 else
948 pRefFormat = pTemplate->GetTextCollFromPool( nPoolFormatId, false );
951 return pRefFormat;
954 const SwFormat *SwHTMLWriter::GetParentFormat( const SwFormat& rFormat, sal_uInt16 nDeep )
956 OSL_ENSURE( nDeep != USHRT_MAX, "Called GetParent for HTML-template!" );
957 const SwFormat *pRefFormat = nullptr;
959 if( nDeep > 0 )
961 // get the pointer for the HTML-Tag template, from which the template is derived
962 pRefFormat = &rFormat;
963 for( sal_uInt16 i=nDeep; i>0; i-- )
964 pRefFormat = pRefFormat->DerivedFrom();
966 if( pRefFormat && pRefFormat->IsDefault() )
967 pRefFormat = nullptr;
970 return pRefFormat;
973 bool swhtml_css1atr_equalFontItems( const SfxPoolItem& r1, const SfxPoolItem& r2 )
975 return static_cast<const SvxFontItem &>(r1).GetFamilyName() ==
976 static_cast<const SvxFontItem &>(r2).GetFamilyName() &&
977 static_cast<const SvxFontItem &>(r1).GetFamily() ==
978 static_cast<const SvxFontItem &>(r2).GetFamily();
981 void SwHTMLWriter::SubtractItemSet( SfxItemSet& rItemSet,
982 const SfxItemSet& rRefItemSet,
983 bool bSetDefaults,
984 bool bClearSame,
985 const SfxItemSet *pRefScriptItemSet )
987 OSL_ENSURE( bSetDefaults || bClearSame,
988 "SwHTMLWriter::SubtractItemSet: No action for this Flag" );
989 SfxItemSet aRefItemSet( *rRefItemSet.GetPool(), rRefItemSet.GetRanges() );
990 aRefItemSet.Set( rRefItemSet );
992 // compare with the Attr-Set of the template
993 SfxWhichIter aIter( rItemSet );
994 sal_uInt16 nWhich = aIter.FirstWhich();
995 while( nWhich )
997 const SfxPoolItem *pRefItem, *pItem;
998 bool bItemSet = ( SfxItemState::SET ==
999 aIter.GetItemState( false, &pItem) );
1000 bool bRefItemSet;
1002 if( pRefScriptItemSet )
1004 switch( nWhich )
1006 case RES_CHRATR_FONT:
1007 case RES_CHRATR_FONTSIZE:
1008 case RES_CHRATR_LANGUAGE:
1009 case RES_CHRATR_POSTURE:
1010 case RES_CHRATR_WEIGHT:
1011 case RES_CHRATR_CJK_FONT:
1012 case RES_CHRATR_CJK_FONTSIZE:
1013 case RES_CHRATR_CJK_LANGUAGE:
1014 case RES_CHRATR_CJK_POSTURE:
1015 case RES_CHRATR_CJK_WEIGHT:
1016 case RES_CHRATR_CTL_FONT:
1017 case RES_CHRATR_CTL_FONTSIZE:
1018 case RES_CHRATR_CTL_LANGUAGE:
1019 case RES_CHRATR_CTL_POSTURE:
1020 case RES_CHRATR_CTL_WEIGHT:
1021 bRefItemSet = ( SfxItemState::SET ==
1022 pRefScriptItemSet->GetItemState( nWhich, true, &pRefItem) );
1023 break;
1024 default:
1025 bRefItemSet = ( SfxItemState::SET ==
1026 aRefItemSet.GetItemState( nWhich, false, &pRefItem) );
1027 break;
1030 else
1032 bRefItemSet = ( SfxItemState::SET ==
1033 aRefItemSet.GetItemState( nWhich, false, &pRefItem) );
1036 if( bItemSet )
1038 if( (bClearSame || pRefScriptItemSet) && bRefItemSet &&
1039 ( *pItem == *pRefItem ||
1040 ((RES_CHRATR_FONT == nWhich ||
1041 RES_CHRATR_CJK_FONT == nWhich ||
1042 RES_CHRATR_CTL_FONT == nWhich) &&
1043 swhtml_css1atr_equalFontItems( *pItem, *pRefItem )) ) )
1045 // the Attribute is in both templates with the same value
1046 // and does not need to be exported
1047 rItemSet.ClearItem( nWhich );
1050 else
1052 if( (bSetDefaults || pRefScriptItemSet) && bRefItemSet )
1054 // the Attribute exists only in the reference; the default
1055 // might have to be exported
1056 rItemSet.Put( rItemSet.GetPool()->GetUserOrPoolDefaultItem(nWhich) );
1060 nWhich = aIter.NextWhich();
1064 void SwHTMLWriter::PrepareFontList( const SvxFontItem& rFontItem,
1065 OUString& rNames,
1066 sal_Unicode cQuote, bool bGeneric )
1068 rNames.clear();
1069 const OUString& rName = rFontItem.GetFamilyName();
1070 bool bContainsKeyword = false;
1071 if( !rName.isEmpty() )
1073 sal_Int32 nStrPos = 0;
1074 while( nStrPos != -1 )
1076 OUString aName = rName.getToken( 0, ';', nStrPos );
1077 aName = comphelper::string::encodeForXml(comphelper::string::strip(aName, ' '));
1078 if( aName.isEmpty() )
1079 continue;
1081 bool bIsKeyword = false;
1082 switch( aName[0] )
1084 case 'c':
1085 case 'C':
1086 bIsKeyword = aName.equalsIgnoreAsciiCaseAscii( sCSS1_PV_cursive );
1087 break;
1089 case 'f':
1090 case 'F':
1091 bIsKeyword = aName.equalsIgnoreAsciiCaseAscii( sCSS1_PV_fantasy );
1092 break;
1094 case 'm':
1095 case 'M':
1096 bIsKeyword = aName.equalsIgnoreAsciiCaseAscii( sCSS1_PV_monospace );
1097 break;
1099 case 's':
1100 case 'S':
1101 bIsKeyword =
1102 aName.equalsIgnoreAsciiCaseAscii( sCSS1_PV_serif ) ||
1103 aName.equalsIgnoreAsciiCaseAscii( sCSS1_PV_sans_serif );
1104 break;
1107 bContainsKeyword |= bIsKeyword;
1109 if( !rNames.isEmpty() )
1110 rNames += ", ";
1111 if( cQuote && !bIsKeyword )
1112 rNames += OUStringChar( cQuote );
1113 rNames += aName;
1114 if( cQuote && !bIsKeyword )
1115 rNames += OUStringChar( cQuote );
1119 if( bContainsKeyword || !bGeneric )
1120 return;
1122 std::string_view pStr;
1123 switch( rFontItem.GetFamily() )
1125 case FAMILY_ROMAN: pStr = sCSS1_PV_serif; break;
1126 case FAMILY_SWISS: pStr = sCSS1_PV_sans_serif; break;
1127 case FAMILY_SCRIPT: pStr = sCSS1_PV_cursive; break;
1128 case FAMILY_DECORATIVE: pStr = sCSS1_PV_fantasy; break;
1129 case FAMILY_MODERN: pStr = sCSS1_PV_monospace; break;
1130 default:
1134 if( !pStr.empty() )
1136 if( !rNames.isEmpty() )
1137 rNames += ", ";
1138 rNames += OStringToOUString( pStr, RTL_TEXTENCODING_ASCII_US );
1142 bool SwHTMLWriter::HasScriptDependentItems( const SfxItemSet& rItemSet,
1143 bool bCheckDropCap )
1145 static const sal_uInt16 aWhichIds[] =
1147 RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT,
1148 RES_CHRATR_FONTSIZE, RES_CHRATR_CJK_FONTSIZE, RES_CHRATR_CTL_FONTSIZE,
1149 RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
1150 RES_CHRATR_POSTURE, RES_CHRATR_CJK_POSTURE, RES_CHRATR_CTL_POSTURE,
1151 RES_CHRATR_WEIGHT, RES_CHRATR_CJK_WEIGHT, RES_CHRATR_CTL_WEIGHT,
1152 0, 0, 0
1155 for( int i=0; aWhichIds[i]; i += 3 )
1157 const SfxPoolItem *pItem = nullptr, *pItemCJK = nullptr, *pItemCTL = nullptr, *pTmp;
1158 int nItemCount = 0;
1159 if( SfxItemState::SET == rItemSet.GetItemState( aWhichIds[i], false,
1160 &pTmp ) )
1162 pItem = pTmp;
1163 nItemCount++;
1165 if( SfxItemState::SET == rItemSet.GetItemState( aWhichIds[i+1], false,
1166 &pTmp ) )
1168 pItemCJK = pTmp;
1169 nItemCount++;
1171 if( SfxItemState::SET == rItemSet.GetItemState( aWhichIds[i+2], false,
1172 &pTmp ) )
1174 pItemCTL = pTmp;
1175 nItemCount++;
1178 // If some of the items are set, but not all, we need script dependent
1179 // styles
1180 if( nItemCount > 0 && nItemCount < 3 )
1181 return true;
1183 if( 3 == nItemCount )
1185 // If all items are set, but some of them have different values,
1186 // we need script dependent styles, too. For font items, we have
1187 // to take care about their special HTML/CSS1 representation.
1188 if( RES_CHRATR_FONT == aWhichIds[i] )
1190 if( !swhtml_css1atr_equalFontItems( *pItem, *pItemCJK ) ||
1191 !swhtml_css1atr_equalFontItems( *pItem, *pItemCTL ) ||
1192 !swhtml_css1atr_equalFontItems( *pItemCJK, *pItemCTL ) )
1193 return true;
1195 else
1197 if( *pItem != *pItemCJK ||
1198 *pItem != *pItemCTL ||
1199 *pItemCJK != *pItemCTL )
1200 return true;
1205 const SwFormatDrop *pDrop;
1206 if( bCheckDropCap &&
1207 (pDrop = rItemSet.GetItemIfSet( RES_PARATR_DROP )) )
1209 const SwCharFormat *pDCCharFormat = pDrop->GetCharFormat();
1210 if( pDCCharFormat )
1212 //sequence of (start, end) property ranges we want to
1213 //query
1214 SfxItemSetFixed<
1215 RES_CHRATR_FONT, RES_CHRATR_FONT,
1216 RES_CHRATR_POSTURE, RES_CHRATR_POSTURE,
1217 RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT,
1218 RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONT,
1219 RES_CHRATR_CJK_POSTURE, RES_CHRATR_CTL_FONT,
1220 RES_CHRATR_CTL_POSTURE, RES_CHRATR_CTL_WEIGHT>
1221 aTstItemSet(*pDCCharFormat->GetAttrSet().GetPool());
1222 aTstItemSet.Set( pDCCharFormat->GetAttrSet() );
1223 return HasScriptDependentItems( aTstItemSet, false );
1227 return false;
1230 static bool OutCSS1Rule( SwHTMLWriter& rWrt, const OUString& rSelector,
1231 const SfxItemSet& rItemSet, bool bHasClass,
1232 bool bCheckForPseudo )
1234 bool bScriptDependent = false;
1235 if( SwHTMLWriter::HasScriptDependentItems( rItemSet, bHasClass ) )
1237 bScriptDependent = true;
1238 std::u16string_view aSelector( rSelector );
1240 std::u16string_view aPseudo;
1241 if( bCheckForPseudo )
1243 size_t nPos = aSelector.rfind( ':' );
1244 if( nPos != std::u16string_view::npos )
1246 aPseudo = aSelector.substr( nPos );
1247 aSelector =aSelector.substr( 0, nPos );
1251 if( !bHasClass )
1253 // If we are exporting styles for a tag we have to export a tag
1254 // rule for all properties that aren't style dependent and
1255 // some class rule for the additional style dependen properties
1257 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_NO_SCRIPT|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1258 &rSelector );
1259 rWrt.OutCSS1_SfxItemSet( rItemSet, false );
1262 //sequence of (start, end) property ranges we want to
1263 //query
1264 SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
1265 RES_CHRATR_LANGUAGE, RES_CHRATR_POSTURE,
1266 RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT,
1267 RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_WEIGHT>
1268 aScriptItemSet( *rItemSet.GetPool() );
1269 aScriptItemSet.Put( rItemSet );
1271 OUString aNewSelector = OUString::Concat(aSelector) + ".western" + aPseudo;
1273 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_WESTERN|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1274 &aNewSelector );
1275 rWrt.OutCSS1_SfxItemSet( aScriptItemSet, false );
1278 aNewSelector = OUString::Concat(aSelector) + ".cjk" + aPseudo;
1280 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_CJK|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1281 &aNewSelector );
1282 rWrt.OutCSS1_SfxItemSet( aScriptItemSet, false );
1285 aNewSelector = OUString::Concat(aSelector) + ".ctl" + aPseudo;
1287 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_CTL|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1288 &aNewSelector );
1289 rWrt.OutCSS1_SfxItemSet( aScriptItemSet, false );
1292 else
1294 // If there are script dependencies and we are derived from a tag,
1295 // when we have to export a style dependent class for all
1296 // scripts
1297 OUString aNewSelector = OUString::Concat(aSelector) + "-western" + aPseudo;
1299 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_WESTERN|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1300 &aNewSelector );
1301 rWrt.OutCSS1_SfxItemSet( rItemSet, false );
1304 aNewSelector = OUString::Concat(aSelector) + "-cjk" + aPseudo;
1306 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_CJK|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1307 &aNewSelector );
1308 rWrt.OutCSS1_SfxItemSet( rItemSet, false );
1311 aNewSelector = OUString::Concat(aSelector) + "-ctl" + aPseudo;
1313 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_CTL|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1314 &aNewSelector );
1315 rWrt.OutCSS1_SfxItemSet( rItemSet, false );
1319 else
1321 // If there are no script dependencies, when all items are
1322 // exported in one step. For hyperlinks only, a script information
1323 // must be there, because these two chr formats don't support
1324 // script dependencies by now.
1325 SwCSS1OutMode aMode( rWrt,
1326 rWrt.m_nCSS1Script|CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1327 &rSelector );
1328 rWrt.OutCSS1_SfxItemSet( rItemSet, false );
1331 return bScriptDependent;
1334 static void OutCSS1DropCapRule(
1335 SwHTMLWriter& rWrt, const OUString& rSelector,
1336 const SwFormatDrop& rDrop, bool bHasClass,
1337 bool bHasScriptDependencies )
1339 const SwCharFormat *pDCCharFormat = rDrop.GetCharFormat();
1340 if( (bHasScriptDependencies && bHasClass) ||
1341 (pDCCharFormat && SwHTMLWriter::HasScriptDependentItems( pDCCharFormat->GetAttrSet(), false ) ) )
1343 std::u16string_view aSelector( rSelector );
1345 std::u16string_view aPseudo;
1346 size_t nPos = aSelector.rfind( ':' );
1347 if( nPos != std::u16string_view::npos )
1349 aPseudo = aSelector.substr( nPos );
1350 aSelector = aSelector.substr( 0, nPos );
1353 if( !bHasClass )
1355 // If we are exporting styles for a tag we have to export a tag
1356 // rule for all properties that aren't style dependent and
1357 // some class rule for the additional style dependen properties
1359 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_NO_SCRIPT|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP,
1360 &rSelector );
1361 OutCSS1_SwFormatDropAttrs( rWrt, rDrop );
1364 SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
1365 RES_CHRATR_LANGUAGE, RES_CHRATR_POSTURE,
1366 RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT,
1367 RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_WEIGHT>
1368 aScriptItemSet( rWrt.m_pDoc->GetAttrPool() );
1369 if( pDCCharFormat )
1370 aScriptItemSet.Set( pDCCharFormat->GetAttrSet() );
1372 OUString aNewSelector = OUString::Concat(aSelector) + ".western" + aPseudo;
1374 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_WESTERN|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP,
1375 &aNewSelector );
1376 OutCSS1_SwFormatDropAttrs( rWrt, rDrop, &aScriptItemSet );
1379 aNewSelector = OUString::Concat(aSelector) + ".cjk" + aPseudo;
1381 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_CJK|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP,
1382 &aNewSelector );
1383 OutCSS1_SwFormatDropAttrs( rWrt, rDrop, &aScriptItemSet );
1386 aNewSelector = OUString::Concat(aSelector) + ".ctl" + aPseudo;
1388 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_CTL|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP,
1389 &aNewSelector );
1390 OutCSS1_SwFormatDropAttrs( rWrt, rDrop, &aScriptItemSet );
1393 else
1395 // If there are script dependencies and we are derived from a tag,
1396 // when we have to export a style dependent class for all
1397 // scripts
1398 OUString aNewSelector = OUString::Concat(aSelector) + "-western" + aPseudo;
1400 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_WESTERN|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP,
1401 &aNewSelector );
1402 OutCSS1_SwFormatDropAttrs( rWrt, rDrop );
1405 aNewSelector = OUString::Concat(aSelector) + "-cjk" + aPseudo;
1407 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_CJK|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP,
1408 &aNewSelector );
1409 OutCSS1_SwFormatDropAttrs( rWrt, rDrop );
1412 aNewSelector = OUString::Concat(aSelector) + "-ctl" + aPseudo;
1414 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_CTL|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP,
1415 &aNewSelector );
1416 OutCSS1_SwFormatDropAttrs( rWrt, rDrop );
1420 else
1422 // If there are no script dependencies, when all items are
1423 // exported in one step. For hyperlinks only, a script information
1424 // must be there, because these two chr formats don't support
1425 // script dependencies by now.
1426 SwCSS1OutMode aMode( rWrt,
1427 rWrt.m_nCSS1Script|CSS1_OUTMODE_RULE|CSS1_OUTMODE_DROPCAP,
1428 &rSelector );
1429 OutCSS1_SwFormatDropAttrs( rWrt, rDrop );
1433 static SwHTMLWriter& OutCSS1_SwFormat( SwHTMLWriter& rWrt, const SwFormat& rFormat,
1434 IDocumentStylePoolAccess/*SwDoc*/ *pDoc, SwDoc *pTemplate )
1436 bool bCharFormat = false;
1437 switch( rFormat.Which() )
1439 case RES_CHRFMT:
1440 bCharFormat = true;
1441 break;
1443 case RES_TXTFMTCOLL:
1444 case RES_CONDTXTFMTCOLL:
1445 // these template-types can be exported
1446 break;
1448 default:
1449 // but not these
1450 return rWrt;
1453 // determine Selector and the to-be-exported Attr-Set-depth
1454 OUString aSelector;
1455 sal_uInt16 nRefPoolId = 0;
1456 sal_uInt16 nDeep = GetCSS1Selector( &rFormat, aSelector, nRefPoolId );
1457 if( !nDeep )
1458 return rWrt; // not derived from a HTML-template
1460 sal_uInt16 nPoolFormatId = rFormat.GetPoolFormatId();
1462 // Determine the to-be-exported Attr-Set. We have to distinguish 3 cases:
1463 // - HTML-Tag templates (nDeep==USHRT_MAX):
1464 // Export Attrs...
1465 // - that are set in the template, but not in the original of the HTML template
1466 // - the Default-Attrs for the Attrs, that are set in the Original of the
1467 // HTML template, but not in the current template.
1468 // - templates directly derived from HTML templates (nDeep==1):
1469 // Export only Attributes of the template Item-Set w/o its parents.
1470 // - templates in-directly derived from HTML templates (nDeep>1):
1471 // Export Attributes of the template Item-Set incl. its Parents,
1472 // but w/o Attributes that are set in the HTML-Tag template.
1474 // create Item-Set with all Attributes from the template
1475 // (all but for nDeep==1)
1476 const SfxItemSet& rFormatItemSet = rFormat.GetAttrSet();
1477 SfxItemSet aItemSet( *rFormatItemSet.GetPool(), rFormatItemSet.GetRanges() );
1478 aItemSet.Set( rFormatItemSet ); // Was nDeep!=1 that is not working
1479 // for script dependent items but should
1480 // not make a difference for any other
1482 bool bSetDefaults = true, bClearSame = true;
1483 const SwFormat *pRefFormat = nullptr;
1484 const SwFormat *pRefFormatScript = nullptr;
1485 switch( nDeep )
1487 case CSS1_FMT_ISTAG:
1488 pRefFormat = SwHTMLWriter::GetTemplateFormat( nRefPoolId, pTemplate == nullptr ? nullptr : &pTemplate->getIDocumentStylePoolAccess() );
1489 break;
1490 case CSS1_FMT_CMPREF:
1491 pRefFormat = SwHTMLWriter::GetTemplateFormat( nRefPoolId, pDoc );
1492 pRefFormatScript = SwHTMLWriter::GetTemplateFormat( nRefPoolId, pTemplate == nullptr ? nullptr : &pTemplate->getIDocumentStylePoolAccess() );
1493 bClearSame = false;
1494 break;
1495 default:
1496 pRefFormat = SwHTMLWriter::GetParentFormat( rFormat, nDeep );
1497 pRefFormatScript = SwHTMLWriter::GetTemplateFormat( nRefPoolId, pTemplate == nullptr ? nullptr : &pTemplate->getIDocumentStylePoolAccess() );
1498 bSetDefaults = false;
1499 break;
1502 if( pRefFormat )
1504 // subtract Item-Set of the Reference template (incl. its Parents)
1505 SwHTMLWriter::SubtractItemSet( aItemSet, pRefFormat->GetAttrSet(),
1506 bSetDefaults, bClearSame,
1507 pRefFormatScript
1508 ? &pRefFormatScript->GetAttrSet()
1509 : nullptr );
1511 if( !bCharFormat )
1513 const SvxULSpaceItem& rULItem = pRefFormat->GetULSpace();
1514 rWrt.m_nDfltTopMargin = rULItem.GetUpper();
1515 rWrt.m_nDfltBottomMargin = rULItem.GetLower();
1518 else if( CSS1_FMT_ISTAG==nDeep && !bCharFormat )
1520 // set Default-distance above and below (for the
1521 // case that there is no reference template)
1522 rWrt.m_nDfltTopMargin = 0;
1523 rWrt.m_nDfltBottomMargin = HTML_PARSPACE;
1524 if( USER_FMT & nPoolFormatId )
1526 // user templates
1527 const OUString& aNm(rFormat.GetName());
1529 if (aNm == "DD 1" || aNm == "DT 1")
1530 rWrt.m_nDfltBottomMargin = 0;
1531 else if (aNm == OOO_STRING_SVTOOLS_HTML_listing)
1532 rWrt.m_nDfltBottomMargin = 0;
1533 else if (aNm == OOO_STRING_SVTOOLS_HTML_preformtxt)
1534 rWrt.m_nDfltBottomMargin = 0;
1535 else if (aNm == OOO_STRING_SVTOOLS_HTML_xmp)
1536 rWrt.m_nDfltBottomMargin = 0;
1538 else
1540 // Pool templates
1541 switch( nPoolFormatId )
1543 case RES_POOLCOLL_HEADLINE1:
1544 case RES_POOLCOLL_HEADLINE2:
1545 case RES_POOLCOLL_HEADLINE3:
1546 case RES_POOLCOLL_HEADLINE4:
1547 case RES_POOLCOLL_HEADLINE5:
1548 case RES_POOLCOLL_HEADLINE6:
1549 rWrt.m_nDfltTopMargin = HTML_HEADSPACE;
1550 break;
1551 case RES_POOLCOLL_SEND_ADDRESS:
1552 case RES_POOLCOLL_HTML_DT:
1553 case RES_POOLCOLL_HTML_DD:
1554 case RES_POOLCOLL_HTML_PRE:
1555 rWrt.m_nDfltBottomMargin = 0;
1556 break;
1561 // if nothing is to be exported ...
1562 if( !aItemSet.Count() )
1563 return rWrt;
1565 // There is no support for script dependent hyperlinks by now.
1566 bool bCheckForPseudo = false;
1567 if( bCharFormat &&
1568 (RES_POOLCHR_INET_NORMAL==nRefPoolId ||
1569 RES_POOLCHR_INET_VISIT==nRefPoolId) )
1570 bCheckForPseudo = true;
1572 // export now the Attributes (incl. selector)
1573 bool bHasScriptDependencies = false;
1574 if( OutCSS1Rule( rWrt, aSelector, aItemSet, CSS1_FMT_ISTAG != nDeep,
1575 bCheckForPseudo ) )
1577 if( bCharFormat )
1578 rWrt.m_aScriptTextStyles.insert( rFormat.GetName() );
1579 else
1581 if( nPoolFormatId==RES_POOLCOLL_TEXT )
1582 rWrt.m_aScriptParaStyles.insert( pDoc->GetTextCollFromPool( RES_POOLCOLL_STANDARD, false )->GetName() );
1583 rWrt.m_aScriptParaStyles.insert( rFormat.GetName() );
1585 bHasScriptDependencies = true;
1588 // export Drop-Caps
1589 if( const SwFormatDrop *pDrop = aItemSet.GetItemIfSet( RES_PARATR_DROP, false ) )
1591 OUString sOut = aSelector + ":" + sCSS1_first_letter;
1592 OutCSS1DropCapRule( rWrt, sOut, *pDrop, CSS1_FMT_ISTAG != nDeep, bHasScriptDependencies );
1595 return rWrt;
1598 static SwHTMLWriter& OutCSS1_SwPageDesc( SwHTMLWriter& rWrt, const SwPageDesc& rPageDesc,
1599 IDocumentStylePoolAccess/*SwDoc*/ *pDoc, SwDoc *pTemplate,
1600 sal_uInt16 nRefPoolId, bool bExtRef,
1601 bool bPseudo )
1603 const SwPageDesc* pRefPageDesc = nullptr;
1604 if( !bExtRef )
1605 pRefPageDesc = pDoc->GetPageDescFromPool( nRefPoolId, false );
1606 else if( pTemplate )
1607 pRefPageDesc = pTemplate->getIDocumentStylePoolAccess().GetPageDescFromPool( nRefPoolId, false );
1609 OUString aSelector = OUString::Concat("@") + sCSS1_page;
1611 if( bPseudo )
1613 std::u16string_view pPseudo;
1614 switch( rPageDesc.GetPoolFormatId() )
1616 case RES_POOLPAGE_FIRST: pPseudo = sCSS1_first; break;
1617 case RES_POOLPAGE_LEFT: pPseudo = sCSS1_left; break;
1618 case RES_POOLPAGE_RIGHT: pPseudo = sCSS1_right; break;
1620 if( !pPseudo.empty() )
1621 aSelector += OUString::Concat(":") + pPseudo;
1624 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_RULE_ON|CSS1_OUTMODE_TEMPLATE,
1625 &aSelector );
1627 // Size: If the only difference is the Landscape-Flag,
1628 // only export Portrait or Landscape. Otherwise export size.
1629 bool bRefLandscape = pRefPageDesc && pRefPageDesc->GetLandscape();
1630 Size aRefSz;
1631 const Size& rSz = rPageDesc.GetMaster().GetFrameSize().GetSize();
1632 if( pRefPageDesc )
1634 aRefSz = pRefPageDesc->GetMaster().GetFrameSize().GetSize();
1635 if( bRefLandscape != rPageDesc.GetLandscape() )
1637 tools::Long nTmp = aRefSz.Height();
1638 aRefSz.setHeight( aRefSz.Width() );
1639 aRefSz.setWidth( nTmp );
1643 // TODO: Bad Hack: On the Page-Tabpage there are small rounding errors
1644 // for the page size. Partially because of bug 25535, we stupidly still
1645 // use the Size-Item from Dialog, even if nothing changed.
1646 // Thus: once one visited the Page-Dialog and left it with OK, we get a
1647 // new page size that then gets exported here. To avoid that, we allow
1648 // here small deviations.
1649 if( std::abs( rSz.Width() - aRefSz.Width() ) <= 2 &&
1650 std::abs( rSz.Height() - aRefSz.Height() ) <= 2 )
1652 if( bRefLandscape != rPageDesc.GetLandscape() )
1654 rWrt.OutCSS1_PropertyAscii( sCSS1_P_size,
1655 rPageDesc.GetLandscape() ? sCSS1_PV_landscape
1656 : sCSS1_PV_portrait );
1659 else
1661 OStringBuffer sVal;
1662 AddUnitPropertyValue(sVal, rSz.Width(), rWrt.GetCSS1Unit());
1663 sVal.append(' ');
1664 AddUnitPropertyValue(sVal, rSz.Height(), rWrt.GetCSS1Unit());
1665 rWrt.OutCSS1_PropertyAscii(sCSS1_P_size, sVal);
1668 // Export the distance-Attributes as normally
1669 const SwFrameFormat &rMaster = rPageDesc.GetMaster();
1670 SfxItemSetFixed<RES_LR_SPACE, RES_UL_SPACE> aItemSet( *rMaster.GetAttrSet().GetPool() );
1671 aItemSet.Set( rMaster.GetAttrSet() );
1673 if( pRefPageDesc )
1675 SwHTMLWriter::SubtractItemSet( aItemSet,
1676 pRefPageDesc->GetMaster().GetAttrSet(),
1677 true );
1680 OutCSS1_SvxULSpace_SvxLRSpace( rWrt, aItemSet );
1682 // If for a Pseudo-Selector no Property had been set, we still
1683 // have to export something, so that the corresponding template is
1684 // created on the next import.
1685 if( rWrt.m_bFirstCSS1Property && bPseudo )
1687 rWrt.OutNewLine();
1688 OString sTmp(OUStringToOString(aSelector, RTL_TEXTENCODING_UTF8));
1689 rWrt.Strm().WriteOString( sTmp ).WriteOString( " {" );
1690 rWrt.m_bFirstCSS1Property = false;
1693 if( !rWrt.m_bFirstCSS1Property )
1694 rWrt.Strm().WriteOString( sCSS1_rule_end );
1696 return rWrt;
1699 static SwHTMLWriter& OutCSS1_SwFootnoteInfo( SwHTMLWriter& rWrt, const SwEndNoteInfo& rInfo,
1700 SwDoc *pDoc, bool bHasNotes, bool bEndNote )
1702 OUString aSelector;
1704 if( bHasNotes )
1706 aSelector = OUString::Concat(OOO_STRING_SVTOOLS_HTML_anchor ".") +
1707 ( bEndNote ? std::u16string_view(u"" OOO_STRING_SVTOOLS_HTML_sdendnote_anc)
1708 : std::u16string_view(u"" OOO_STRING_SVTOOLS_HTML_sdfootnote_anc) );
1709 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_RULE|CSS1_OUTMODE_TEMPLATE,
1710 &aSelector );
1711 rWrt.OutCSS1_PropertyAscii( sCSS1_P_font_size,
1712 sHTML_FTN_fontheight );
1713 rWrt.Strm().WriteOString( sCSS1_rule_end );
1716 const SwCharFormat *pSymCharFormat = rInfo.GetCharFormat( *pDoc );
1717 if( pSymCharFormat )
1719 const SfxItemSet& rFormatItemSet = pSymCharFormat->GetAttrSet();
1720 SfxItemSet aItemSet( *rFormatItemSet.GetPool(), rFormatItemSet.GetRanges() );
1721 aItemSet.Set( rFormatItemSet );
1723 // If there are footnotes or endnotes, then all Attributes have to be
1724 // exported, so that Netscape displays the document correctly.
1725 // Otherwise it is sufficient, to export the differences to the
1726 // footnote and endnote template.
1727 if( !bHasNotes && rWrt.m_xTemplate.is() )
1729 SwFormat *pRefFormat = rWrt.m_xTemplate->getIDocumentStylePoolAccess().GetCharFormatFromPool(
1730 static_cast< sal_uInt16 >(bEndNote ? RES_POOLCHR_ENDNOTE : RES_POOLCHR_FOOTNOTE) );
1731 if( pRefFormat )
1732 SwHTMLWriter::SubtractItemSet( aItemSet, pRefFormat->GetAttrSet(),
1733 true );
1735 if( aItemSet.Count() )
1737 aSelector = OUString::Concat(OOO_STRING_SVTOOLS_HTML_anchor ".") +
1738 ( bEndNote ? std::u16string_view(u"" OOO_STRING_SVTOOLS_HTML_sdendnote_sym)
1739 : std::u16string_view(
1740 u"" OOO_STRING_SVTOOLS_HTML_sdfootnote_sym));
1741 if( OutCSS1Rule( rWrt, aSelector, aItemSet, true, false ))
1742 rWrt.m_aScriptTextStyles.insert( pSymCharFormat->GetName() );
1746 return rWrt;
1749 SwHTMLWriter& OutCSS1_BodyTagStyleOpt( SwHTMLWriter& rWrt, const SfxItemSet& rItemSet )
1751 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_STYLE_OPT_ON |
1752 CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_BODY, nullptr );
1754 // Only export the attributes of the page template.
1755 // The attributes of the default paragraph template were
1756 // considered already when exporting the paragraph template.
1758 const SfxPoolItem *pItem;
1759 if( SfxItemState::SET == rItemSet.GetItemState( RES_BACKGROUND, false,
1760 &pItem ) )
1762 OUString rEmbeddedGraphicName;
1763 OutCSS1_SvxBrush( rWrt, *pItem, sw::Css1Background::Page, &rEmbeddedGraphicName );
1766 if( SfxItemState::SET == rItemSet.GetItemState( RES_BOX, false,
1767 &pItem ))
1769 OutCSS1_SvxBox( rWrt, *pItem );
1772 if( !rWrt.m_bFirstCSS1Property )
1774 // if a Property was exported as part of a Style-Option,
1775 // the Option still needs to be finished
1776 rWrt.Strm().WriteChar( '\"' );
1779 return rWrt;
1782 SwHTMLWriter& OutCSS1_ParaTagStyleOpt( SwHTMLWriter& rWrt, const SfxItemSet& rItemSet, std::string_view rAdd )
1784 SwCSS1OutMode aMode( rWrt, rWrt.m_nCSS1Script|CSS1_OUTMODE_STYLE_OPT |
1785 CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_PARA, nullptr );
1786 rWrt.OutCSS1_SfxItemSet( rItemSet, false, rAdd );
1788 return rWrt;
1791 SwHTMLWriter& OutCSS1_TableBGStyleOpt( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
1793 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_STYLE_OPT_ON |
1794 CSS1_OUTMODE_ENCODE|
1795 CSS1_OUTMODE_TABLEBOX, nullptr );
1796 OutCSS1_SvxBrush( rWrt, rHt, sw::Css1Background::TableRow, nullptr );
1798 if (!rWrt.m_bFirstCSS1Property)
1799 rWrt.Strm().WriteChar(cCSS1_style_opt_end);
1801 return rWrt;
1804 SwHTMLWriter& OutCSS1_NumberBulletListStyleOpt( SwHTMLWriter& rWrt, const SwNumRule& rNumRule,
1805 sal_uInt8 nLevel )
1807 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_STYLE_OPT |
1808 CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_PARA, nullptr );
1810 const SwNumFormat& rNumFormat = rNumRule.Get( nLevel );
1812 tools::Long nLSpace = rNumFormat.GetAbsLSpace();
1813 tools::Long nFirstLineOffset = rNumFormat.GetFirstLineOffset();
1814 tools::Long nDfltFirstLineOffset = HTML_NUMBER_BULLET_INDENT;
1815 if( nLevel > 0 )
1817 const SwNumFormat& rPrevNumFormat = rNumRule.Get( nLevel-1 );
1818 nLSpace -= rPrevNumFormat.GetAbsLSpace();
1819 nDfltFirstLineOffset = rPrevNumFormat.GetFirstLineOffset();
1822 if( rWrt.IsHTMLMode(HTMLMODE_LSPACE_IN_NUMBER_BULLET) &&
1823 nLSpace != HTML_NUMBER_BULLET_MARGINLEFT )
1824 rWrt.OutCSS1_UnitProperty( sCSS1_P_margin_left, nLSpace );
1826 if( rWrt.IsHTMLMode(HTMLMODE_FRSTLINE_IN_NUMBER_BULLET) &&
1827 nFirstLineOffset != nDfltFirstLineOffset )
1828 rWrt.OutCSS1_UnitProperty( sCSS1_P_text_indent, nFirstLineOffset );
1830 if( !rWrt.m_bFirstCSS1Property )
1831 rWrt.Strm().WriteChar( '\"' );
1833 return rWrt;
1836 void SwHTMLWriter::OutCSS1_FrameFormatOptions( const SwFrameFormat& rFrameFormat,
1837 HtmlFrmOpts nFrameOpts,
1838 const SdrObject *pSdrObj,
1839 const SfxItemSet *pItemSet )
1841 SwCSS1OutMode aMode( *this, CSS1_OUTMODE_STYLE_OPT_ON |
1842 CSS1_OUTMODE_ENCODE|
1843 CSS1_OUTMODE_FRAME, nullptr );
1845 const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient();
1846 SvxLRSpaceItem aLRItem( rFrameFormat.GetLRSpace() );
1847 SvxULSpaceItem aULItem( rFrameFormat.GetULSpace() );
1848 if( nFrameOpts & HtmlFrmOpts::SAlign )
1850 const SwFormatAnchor& rAnchor = rFrameFormat.GetAnchor();
1851 switch( rAnchor.GetAnchorId() )
1853 case RndStdIds::FLY_AT_PARA:
1854 case RndStdIds::FLY_AT_CHAR:
1855 if( text::RelOrientation::FRAME == rHoriOri.GetRelationOrient() ||
1856 text::RelOrientation::PRINT_AREA == rHoriOri.GetRelationOrient() )
1858 if( !(nFrameOpts & HtmlFrmOpts::Align) )
1860 // float
1861 std::string_view pStr = text::HoriOrientation::RIGHT==rHoriOri.GetHoriOrient()
1862 ? sCSS1_PV_right
1863 : sCSS1_PV_left;
1864 OutCSS1_PropertyAscii( sCSS1_P_float, pStr );
1866 break;
1868 [[fallthrough]];
1870 case RndStdIds::FLY_AT_PAGE:
1871 case RndStdIds::FLY_AT_FLY:
1873 // position
1874 OutCSS1_PropertyAscii( sCSS1_P_position, sCSS1_PV_absolute );
1876 // For top/left we need to subtract the distance to the frame
1877 // from the position, as in CSS1 it is added to the position.
1878 // This works also for automatically aligned frames, even that
1879 // in this case Writer also adds the distance; because in this
1880 // case the Orient-Attribute contains the correct position.
1882 // top
1883 tools::Long nXPos=0, nYPos=0;
1884 bool bOutXPos = false, bOutYPos = false;
1885 if( RES_DRAWFRMFMT == rFrameFormat.Which() )
1887 OSL_ENSURE( pSdrObj, "Do not pass a SdrObject. Inefficient" );
1888 if( !pSdrObj )
1889 pSdrObj = rFrameFormat.FindSdrObject();
1890 OSL_ENSURE( pSdrObj, "Where is the SdrObject" );
1891 if( pSdrObj )
1893 Point aPos( pSdrObj->GetRelativePos() );
1894 nXPos = aPos.X();
1895 nYPos = aPos.Y();
1897 bOutXPos = bOutYPos = true;
1899 else
1901 bOutXPos = text::RelOrientation::CHAR != rHoriOri.GetRelationOrient();
1902 nXPos = text::HoriOrientation::NONE == rHoriOri.GetHoriOrient()
1903 ? rHoriOri.GetPos() : 0;
1905 const SwFormatVertOrient& rVertOri = rFrameFormat.GetVertOrient();
1906 bOutYPos = text::RelOrientation::CHAR != rVertOri.GetRelationOrient();
1907 nYPos = text::VertOrientation::NONE == rVertOri.GetVertOrient()
1908 ? rVertOri.GetPos() : 0;
1911 if( bOutYPos )
1913 if( IsHTMLMode( HTMLMODE_FLY_MARGINS) )
1915 nYPos -= aULItem.GetUpper();
1916 if( nYPos < 0 )
1918 aULItem.SetUpper( o3tl::narrowing<sal_uInt16>(aULItem.GetUpper() + nYPos) );
1919 nYPos = 0;
1923 OutCSS1_UnitProperty( sCSS1_P_top, nYPos );
1926 if( bOutXPos )
1928 // left
1929 if( IsHTMLMode( HTMLMODE_FLY_MARGINS) )
1931 nXPos -= aLRItem.ResolveLeft({});
1932 if( nXPos < 0 )
1934 aLRItem.SetLeft(SvxIndentValue::twips(
1935 o3tl::narrowing<sal_uInt16>(aLRItem.ResolveLeft({}) + nXPos)));
1936 nXPos = 0;
1940 OutCSS1_UnitProperty( sCSS1_P_left, nXPos );
1943 break;
1945 default:
1950 // width/height
1951 if( nFrameOpts & HtmlFrmOpts::SSize )
1953 if( RES_DRAWFRMFMT == rFrameFormat.Which() )
1955 OSL_ENSURE( pSdrObj, "Do not pass a SdrObject. Inefficient" );
1956 if( !pSdrObj )
1957 pSdrObj = rFrameFormat.FindSdrObject();
1958 OSL_ENSURE( pSdrObj, "Where is the SdrObject" );
1959 if( pSdrObj )
1961 Size aTwipSz( pSdrObj->GetLogicRect().GetSize() );
1962 if( nFrameOpts & HtmlFrmOpts::SWidth )
1964 if( nFrameOpts & HtmlFrmOpts::SPixSize )
1965 OutCSS1_PixelProperty( sCSS1_P_width, aTwipSz.Width() );
1966 else
1967 OutCSS1_UnitProperty( sCSS1_P_width, aTwipSz.Width() );
1969 if( nFrameOpts & HtmlFrmOpts::SHeight )
1971 if( nFrameOpts & HtmlFrmOpts::SPixSize )
1972 OutCSS1_PixelProperty( sCSS1_P_height, aTwipSz.Height() );
1973 else
1974 OutCSS1_UnitProperty( sCSS1_P_height, aTwipSz.Height() );
1978 else
1980 OSL_ENSURE( HtmlFrmOpts::AbsSize & nFrameOpts,
1981 "Export absolute size" );
1982 OSL_ENSURE( HtmlFrmOpts::AnySize & nFrameOpts,
1983 "Export every size" );
1984 Css1FrameSize nMode = Css1FrameSize::NONE;
1985 if( nFrameOpts & HtmlFrmOpts::SWidth )
1986 nMode |= Css1FrameSize::Width;
1987 if( nFrameOpts & HtmlFrmOpts::SHeight )
1988 nMode |= Css1FrameSize::MinHeight|Css1FrameSize::FixHeight;
1989 if( nFrameOpts & HtmlFrmOpts::SPixSize )
1990 nMode |= Css1FrameSize::Pixel;
1992 OutCSS1_SwFormatFrameSize( *this, rFrameFormat.GetFrameSize(), nMode );
1996 const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
1997 // margin-*
1998 if( (nFrameOpts & HtmlFrmOpts::SSpace) &&
1999 IsHTMLMode( HTMLMODE_FLY_MARGINS) )
2001 const SvxLRSpaceItem *pLRItem = nullptr;
2002 const SvxULSpaceItem *pULItem = nullptr;
2003 if( SfxItemState::SET == rItemSet.GetItemState( RES_LR_SPACE ) )
2004 pLRItem = &aLRItem;
2005 if( SfxItemState::SET == rItemSet.GetItemState( RES_UL_SPACE ) )
2006 pULItem = &aULItem;
2007 if( pLRItem || pULItem )
2008 OutCSS1_SvxULSpace_SvxLRSpace( *this, pULItem, pLRItem );
2011 // border
2012 if( nFrameOpts & HtmlFrmOpts::SBorder )
2014 const SfxPoolItem* pItem;
2015 if( nFrameOpts & HtmlFrmOpts::SNoBorder )
2016 OutCSS1_SvxBox( *this, rFrameFormat.GetBox() );
2017 else if( SfxItemState::SET==rItemSet.GetItemState( RES_BOX, true, &pItem ) )
2018 OutCSS1_SvxBox( *this, *pItem );
2021 // background (if, then the color must be set also)
2022 if( nFrameOpts & HtmlFrmOpts::SBackground )
2023 OutCSS1_FrameFormatBackground( rFrameFormat );
2025 if( pItemSet )
2026 OutCSS1_SfxItemSet( *pItemSet, false );
2028 if( !m_bFirstCSS1Property )
2029 Strm().WriteChar( '\"' );
2032 void SwHTMLWriter::OutCSS1_TableFrameFormatOptions( const SwFrameFormat& rFrameFormat )
2034 SwCSS1OutMode aMode( *this, CSS1_OUTMODE_STYLE_OPT_ON |
2035 CSS1_OUTMODE_ENCODE|
2036 CSS1_OUTMODE_TABLE, nullptr );
2038 const SfxPoolItem *pItem;
2039 const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
2040 if( SfxItemState::SET==rItemSet.GetItemState( RES_BACKGROUND, false, &pItem ) )
2041 OutCSS1_SvxBrush( *this, *pItem, sw::Css1Background::Table, nullptr );
2043 if( IsHTMLMode( HTMLMODE_PRINT_EXT ) )
2044 OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( *this, rItemSet, false );
2046 if( SfxItemState::SET==rItemSet.GetItemState( RES_LAYOUT_SPLIT, false, &pItem ) )
2047 OutCSS1_SwFormatLayoutSplit( *this, *pItem );
2049 if (mbXHTML)
2051 sal_Int16 eTabHoriOri = rFrameFormat.GetHoriOrient().GetHoriOrient();
2052 if (eTabHoriOri == text::HoriOrientation::CENTER)
2054 // Emit XHTML's center using inline CSS.
2055 OutCSS1_Property(sCSS1_P_margin_left, "auto", nullptr, sw::Css1Background::Table);
2056 OutCSS1_Property(sCSS1_P_margin_right, "auto", nullptr, sw::Css1Background::Table);
2060 if( !m_bFirstCSS1Property )
2061 Strm().WriteChar( '\"' );
2064 void SwHTMLWriter::OutCSS1_TableCellBordersAndBG(SwFrameFormat const& rFrameFormat, const SvxBrushItem *pBrushItem)
2066 SwCSS1OutMode const aMode( *this,
2067 CSS1_OUTMODE_STYLE_OPT_ON|CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_TABLEBOX, nullptr );
2068 if (pBrushItem)
2069 OutCSS1_SvxBrush(*this, *pBrushItem, sw::Css1Background::TableCell, nullptr);
2070 OutCSS1_SvxBox(*this, rFrameFormat.GetBox());
2071 if (!m_bFirstCSS1Property)
2072 Strm().WriteChar(cCSS1_style_opt_end);
2075 void SwHTMLWriter::OutCSS1_SectionFormatOptions( const SwFrameFormat& rFrameFormat, const SwFormatCol *pCol )
2077 SwCSS1OutMode aMode( *this, CSS1_OUTMODE_STYLE_OPT_ON |
2078 CSS1_OUTMODE_ENCODE|
2079 CSS1_OUTMODE_SECTION, nullptr );
2081 const SfxPoolItem *pItem;
2082 const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
2083 if( SfxItemState::SET==rItemSet.GetItemState( RES_BACKGROUND, false, &pItem ) )
2084 OutCSS1_SvxBrush( *this, *pItem, sw::Css1Background::Section, nullptr );
2086 if (mbXHTML)
2088 SvxFrameDirection nDir = GetHTMLDirection(rFrameFormat.GetAttrSet());
2089 OString sConvertedDirection = convertDirection(nDir);
2090 if (!sConvertedDirection.isEmpty())
2092 OutCSS1_Property(sCSS1_P_dir, sConvertedDirection, nullptr,
2093 sw::Css1Background::Section);
2097 if (pCol)
2099 OString sColumnCount(OString::number(static_cast<sal_Int32>(pCol->GetNumCols())));
2100 OutCSS1_PropertyAscii(sCSS1_P_column_count, sColumnCount);
2103 if( !m_bFirstCSS1Property )
2104 Strm().WriteChar( '\"' );
2107 static bool OutCSS1_FrameFormatBrush( SwHTMLWriter& rWrt,
2108 const SvxBrushItem& rBrushItem )
2110 bool bWritten = false;
2111 /// output brush of frame format, if its background color is not "no fill"/"auto fill"
2112 /// or it has a background graphic.
2113 if( rBrushItem.GetColor() != COL_TRANSPARENT ||
2114 !rBrushItem.GetGraphicLink().isEmpty() ||
2115 0 != rBrushItem.GetGraphicPos() )
2117 OutCSS1_SvxBrush( rWrt, rBrushItem, sw::Css1Background::Fly, nullptr );
2118 bWritten = true;
2120 return bWritten;
2123 void SwHTMLWriter::OutCSS1_FrameFormatBackground( const SwFrameFormat& rFrameFormat )
2125 // If the frame itself has a background, then export.
2126 if( OutCSS1_FrameFormatBrush( *this, *rFrameFormat.makeBackgroundBrushItem() ) )
2127 return;
2129 // If the frame is not linked to a page, we use the background of the anchor.
2130 const SwFormatAnchor& rAnchor = rFrameFormat.GetAnchor();
2131 RndStdIds eAnchorId = rAnchor.GetAnchorId();
2132 const SwNode *pAnchorNode = rAnchor.GetAnchorNode();
2133 if (RndStdIds::FLY_AT_PAGE != eAnchorId && pAnchorNode)
2135 if( pAnchorNode->IsContentNode() )
2137 // If the frame is linked to a content-node,
2138 // we take the background of the content-node, if it has one.
2139 if( OutCSS1_FrameFormatBrush( *this,
2140 pAnchorNode->GetContentNode()->GetSwAttrSet().GetBackground()) )
2141 return;
2143 // Otherwise we also could be in a table
2144 const SwTableNode *pTableNd = pAnchorNode->FindTableNode();
2145 if( pTableNd )
2147 const SwStartNode *pBoxSttNd = pAnchorNode->FindTableBoxStartNode();
2148 const SwTableBox *pBox =
2149 pTableNd->GetTable().GetTableBox( pBoxSttNd->GetIndex() );
2151 // If the box has a background, we take it.
2152 if( OutCSS1_FrameFormatBrush( *this,
2153 *pBox->GetFrameFormat()->makeBackgroundBrushItem() ) )
2154 return;
2156 // Otherwise we use that of the lines
2157 const SwTableLine *pLine = pBox->GetUpper();
2158 while( pLine )
2160 if( OutCSS1_FrameFormatBrush( *this,
2161 *pLine->GetFrameFormat()->makeBackgroundBrushItem() ) )
2162 return;
2163 pBox = pLine->GetUpper();
2164 pLine = pBox ? pBox->GetUpper() : nullptr;
2167 // If there was none either, we use the background of the table.
2168 if( OutCSS1_FrameFormatBrush( *this,
2169 *pTableNd->GetTable().GetFrameFormat()->makeBackgroundBrushItem() ) )
2170 return;
2175 // If the anchor is again in a Fly-Frame, use the background of the Fly-Frame.
2176 const SwFrameFormat *pFrameFormat = pAnchorNode->GetFlyFormat();
2177 if( pFrameFormat )
2179 OutCSS1_FrameFormatBackground( *pFrameFormat );
2180 return;
2184 // At last there is the background of the page, and as the final rescue
2185 // the value of the Config.
2186 assert(m_pCurrPageDesc && "no page template found");
2187 if( OutCSS1_FrameFormatBrush( *this,
2188 *m_pCurrPageDesc->GetMaster().makeBackgroundBrushItem() ) )
2189 return;
2191 Color aColor( COL_WHITE );
2193 // The background color is normally only used in Browse-Mode.
2194 // We always use it for a HTML document, but for a text document
2195 // only if viewed in Browse-Mode.
2196 if( m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) ||
2197 m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE))
2199 SwViewShell *pVSh = m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
2200 if ( pVSh &&
2201 COL_TRANSPARENT != pVSh->GetViewOptions()->GetRetoucheColor())
2202 aColor = pVSh->GetViewOptions()->GetRetoucheColor();
2205 OutCSS1_PropertyAscii(sCSS1_P_background, GetCSS1_Color(aColor));
2208 static SwHTMLWriter& OutCSS1_SvxTextLn_SvxCrOut_SvxBlink( SwHTMLWriter& rWrt,
2209 const SvxUnderlineItem *pUItem,
2210 const SvxOverlineItem *pOItem,
2211 const SvxCrossedOutItem *pCOItem,
2212 const SvxBlinkItem *pBItem )
2214 bool bNone = false;
2215 OStringBuffer sOut;
2217 if( pUItem )
2219 switch( pUItem->GetLineStyle() )
2221 case LINESTYLE_NONE:
2222 bNone = true;
2223 break;
2224 case LINESTYLE_DONTKNOW:
2225 break;
2226 default:
2227 if( !rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
2229 // this also works in HTML does not need to be written as
2230 // a STYLE-Options, and must not be written as Hint
2231 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT) || rWrt.mbReqIF,
2232 "write underline as Hint?" );
2233 sOut.append(sCSS1_PV_underline);
2235 break;
2239 if( pOItem )
2241 switch( pOItem->GetLineStyle() )
2243 case LINESTYLE_NONE:
2244 bNone = true;
2245 break;
2246 case LINESTYLE_DONTKNOW:
2247 break;
2248 default:
2249 if( !rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
2251 // this also works in HTML does not need to be written as
2252 // a STYLE-Options, and must not be written as Hint
2253 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT),
2254 "write overline as Hint?" );
2255 if (!sOut.isEmpty())
2256 sOut.append(' ');
2257 sOut.append(sCSS1_PV_overline);
2259 break;
2263 if( pCOItem )
2265 switch( pCOItem->GetStrikeout() )
2267 case STRIKEOUT_NONE:
2268 bNone = true;
2269 break;
2270 case STRIKEOUT_DONTKNOW:
2271 break;
2272 default:
2273 if( !rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
2275 // this also works in HTML does not need to be written as
2276 // a STYLE-Options, and must not be written as Hint
2277 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT) || rWrt.mbReqIF,
2278 "write crossedOut as Hint?" );
2279 if (!sOut.isEmpty())
2280 sOut.append(' ');
2281 sOut.append(sCSS1_PV_line_through);
2283 break;
2287 if( pBItem )
2289 if( !pBItem->GetValue() )
2291 bNone = true;
2293 else if( !rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
2295 // this also works in HTML does not need to be written as
2296 // a STYLE-Options, and must not be written as Hint
2297 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT),
2298 "write blink as Hint?" );
2299 if (!sOut.isEmpty())
2300 sOut.append(' ');
2301 sOut.append(sCSS1_PV_blink);
2305 if (!sOut.isEmpty())
2306 rWrt.OutCSS1_PropertyAscii( sCSS1_P_text_decoration, sOut );
2307 else if( bNone )
2308 rWrt.OutCSS1_PropertyAscii( sCSS1_P_text_decoration, sCSS1_PV_none );
2310 return rWrt;
2313 static SwHTMLWriter& OutCSS1_SvxCaseMap( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2315 switch( static_cast<const SvxCaseMapItem&>(rHt).GetCaseMap() )
2317 case SvxCaseMap::NotMapped:
2318 rWrt.OutCSS1_PropertyAscii( sCSS1_P_font_variant, sCSS1_PV_normal );
2319 break;
2320 case SvxCaseMap::SmallCaps:
2321 rWrt.OutCSS1_PropertyAscii( sCSS1_P_font_variant, sCSS1_PV_small_caps );
2322 break;
2323 case SvxCaseMap::Uppercase:
2324 rWrt.OutCSS1_PropertyAscii( sCSS1_P_text_transform, sCSS1_PV_uppercase );
2325 break;
2326 case SvxCaseMap::Lowercase:
2327 rWrt.OutCSS1_PropertyAscii( sCSS1_P_text_transform, sCSS1_PV_lowercase );
2328 break;
2329 case SvxCaseMap::Capitalize:
2330 rWrt.OutCSS1_PropertyAscii( sCSS1_P_text_transform, sCSS1_PV_capitalize );
2331 break;
2332 default:
2336 return rWrt;
2339 static SwHTMLWriter& OutCSS1_SvxColor( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2341 // Colors do not need to be exported for Style-Option.
2342 if( rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) &&
2343 !rWrt.m_bCfgPreferStyles )
2344 return rWrt;
2345 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT),
2346 "write color as Hint?" );
2348 Color aColor( static_cast<const SvxColorItem&>(rHt).GetValue() );
2349 if( COL_AUTO == aColor )
2350 aColor = COL_BLACK;
2352 rWrt.OutCSS1_PropertyAscii(sCSS1_P_color, GetCSS1_Color(aColor));
2354 return rWrt;
2357 static SwHTMLWriter& OutCSS1_SvxCrossedOut( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2359 // This function only exports Hints!
2360 // Otherwise OutCSS1_SvxTextLn_SvxCrOut_SvxBlink() is called directly.
2362 if( rWrt.IsCSS1Source(CSS1_OUTMODE_HINT) )
2363 OutCSS1_SvxTextLn_SvxCrOut_SvxBlink( rWrt,
2364 nullptr, nullptr, static_cast<const SvxCrossedOutItem *>(&rHt), nullptr );
2366 return rWrt;
2369 static SwHTMLWriter& OutCSS1_SvxFont( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2371 // No need to export Fonts for the Style-Option.
2372 if( rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
2373 return rWrt;
2375 sal_uInt16 nScript = CSS1_OUTMODE_WESTERN;
2376 switch( rHt.Which() )
2378 case RES_CHRATR_CJK_FONT: nScript = CSS1_OUTMODE_CJK; break;
2379 case RES_CHRATR_CTL_FONT: nScript = CSS1_OUTMODE_CTL; break;
2381 if( !rWrt.IsCSS1Script( nScript ) )
2382 return rWrt;
2384 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT),
2385 "write Font as Hint?" );
2387 OUString sOut;
2388 // MS IE3b1 has problems with single quotes
2389 sal_uInt16 nMode = rWrt.m_nCSS1OutMode & CSS1_OUTMODE_ANY_ON;
2390 sal_Unicode cQuote = nMode == CSS1_OUTMODE_RULE_ON ? '\"' : '\'';
2391 SwHTMLWriter::PrepareFontList( static_cast<const SvxFontItem&>(rHt), sOut, cQuote,
2392 true );
2394 rWrt.OutCSS1_Property( sCSS1_P_font_family, sOut );
2396 return rWrt;
2399 static SwHTMLWriter& OutCSS1_SvxFontHeight( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2401 // Font-Height need not be exported in the Style-Option.
2402 // For Drop-Caps another Font-Size is exported.
2403 if( rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ||
2404 rWrt.IsCSS1Source( CSS1_OUTMODE_DROPCAP ) )
2405 return rWrt;
2407 sal_uInt16 nScript = CSS1_OUTMODE_WESTERN;
2408 switch( rHt.Which() )
2410 case RES_CHRATR_CJK_FONTSIZE: nScript = CSS1_OUTMODE_CJK; break;
2411 case RES_CHRATR_CTL_FONTSIZE: nScript = CSS1_OUTMODE_CTL; break;
2413 if( !rWrt.IsCSS1Script( nScript ) )
2414 return rWrt;
2416 sal_uInt32 nHeight = static_cast<const SvxFontHeightItem&>(rHt).GetHeight();
2417 OString sHeight(OString::number(nHeight/20) + sCSS1_UNIT_pt);
2418 rWrt.OutCSS1_PropertyAscii(sCSS1_P_font_size, sHeight);
2420 return rWrt;
2423 static SwHTMLWriter& OutCSS1_SvxPosture( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2425 sal_uInt16 nScript = CSS1_OUTMODE_WESTERN;
2426 switch( rHt.Which() )
2428 case RES_CHRATR_CJK_POSTURE: nScript = CSS1_OUTMODE_CJK; break;
2429 case RES_CHRATR_CTL_POSTURE: nScript = CSS1_OUTMODE_CTL; break;
2431 if( !rWrt.IsCSS1Script( nScript ) )
2432 return rWrt;
2434 std::string_view pStr;
2435 switch( static_cast<const SvxPostureItem&>(rHt).GetPosture() )
2437 case ITALIC_NONE: pStr = sCSS1_PV_normal; break;
2438 case ITALIC_OBLIQUE: pStr = sCSS1_PV_oblique; break;
2439 case ITALIC_NORMAL:
2440 if( !rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
2442 // this also works in HTML does not need to be written as
2443 // a STYLE-Options, and must not be written as Hint
2444 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT),
2445 "write italic as Hint?" );
2446 pStr = sCSS1_PV_italic;
2448 break;
2449 default:
2453 if( !pStr.empty() )
2454 rWrt.OutCSS1_PropertyAscii( sCSS1_P_font_style, pStr );
2456 return rWrt;
2459 static SwHTMLWriter& OutCSS1_SvxKerning( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2461 sal_Int16 nValue = static_cast<const SvxKerningItem&>(rHt).GetValue();
2462 if( nValue )
2464 OStringBuffer sOut;
2465 if( nValue < 0 )
2467 sOut.append('-');
2468 nValue = -nValue;
2471 // Width as n.n pt
2472 nValue = (nValue + 1) / 2; // 1/10pt
2473 sOut.append(OString::number(nValue / 10) + "." + OString::number(nValue % 10) +
2474 sCSS1_UNIT_pt);
2476 rWrt.OutCSS1_PropertyAscii(sCSS1_P_letter_spacing, sOut);
2477 sOut.setLength(0);
2479 else
2481 rWrt.OutCSS1_PropertyAscii( sCSS1_P_letter_spacing,
2482 sCSS1_PV_normal );
2485 return rWrt;
2488 static SwHTMLWriter& OutCSS1_SvxLanguage( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2490 // Only export Language rules
2491 if( rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
2492 return rWrt;
2494 sal_uInt16 nScript = CSS1_OUTMODE_WESTERN;
2495 switch( rHt.Which() )
2497 case RES_CHRATR_CJK_LANGUAGE: nScript = CSS1_OUTMODE_CJK; break;
2498 case RES_CHRATR_CTL_LANGUAGE: nScript = CSS1_OUTMODE_CTL; break;
2500 if( !rWrt.IsCSS1Script( nScript ) )
2501 return rWrt;
2503 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT),
2504 "write Language as Hint?" );
2506 LanguageType eLang = static_cast<const SvxLanguageItem &>(rHt).GetLanguage();
2507 if( LANGUAGE_DONTKNOW == eLang )
2508 return rWrt;
2510 OUString sOut = LanguageTag::convertToBcp47( eLang );
2512 rWrt.OutCSS1_Property( sCSS1_P_so_language, sOut );
2514 return rWrt;
2517 static SwHTMLWriter& OutCSS1_SvxUnderline( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2519 // This function only exports Hints!
2520 // Otherwise OutCSS1_SvxTextLn_SvxCrOut_SvxBlink() is called directly.
2522 if( rWrt.IsCSS1Source(CSS1_OUTMODE_HINT) )
2523 OutCSS1_SvxTextLn_SvxCrOut_SvxBlink( rWrt,
2524 static_cast<const SvxUnderlineItem *>(&rHt), nullptr, nullptr, nullptr );
2526 return rWrt;
2529 static SwHTMLWriter& OutCSS1_SvxOverline( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2531 // This function only exports Hints!
2532 // Otherwise OutCSS1_SvxTextLn_SvxCrOut_SvxBlink() is called directly.
2534 if( rWrt.IsCSS1Source(CSS1_OUTMODE_HINT) )
2535 OutCSS1_SvxTextLn_SvxCrOut_SvxBlink( rWrt,
2536 nullptr, static_cast<const SvxOverlineItem *>(&rHt), nullptr, nullptr );
2538 return rWrt;
2541 static SwHTMLWriter& OutCSS1_SvxHidden( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2543 if ( static_cast<const SvxCharHiddenItem&>(rHt).GetValue() )
2544 rWrt.OutCSS1_PropertyAscii( sCSS1_P_display, sCSS1_PV_none );
2546 return rWrt;
2549 static SwHTMLWriter& OutCSS1_SvxFontWeight( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2551 sal_uInt16 nScript = CSS1_OUTMODE_WESTERN;
2552 switch( rHt.Which() )
2554 case RES_CHRATR_CJK_WEIGHT: nScript = CSS1_OUTMODE_CJK; break;
2555 case RES_CHRATR_CTL_WEIGHT: nScript = CSS1_OUTMODE_CTL; break;
2557 if( !rWrt.IsCSS1Script( nScript ) )
2558 return rWrt;
2560 std::string_view pStr;
2561 switch( static_cast<const SvxWeightItem&>(rHt).GetWeight() )
2563 case WEIGHT_ULTRALIGHT: pStr = sCSS1_PV_extra_light; break;
2564 case WEIGHT_LIGHT: pStr = sCSS1_PV_light; break;
2565 case WEIGHT_SEMILIGHT: pStr = sCSS1_PV_demi_light; break;
2566 case WEIGHT_NORMAL: pStr = sCSS1_PV_normal; break;
2567 case WEIGHT_SEMIBOLD: pStr = sCSS1_PV_demi_bold; break;
2568 case WEIGHT_BOLD:
2569 if( !rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
2571 // this also works in HTML does not need to be written as
2572 // a STYLE-Options, and must not be written as Hint
2573 OSL_ENSURE( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT),
2574 "write bold as Hint?" );
2575 pStr = sCSS1_PV_bold;
2577 break;
2578 case WEIGHT_ULTRABOLD: pStr = sCSS1_PV_extra_bold; break;
2579 default:
2580 pStr = sCSS1_PV_normal;
2583 if( !pStr.empty() )
2584 rWrt.OutCSS1_PropertyAscii( sCSS1_P_font_weight, pStr );
2586 return rWrt;
2589 static SwHTMLWriter& OutCSS1_SvxBlink( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2591 // This function only exports Hints!
2592 // Otherwise OutCSS1_SvxTextLn_SvxCrOut_SvxBlink() is called directly.
2594 if( rWrt.IsCSS1Source(CSS1_OUTMODE_HINT) )
2595 OutCSS1_SvxTextLn_SvxCrOut_SvxBlink( rWrt,
2596 nullptr, nullptr, nullptr, static_cast<const SvxBlinkItem *>(&rHt) );
2598 return rWrt;
2601 static SwHTMLWriter& OutCSS1_SvxLineSpacing( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2603 // Netscape4 has big problems with cell heights if the line spacing is
2604 // changed within a table and the width of the table is not calculated
2605 // automatically (== if there is a WIDTH-Option)
2606 if( rWrt.m_bOutTable && rWrt.m_bCfgNetscape4 )
2607 return rWrt;
2609 const SvxLineSpacingItem& rLSItem = static_cast<const SvxLineSpacingItem&>(rHt);
2611 sal_uInt16 nHeight = 0;
2612 sal_uInt16 nPercentHeight = 0;
2613 SvxLineSpaceRule eLineSpace = rLSItem.GetLineSpaceRule();
2614 switch( rLSItem.GetInterLineSpaceRule() )
2616 case SvxInterLineSpaceRule::Off:
2617 case SvxInterLineSpaceRule::Fix:
2619 switch( eLineSpace )
2621 case SvxLineSpaceRule::Min:
2622 case SvxLineSpaceRule::Fix:
2623 nHeight = rLSItem.GetLineHeight();
2624 break;
2625 case SvxLineSpaceRule::Auto:
2626 nPercentHeight = 100;
2627 break;
2628 default:
2632 break;
2633 case SvxInterLineSpaceRule::Prop:
2634 nPercentHeight = rLSItem.GetPropLineSpace();
2635 break;
2637 default:
2641 if( nHeight )
2642 rWrt.OutCSS1_UnitProperty( sCSS1_P_line_height, static_cast<tools::Long>(nHeight) );
2643 else if( nPercentHeight &&
2644 !(nPercentHeight < 115 && rWrt.m_bParaDotLeaders )) // avoid HTML scrollbars and missing descenders
2646 OString sHeight(OString::number(nPercentHeight) + "%");
2647 rWrt.OutCSS1_PropertyAscii(sCSS1_P_line_height, sHeight);
2650 return rWrt;
2653 static SwHTMLWriter& OutCSS1_SvxAdjust( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2655 // Export Alignment in Style-Option only if the Tag does not allow ALIGN=xxx
2656 if( rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) &&
2657 !rWrt.m_bNoAlign)
2658 return rWrt;
2660 std::string_view pStr;
2661 switch( static_cast<const SvxAdjustItem&>(rHt).GetAdjust() )
2663 case SvxAdjust::Left: pStr = sCSS1_PV_left; break;
2664 case SvxAdjust::Right: pStr = sCSS1_PV_right; break;
2665 case SvxAdjust::Block: pStr = sCSS1_PV_justify; break;
2666 case SvxAdjust::Center: pStr = sCSS1_PV_center; break;
2667 default:
2671 if( !pStr.empty() )
2672 rWrt.OutCSS1_PropertyAscii( sCSS1_P_text_align, pStr );
2674 return rWrt;
2677 static SwHTMLWriter& OutCSS1_SvxFormatSplit( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2679 std::string_view pStr = static_cast<const SvxFormatSplitItem&>(rHt).GetValue()
2680 ? sCSS1_PV_auto
2681 : sCSS1_PV_avoid;
2682 rWrt.OutCSS1_PropertyAscii( sCSS1_P_page_break_inside, pStr );
2684 return rWrt;
2687 static SwHTMLWriter& OutCSS1_SwFormatLayoutSplit( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2689 std::string_view pStr = static_cast<const SwFormatLayoutSplit&>(rHt).GetValue()
2690 ? sCSS1_PV_auto
2691 : sCSS1_PV_avoid;
2692 rWrt.OutCSS1_PropertyAscii( sCSS1_P_page_break_inside, pStr );
2694 return rWrt;
2697 static SwHTMLWriter& OutCSS1_SvxWidows( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2699 OString aStr(OString::number(static_cast<const SvxWidowsItem&>(rHt).GetValue()));
2700 rWrt.OutCSS1_PropertyAscii( sCSS1_P_widows, aStr );
2702 return rWrt;
2705 static SwHTMLWriter& OutCSS1_SvxOrphans( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2707 OString aStr(OString::number(static_cast<const SvxOrphansItem&>(rHt).GetValue()));
2708 rWrt.OutCSS1_PropertyAscii( sCSS1_P_orphans, aStr );
2710 return rWrt;
2713 static void OutCSS1_SwFormatDropAttrs( SwHTMLWriter& rHWrt,
2714 const SwFormatDrop& rDrop,
2715 const SfxItemSet *pCharFormatItemSet )
2717 // Text flows around on right side
2718 rHWrt.OutCSS1_PropertyAscii( sCSS1_P_float, sCSS1_PV_left );
2720 // number of lines -> use % for Font-Height!
2721 OString sOut(OString::number(rDrop.GetLines()*100) + "%");
2722 rHWrt.OutCSS1_PropertyAscii(sCSS1_P_font_size, sOut);
2724 // distance to Text = right margin
2725 sal_uInt16 nDistance = rDrop.GetDistance();
2726 if( nDistance > 0 )
2727 rHWrt.OutCSS1_UnitProperty( sCSS1_P_margin_right, nDistance );
2729 const SwCharFormat *pDCCharFormat = rDrop.GetCharFormat();
2730 if( pCharFormatItemSet )
2731 rHWrt.OutCSS1_SfxItemSet( *pCharFormatItemSet );
2732 else if( pDCCharFormat )
2733 rHWrt.OutCSS1_SfxItemSet( pDCCharFormat->GetAttrSet() );
2734 else if( (rHWrt.m_nCSS1OutMode & CSS1_OUTMODE_ANY_OFF) == CSS1_OUTMODE_RULE_OFF )
2735 rHWrt.Strm().WriteOString( sCSS1_rule_end );
2739 static SwHTMLWriter& OutCSS1_SwFormatDrop( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2741 // never export as an Option of a paragraph, but only as Hints
2742 if( !rWrt.IsCSS1Source(CSS1_OUTMODE_HINT) )
2743 return rWrt;
2745 if( rWrt.m_bTagOn )
2747 SwCSS1OutMode aMode( rWrt,
2748 rWrt.m_nCSS1Script|CSS1_OUTMODE_SPAN_TAG1_ON|CSS1_OUTMODE_ENCODE|
2749 CSS1_OUTMODE_DROPCAP, nullptr );
2751 OutCSS1_SwFormatDropAttrs( rWrt, static_cast<const SwFormatDrop&>(rHt) );
2752 // A "> is already printed by the calling OutCSS1_HintAsSpanTag.
2754 else
2756 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false );
2759 return rWrt;
2762 static SwHTMLWriter& OutCSS1_SwFormatFrameSize( SwHTMLWriter& rWrt, const SfxPoolItem& rHt,
2763 Css1FrameSize nMode )
2765 const SwFormatFrameSize& rFSItem = static_cast<const SwFormatFrameSize&>(rHt);
2767 if( nMode & Css1FrameSize::Width )
2769 sal_uInt8 nPercentWidth = rFSItem.GetWidthPercent();
2770 if( nPercentWidth )
2772 OString sOut(OString::number(nPercentWidth) + "%");
2773 rWrt.OutCSS1_PropertyAscii(sCSS1_P_width, sOut);
2775 else if( nMode & Css1FrameSize::Pixel )
2777 rWrt.OutCSS1_PixelProperty( sCSS1_P_width,
2778 rFSItem.GetSize().Width() );
2780 else
2782 rWrt.OutCSS1_UnitProperty( sCSS1_P_width,
2783 rFSItem.GetSize().Width() );
2787 return rWrt;
2790 static SwHTMLWriter& OutCSS1_SvxFirstLineIndent(SwHTMLWriter & rWrt, SfxPoolItem const& rHt)
2792 const SvxFirstLineIndentItem & rFirstLine(static_cast<const SvxFirstLineIndentItem&>(rHt));
2794 // No Export of a firm attribute is needed if the new values
2795 // match that of the current template
2797 // The LineIndent of the first line might contain the room for numbering
2798 tools::Long nFirstLineIndent
2799 = static_cast<tools::Long>(rFirstLine.ResolveTextFirstLineOffset({}))
2800 - rWrt.m_nFirstLineIndent;
2801 if (rWrt.m_nDfltFirstLineIndent != nFirstLineIndent)
2803 rWrt.OutCSS1_UnitProperty(sCSS1_P_text_indent, nFirstLineIndent);
2806 return rWrt;
2809 static SwHTMLWriter& OutCSS1_SvxTextLeftMargin(SwHTMLWriter & rWrt, SfxPoolItem const& rHt)
2811 const SvxTextLeftMarginItem& rLeftMargin(static_cast<const SvxTextLeftMarginItem&>(rHt));
2813 // No Export of a firm attribute is needed if the new values
2814 // match that of the current template
2816 // A left margin can exist because of a list nearby
2817 tools::Long nLeftMargin = rLeftMargin.ResolveTextLeft({}) - rWrt.m_nLeftMargin;
2818 if (rWrt.m_nDfltLeftMargin != nLeftMargin)
2820 rWrt.OutCSS1_UnitProperty(sCSS1_P_margin_left, nLeftMargin);
2822 // max-width = max-width - margin-left for TOC paragraphs with dot leaders
2823 if (rWrt.m_bParaDotLeaders)
2824 rWrt.OutCSS1_UnitProperty(sCSS1_P_max_width, o3tl::convert(DOT_LEADERS_MAX_WIDTH, o3tl::Length::cm, o3tl::Length::twip) - nLeftMargin);
2828 return rWrt;
2831 static SwHTMLWriter& OutCSS1_SvxRightMargin(SwHTMLWriter & rWrt, SfxPoolItem const& rHt)
2833 const SvxRightMarginItem& rRightMargin(static_cast<const SvxRightMarginItem&>(rHt));
2835 // No Export of a firm attribute is needed if the new values
2836 // match that of the current template
2838 if (rWrt.m_nDfltRightMargin != rRightMargin.ResolveRight({}))
2840 rWrt.OutCSS1_UnitProperty(sCSS1_P_margin_right, rRightMargin.ResolveRight({}));
2843 return rWrt;
2846 static SwHTMLWriter& OutCSS1_SvxLRSpace( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2848 const SvxLRSpaceItem& rLRItem = static_cast<const SvxLRSpaceItem&>(rHt);
2850 // No Export of a firm attribute is needed if the new values
2851 // match that of the current template
2853 // A left margin can exist because of a list nearby
2854 tools::Long nLeftMargin = rLRItem.ResolveTextLeft({}) - rWrt.m_nLeftMargin;
2855 if( rWrt.m_nDfltLeftMargin != nLeftMargin )
2857 rWrt.OutCSS1_UnitProperty( sCSS1_P_margin_left, nLeftMargin );
2859 // max-width = max-width - margin-left for TOC paragraphs with dot leaders
2860 if( rWrt.m_bParaDotLeaders )
2861 rWrt.OutCSS1_UnitProperty( sCSS1_P_max_width, o3tl::convert(DOT_LEADERS_MAX_WIDTH, o3tl::Length::cm, o3tl::Length::twip) - nLeftMargin );
2865 if (rWrt.m_nDfltRightMargin != rLRItem.ResolveRight({}))
2867 rWrt.OutCSS1_UnitProperty(sCSS1_P_margin_right, rLRItem.ResolveRight({}));
2870 // The LineIndent of the first line might contain the room for numbering
2871 tools::Long nFirstLineIndent = static_cast<tools::Long>(rLRItem.ResolveTextFirstLineOffset({}))
2872 - rWrt.m_nFirstLineIndent;
2873 if( rWrt.m_nDfltFirstLineIndent != nFirstLineIndent )
2875 rWrt.OutCSS1_UnitProperty( sCSS1_P_text_indent,
2876 nFirstLineIndent );
2879 return rWrt;
2882 static SwHTMLWriter& OutCSS1_SvxULSpace( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
2884 const SvxULSpaceItem& rULItem = static_cast<const SvxULSpaceItem&>(rHt);
2886 if( rWrt.m_nDfltTopMargin != rULItem.GetUpper() )
2888 rWrt.OutCSS1_UnitProperty( sCSS1_P_margin_top,
2889 static_cast<tools::Long>(rULItem.GetUpper()) );
2892 if( rWrt.m_nDfltBottomMargin != rULItem.GetLower() )
2894 rWrt.OutCSS1_UnitProperty( sCSS1_P_margin_bottom,
2895 static_cast<tools::Long>(rULItem.GetLower()) );
2898 return rWrt;
2901 static SwHTMLWriter& OutCSS1_SvxULSpace_SvxLRSpace( SwHTMLWriter& rWrt,
2902 const SvxULSpaceItem *pULItem,
2903 const SvxLRSpaceItem *pLRItem )
2905 if (pLRItem && pULItem && pLRItem->GetLeft() == pLRItem->GetRight()
2906 && pLRItem->GetLeft() == SvxIndentValue::twips(pULItem->GetUpper())
2907 && pLRItem->GetLeft() == SvxIndentValue::twips(pULItem->GetLower())
2908 && pLRItem->GetLeft() != SvxIndentValue::twips(rWrt.m_nDfltLeftMargin)
2909 && pLRItem->GetRight() != SvxIndentValue::twips(rWrt.m_nDfltRightMargin)
2910 && pULItem->GetUpper() != rWrt.m_nDfltTopMargin
2911 && pULItem->GetLower() != rWrt.m_nDfltBottomMargin)
2913 rWrt.OutCSS1_UnitProperty(sCSS1_P_margin, pLRItem->ResolveLeft({}));
2915 else
2917 if( pLRItem )
2918 OutCSS1_SvxLRSpace( rWrt, *pLRItem );
2919 if( pULItem )
2920 OutCSS1_SvxULSpace( rWrt, *pULItem );
2923 return rWrt;
2926 static SwHTMLWriter& OutCSS1_SvxULSpace_SvxLRSpace( SwHTMLWriter& rWrt,
2927 const SfxItemSet& rItemSet )
2929 const SvxLRSpaceItem *pLRSpace = rItemSet.GetItemIfSet( RES_LR_SPACE, false/*bDeep*/ );
2930 const SvxULSpaceItem *pULSpace = rItemSet.GetItemIfSet( RES_UL_SPACE, false/*bDeep*/ );
2932 if( pLRSpace || pULSpace )
2933 OutCSS1_SvxULSpace_SvxLRSpace( rWrt, pULSpace, pLRSpace );
2935 return rWrt;
2938 static SwHTMLWriter& OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( SwHTMLWriter& rWrt,
2939 const SvxFormatBreakItem *pBreakItem,
2940 const SwFormatPageDesc *pPDescItem,
2941 const SvxFormatKeepItem *pKeepItem )
2943 if( !rWrt.IsHTMLMode(HTMLMODE_PRINT_EXT) )
2944 return rWrt;
2946 std::string_view pBreakBefore;
2947 std::string_view pBreakAfter;
2949 if( pKeepItem )
2951 pBreakAfter = pKeepItem->GetValue() ? sCSS1_PV_avoid : sCSS1_PV_auto;
2953 if( pBreakItem )
2955 switch( pBreakItem->GetBreak() )
2957 case SvxBreak::NONE:
2958 pBreakBefore = sCSS1_PV_auto;
2959 if( pBreakAfter.empty() )
2960 pBreakAfter = sCSS1_PV_auto;
2961 break;
2963 case SvxBreak::PageBefore:
2964 pBreakBefore = sCSS1_PV_always;
2965 break;
2967 case SvxBreak::PageAfter:
2968 pBreakAfter= sCSS1_PV_always;
2969 break;
2971 default:
2975 if( pPDescItem )
2977 const SwPageDesc *pPDesc = pPDescItem->GetPageDesc();
2978 if( pPDesc )
2980 switch( pPDesc->GetPoolFormatId() )
2982 case RES_POOLPAGE_LEFT: pBreakBefore = sCSS1_PV_left; break;
2983 case RES_POOLPAGE_RIGHT: pBreakBefore = sCSS1_PV_right; break;
2984 default: pBreakBefore = sCSS1_PV_always; break;
2987 else if( pBreakBefore.empty() )
2989 pBreakBefore = sCSS1_PV_auto;
2993 if (rWrt.mbSkipHeaderFooter)
2994 // No page break when writing only a fragment.
2995 return rWrt;
2997 if( !pBreakBefore.empty() )
2998 rWrt.OutCSS1_PropertyAscii( sCSS1_P_page_break_before,
2999 pBreakBefore );
3000 if( !pBreakAfter.empty() )
3001 rWrt.OutCSS1_PropertyAscii( sCSS1_P_page_break_after,
3002 pBreakAfter );
3004 return rWrt;
3007 static SwHTMLWriter& OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( SwHTMLWriter& rWrt,
3008 const SfxItemSet& rItemSet,
3009 bool bDeep )
3011 const SvxFormatBreakItem *pBreakItem = rItemSet.GetItemIfSet( RES_BREAK, bDeep );
3013 const SwFormatPageDesc *pPDescItem = nullptr;
3014 if( !rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) ||
3015 !rWrt.m_bCSS1IgnoreFirstPageDesc ||
3016 rWrt.m_pStartNdIdx->GetIndex() !=
3017 rWrt.m_pCurrentPam->GetPoint()->GetNodeIndex() )
3018 pPDescItem = rItemSet.GetItemIfSet( RES_PAGEDESC, bDeep );
3020 const SvxFormatKeepItem *pKeepItem = rItemSet.GetItemIfSet( RES_KEEP, bDeep );
3022 if( pBreakItem || pPDescItem || pKeepItem )
3023 OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( rWrt, pBreakItem,
3024 pPDescItem, pKeepItem );
3026 return rWrt;
3029 // Wrapper for OutCSS1_SfxItemSet etc.
3030 static SwHTMLWriter& OutCSS1_SvxBrush( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
3032 OutCSS1_SvxBrush( rWrt, rHt, sw::Css1Background::Attr, nullptr );
3033 return rWrt;
3036 static SwHTMLWriter& OutCSS1_SvxBrush( SwHTMLWriter& rWrt, const SfxPoolItem& rHt,
3037 sw::Css1Background nMode,
3038 const OUString* pGraphicName)
3040 // The Character-Attribute is skipped, if we are about to
3041 // exporting options
3042 if( rHt.Which() < RES_CHRATR_END &&
3043 rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
3044 return rWrt;
3046 // start getting a few values
3047 // const Brush &rBrush = static_cast<const SvxBrushItem &>(rHt).GetBrush();
3048 const Color & rColor = static_cast<const SvxBrushItem &>(rHt).GetColor();
3049 OUString aLink = pGraphicName ? *pGraphicName
3050 : static_cast<const SvxBrushItem &>(rHt).GetGraphicLink();
3051 bool bOwn = false;
3052 SvxGraphicPosition ePos = static_cast<const SvxBrushItem &>(rHt).GetGraphicPos();
3053 if( sw::Css1Background::Page == nMode && !rWrt.mbEmbedImages )
3055 // page style images are exported if not tiled
3056 if( aLink.isEmpty() || GPOS_TILED==ePos )
3057 return rWrt;
3060 // get the color
3061 bool bColor = false;
3062 /// set <bTransparent> to true, if color is "no fill"/"auto fill"
3063 bool bTransparent = (rColor == COL_TRANSPARENT);
3064 Color aColor;
3065 if( !bTransparent )
3067 aColor = rColor;
3068 bColor = true;
3071 // and now the Graphic
3072 OUString aGraphicInBase64;
3074 // Embedded Graphic -> export WriteEmbedded
3075 const Graphic* pGrf = nullptr;
3076 if( rWrt.mbEmbedImages || aLink.isEmpty())
3078 pGrf = static_cast<const SvxBrushItem &>(rHt).GetGraphic();
3079 if( pGrf )
3081 if( !XOutBitmap::GraphicToBase64(*pGrf, aGraphicInBase64) )
3083 rWrt.m_nWarn = WARN_SWG_POOR_LOAD;
3086 aLink.clear();
3088 else if( !pGraphicName && rWrt.m_bCfgCpyLinkedGrfs )
3090 OUString aGraphicAsLink = aLink;
3091 bOwn = rWrt.CopyLocalFileToINet( aGraphicAsLink );
3092 aLink = aGraphicAsLink;
3094 // In tables we only export something if there is a Graphic
3095 if( (nMode == sw::Css1Background::Table || nMode == sw::Css1Background::TableRow) && !pGrf && !aLink.isEmpty())
3096 return rWrt;
3098 // if necessary, add the orientation of the Graphic
3099 std::u16string_view pRepeat, pHori;
3100 std::string_view pVert;
3101 if( pGrf || !aLink.isEmpty() )
3103 if( GPOS_TILED==ePos )
3105 pRepeat = sCSS1_PV_repeat;
3107 else
3109 switch( ePos )
3111 case GPOS_LT:
3112 case GPOS_MT:
3113 case GPOS_RT:
3114 pHori = sCSS1_PV_top;
3115 break;
3117 case GPOS_LM:
3118 case GPOS_MM:
3119 case GPOS_RM:
3120 pHori = sCSS1_PV_middle;
3121 break;
3123 case GPOS_LB:
3124 case GPOS_MB:
3125 case GPOS_RB:
3126 pHori = sCSS1_PV_bottom;
3127 break;
3129 default:
3133 switch( ePos )
3135 case GPOS_LT:
3136 case GPOS_LM:
3137 case GPOS_LB:
3138 pVert = sCSS1_PV_left;
3139 break;
3141 case GPOS_MT:
3142 case GPOS_MM:
3143 case GPOS_MB:
3144 pVert = sCSS1_PV_center;
3145 break;
3147 case GPOS_RT:
3148 case GPOS_RM:
3149 case GPOS_RB:
3150 pVert = sCSS1_PV_right;
3151 break;
3153 default:
3157 if( !pHori.empty() || !pVert.empty() )
3158 pRepeat = sCSS1_PV_no_repeat;
3162 // now build the string
3163 OUString sOut;
3164 if( !pGrf && aLink.isEmpty() && !bColor )
3166 // no color and no Link, but a transparent Brush
3167 if( bTransparent && sw::Css1Background::Fly != nMode )
3168 sOut += sCSS1_PV_transparent;
3170 else
3172 if( bColor )
3174 OString sTmp(GetCSS1_Color(aColor));
3175 sOut += OStringToOUString(sTmp, RTL_TEXTENCODING_ASCII_US);
3178 if( pGrf || !aLink.isEmpty() )
3180 if( bColor )
3181 sOut += " ";
3183 if(pGrf)
3185 sOut += OUString::Concat(sCSS1_url) +
3186 "(\'" OOO_STRING_SVTOOLS_HTML_O_data ":" + aGraphicInBase64 + "\')";
3188 else
3190 sOut += OUString::Concat(sCSS1_url) + "(" + rWrt.normalizeURL(aLink, bOwn) + ")";
3193 if( !pRepeat.empty() )
3195 sOut += OUString::Concat(" ") + pRepeat;
3198 if( !pHori.empty() )
3200 sOut += OUString::Concat(" ") + pHori;
3202 if( !pVert.empty() )
3204 sOut += " " + OStringToOUString(pVert, RTL_TEXTENCODING_ASCII_US);
3207 sOut += OUString::Concat(" ") + sCSS1_PV_scroll + " ";
3211 if( !sOut.isEmpty() )
3213 rWrt.OutCSS1_Property(sCSS1_P_background, std::string_view(), &sOut,
3214 nMode);
3217 return rWrt;
3220 static void OutCSS1_SvxBorderLine( SwHTMLWriter& rWrt,
3221 std::string_view pProperty,
3222 const SvxBorderLine *pLine )
3224 if( !pLine || pLine->isEmpty() )
3226 rWrt.OutCSS1_PropertyAscii( pProperty, sCSS1_PV_none );
3227 return;
3230 sal_Int32 nWidth = pLine->GetWidth();
3232 OStringBuffer sOut;
3233 if( nWidth <= o3tl::convert(1, o3tl::Length::px, o3tl::Length::twip) )
3235 // If the width is smaller than one pixel, then export as 1px
3236 // so that Netscape and IE show the line.
3237 sOut.append("1px");
3239 else
3241 nWidth *= 5; // 1/100pt
3243 // width in n.nn pt
3244 sOut.append(OString::number(nWidth / 100) + "." + OString::number((nWidth/10) % 10) +
3245 OString::number(nWidth % 10) + sCSS1_UNIT_pt);
3248 // Line-Style: solid or double
3249 sOut.append(' ');
3250 switch (pLine->GetBorderLineStyle())
3252 case SvxBorderLineStyle::SOLID:
3253 sOut.append(sCSS1_PV_solid);
3254 break;
3255 case SvxBorderLineStyle::DOTTED:
3256 sOut.append(sCSS1_PV_dotted);
3257 break;
3258 case SvxBorderLineStyle::DASHED:
3259 sOut.append(sCSS1_PV_dashed);
3260 break;
3261 case SvxBorderLineStyle::DOUBLE:
3262 case SvxBorderLineStyle::THINTHICK_SMALLGAP:
3263 case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
3264 case SvxBorderLineStyle::THINTHICK_LARGEGAP:
3265 case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
3266 case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
3267 case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
3268 sOut.append(sCSS1_PV_double);
3269 break;
3270 case SvxBorderLineStyle::EMBOSSED:
3271 sOut.append(sCSS1_PV_ridge);
3272 break;
3273 case SvxBorderLineStyle::ENGRAVED:
3274 sOut.append(sCSS1_PV_groove);
3275 break;
3276 case SvxBorderLineStyle::INSET:
3277 sOut.append(sCSS1_PV_inset);
3278 break;
3279 case SvxBorderLineStyle::OUTSET:
3280 sOut.append(sCSS1_PV_outset);
3281 break;
3282 default:
3283 sOut.append(sCSS1_PV_none);
3285 sOut.append(' ');
3287 // and also the color
3288 sOut.append(GetCSS1_Color(pLine->GetColor()));
3290 rWrt.OutCSS1_PropertyAscii(pProperty, sOut);
3293 SwHTMLWriter& OutCSS1_SvxBox( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
3295 // Avoid interference between character and paragraph attributes
3296 if( rHt.Which() < RES_CHRATR_END &&
3297 rWrt.IsCSS1Source( CSS1_OUTMODE_PARA ) )
3298 return rWrt;
3300 if( rHt.Which() == RES_CHRATR_BOX )
3302 static constexpr std::string_view inline_block("inline-block");
3303 if( rWrt.m_bTagOn )
3305 // Inline-block to make the line height changing correspond to the character border
3306 rWrt.OutCSS1_PropertyAscii(sCSS1_P_display, inline_block);
3308 else
3310 if (!IgnorePropertyForReqIF(rWrt.mbReqIF, sCSS1_P_display, inline_block))
3311 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false );
3312 return rWrt;
3316 const SvxBoxItem& rBoxItem = static_cast<const SvxBoxItem&>(rHt);
3317 const SvxBorderLine *pTop = rBoxItem.GetTop();
3318 const SvxBorderLine *pBottom = rBoxItem.GetBottom();
3319 const SvxBorderLine *pLeft = rBoxItem.GetLeft();
3320 const SvxBorderLine *pRight = rBoxItem.GetRight();
3322 if( (pTop && pBottom && pLeft && pRight &&
3323 *pTop == *pBottom && *pTop == *pLeft && *pTop == *pRight) ||
3324 (!pTop && !pBottom && !pLeft && !pRight) )
3326 // all Lines are set and equal, or all Lines are not set
3327 // => border : ...
3328 OutCSS1_SvxBorderLine( rWrt, sCSS1_P_border, pTop );
3330 else
3332 // otherwise export all Lines separately
3333 OutCSS1_SvxBorderLine( rWrt, sCSS1_P_border_top, pTop );
3334 OutCSS1_SvxBorderLine( rWrt, sCSS1_P_border_bottom, pBottom );
3335 OutCSS1_SvxBorderLine( rWrt, sCSS1_P_border_left, pLeft );
3336 OutCSS1_SvxBorderLine( rWrt, sCSS1_P_border_right, pRight );
3339 tools::Long nTopDist = pTop ? rBoxItem.GetDistance( SvxBoxItemLine::TOP ) : 0;
3340 tools::Long nBottomDist = pBottom ? rBoxItem.GetDistance( SvxBoxItemLine::BOTTOM ) : 0;
3341 tools::Long nLeftDist = pLeft ? rBoxItem.GetDistance( SvxBoxItemLine::LEFT ) : 0;
3342 tools::Long nRightDist = pRight ? rBoxItem.GetDistance( SvxBoxItemLine::RIGHT ) : 0;
3344 if( nTopDist == nBottomDist && nLeftDist == nRightDist )
3346 OStringBuffer sVal;
3347 AddUnitPropertyValue(sVal, nTopDist, rWrt.GetCSS1Unit());
3348 if( nTopDist != nLeftDist )
3350 sVal.append(' ');
3351 AddUnitPropertyValue(sVal, nLeftDist, rWrt.GetCSS1Unit());
3353 rWrt.OutCSS1_PropertyAscii(sCSS1_P_padding, sVal);
3355 else
3357 rWrt.OutCSS1_UnitProperty( sCSS1_P_padding_top, nTopDist );
3358 rWrt.OutCSS1_UnitProperty( sCSS1_P_padding_bottom, nBottomDist );
3359 rWrt.OutCSS1_UnitProperty( sCSS1_P_padding_left, nLeftDist );
3360 rWrt.OutCSS1_UnitProperty( sCSS1_P_padding_right, nRightDist );
3363 return rWrt;
3366 static SwHTMLWriter& OutCSS1_SvxFrameDirection( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
3368 // Language will be exported rules only
3369 if( !rWrt.IsCSS1Source( CSS1_OUTMODE_TEMPLATE ) )
3370 return rWrt;
3372 SvxFrameDirection nDir =
3373 static_cast< const SvxFrameDirectionItem& >( rHt ).GetValue();
3374 std::string_view pStr;
3375 switch( nDir )
3377 case SvxFrameDirection::Horizontal_LR_TB:
3378 case SvxFrameDirection::Vertical_LR_TB:
3379 pStr = sCSS1_PV_ltr;
3380 break;
3381 case SvxFrameDirection::Horizontal_RL_TB:
3382 case SvxFrameDirection::Vertical_RL_TB:
3383 pStr = sCSS1_PV_rtl;
3384 break;
3385 case SvxFrameDirection::Environment:
3386 pStr = sCSS1_PV_inherit;
3387 break;
3388 default: break;
3391 if( !pStr.empty() )
3392 rWrt.OutCSS1_PropertyAscii( sCSS1_P_direction, pStr );
3394 return rWrt;
3398 * Place here the table for the HTML-Function-Pointer to the
3399 * Export-Functions.
3400 * They are local structures, only needed within the HTML-DLL.
3403 SwAttrFnTab const aCSS1AttrFnTab = {
3404 /* RES_CHRATR_CASEMAP */ OutCSS1_SvxCaseMap,
3405 /* RES_CHRATR_CHARSETCOLOR */ nullptr,
3406 /* RES_CHRATR_COLOR */ OutCSS1_SvxColor,
3407 /* RES_CHRATR_CONTOUR */ nullptr,
3408 /* RES_CHRATR_CROSSEDOUT */ OutCSS1_SvxCrossedOut,
3409 /* RES_CHRATR_ESCAPEMENT */ nullptr,
3410 /* RES_CHRATR_FONT */ OutCSS1_SvxFont,
3411 /* RES_CHRATR_FONTSIZE */ OutCSS1_SvxFontHeight,
3412 /* RES_CHRATR_KERNING */ OutCSS1_SvxKerning,
3413 /* RES_CHRATR_LANGUAGE */ OutCSS1_SvxLanguage,
3414 /* RES_CHRATR_POSTURE */ OutCSS1_SvxPosture,
3415 /* RES_CHRATR_UNUSED1*/ nullptr,
3416 /* RES_CHRATR_SHADOWED */ nullptr,
3417 /* RES_CHRATR_UNDERLINE */ OutCSS1_SvxUnderline,
3418 /* RES_CHRATR_WEIGHT */ OutCSS1_SvxFontWeight,
3419 /* RES_CHRATR_WORDLINEMODE */ nullptr,
3420 /* RES_CHRATR_AUTOKERN */ nullptr,
3421 /* RES_CHRATR_BLINK */ OutCSS1_SvxBlink,
3422 /* RES_CHRATR_NOHYPHEN */ nullptr, // new: don't separate
3423 /* RES_CHRATR_UNUSED2 */ nullptr,
3424 /* RES_CHRATR_BACKGROUND */ OutCSS1_SvxBrush, // new: character background
3425 /* RES_CHRATR_CJK_FONT */ OutCSS1_SvxFont,
3426 /* RES_CHRATR_CJK_FONTSIZE */ OutCSS1_SvxFontHeight,
3427 /* RES_CHRATR_CJK_LANGUAGE */ OutCSS1_SvxLanguage,
3428 /* RES_CHRATR_CJK_POSTURE */ OutCSS1_SvxPosture,
3429 /* RES_CHRATR_CJK_WEIGHT */ OutCSS1_SvxFontWeight,
3430 /* RES_CHRATR_CTL_FONT */ OutCSS1_SvxFont,
3431 /* RES_CHRATR_CTL_FONTSIZE */ OutCSS1_SvxFontHeight,
3432 /* RES_CHRATR_CTL_LANGUAGE */ OutCSS1_SvxLanguage,
3433 /* RES_CHRATR_CTL_POSTURE */ OutCSS1_SvxPosture,
3434 /* RES_CHRATR_CTL_WEIGHT */ OutCSS1_SvxFontWeight,
3435 /* RES_CHRATR_ROTATE */ nullptr,
3436 /* RES_CHRATR_EMPHASIS_MARK */ nullptr,
3437 /* RES_CHRATR_TWO_LINES */ nullptr,
3438 /* RES_CHRATR_SCALEW */ nullptr,
3439 /* RES_CHRATR_RELIEF */ nullptr,
3440 /* RES_CHRATR_HIDDEN */ OutCSS1_SvxHidden,
3441 /* RES_CHRATR_OVERLINE */ OutCSS1_SvxOverline,
3442 /* RES_CHRATR_RSID */ nullptr,
3443 /* RES_CHRATR_BOX */ OutCSS1_SvxBox,
3444 /* RES_CHRATR_SHADOW */ nullptr,
3445 /* RES_CHRATR_HIGHLIGHT */ nullptr,
3446 /* RES_CHRATR_GRABBAG */ nullptr,
3447 /* RES_CHRATR_BIDIRTL */ nullptr,
3448 /* RES_CHRATR_IDCTHINT */ nullptr,
3450 /* RES_TXTATR_REFMARK */ nullptr,
3451 /* RES_TXTATR_TOXMARK */ nullptr,
3452 /* RES_TXTATR_META */ nullptr,
3453 /* RES_TXTATR_METAFIELD */ nullptr,
3454 /* RES_TXTATR_AUTOFMT */ nullptr,
3455 /* RES_TXTATR_INETFMT */ nullptr,
3456 /* RES_TXTATR_CHARFMT */ nullptr,
3457 /* RES_TXTATR_CJK_RUBY */ nullptr,
3458 /* RES_TXTATR_UNKNOWN_CONTAINER */ nullptr,
3459 /* RES_TXTATR_INPUTFIELD */ nullptr,
3460 /* RES_TXTATR_CONTENTCONTROL */ nullptr,
3462 /* RES_TXTATR_FIELD */ nullptr,
3463 /* RES_TXTATR_FLYCNT */ nullptr,
3464 /* RES_TXTATR_FTN */ nullptr,
3465 /* RES_TXTATR_ANNOTATION */ nullptr,
3466 /* RES_TXTATR_LINEBREAK */ nullptr,
3467 /* RES_TXTATR_DUMMY1 */ nullptr, // Dummy:
3469 /* RES_PARATR_LINESPACING */ OutCSS1_SvxLineSpacing,
3470 /* RES_PARATR_ADJUST */ OutCSS1_SvxAdjust,
3471 /* RES_PARATR_SPLIT */ OutCSS1_SvxFormatSplit,
3472 /* RES_PARATR_ORPHANS */ OutCSS1_SvxOrphans,
3473 /* RES_PARATR_WIDOWS */ OutCSS1_SvxWidows,
3474 /* RES_PARATR_TABSTOP */ nullptr,
3475 /* RES_PARATR_HYPHENZONE*/ nullptr,
3476 /* RES_PARATR_DROP */ OutCSS1_SwFormatDrop,
3477 /* RES_PARATR_REGISTER */ nullptr, // new: register-true
3478 /* RES_PARATR_NUMRULE */ nullptr,
3479 /* RES_PARATR_SCRIPTSPACE */ nullptr,
3480 /* RES_PARATR_HANGINGPUNCTUATION */ nullptr,
3481 /* RES_PARATR_FORBIDDEN_RULES */ nullptr, // new
3482 /* RES_PARATR_VERTALIGN */ nullptr, // new
3483 /* RES_PARATR_SNAPTOGRID*/ nullptr, // new
3484 /* RES_PARATR_CONNECT_TO_BORDER */ nullptr, // new
3485 /* RES_PARATR_OUTLINELEVEL */ nullptr, // new since cws outlinelevel
3486 /* RES_PARATR_RSID */ nullptr, // new
3487 /* RES_PARATR_GRABBAG */ nullptr,
3489 /* RES_PARATR_LIST_ID */ nullptr, // new
3490 /* RES_PARATR_LIST_LEVEL */ nullptr, // new
3491 /* RES_PARATR_LIST_ISRESTART */ nullptr, // new
3492 /* RES_PARATR_LIST_RESTARTVALUE */ nullptr, // new
3493 /* RES_PARATR_LIST_ISCOUNTED */ nullptr, // new
3494 /* RES_PARATR_LIST_AUTOFMT */ nullptr, // new
3496 /* RES_FILL_ORDER */ nullptr,
3497 /* RES_FRM_SIZE */ nullptr,
3498 /* RES_PAPER_BIN */ nullptr,
3499 /* RES_MARGIN_FIRSTLINE */ OutCSS1_SvxFirstLineIndent,
3500 /* RES_MARGIN_TEXTLEFT */ OutCSS1_SvxTextLeftMargin,
3501 /* RES_MARGIN_RIGHT */ OutCSS1_SvxRightMargin,
3502 /* RES_MARGIN_LEFT */ nullptr,
3503 /* RES_MARGIN_GUTTER */ nullptr,
3504 /* RES_MARGIN_GUTTER_RIGHT */ nullptr,
3505 /* RES_LR_SPACE */ OutCSS1_SvxLRSpace,
3506 /* RES_UL_SPACE */ OutCSS1_SvxULSpace,
3507 /* RES_PAGEDESC */ nullptr,
3508 /* RES_BREAK */ nullptr,
3509 /* RES_CNTNT */ nullptr,
3510 /* RES_HEADER */ nullptr,
3511 /* RES_FOOTER */ nullptr,
3512 /* RES_PRINT */ nullptr,
3513 /* RES_OPAQUE */ nullptr,
3514 /* RES_PROTECT */ nullptr,
3515 /* RES_SURROUND */ nullptr,
3516 /* RES_VERT_ORIENT */ nullptr,
3517 /* RES_HORI_ORIENT */ nullptr,
3518 /* RES_ANCHOR */ nullptr,
3519 /* RES_BACKGROUND */ OutCSS1_SvxBrush,
3520 /* RES_BOX */ OutCSS1_SvxBox,
3521 /* RES_SHADOW */ nullptr,
3522 /* RES_FRMMACRO */ nullptr,
3523 /* RES_COL */ nullptr,
3524 /* RES_KEEP */ nullptr,
3525 /* RES_URL */ nullptr,
3526 /* RES_EDIT_IN_READONLY */ nullptr,
3527 /* RES_LAYOUT_SPLIT */ nullptr,
3528 /* RES_CHAIN */ nullptr,
3529 /* RES_TEXTGRID */ nullptr,
3530 /* RES_LINENUMBER */ nullptr,
3531 /* RES_FTN_AT_TXTEND */ nullptr,
3532 /* RES_END_AT_TXTEND */ nullptr,
3533 /* RES_COLUMNBALANCE */ nullptr,
3534 /* RES_FRAMEDIR */ OutCSS1_SvxFrameDirection,
3535 /* RES_HEADER_FOOTER_EAT_SPACING */ nullptr,
3536 /* RES_ROW_SPLIT */ nullptr,
3537 /* RES_FLY_SPLIT */ nullptr,
3538 /* RES_FOLLOW_TEXT_FLOW */ nullptr,
3539 /* RES_COLLAPSING_BORDERS */ nullptr,
3540 /* RES_WRAP_INFLUENCE_ON_OBJPOS */ nullptr,
3541 /* RES_AUTO_STYLE */ nullptr,
3542 /* RES_FRMATR_STYLE_NAME */ nullptr,
3543 /* RES_FRMATR_CONDITIONAL_STYLE_NAME */ nullptr,
3544 /* RES_FRMATR_GRABBAG */ nullptr,
3545 /* RES_TEXT_VERT_ADJUST */ nullptr,
3546 /* RES_BACKGROUND_FULL_SIZE */ nullptr,
3547 /* RES_RTL_GUTTER */ nullptr,
3548 /* RES_DECORATIVE */ nullptr,
3550 /* RES_GRFATR_MIRRORGRF */ nullptr,
3551 /* RES_GRFATR_CROPGRF */ nullptr,
3552 /* RES_GRFATR_ROTATION */ nullptr,
3553 /* RES_GRFATR_LUMINANCE */ nullptr,
3554 /* RES_GRFATR_CONTRAST */ nullptr,
3555 /* RES_GRFATR_CHANNELR */ nullptr,
3556 /* RES_GRFATR_CHANNELG */ nullptr,
3557 /* RES_GRFATR_CHANNELB */ nullptr,
3558 /* RES_GRFATR_GAMMA */ nullptr,
3559 /* RES_GRFATR_INVERT */ nullptr,
3560 /* RES_GRFATR_TRANSPARENCY */ nullptr,
3561 /* RES_GRFATR_DRWAMODE */ nullptr,
3562 /* RES_GRFATR_DUMMY3 */ nullptr,
3563 /* RES_GRFATR_DUMMY4 */ nullptr,
3564 /* RES_GRFATR_DUMMY5 */ nullptr,
3566 /* RES_BOXATR_FORMAT */ nullptr,
3567 /* RES_BOXATR_FORMULA */ nullptr,
3568 /* RES_BOXATR_VALUE */ nullptr
3571 static_assert(SAL_N_ELEMENTS(aCSS1AttrFnTab) == RES_BOXATR_END);
3573 void SwHTMLWriter::OutCSS1_SfxItemSet( const SfxItemSet& rItemSet,
3574 bool bDeep, std::string_view rAdd )
3576 // print ItemSet, including all attributes
3577 Out_SfxItemSet( aCSS1AttrFnTab, *this, rItemSet, bDeep );
3579 // some Attributes require special treatment
3581 // Underline, Overline, CrossedOut and Blink form together a CSS1-Property
3582 // (doesn't work of course for Hints)
3583 if( !IsCSS1Source(CSS1_OUTMODE_HINT) )
3585 const SvxUnderlineItem *pUnderlineItem =
3586 rItemSet.GetItemIfSet( RES_CHRATR_UNDERLINE, bDeep );
3588 const SvxOverlineItem *pOverlineItem =
3589 rItemSet.GetItemIfSet( RES_CHRATR_OVERLINE, bDeep );
3591 const SvxCrossedOutItem *pCrossedOutItem =
3592 rItemSet.GetItemIfSet( RES_CHRATR_CROSSEDOUT, bDeep );
3594 const SvxBlinkItem *pBlinkItem =
3595 rItemSet.GetItemIfSet( RES_CHRATR_BLINK, bDeep );
3597 if( pUnderlineItem || pOverlineItem || pCrossedOutItem || pBlinkItem )
3598 OutCSS1_SvxTextLn_SvxCrOut_SvxBlink( *this, pUnderlineItem,
3599 pOverlineItem,
3600 pCrossedOutItem,
3601 pBlinkItem );
3603 OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( *this, rItemSet, bDeep );
3606 if (!rAdd.empty())
3608 for (std::size_t index = 0; index != std::string_view::npos;)
3610 std::string_view attr = o3tl::trim(o3tl::getToken(rAdd, ':', index));
3611 assert(!attr.empty());
3612 assert(index != std::string_view::npos);
3614 std::string_view val = o3tl::trim(o3tl::getToken(rAdd, ':', index));
3615 assert(!val.empty());
3616 OutCSS1_PropertyAscii(attr, val);
3620 if( m_bFirstCSS1Property )
3621 return;
3623 // if a Property was exported as part of a Style-Option,
3624 // the Option still needs to be finished
3625 OStringBuffer sOut;
3626 switch( m_nCSS1OutMode & CSS1_OUTMODE_ANY_OFF )
3628 case CSS1_OUTMODE_SPAN_TAG_OFF:
3629 sOut.append(sCSS1_span_tag_end);
3630 break;
3632 case CSS1_OUTMODE_STYLE_OPT_OFF:
3633 sOut.append(cCSS1_style_opt_end);
3634 break;
3636 case CSS1_OUTMODE_RULE_OFF:
3637 sOut.append(sCSS1_rule_end);
3638 break;
3640 if (!sOut.isEmpty())
3641 Strm().WriteOString( sOut );
3644 SwHTMLWriter& OutCSS1_HintSpanTag( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
3646 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_SPAN_TAG |
3647 CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_HINT, nullptr );
3649 Out( aCSS1AttrFnTab, rHt, rWrt );
3651 if( !rWrt.m_bFirstCSS1Property && rWrt.m_bTagOn )
3652 rWrt.Strm().WriteOString( sCSS1_span_tag_end );
3654 return rWrt;
3657 SwHTMLWriter& OutCSS1_HintStyleOpt( SwHTMLWriter& rWrt, const SfxPoolItem& rHt )
3659 SwCSS1OutMode aMode( rWrt, CSS1_OUTMODE_STYLE_OPT_ON |
3660 CSS1_OUTMODE_ENCODE|
3661 CSS1_OUTMODE_HINT, nullptr );
3663 Out( aCSS1AttrFnTab, rHt, rWrt );
3665 if( !rWrt.m_bFirstCSS1Property )
3666 rWrt.Strm().WriteChar( '\"' );
3668 return rWrt;
3671 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */