1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <hintids.hxx>
21 #include <com/sun/star/i18n/ScriptType.hpp>
22 #include <com/sun/star/i18n/XBreakIterator.hpp>
23 #include <comphelper/string.hxx>
25 #include <vcl/svapp.hxx>
26 #include <svtools/htmlout.hxx>
27 #include <svtools/htmlkywd.hxx>
28 #include <svtools/htmltokn.h>
29 #include <svl/whiter.hxx>
30 #include <sfx2/event.hxx>
31 #include <sfx2/htmlmode.hxx>
32 #include <editeng/escapementitem.hxx>
33 #include <editeng/formatbreakitem.hxx>
34 #include <editeng/boxitem.hxx>
35 #include <editeng/ulspitem.hxx>
36 #include <editeng/udlnitem.hxx>
37 #include <editeng/crossedoutitem.hxx>
38 #include <editeng/blinkitem.hxx>
39 #include <editeng/colritem.hxx>
40 #include <editeng/fontitem.hxx>
41 #include <editeng/fhgtitem.hxx>
42 #include <editeng/postitem.hxx>
43 #include <editeng/wghtitem.hxx>
44 #include <editeng/adjustitem.hxx>
45 #include <editeng/lrspitem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <editeng/frmdiritem.hxx>
48 #include <fchrfmt.hxx>
49 #include <fmtautofmt.hxx>
50 #include <fmtfsize.hxx>
51 #include <fmtclds.hxx>
52 #include <fmtpdsc.hxx>
53 #include <fmtflcnt.hxx>
54 #include <fmtinfmt.hxx>
55 #include <txatbase.hxx>
57 #include <charfmt.hxx>
60 #include <IDocumentStylePoolAccess.hxx>
64 #include <poolfmt.hxx>
65 #include <pagedesc.hxx>
66 #include <swtable.hxx>
68 #include <breakit.hxx>
69 #include "htmlatr.hxx"
70 #include "htmlnum.hxx"
71 #include "wrthtml.hxx"
72 #include "htmlfly.hxx"
73 #include <numrule.hxx>
74 #include <rtl/character.hxx>
75 #include <osl/diagnose.h>
78 #include <svtools/HtmlWriter.hxx>
79 #include <o3tl/string_view.hxx>
86 HTMLOutEvent
const aAnchorEventTable
[] =
88 { OOO_STRING_SVTOOLS_HTML_O_SDonclick
, OOO_STRING_SVTOOLS_HTML_O_onclick
, SvMacroItemId::OnClick
},
89 { OOO_STRING_SVTOOLS_HTML_O_SDonmouseover
, OOO_STRING_SVTOOLS_HTML_O_onmouseover
, SvMacroItemId::OnMouseOver
},
90 { OOO_STRING_SVTOOLS_HTML_O_SDonmouseout
, OOO_STRING_SVTOOLS_HTML_O_onmouseout
, SvMacroItemId::OnMouseOut
},
91 { nullptr, nullptr, SvMacroItemId::NONE
}
94 static SwHTMLWriter
& OutHTML_SvxAdjust( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
);
96 sal_uInt16
SwHTMLWriter::GetDefListLvl( std::u16string_view rNm
, sal_uInt16 nPoolId
)
98 if( nPoolId
== RES_POOLCOLL_HTML_DD
)
100 return 1 | HTML_DLCOLL_DD
;
102 else if( nPoolId
== RES_POOLCOLL_HTML_DT
)
104 return 1 | HTML_DLCOLL_DT
;
107 OUString sDTDD
= OOO_STRING_SVTOOLS_HTML_dt
" ";
108 if( o3tl::starts_with(rNm
, sDTDD
) )
109 // DefinitionList - term
110 return o3tl::narrowing
<sal_uInt16
>(o3tl::toInt32(rNm
.substr( sDTDD
.getLength() ))) | HTML_DLCOLL_DT
;
112 sDTDD
= OOO_STRING_SVTOOLS_HTML_dd
" ";
113 if( o3tl::starts_with(rNm
, sDTDD
) )
114 // DefinitionList - definition
115 return o3tl::narrowing
<sal_uInt16
>(o3tl::toInt32(rNm
.substr( sDTDD
.getLength() ))) | HTML_DLCOLL_DD
;
120 void SwHTMLWriter::OutAndSetDefList( sal_uInt16 nNewLvl
)
122 // possibly, we first need to start a new list
123 if( m_nDefListLvl
< nNewLvl
)
125 // output </pre> for the previous(!) paragraph, if required.
126 // Preferable, the <pre> is exported by OutHTML_SwFormatOff for the
127 // previous paragraph already, but that's not possible, because a very
128 // deep look at the next paragraph (this one) is required to figure
129 // out that a def list starts here.
131 ChangeParaToken( HtmlTokenId::NONE
);
133 // write according to the level difference
134 for( sal_uInt16 i
=m_nDefListLvl
; i
<nNewLvl
; i
++ )
138 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_deflist
) );
139 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_dd
) );
141 m_bLFPossible
= true;
144 else if( m_nDefListLvl
> nNewLvl
)
146 for( sal_uInt16 i
=nNewLvl
; i
< m_nDefListLvl
; i
++ )
151 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_dd
), false );
152 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_deflist
), false );
153 m_bLFPossible
= true;
157 m_nDefListLvl
= nNewLvl
;
160 void SwHTMLWriter::ChangeParaToken( HtmlTokenId nNew
)
162 if( nNew
!= m_nLastParaToken
&& HtmlTokenId::PREFORMTXT_ON
== m_nLastParaToken
)
164 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_preformtxt
), false );
165 m_bLFPossible
= true;
167 m_nLastParaToken
= nNew
;
170 sal_uInt16
SwHTMLWriter::GetCSS1ScriptForScriptType( sal_uInt16 nScriptType
)
172 sal_uInt16 nRet
= CSS1_OUTMODE_ANY_SCRIPT
;
174 switch( nScriptType
)
176 case i18n::ScriptType::LATIN
:
177 nRet
= CSS1_OUTMODE_WESTERN
;
179 case i18n::ScriptType::ASIAN
:
180 nRet
= CSS1_OUTMODE_CJK
;
182 case i18n::ScriptType::COMPLEX
:
183 nRet
= CSS1_OUTMODE_CTL
;
190 // a single output function should be enough for all formats
192 * Output the formats as follows
193 * - output the tag for formats for which a corresponding HTML tag exist
194 * - for all the other formats, output a paragraph tag <P> and set bUserFormat
195 * - if a paragraph alignment is set for the supplied ItemSet of the node or
196 * for the ItemSet of the format, output an ALIGN=xxx if HTML allows it
197 * - In all cases, hard attribute is written as STYLE option.
198 * If bUserFormat is not set, only the supplied ItemSet is considered.
199 * Otherwise, attributes of the format are output as well.
204 struct SwHTMLTextCollOutputInfo
206 OString aToken
; // End token to be output
207 std::optional
<SfxItemSet
> moItemSet
; // hard attribute
209 bool bInNumberBulletList
; // in an enumerated list;
210 bool bParaPossible
; // a </P> may be output additionally
211 bool bOutPara
; // a </P> is supposed to be output
212 bool bOutDiv
; // write a </DIV>
214 SwHTMLTextCollOutputInfo() :
215 bInNumberBulletList( false ),
216 bParaPossible( false ),
221 bool HasParaToken() const { return aToken
.getLength()==1 && aToken
[0]=='P'; }
222 bool ShouldOutputToken() const { return bOutPara
|| !HasParaToken(); }
227 SwHTMLFormatInfo::SwHTMLFormatInfo( const SwFormat
*pF
, SwDoc
*pDoc
, SwDoc
*pTemplate
,
229 LanguageType eDfltLang
,
230 sal_uInt16 nCSS1Script
)
234 , nFirstLineIndent(0)
237 , bScriptDependent( false )
239 sal_uInt16 nRefPoolId
= 0;
240 // Get the selector of the format
241 sal_uInt16 nDeep
= SwHTMLWriter::GetCSS1Selector( pFormat
, aToken
, aClass
,
243 OSL_ENSURE( nDeep
? !aToken
.isEmpty() : aToken
.isEmpty(),
244 "Something seems to be wrong with this token!" );
245 OSL_ENSURE( nDeep
? nRefPoolId
!= 0 : nRefPoolId
== 0,
246 "Something seems to be wrong with the comparison style!" );
248 bool bTextColl
= pFormat
->Which() == RES_TXTFMTCOLL
||
249 pFormat
->Which() == RES_CONDTXTFMTCOLL
;
251 const SwFormat
*pReferenceFormat
= nullptr; // Comparison format
254 // It's an HTML-tag style or this style is derived from such
258 // if no styles are exported, it may be necessary to additionally
259 // write hard attribute
263 case CSS1_FMT_CMPREF
:
264 // for HTML-tag styles the differences to the original
266 pReferenceFormat
= SwHTMLWriter::GetTemplateFormat( nRefPoolId
,
267 &pTemplate
->getIDocumentStylePoolAccess() );
271 // otherwise, the differences to the HTML-tag style of the
272 // original or the ones to the current document, if it the
273 // HTML-tag style is not available
275 pReferenceFormat
= SwHTMLWriter::GetTemplateFormat( nRefPoolId
,
276 &pTemplate
->getIDocumentStylePoolAccess() );
278 pReferenceFormat
= SwHTMLWriter::GetParentFormat( *pFormat
, nDeep
);
285 // HTML-tag styles that are not derived from a paragraph style
286 // must be exported as hard attribute relative to the text-body
287 // style. For a 'not-styles' export, the one of the HTML style
288 // should be used as a reference
289 if( !bOutStyles
&& pTemplate
)
290 pReferenceFormat
= pTemplate
->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT
, false );
292 pReferenceFormat
= pDoc
->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT
, false );
295 if( pReferenceFormat
|| nDeep
==0 )
297 moItemSet
.emplace( *pFormat
->GetAttrSet().GetPool(),
298 pFormat
->GetAttrSet().GetRanges() );
299 // if the differences to a different style are supposed to be
300 // written, hard attribute is necessary. This is always true
301 // for styles that are not derived from HTML-tag styles.
303 moItemSet
->Set( pFormat
->GetAttrSet() );
305 if( pReferenceFormat
)
306 SwHTMLWriter::SubtractItemSet( *moItemSet
, pReferenceFormat
->GetAttrSet(), true );
308 // delete ItemSet that is empty straight away. This will save work
310 if( !moItemSet
->Count() )
321 // We have to add hard attributes for any script dependent
322 // item that is not accessed by the style
323 static const sal_uInt16 aWhichIds
[3][4] =
325 { RES_CHRATR_FONT
, RES_CHRATR_FONTSIZE
,
326 RES_CHRATR_POSTURE
, RES_CHRATR_WEIGHT
},
327 { RES_CHRATR_CJK_FONT
, RES_CHRATR_CJK_FONTSIZE
,
328 RES_CHRATR_CJK_POSTURE
, RES_CHRATR_CJK_WEIGHT
},
329 { RES_CHRATR_CTL_FONT
, RES_CHRATR_CTL_FONTSIZE
,
330 RES_CHRATR_CTL_POSTURE
, RES_CHRATR_CTL_WEIGHT
}
334 sal_uInt16 aSets
[2] = {0,0};
335 switch( nCSS1Script
)
337 case CSS1_OUTMODE_WESTERN
:
342 case CSS1_OUTMODE_CJK
:
347 case CSS1_OUTMODE_CTL
:
353 for( int i
=0; i
<4; ++i
)
355 const SfxPoolItem
& rRef
= pFormat
->GetFormatAttr( aWhichIds
[nRef
][i
] );
356 for(sal_uInt16 nSet
: aSets
)
358 const SfxPoolItem
& rSet
= pFormat
->GetFormatAttr( aWhichIds
[nSet
][i
] );
362 moItemSet
.emplace( *pFormat
->GetAttrSet().GetPool(),
363 pFormat
->GetAttrSet().GetRanges() );
364 moItemSet
->Put( rSet
);
370 // remember all the different default spacings from the style or
371 // the comparison style.
372 SvxFirstLineIndentItem
const& rFirstLine(
373 (pReferenceFormat
? pReferenceFormat
: pFormat
)->GetFirstLineIndent());
374 SvxTextLeftMarginItem
const& rTextLeftMargin(
375 (pReferenceFormat
? pReferenceFormat
: pFormat
)->GetTextLeftMargin());
376 SvxRightMarginItem
const& rRightMargin(
377 (pReferenceFormat
? pReferenceFormat
: pFormat
)->GetRightMargin());
378 nLeftMargin
= rTextLeftMargin
.GetTextLeft();
379 nRightMargin
= rRightMargin
.GetRight();
380 nFirstLineIndent
= rFirstLine
.GetTextFirstLineOffset();
382 const SvxULSpaceItem
&rULSpace
=
383 (pReferenceFormat
? pReferenceFormat
: pFormat
)->GetULSpace();
384 nTopMargin
= rULSpace
.GetUpper();
385 nBottomMargin
= rULSpace
.GetLower();
387 // export language if it differs from the default language
388 sal_uInt16 nWhichId
=
389 SwHTMLWriter::GetLangWhichIdFromScript( nCSS1Script
);
390 const SvxLanguageItem
& rLang
=
391 static_cast<const SvxLanguageItem
&>(pFormat
->GetFormatAttr( nWhichId
));
392 LanguageType eLang
= rLang
.GetLanguage();
393 if( eLang
!= eDfltLang
)
396 moItemSet
.emplace( *pFormat
->GetAttrSet().GetPool(),
397 pFormat
->GetAttrSet().GetRanges() );
398 moItemSet
->Put( rLang
);
401 static const sal_uInt16 aWhichIds
[3] =
402 { RES_CHRATR_LANGUAGE
, RES_CHRATR_CJK_LANGUAGE
,
403 RES_CHRATR_CTL_LANGUAGE
};
404 for(sal_uInt16 i
: aWhichIds
)
408 const SvxLanguageItem
& rTmpLang
=
409 static_cast<const SvxLanguageItem
&>(pFormat
->GetFormatAttr(i
));
410 if( rTmpLang
.GetLanguage() != eLang
)
413 moItemSet
.emplace( *pFormat
->GetAttrSet().GetPool(),
414 pFormat
->GetAttrSet().GetRanges() );
415 moItemSet
->Put( rTmpLang
);
422 SwHTMLFormatInfo::~SwHTMLFormatInfo()
426 static void OutHTML_SwFormat( SwHTMLWriter
& rWrt
, const SwFormat
& rFormat
,
427 const SfxItemSet
*pNodeItemSet
,
428 SwHTMLTextCollOutputInfo
& rInfo
)
430 OSL_ENSURE( RES_CONDTXTFMTCOLL
==rFormat
.Which() || RES_TXTFMTCOLL
==rFormat
.Which(),
431 "not a paragraph style" );
434 sal_uInt16 nNewDefListLvl
= 0;
435 sal_uInt16 nNumStart
= USHRT_MAX
;
436 bool bForceDL
= false;
438 rInfo
.bInNumberBulletList
= false; // Are we in a list?
439 bool bNumbered
= false; // The current paragraph is numbered
440 bool bPara
= false; // the current token is <P>
441 rInfo
.bParaPossible
= false; // a <P> may be additionally output
442 bool bNoEndTag
= false; // don't output an end tag
444 rWrt
.m_bNoAlign
= false; // no ALIGN=... possible
448 rWrt
.m_bNoAlign
= true;
451 sal_uInt8 nBulletGrfLvl
= 255; // The bullet graphic we want to output
453 // Are we in a bulleted or numbered list?
454 const SwTextNode
* pTextNd
= rWrt
.m_pCurrentPam
->GetPointNode().GetTextNode();
456 SwHTMLNumRuleInfo aNumInfo
;
457 if( rWrt
.GetNextNumInfo() )
459 aNumInfo
= *rWrt
.GetNextNumInfo();
460 rWrt
.ClearNextNumInfo();
464 aNumInfo
.Set( *pTextNd
);
467 if( aNumInfo
.GetNumRule() )
469 rInfo
.bInNumberBulletList
= true;
472 // is the current paragraph numbered?
473 bNumbered
= aNumInfo
.IsNumbered();
474 sal_uInt8 nLvl
= aNumInfo
.GetLevel();
476 OSL_ENSURE( pTextNd
->GetActualListLevel() == nLvl
,
477 "Remembered Num level is wrong" );
478 OSL_ENSURE( bNumbered
== pTextNd
->IsCountedInList(),
479 "Remembered numbering state is wrong" );
483 nBulletGrfLvl
= nLvl
; // only temporarily!!!
485 // correction of re-factoring done by cws swnumtree:
486 // - <nNumStart> has to contain the restart value, if the
487 // numbering is restarted at this text node. Value <USHRT_MAX>
488 // indicates, that no additional restart value has to be written.
489 if ( pTextNd
->IsListRestart() )
491 nNumStart
= static_cast< sal_uInt16
>(pTextNd
->GetActualListStartValue());
493 OSL_ENSURE( rWrt
.m_nLastParaToken
== HtmlTokenId::NONE
,
494 "<PRE> was not closed before <LI>." );
498 // Now, we're getting the token and, if necessary, the class
499 std::unique_ptr
<SwHTMLFormatInfo
> pTmpInfo(new SwHTMLFormatInfo(&rFormat
));
500 SwHTMLFormatInfo
*pFormatInfo
;
501 SwHTMLFormatInfos::iterator it
= rWrt
.m_TextCollInfos
.find( pTmpInfo
);
502 if (it
!= rWrt
.m_TextCollInfos
.end())
504 pFormatInfo
= it
->get();
508 pFormatInfo
= new SwHTMLFormatInfo( &rFormat
, rWrt
.m_pDoc
, rWrt
.m_xTemplate
.get(),
509 rWrt
.m_bCfgOutStyles
, rWrt
.m_eLang
,
510 rWrt
.m_nCSS1Script
);
511 rWrt
.m_TextCollInfos
.insert(std::unique_ptr
<SwHTMLFormatInfo
>(pFormatInfo
));
512 if( rWrt
.m_aScriptParaStyles
.count( rFormat
.GetName() ) )
513 pFormatInfo
->bScriptDependent
= true;
516 // Now, we define what is possible due to the token
517 HtmlTokenId nToken
= HtmlTokenId::NONE
; // token for tag change
518 bool bOutNewLine
= false; // only output a single LF?
519 if( !pFormatInfo
->aToken
.isEmpty() )
521 // It is an HTML-tag style or the style is derived from such a
523 rInfo
.aToken
= pFormatInfo
->aToken
;
525 if (rInfo
.aToken
== OOO_STRING_SVTOOLS_HTML_address
)
527 rInfo
.bParaPossible
= true;
528 rWrt
.m_bNoAlign
= true;
530 else if (rInfo
.aToken
== OOO_STRING_SVTOOLS_HTML_blockquote
)
532 rInfo
.bParaPossible
= true;
533 rWrt
.m_bNoAlign
= true;
535 else if (rInfo
.aToken
== OOO_STRING_SVTOOLS_HTML_parabreak
)
539 else if (rInfo
.aToken
== OOO_STRING_SVTOOLS_HTML_preformtxt
)
541 if (HtmlTokenId::PREFORMTXT_ON
== rWrt
.m_nLastParaToken
)
547 nToken
= HtmlTokenId::PREFORMTXT_ON
;
548 rWrt
.m_bNoAlign
= true;
552 else if (rInfo
.aToken
== OOO_STRING_SVTOOLS_HTML_dt
|| rInfo
.aToken
== OOO_STRING_SVTOOLS_HTML_dd
)
554 bDT
= rInfo
.aToken
== OOO_STRING_SVTOOLS_HTML_dt
;
555 rInfo
.bParaPossible
= !bDT
;
556 rWrt
.m_bNoAlign
= true;
562 // all styles that do not correspond to an HTML tag, or that are
563 // not derived from it, are exported as <P>
565 rInfo
.aToken
= OOO_STRING_SVTOOLS_HTML_parabreak
;
569 // If necessary, take the hard attribute from the style
570 if( pFormatInfo
->moItemSet
)
572 OSL_ENSURE(!rInfo
.moItemSet
, "Where does this ItemSet come from?");
573 rInfo
.moItemSet
.emplace( *pFormatInfo
->moItemSet
);
576 // additionally, add the hard attribute from the paragraph
580 rInfo
.moItemSet
->Put( *pNodeItemSet
);
582 rInfo
.moItemSet
.emplace( *pNodeItemSet
);
585 // we will need the lower spacing of the paragraph later on
586 const SvxULSpaceItem
& rULSpace
=
587 pNodeItemSet
? pNodeItemSet
->Get(RES_UL_SPACE
)
588 : rFormat
.GetULSpace();
590 if( (rWrt
.m_bOutHeader
&&
591 rWrt
.m_pCurrentPam
->GetPoint()->GetNodeIndex() ==
592 rWrt
.m_pCurrentPam
->GetMark()->GetNodeIndex()) ||
595 if( rWrt
.m_bCfgOutStyles
)
597 SvxULSpaceItem
aULSpaceItem( rULSpace
);
598 if( rWrt
.m_bOutHeader
)
599 aULSpaceItem
.SetLower( rWrt
.m_nHeaderFooterSpace
);
601 aULSpaceItem
.SetUpper( rWrt
.m_nHeaderFooterSpace
);
603 if (!rInfo
.moItemSet
)
605 rInfo
.moItemSet
.emplace(*rFormat
.GetAttrSet().GetPool(), svl::Items
<RES_UL_SPACE
, RES_UL_SPACE
>);
607 rInfo
.moItemSet
->Put( aULSpaceItem
);
609 rWrt
.m_bOutHeader
= false;
610 rWrt
.m_bOutFooter
= false;
615 // output a line break (without indentation) at the beginning of the
617 rInfo
.aToken
.clear(); // don't output an end tag
618 rWrt
.Strm().WriteOString( SAL_NEWLINE_STRING
);
623 // should an ALIGN=... be written?
624 const SvxAdjustItem
* pAdjItem
= nullptr;
626 if( rInfo
.moItemSet
)
627 pAdjItem
= rInfo
.moItemSet
->GetItemIfSet( RES_PARATR_ADJUST
, false );
629 // Consider the lower spacing of the paragraph? (never in the last
630 // paragraph of tables)
631 bool bUseParSpace
= !rWrt
.m_bOutTable
||
632 (rWrt
.m_pCurrentPam
->GetPoint()->GetNodeIndex() !=
633 rWrt
.m_pCurrentPam
->GetMark()->GetNodeIndex());
634 // If styles are exported, indented paragraphs become definition lists
635 SvxFirstLineIndentItem
const& rFirstLine(
636 pNodeItemSet
? pNodeItemSet
->Get(RES_MARGIN_FIRSTLINE
)
637 : rFormat
.GetFirstLineIndent());
638 SvxTextLeftMarginItem
const& rTextLeftMargin(
639 pNodeItemSet
? pNodeItemSet
->Get(RES_MARGIN_TEXTLEFT
)
640 : rFormat
.GetTextLeftMargin());
641 if( (!rWrt
.m_bCfgOutStyles
|| bForceDL
) && !rInfo
.bInNumberBulletList
)
643 sal_Int32 nLeftMargin
;
645 nLeftMargin
= rTextLeftMargin
.GetTextLeft();
647 nLeftMargin
= rTextLeftMargin
.GetTextLeft() > pFormatInfo
->nLeftMargin
648 ? rTextLeftMargin
.GetTextLeft() - pFormatInfo
->nLeftMargin
651 if( nLeftMargin
> 0 && rWrt
.m_nDefListMargin
> 0 )
653 nNewDefListLvl
= static_cast< sal_uInt16
>((nLeftMargin
+ (rWrt
.m_nDefListMargin
/2)) /
654 rWrt
.m_nDefListMargin
);
655 if( nNewDefListLvl
== 0 && bForceDL
&& !bDT
)
660 // If the left margin is 0 or negative, emulating indent
661 // with <dd> does not work. We then set a def list only if
662 // the dd style is used.
663 nNewDefListLvl
= (bForceDL
&& !bDT
) ? 1 : 0;
666 bool bIsNextTextNode
=
667 rWrt
.m_pDoc
->GetNodes()[rWrt
.m_pCurrentPam
->GetPoint()->GetNodeIndex()+1]
670 if( bForceDL
&& bDT
)
672 // Instead of a DD we must use a DT from the level above this one.
675 else if( !nNewDefListLvl
&& !rWrt
.m_bCfgOutStyles
&& bPara
&&
676 rULSpace
.GetLower()==0 &&
677 ((bUseParSpace
&& bIsNextTextNode
) || rWrt
.m_nDefListLvl
==1) &&
678 (!pAdjItem
|| SvxAdjust::Left
==pAdjItem
->GetAdjust()) )
680 // Export paragraphs without a lower spacing as DT
683 rInfo
.bParaPossible
= false;
684 rWrt
.m_bNoAlign
= true;
688 if( nNewDefListLvl
!= rWrt
.m_nDefListLvl
)
689 rWrt
.OutAndSetDefList( nNewDefListLvl
);
691 // if necessary, start a bulleted or numbered list
692 if( rInfo
.bInNumberBulletList
)
694 OSL_ENSURE( !rWrt
.m_nDefListLvl
, "DL cannot be inside OL!" );
695 OutHTML_NumberBulletListStart( rWrt
, aNumInfo
);
699 if( !rWrt
.m_aBulletGrfs
[nBulletGrfLvl
].isEmpty() )
706 // Take the defaults of the style, because they don't need to be
708 rWrt
.m_nDfltLeftMargin
= pFormatInfo
->nLeftMargin
;
709 rWrt
.m_nDfltRightMargin
= pFormatInfo
->nRightMargin
;
710 rWrt
.m_nDfltFirstLineIndent
= pFormatInfo
->nFirstLineIndent
;
712 if( rInfo
.bInNumberBulletList
)
714 if( !rWrt
.IsHTMLMode( HTMLMODE_LSPACE_IN_NUMBER_BULLET
) )
715 rWrt
.m_nDfltLeftMargin
= rTextLeftMargin
.GetTextLeft();
717 // In numbered lists, don't output a first line indent.
718 rWrt
.m_nFirstLineIndent
= rFirstLine
.GetTextFirstLineOffset();
721 if( rInfo
.bInNumberBulletList
&& bNumbered
&& bPara
&& !rWrt
.m_bCfgOutStyles
)
723 // a single LI doesn't have spacing
724 rWrt
.m_nDfltTopMargin
= 0;
725 rWrt
.m_nDfltBottomMargin
= 0;
727 else if( rWrt
.m_nDefListLvl
&& bPara
)
729 // a single DD doesn't have spacing, as well
730 rWrt
.m_nDfltTopMargin
= 0;
731 rWrt
.m_nDfltBottomMargin
= 0;
735 rWrt
.m_nDfltTopMargin
= pFormatInfo
->nTopMargin
;
736 // if in the last paragraph of a table the lower paragraph spacing
737 // is changed, Netscape doesn't get it. That's why we don't
738 // export anything here for now, by setting this spacing to the
740 if( rWrt
.m_bCfgNetscape4
&& !bUseParSpace
)
741 rWrt
.m_nDfltBottomMargin
= rULSpace
.GetLower();
743 rWrt
.m_nDfltBottomMargin
= pFormatInfo
->nBottomMargin
;
746 if( rWrt
.m_nDefListLvl
)
749 (rWrt
.m_nDefListLvl
-1) * rWrt
.m_nDefListMargin
;
752 if( rWrt
.m_bLFPossible
&& !rWrt
.m_bFirstLine
)
753 rWrt
.OutNewLine(); // paragraph tag on a new line
754 rInfo
.bOutPara
= false;
756 // this is now our new token
757 rWrt
.ChangeParaToken( nToken
);
759 bool bHasParSpace
= bUseParSpace
&& rULSpace
.GetLower() > 0;
760 // XHTML doesn't allow character children for <blockquote>.
761 bool bXhtmlBlockQuote
= rWrt
.mbXHTML
&& rInfo
.aToken
== OOO_STRING_SVTOOLS_HTML_blockquote
;
763 // if necessary, start a new list item
764 bool bNumberedForListItem
= bNumbered
;
765 if (!bNumberedForListItem
)
767 // Open a list also for the leading unnumbered nodes (= list headers in ODF terminology);
768 // to do that, detect if this unnumbered node is the first in this list
769 const auto& rPrevListInfo
= rWrt
.GetNumInfo();
770 if (rPrevListInfo
.GetNumRule() != aNumInfo
.GetNumRule() || aNumInfo
.IsRestart(rPrevListInfo
)
771 || rPrevListInfo
.GetDepth() < aNumInfo
.GetDepth())
772 bNumberedForListItem
= true;
774 if( rInfo
.bInNumberBulletList
&& bNumberedForListItem
)
776 HtmlWriter
html(rWrt
.Strm(), rWrt
.maNamespace
);
777 html
.prettyPrint(rWrt
.m_bPrettyPrint
);
778 html
.start(OOO_STRING_SVTOOLS_HTML_li
);
781 // Handles list headers (<text:list-header> ODF element)
782 html
.attribute(OOO_STRING_SVTOOLS_HTML_O_style
, "display: block");
784 else if (USHRT_MAX
!= nNumStart
)
785 html
.attribute(OOO_STRING_SVTOOLS_HTML_O_value
, OString::number(nNumStart
));
786 // Finish the opening element, but don't close it.
790 if( rWrt
.m_nDefListLvl
> 0 && !bForceDL
)
792 OString aTag
= bDT
? OOO_STRING_SVTOOLS_HTML_dt
: OOO_STRING_SVTOOLS_HTML_dd
;
793 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + aTag
) );
797 rWrt
.IsHTMLMode( HTMLMODE_NO_CONTROL_CENTERING
) &&
800 // The align=... attribute does behave strange in netscape
801 // if there are controls in a paragraph, because the control and
802 // all text behind the control does not recognize this attribute.
803 OString sOut
= "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division
;
804 rWrt
.Strm().WriteOString( sOut
);
806 rWrt
.m_bTextAttr
= false;
807 rWrt
.m_bOutOpts
= true;
808 OutHTML_SvxAdjust( rWrt
, *pAdjItem
);
809 rWrt
.Strm().WriteChar( '>' );
811 rWrt
.m_bNoAlign
= false;
812 rInfo
.bOutDiv
= true;
813 rWrt
.IncIndentLevel();
814 rWrt
.m_bLFPossible
= true;
818 // for BLOCKQUOTE, ADDRESS and DD we output another paragraph token, if
819 // - no styles are written and
820 // - a lower spacing or a paragraph alignment exists
821 // Also, XHTML does not allow character children in this context.
822 OString aToken
= rInfo
.aToken
;
823 if( (!rWrt
.m_bCfgOutStyles
|| rWrt
.mbXHTML
) && rInfo
.bParaPossible
&& !bPara
&&
824 (bHasParSpace
|| bXhtmlBlockQuote
|| pAdjItem
) )
826 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + rInfo
.aToken
) );
827 aToken
= OOO_STRING_SVTOOLS_HTML_parabreak
;
829 rWrt
.m_bNoAlign
= false;
834 eLang
= static_cast<const SvxLanguageItem
&>(rInfo
.moItemSet
->Get(SwHTMLWriter::GetLangWhichIdFromScript(rWrt
.m_nCSS1Script
))).GetLanguage();
836 eLang
= rWrt
.m_eLang
;
838 if( rInfo
.moItemSet
)
840 static const TypedWhichId
<SvxLanguageItem
> aWhichIds
[3] = { RES_CHRATR_LANGUAGE
, RES_CHRATR_CJK_LANGUAGE
, RES_CHRATR_CTL_LANGUAGE
};
842 for(auto const & i
: aWhichIds
)
844 // export language if it differs from the default language only.
845 const SvxLanguageItem
* pTmpItem
= rInfo
.moItemSet
->GetItemIfSet( i
);
846 if( pTmpItem
&& pTmpItem
->GetLanguage() == eLang
)
847 rInfo
.moItemSet
->ClearItem( i
);
851 // and the text direction
852 SvxFrameDirection nDir
= rWrt
.GetHTMLDirection(
853 (pNodeItemSet
? pNodeItemSet
->Get( RES_FRAMEDIR
)
854 : rFormat
.GetFrameDir() ).GetValue() );
856 // We only write a <P>, if
857 // - we are not inside OL/UL/DL, or
858 // - the paragraph of an OL/UL is not numbered or
859 // - styles are not exported and
860 // - a lower spacing, or
861 // - a paragraph alignment exists, or
862 // - styles are exported and
863 // - the text body style was changed, or
864 // - a user format is exported, or
865 // - a paragraph attribute exists
867 (!rInfo
.bInNumberBulletList
&& !rWrt
.m_nDefListLvl
) ||
868 (rInfo
.bInNumberBulletList
&& !bNumbered
) ||
869 (!rWrt
.m_bCfgOutStyles
&&
870 (bHasParSpace
|| bXhtmlBlockQuote
|| pAdjItem
||
871 (eLang
!= LANGUAGE_DONTKNOW
&& eLang
!= rWrt
.m_eLang
))) ||
872 nDir
!= rWrt
.m_nDirection
||
873 rWrt
.m_bCfgOutStyles
)
875 // now, options are output
876 rWrt
.m_bTextAttr
= false;
877 rWrt
.m_bOutOpts
= true;
879 OString sOut
= "<" + rWrt
.GetNamespace() + aToken
;
881 if( eLang
!= LANGUAGE_DONTKNOW
&& eLang
!= rWrt
.m_eLang
)
883 rWrt
.Strm().WriteOString( sOut
);
885 rWrt
.OutLanguage( eLang
);
888 if( nDir
!= rWrt
.m_nDirection
)
890 if( !sOut
.isEmpty() )
892 rWrt
.Strm().WriteOString( sOut
);
895 rWrt
.OutDirection( nDir
);
898 if( rWrt
.m_bCfgOutStyles
&&
899 (!pFormatInfo
->aClass
.isEmpty() || pFormatInfo
->bScriptDependent
) )
901 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_class
"=\"";
902 rWrt
.Strm().WriteOString( sOut
);
904 OUString
aClass( pFormatInfo
->aClass
);
905 if( pFormatInfo
->bScriptDependent
)
907 if( !aClass
.isEmpty() )
909 switch( rWrt
.m_nCSS1Script
)
911 case CSS1_OUTMODE_WESTERN
:
914 case CSS1_OUTMODE_CJK
:
917 case CSS1_OUTMODE_CTL
:
922 HTMLOutFuncs::Out_String( rWrt
.Strm(), aClass
);
925 rWrt
.Strm().WriteOString( sOut
);
928 // if necessary, output alignment
929 if( !rWrt
.m_bNoAlign
&& pAdjItem
)
930 OutHTML_SvxAdjust( rWrt
, *pAdjItem
);
932 rWrt
.m_bParaDotLeaders
= bPara
&& rWrt
.m_bCfgPrintLayout
&& rWrt
.indexOfDotLeaders(
933 pTextNd
->GetAnyFormatColl().GetPoolFormatId(), pTextNd
->GetText()) > -1;
935 // and now, if necessary, the STYLE options
936 if (rWrt
.m_bCfgOutStyles
&& rInfo
.moItemSet
)
938 OutCSS1_ParaTagStyleOpt( rWrt
, *rInfo
.moItemSet
);
941 if (rWrt
.m_bParaDotLeaders
) {
942 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_class
"=\""
943 sCSS2_P_CLASS_leaders
"\"><"
944 OOO_STRING_SVTOOLS_HTML_O_span
;
945 rWrt
.Strm().WriteOString( sOut
);
949 rWrt
.Strm().WriteChar( '>' );
951 // is a </P> supposed to be written?
954 ( rWrt
.m_bCfgOutStyles
|| bHasParSpace
);
956 // if no end tag is supposed to be written, delete it
958 rInfo
.aToken
.clear();
961 if( nBulletGrfLvl
!= 255 )
963 OSL_ENSURE( aNumInfo
.GetNumRule(), "Where is the numbering gone???" );
964 OSL_ENSURE( nBulletGrfLvl
< MAXLEVEL
, "There are not this many layers." );
965 const SwNumFormat
& rNumFormat
= aNumInfo
.GetNumRule()->Get(nBulletGrfLvl
);
966 OutHTML_BulletImage( rWrt
, OOO_STRING_SVTOOLS_HTML_image
, rNumFormat
.GetBrush(),
967 rWrt
.m_aBulletGrfs
[nBulletGrfLvl
]);
970 rWrt
.GetNumInfo() = aNumInfo
;
972 // reset the defaults
973 rWrt
.m_nDfltLeftMargin
= 0;
974 rWrt
.m_nDfltRightMargin
= 0;
975 rWrt
.m_nDfltFirstLineIndent
= 0;
976 rWrt
.m_nDfltTopMargin
= 0;
977 rWrt
.m_nDfltBottomMargin
= 0;
978 rWrt
.m_nLeftMargin
= 0;
979 rWrt
.m_nFirstLineIndent
= 0;
982 static void OutHTML_SwFormatOff( SwHTMLWriter
& rWrt
, const SwHTMLTextCollOutputInfo
& rInfo
)
984 // if there is no token, we don't need to output anything
985 if( rInfo
.aToken
.isEmpty() )
987 rWrt
.FillNextNumInfo();
988 const SwHTMLNumRuleInfo
& rNextInfo
= *rWrt
.GetNextNumInfo();
989 // a bulleted list must be closed in PRE as well
990 if( rInfo
.bInNumberBulletList
)
993 const SwHTMLNumRuleInfo
& rNRInfo
= rWrt
.GetNumInfo();
994 if( rNextInfo
.GetNumRule() != rNRInfo
.GetNumRule() ||
995 rNextInfo
.GetDepth() != rNRInfo
.GetDepth() ||
996 rNextInfo
.IsNumbered() || rNextInfo
.IsRestart(rNRInfo
) )
997 rWrt
.ChangeParaToken( HtmlTokenId::NONE
);
998 OutHTML_NumberBulletListEnd( rWrt
, rNextInfo
);
1000 else if( rNextInfo
.GetNumRule() != nullptr )
1001 rWrt
.ChangeParaToken( HtmlTokenId::NONE
);
1006 if( rInfo
.ShouldOutputToken() )
1008 if( rWrt
.m_bPrettyPrint
&& rWrt
.m_bLFPossible
)
1009 rWrt
.OutNewLine( true );
1011 // if necessary, for BLOCKQUOTE, ADDRESS and DD another paragraph token
1013 // - no styles are written and
1014 // - a lower spacing exists
1015 if( rInfo
.bParaPossible
&& rInfo
.bOutPara
)
1016 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_parabreak
), false );
1018 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + rInfo
.aToken
), false );
1019 rWrt
.m_bLFPossible
=
1020 rInfo
.aToken
!= OOO_STRING_SVTOOLS_HTML_dt
&&
1021 rInfo
.aToken
!= OOO_STRING_SVTOOLS_HTML_dd
&&
1022 rInfo
.aToken
!= OOO_STRING_SVTOOLS_HTML_li
;
1026 rWrt
.DecIndentLevel();
1027 if( rWrt
.m_bLFPossible
)
1029 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division
), false );
1030 rWrt
.m_bLFPossible
= true;
1033 // if necessary, close the list item, then close a bulleted or numbered list
1034 if( rInfo
.bInNumberBulletList
)
1036 rWrt
.FillNextNumInfo();
1037 OutHTML_NumberBulletListEnd( rWrt
, *rWrt
.GetNextNumInfo() );
1043 class HTMLStartEndPos
1047 std::unique_ptr
<SfxPoolItem
> m_pItem
;
1051 HTMLStartEndPos( const SfxPoolItem
& rItem
, sal_Int32 nStt
, sal_Int32 nE
);
1053 const SfxPoolItem
* GetItem() const { return m_pItem
.get(); }
1055 void SetStart(sal_Int32 nStt
) { m_nStart
= nStt
; }
1056 sal_Int32
GetStart() const { return m_nStart
; }
1058 sal_Int32
GetEnd() const { return m_nEnd
; }
1059 void SetEnd(sal_Int32 nE
) { m_nEnd
= nE
; }
1064 HTMLStartEndPos::HTMLStartEndPos(const SfxPoolItem
& rItem
, sal_Int32 nStt
, sal_Int32 nE
)
1067 , m_pItem(rItem
.Clone())
1070 typedef std::vector
<HTMLStartEndPos
*> HTMLStartEndPositions
;
1074 enum HTMLOnOffState
{ HTML_NOT_SUPPORTED
, // unsupported Attribute
1075 HTML_REAL_VALUE
, // Attribute with value
1076 HTML_ON_VALUE
, // Attribute is On-Tag
1077 HTML_OFF_VALUE
, // Attribute is Off-Tag
1078 HTML_CHRFMT_VALUE
, // Attribute for character format
1079 HTML_COLOR_VALUE
, // Attribute for foreground color
1080 HTML_STYLE_VALUE
, // Attribute must be exported as style
1081 HTML_DROPCAP_VALUE
, // DropCap-Attribute
1082 HTML_AUTOFMT_VALUE
}; // Attribute for automatic character styles
1086 HTMLStartEndPositions m_aStartLst
; // list, sorted for start positions
1087 HTMLStartEndPositions m_aEndLst
; // list, sorted for end positions
1088 std::deque
<sal_Int32
> m_aScriptChgLst
; // positions where script changes
1089 // 0 is not contained in this list,
1090 // but the text length
1091 // the script that is valid up to the position
1092 // contained in aScriptChgList at the same index
1093 std::vector
<sal_uInt16
> m_aScriptLst
;
1095 SwDoc
* m_pDoc
; // the current document
1096 SwDoc
* m_pTemplate
; // the HTML template (or 0)
1097 std::optional
<Color
> m_xDefaultColor
; // the default foreground colors
1098 std::set
<OUString
>& m_rScriptTextStyles
;
1100 sal_uLong m_nHTMLMode
;
1101 bool m_bOutStyles
: 1; // are styles exported
1103 // Insert/remove a SttEndPos in/from the Start and End lists.
1104 // The end position is known.
1105 void InsertItem_( HTMLStartEndPos
*pPos
, HTMLStartEndPositions::size_type nEndPos
);
1106 void RemoveItem_( HTMLStartEndPositions::size_type nEndPos
);
1108 // determine the 'type' of the attribute
1109 HTMLOnOffState
GetHTMLItemState( const SfxPoolItem
& rItem
);
1111 // does a specific OnTag item exist
1112 bool ExistsOnTagItem( sal_uInt16 nWhich
, sal_Int32 nPos
);
1114 // does an item exist that can be used to disable an attribute that
1115 // is exported the same way as the supplied item in the same range?
1116 bool ExistsOffTagItem( sal_uInt16 nWhich
, sal_Int32 nStartPos
,
1117 sal_Int32 nEndPos
);
1119 // adapt the end of a split item
1120 void FixSplittedItem( HTMLStartEndPos
*pPos
, sal_Int32 nNewEnd
,
1121 HTMLStartEndPositions::size_type nStartPos
);
1123 // insert an attribute in the lists and, if necessary, split it
1124 void InsertItem( const SfxPoolItem
& rItem
, sal_Int32 nStart
,
1127 // split an already existing attribute
1128 void SplitItem( const SfxPoolItem
& rItem
, sal_Int32 nStart
,
1131 // Insert without taking care of script
1132 void InsertNoScript( const SfxPoolItem
& rItem
, sal_Int32 nStart
,
1133 sal_Int32 nEnd
, SwHTMLFormatInfos
& rFormatInfos
,
1136 const SwHTMLFormatInfo
*GetFormatInfo( const SwFormat
& rFormat
,
1137 SwHTMLFormatInfos
& rFormatInfos
);
1141 HTMLEndPosLst( SwDoc
*pDoc
, SwDoc
* pTemplate
, std::optional
<Color
> xDfltColor
,
1142 bool bOutStyles
, sal_uLong nHTMLMode
,
1143 const OUString
& rText
, std::set
<OUString
>& rStyles
);
1146 // insert an attribute
1147 void Insert( const SfxPoolItem
& rItem
, sal_Int32 nStart
, sal_Int32 nEnd
,
1148 SwHTMLFormatInfos
& rFormatInfos
, bool bParaAttrs
=false );
1149 void Insert( const SfxItemSet
& rItemSet
, sal_Int32 nStart
, sal_Int32 nEnd
,
1150 SwHTMLFormatInfos
& rFormatInfos
, bool bDeep
,
1151 bool bParaAttrs
=false );
1152 void Insert( const SwDrawFrameFormat
& rFormat
, sal_Int32 nPos
,
1153 SwHTMLFormatInfos
& rFormatInfos
);
1155 sal_uInt16
GetScriptAtPos( sal_Int32 nPos
,
1158 void OutStartAttrs( SwHTMLWriter
& rWrt
, sal_Int32 nPos
);
1159 void OutEndAttrs( SwHTMLWriter
& rWrt
, sal_Int32 nPos
);
1161 bool IsHTMLMode(sal_uLong nMode
) const { return (m_nHTMLMode
& nMode
) != 0; }
1166 void HTMLEndPosLst::InsertItem_( HTMLStartEndPos
*pPos
, HTMLStartEndPositions::size_type nEndPos
)
1168 // Insert the attribute in the Start list behind all attributes that
1169 // were started before, or at the same position.
1170 sal_Int32 nStart
= pPos
->GetStart();
1171 HTMLStartEndPositions::size_type i
{0};
1173 while (i
< m_aStartLst
.size() && m_aStartLst
[i
]->GetStart() <= nStart
)
1175 m_aStartLst
.insert(m_aStartLst
.begin() + i
, pPos
);
1177 // the position in the End list was supplied
1178 m_aEndLst
.insert(m_aEndLst
.begin() + nEndPos
, pPos
);
1181 void HTMLEndPosLst::RemoveItem_( HTMLStartEndPositions::size_type nEndPos
)
1183 HTMLStartEndPos
* pPos
= m_aEndLst
[nEndPos
];
1185 // now, we are looking for it in the Start list
1186 HTMLStartEndPositions::iterator it
= std::find(m_aStartLst
.begin(), m_aStartLst
.end(), pPos
);
1187 OSL_ENSURE(it
!= m_aStartLst
.end(), "Item not found in Start List!");
1188 if (it
!= m_aStartLst
.end())
1189 m_aStartLst
.erase(it
);
1191 m_aEndLst
.erase(m_aEndLst
.begin() + nEndPos
);
1196 HTMLOnOffState
HTMLEndPosLst::GetHTMLItemState( const SfxPoolItem
& rItem
)
1198 HTMLOnOffState eState
= HTML_NOT_SUPPORTED
;
1199 switch( rItem
.Which() )
1201 case RES_CHRATR_POSTURE
:
1202 case RES_CHRATR_CJK_POSTURE
:
1203 case RES_CHRATR_CTL_POSTURE
:
1204 switch( static_cast<const SvxPostureItem
&>(rItem
).GetPosture() )
1207 eState
= HTML_ON_VALUE
;
1210 eState
= HTML_OFF_VALUE
;
1213 if( IsHTMLMode(HTMLMODE_SOME_STYLES
) )
1214 eState
= HTML_STYLE_VALUE
;
1219 case RES_CHRATR_CROSSEDOUT
:
1220 switch( rItem
.StaticWhichCast(RES_CHRATR_CROSSEDOUT
).GetStrikeout() )
1222 case STRIKEOUT_SINGLE
:
1223 case STRIKEOUT_DOUBLE
:
1224 eState
= HTML_ON_VALUE
;
1226 case STRIKEOUT_NONE
:
1227 eState
= HTML_OFF_VALUE
;
1234 case RES_CHRATR_ESCAPEMENT
:
1235 switch( static_cast<SvxEscapement
>(rItem
.StaticWhichCast(RES_CHRATR_ESCAPEMENT
).GetEnumValue()) )
1237 case SvxEscapement::Superscript
:
1238 case SvxEscapement::Subscript
:
1239 eState
= HTML_ON_VALUE
;
1241 case SvxEscapement::Off
:
1242 eState
= HTML_OFF_VALUE
;
1249 case RES_CHRATR_UNDERLINE
:
1250 switch( rItem
.StaticWhichCast(RES_CHRATR_UNDERLINE
).GetLineStyle() )
1252 case LINESTYLE_SINGLE
:
1253 eState
= HTML_ON_VALUE
;
1255 case LINESTYLE_NONE
:
1256 eState
= HTML_OFF_VALUE
;
1259 if( IsHTMLMode(HTMLMODE_SOME_STYLES
) )
1260 eState
= HTML_STYLE_VALUE
;
1265 case RES_CHRATR_OVERLINE
:
1266 case RES_CHRATR_HIDDEN
:
1267 if( IsHTMLMode(HTMLMODE_SOME_STYLES
) )
1268 eState
= HTML_STYLE_VALUE
;
1271 case RES_CHRATR_WEIGHT
:
1272 case RES_CHRATR_CJK_WEIGHT
:
1273 case RES_CHRATR_CTL_WEIGHT
:
1274 switch( static_cast<const SvxWeightItem
&>(rItem
).GetWeight() )
1277 eState
= HTML_ON_VALUE
;
1280 eState
= HTML_OFF_VALUE
;
1283 if( IsHTMLMode(HTMLMODE_SOME_STYLES
) )
1284 eState
= HTML_STYLE_VALUE
;
1289 case RES_CHRATR_BLINK
:
1290 eState
= rItem
.StaticWhichCast(RES_CHRATR_BLINK
).GetValue() ? HTML_ON_VALUE
1294 case RES_CHRATR_COLOR
:
1295 eState
= HTML_COLOR_VALUE
;
1298 case RES_CHRATR_FONT
:
1299 case RES_CHRATR_FONTSIZE
:
1300 case RES_CHRATR_LANGUAGE
:
1301 case RES_CHRATR_CJK_FONT
:
1302 case RES_CHRATR_CJK_FONTSIZE
:
1303 case RES_CHRATR_CJK_LANGUAGE
:
1304 case RES_CHRATR_CTL_FONT
:
1305 case RES_CHRATR_CTL_FONTSIZE
:
1306 case RES_CHRATR_CTL_LANGUAGE
:
1307 case RES_TXTATR_INETFMT
:
1308 eState
= HTML_REAL_VALUE
;
1311 case RES_TXTATR_CHARFMT
:
1312 eState
= HTML_CHRFMT_VALUE
;
1315 case RES_TXTATR_AUTOFMT
:
1316 eState
= HTML_AUTOFMT_VALUE
;
1319 case RES_CHRATR_CASEMAP
:
1320 eState
= HTML_STYLE_VALUE
;
1323 case RES_CHRATR_KERNING
:
1324 eState
= HTML_STYLE_VALUE
;
1327 case RES_CHRATR_BACKGROUND
:
1328 if( IsHTMLMode(HTMLMODE_SOME_STYLES
) )
1329 eState
= HTML_STYLE_VALUE
;
1332 case RES_PARATR_DROP
:
1333 eState
= HTML_DROPCAP_VALUE
;
1336 case RES_CHRATR_BOX
:
1337 if( IsHTMLMode(HTMLMODE_SOME_STYLES
) )
1338 eState
= HTML_STYLE_VALUE
;
1345 bool HTMLEndPosLst::ExistsOnTagItem( sal_uInt16 nWhich
, sal_Int32 nPos
)
1347 for (auto pTest
: m_aStartLst
)
1349 if( pTest
->GetStart() > nPos
)
1351 // this attribute, and all attributes that follow, start later
1354 else if( pTest
->GetEnd() > nPos
)
1356 // the attribute starts before, or at, the current position and
1358 const SfxPoolItem
*pItem
= pTest
->GetItem();
1359 if( pItem
->Which() == nWhich
&&
1360 HTML_ON_VALUE
== GetHTMLItemState(*pItem
) )
1362 // an OnTag attribute was found
1371 bool HTMLEndPosLst::ExistsOffTagItem( sal_uInt16 nWhich
, sal_Int32 nStartPos
,
1374 if( nWhich
!= RES_CHRATR_CROSSEDOUT
&&
1375 nWhich
!= RES_CHRATR_UNDERLINE
&&
1376 nWhich
!= RES_CHRATR_BLINK
)
1381 for (auto pTest
: m_aStartLst
)
1383 if( pTest
->GetStart() > nStartPos
)
1385 // this attribute, and all attributes that follow, start later
1388 else if( pTest
->GetStart()==nStartPos
&&
1389 pTest
->GetEnd()==nEndPos
)
1391 // the attribute starts before or at the current position and
1393 const SfxPoolItem
*pItem
= pTest
->GetItem();
1394 sal_uInt16 nTstWhich
= pItem
->Which();
1395 if( (nTstWhich
== RES_CHRATR_CROSSEDOUT
||
1396 nTstWhich
== RES_CHRATR_UNDERLINE
||
1397 nTstWhich
== RES_CHRATR_BLINK
) &&
1398 HTML_OFF_VALUE
== GetHTMLItemState(*pItem
) )
1400 // an OffTag attribute was found that is exported the same
1401 // way as the current item
1410 void HTMLEndPosLst::FixSplittedItem( HTMLStartEndPos
*pPos
, sal_Int32 nNewEnd
,
1411 HTMLStartEndPositions::size_type nStartPos
)
1413 // fix the end position accordingly
1414 pPos
->SetEnd( nNewEnd
);
1416 // remove the item from the End list
1417 HTMLStartEndPositions::iterator it
= std::find(m_aEndLst
.begin(), m_aEndLst
.end(), pPos
);
1418 OSL_ENSURE(it
!= m_aEndLst
.end(), "Item not found in End List!");
1419 if (it
!= m_aEndLst
.end())
1420 m_aEndLst
.erase(it
);
1422 // from now on, it is closed as the last one at the corresponding position
1423 HTMLStartEndPositions::size_type nEndPos
{0};
1424 while (nEndPos
< m_aEndLst
.size() && m_aEndLst
[nEndPos
]->GetEnd() <= nNewEnd
)
1426 m_aEndLst
.insert(m_aEndLst
.begin() + nEndPos
, pPos
);
1428 // now, adjust the attributes that got started afterwards
1429 for (HTMLStartEndPositions::size_type i
= nStartPos
+ 1; i
< m_aStartLst
.size(); ++i
)
1431 HTMLStartEndPos
* pTest
= m_aStartLst
[i
];
1432 sal_Int32 nTestEnd
= pTest
->GetEnd();
1433 if( pTest
->GetStart() >= nNewEnd
)
1435 // the Test attribute and all the following ones start, after the
1436 // split attribute ends
1439 else if( nTestEnd
> nNewEnd
)
1441 // the Test attribute starts before the split attribute
1442 // ends, and ends afterwards, i.e., it must be split, as well
1445 pTest
->SetEnd( nNewEnd
);
1447 // remove the attribute from the End list
1448 it
= std::find(m_aEndLst
.begin(), m_aEndLst
.end(), pTest
);
1449 OSL_ENSURE(it
!= m_aEndLst
.end(), "Item not found in End List!");
1450 if (it
!= m_aEndLst
.end())
1451 m_aEndLst
.erase(it
);
1453 // it now ends as the first attribute in the respective position.
1454 // We already know this position in the End list.
1455 m_aEndLst
.insert(m_aEndLst
.begin() + nEndPos
, pTest
);
1457 // insert the 'rest' of the attribute
1458 InsertItem( *pTest
->GetItem(), nNewEnd
, nTestEnd
);
1463 void HTMLEndPosLst::InsertItem( const SfxPoolItem
& rItem
, sal_Int32 nStart
,
1466 HTMLStartEndPositions::size_type i
;
1467 for (i
= 0; i
< m_aEndLst
.size(); i
++)
1469 HTMLStartEndPos
* pTest
= m_aEndLst
[i
];
1470 sal_Int32 nTestEnd
= pTest
->GetEnd();
1471 if( nTestEnd
<= nStart
)
1473 // the Test attribute ends, before the new one starts
1476 else if( nTestEnd
< nEnd
)
1478 if( pTest
->GetStart() < nStart
)
1480 // the Test attribute ends, before the new one ends. Thus, the
1481 // new attribute must be split.
1482 InsertItem_( new HTMLStartEndPos( rItem
, nStart
, nTestEnd
), i
);
1488 // the Test attribute (and all that follow) ends, before the new
1494 // one attribute must still be inserted
1495 InsertItem_( new HTMLStartEndPos( rItem
, nStart
, nEnd
), i
);
1498 void HTMLEndPosLst::SplitItem( const SfxPoolItem
& rItem
, sal_Int32 nStart
,
1501 sal_uInt16 nWhich
= rItem
.Which();
1503 // first, we must search for the old items by using the start list and
1504 // determine the new item range
1506 for (HTMLStartEndPositions::size_type i
= 0; i
< m_aStartLst
.size(); ++i
)
1508 HTMLStartEndPos
* pTest
= m_aStartLst
[i
];
1509 sal_Int32 nTestStart
= pTest
->GetStart();
1510 sal_Int32 nTestEnd
= pTest
->GetEnd();
1512 if( nTestStart
>= nEnd
)
1514 // this attribute, and all that follow, start later
1517 else if( nTestEnd
> nStart
)
1519 // the Test attribute ends in the range that must be deleted
1520 const SfxPoolItem
*pItem
= pTest
->GetItem();
1522 // only the corresponding OnTag attributes have to be considered
1523 if( pItem
->Which() == nWhich
&&
1524 HTML_ON_VALUE
== GetHTMLItemState( *pItem
) )
1526 bool bDelete
= true;
1528 if( nTestStart
< nStart
)
1530 // the start of the new attribute corresponds to the new
1531 // end of the attribute
1532 FixSplittedItem( pTest
, nStart
, i
);
1537 // the Test item only starts after the new end of the
1538 // attribute. Therefore, it can be completely erased.
1539 m_aStartLst
.erase(m_aStartLst
.begin() + i
);
1542 HTMLStartEndPositions::iterator it
1543 = std::find(m_aEndLst
.begin(), m_aEndLst
.end(), pTest
);
1544 OSL_ENSURE(it
!= m_aEndLst
.end(), "Item not found in End List!");
1545 if (it
!= m_aEndLst
.end())
1546 m_aEndLst
.erase(it
);
1549 // if necessary, insert the second part of the split
1551 if( nTestEnd
> nEnd
)
1553 InsertItem( *pTest
->GetItem(), nEnd
, nTestEnd
);
1563 const SwHTMLFormatInfo
*HTMLEndPosLst::GetFormatInfo( const SwFormat
& rFormat
,
1564 SwHTMLFormatInfos
& rFormatInfos
)
1566 SwHTMLFormatInfo
*pFormatInfo
;
1567 std::unique_ptr
<SwHTMLFormatInfo
> pTmpInfo(new SwHTMLFormatInfo(&rFormat
));
1568 SwHTMLFormatInfos::iterator it
= rFormatInfos
.find( pTmpInfo
);
1569 if (it
!= rFormatInfos
.end())
1571 pFormatInfo
= it
->get();
1575 pFormatInfo
= new SwHTMLFormatInfo(&rFormat
, m_pDoc
, m_pTemplate
, m_bOutStyles
);
1576 rFormatInfos
.insert(std::unique_ptr
<SwHTMLFormatInfo
>(pFormatInfo
));
1577 if (m_rScriptTextStyles
.count(rFormat
.GetName()))
1578 pFormatInfo
->bScriptDependent
= true;
1584 HTMLEndPosLst::HTMLEndPosLst(SwDoc
* pD
, SwDoc
* pTempl
, std::optional
<Color
> xDfltCol
, bool bStyles
,
1585 sal_uLong nMode
, const OUString
& rText
, std::set
<OUString
>& rStyles
)
1587 , m_pTemplate(pTempl
)
1588 , m_xDefaultColor(std::move(xDfltCol
))
1589 , m_rScriptTextStyles(rStyles
)
1590 , m_nHTMLMode(nMode
)
1591 , m_bOutStyles(bStyles
)
1593 sal_Int32 nEndPos
= rText
.getLength();
1595 while( nPos
< nEndPos
)
1597 sal_uInt16 nScript
= g_pBreakIt
->GetBreakIter()->getScriptType( rText
, nPos
);
1598 nPos
= g_pBreakIt
->GetBreakIter()->endOfScript( rText
, nPos
, nScript
);
1599 m_aScriptChgLst
.push_back(nPos
);
1600 m_aScriptLst
.push_back(nScript
);
1604 HTMLEndPosLst::~HTMLEndPosLst()
1606 OSL_ENSURE(m_aStartLst
.empty(), "Start List not empty in destructor");
1607 OSL_ENSURE(m_aEndLst
.empty(), "End List not empty in destructor");
1610 void HTMLEndPosLst::InsertNoScript( const SfxPoolItem
& rItem
,
1611 sal_Int32 nStart
, sal_Int32 nEnd
,
1612 SwHTMLFormatInfos
& rFormatInfos
, bool bParaAttrs
)
1614 // no range ?? in that case, don't take it, it will never take effect !!
1615 if( nStart
== nEnd
)
1618 bool bSet
= false, bSplit
= false;
1619 switch( GetHTMLItemState(rItem
) )
1622 // output the attribute, if it isn't 'on', already
1623 if( !ExistsOnTagItem( rItem
.Which(), nStart
) )
1627 case HTML_OFF_VALUE
:
1628 // If the corresponding attribute is 'on', split it.
1629 // Additionally, output it as Style, if it is not set for the
1630 // whole paragraph, because in that case it was already output
1631 // together with the paragraph tag.
1632 if( ExistsOnTagItem( rItem
.Which(), nStart
) )
1634 bSet
= m_bOutStyles
&& !bParaAttrs
&& !ExistsOffTagItem(rItem
.Which(), nStart
, nEnd
);
1637 case HTML_REAL_VALUE
:
1638 // we can always output the attribute
1642 case HTML_STYLE_VALUE
:
1643 // We can only output the attribute as CSS1. If it is set for
1644 // the paragraph, it was already output with the paragraph tag.
1645 // The only exception is the character-background attribute. This
1646 // attribute must always be handled like a Hint.
1648 && (!bParaAttrs
|| rItem
.Which() == RES_CHRATR_BACKGROUND
1649 || rItem
.Which() == RES_CHRATR_BOX
|| rItem
.Which() == RES_CHRATR_OVERLINE
);
1652 case HTML_CHRFMT_VALUE
:
1654 OSL_ENSURE( RES_TXTATR_CHARFMT
== rItem
.Which(),
1655 "Not a character style after all" );
1656 const SwFormatCharFormat
& rChrFormat
= rItem
.StaticWhichCast(RES_TXTATR_CHARFMT
);
1657 const SwCharFormat
* pFormat
= rChrFormat
.GetCharFormat();
1659 const SwHTMLFormatInfo
*pFormatInfo
= GetFormatInfo( *pFormat
, rFormatInfos
);
1660 if( !pFormatInfo
->aToken
.isEmpty() )
1662 // output the character style tag before the hard
1664 InsertItem( rItem
, nStart
, nEnd
);
1666 if( pFormatInfo
->moItemSet
)
1668 Insert( *pFormatInfo
->moItemSet
, nStart
, nEnd
,
1669 rFormatInfos
, true, bParaAttrs
);
1674 case HTML_AUTOFMT_VALUE
:
1676 OSL_ENSURE( RES_TXTATR_AUTOFMT
== rItem
.Which(),
1677 "Not an automatic style, after all" );
1678 const SwFormatAutoFormat
& rAutoFormat
= rItem
.StaticWhichCast(RES_TXTATR_AUTOFMT
);
1679 const std::shared_ptr
<SfxItemSet
>& pSet
= rAutoFormat
.GetStyleHandle();
1681 Insert( *pSet
, nStart
, nEnd
, rFormatInfos
, true, bParaAttrs
);
1685 case HTML_COLOR_VALUE
:
1686 // A foreground color as a paragraph attribute is only exported if
1687 // it is not the same as the default color.
1689 OSL_ENSURE( RES_CHRATR_COLOR
== rItem
.Which(),
1690 "Not a foreground color, after all" );
1691 Color
aColor( rItem
.StaticWhichCast(RES_CHRATR_COLOR
).GetValue() );
1692 if( COL_AUTO
== aColor
)
1694 bSet
= !bParaAttrs
|| !m_xDefaultColor
|| !m_xDefaultColor
->IsRGBEqual(aColor
);
1698 case HTML_DROPCAP_VALUE
:
1700 OSL_ENSURE( RES_PARATR_DROP
== rItem
.Which(),
1701 "Not a drop cap, after all" );
1702 const SwFormatDrop
& rDrop
= rItem
.StaticWhichCast(RES_PARATR_DROP
);
1703 nEnd
= nStart
+ rDrop
.GetChars();
1706 // At least use the attributes of the character style
1707 const SwCharFormat
*pCharFormat
= rDrop
.GetCharFormat();
1710 Insert( pCharFormat
->GetAttrSet(), nStart
, nEnd
,
1711 rFormatInfos
, true, bParaAttrs
);
1725 InsertItem( rItem
, nStart
, nEnd
);
1727 SplitItem( rItem
, nStart
, nEnd
);
1730 void HTMLEndPosLst::Insert( const SfxPoolItem
& rItem
,
1731 sal_Int32 nStart
, sal_Int32 nEnd
,
1732 SwHTMLFormatInfos
& rFormatInfos
, bool bParaAttrs
)
1734 bool bDependsOnScript
= false, bDependsOnAnyScript
= false;
1735 sal_uInt16 nScript
= i18n::ScriptType::LATIN
;
1736 switch( rItem
.Which() )
1738 case RES_CHRATR_FONT
:
1739 case RES_CHRATR_FONTSIZE
:
1740 case RES_CHRATR_LANGUAGE
:
1741 case RES_CHRATR_POSTURE
:
1742 case RES_CHRATR_WEIGHT
:
1743 bDependsOnScript
= true;
1744 nScript
= i18n::ScriptType::LATIN
;
1747 case RES_CHRATR_CJK_FONT
:
1748 case RES_CHRATR_CJK_FONTSIZE
:
1749 case RES_CHRATR_CJK_LANGUAGE
:
1750 case RES_CHRATR_CJK_POSTURE
:
1751 case RES_CHRATR_CJK_WEIGHT
:
1752 bDependsOnScript
= true;
1753 nScript
= i18n::ScriptType::ASIAN
;
1756 case RES_CHRATR_CTL_FONT
:
1757 case RES_CHRATR_CTL_FONTSIZE
:
1758 case RES_CHRATR_CTL_LANGUAGE
:
1759 case RES_CHRATR_CTL_POSTURE
:
1760 case RES_CHRATR_CTL_WEIGHT
:
1761 bDependsOnScript
= true;
1762 nScript
= i18n::ScriptType::COMPLEX
;
1764 case RES_TXTATR_CHARFMT
:
1766 const SwFormatCharFormat
& rChrFormat
= rItem
.StaticWhichCast(RES_TXTATR_CHARFMT
);
1767 const SwCharFormat
* pFormat
= rChrFormat
.GetCharFormat();
1768 const SwHTMLFormatInfo
*pFormatInfo
= GetFormatInfo( *pFormat
, rFormatInfos
);
1769 if( pFormatInfo
->bScriptDependent
)
1771 bDependsOnScript
= true;
1772 bDependsOnAnyScript
= true;
1776 case RES_TXTATR_INETFMT
:
1778 if (GetFormatInfo(*m_pDoc
->getIDocumentStylePoolAccess().GetCharFormatFromPool(
1779 RES_POOLCHR_INET_NORMAL
),
1782 || GetFormatInfo(*m_pDoc
->getIDocumentStylePoolAccess().GetCharFormatFromPool(
1783 RES_POOLCHR_INET_VISIT
),
1787 bDependsOnScript
= true;
1788 bDependsOnAnyScript
= true;
1794 if( bDependsOnScript
)
1796 sal_Int32 nPos
= nStart
;
1797 for (size_t i
= 0; i
< m_aScriptChgLst
.size(); i
++)
1799 sal_Int32 nChgPos
= m_aScriptChgLst
[i
];
1800 if( nPos
>= nChgPos
)
1802 // the hint starts behind or at the next script change,
1803 // so we may continue with this position.
1806 if( nEnd
<= nChgPos
)
1808 // the (rest of) the hint ends before or at the next script
1809 // change, so we can insert it, but only if it belongs
1810 // to the current script.
1811 if (bDependsOnAnyScript
|| nScript
== m_aScriptLst
[i
])
1812 InsertNoScript( rItem
, nPos
, nEnd
, rFormatInfos
,
1817 // the hint starts before the next script change and ends behind
1818 // it, so we can insert a hint up to the next script change and
1819 // continue with the rest of the hint.
1820 if (bDependsOnAnyScript
|| nScript
== m_aScriptLst
[i
])
1821 InsertNoScript( rItem
, nPos
, nChgPos
, rFormatInfos
, bParaAttrs
);
1827 InsertNoScript( rItem
, nStart
, nEnd
, rFormatInfos
, bParaAttrs
);
1831 void HTMLEndPosLst::Insert( const SfxItemSet
& rItemSet
,
1832 sal_Int32 nStart
, sal_Int32 nEnd
,
1833 SwHTMLFormatInfos
& rFormatInfos
,
1834 bool bDeep
, bool bParaAttrs
)
1836 SfxWhichIter
aIter( rItemSet
);
1838 sal_uInt16 nWhich
= aIter
.FirstWhich();
1841 const SfxPoolItem
*pItem
;
1842 if( SfxItemState::SET
== aIter
.GetItemState( bDeep
, &pItem
) )
1844 Insert( *pItem
, nStart
, nEnd
, rFormatInfos
, bParaAttrs
);
1847 nWhich
= aIter
.NextWhich();
1851 void HTMLEndPosLst::Insert( const SwDrawFrameFormat
& rFormat
, sal_Int32 nPos
,
1852 SwHTMLFormatInfos
& rFormatInfos
)
1854 const SdrObject
* pTextObj
= SwHTMLWriter::GetMarqueeTextObj( rFormat
);
1859 // get the edit engine attributes of the object as SW attributes and
1860 // insert them as hints. Because of the amount of Hints the styles
1861 // are not considered!
1862 const SfxItemSet
& rFormatItemSet
= rFormat
.GetAttrSet();
1863 SfxItemSetFixed
<RES_CHRATR_BEGIN
, RES_CHRATR_END
> aItemSet( *rFormatItemSet
.GetPool() );
1864 SwHTMLWriter::GetEEAttrsFromDrwObj( aItemSet
, pTextObj
);
1865 bool bOutStylesOld
= m_bOutStyles
;
1866 m_bOutStyles
= false;
1867 Insert( aItemSet
, nPos
, nPos
+1, rFormatInfos
, false );
1868 m_bOutStyles
= bOutStylesOld
;
1871 sal_uInt16
HTMLEndPosLst::GetScriptAtPos( sal_Int32 nPos
, sal_uInt16 nWeak
)
1873 sal_uInt16 nRet
= CSS1_OUTMODE_ANY_SCRIPT
;
1875 size_t nScriptChgs
= m_aScriptChgLst
.size();
1877 while (i
< nScriptChgs
&& nPos
>= m_aScriptChgLst
[i
])
1879 OSL_ENSURE( i
< nScriptChgs
, "script list is too short" );
1880 if( i
< nScriptChgs
)
1882 if (i18n::ScriptType::WEAK
== m_aScriptLst
[i
])
1885 nRet
= SwHTMLWriter::GetCSS1ScriptForScriptType(m_aScriptLst
[i
]);
1891 void HTMLEndPosLst::OutStartAttrs( SwHTMLWriter
& rWrt
, sal_Int32 nPos
)
1893 rWrt
.m_bTagOn
= true;
1895 // Character border attribute must be the first which is written out
1896 // because of border merge.
1897 HTMLStartEndPositions::size_type nCharBoxIndex
= 0;
1898 while (nCharBoxIndex
< m_aStartLst
.size()
1899 && m_aStartLst
[nCharBoxIndex
]->GetItem()->Which() != RES_CHRATR_BOX
)
1904 // the attributes of the start list are sorted in ascending order
1905 for (HTMLStartEndPositions::size_type i
= 0; i
< m_aStartLst
.size(); ++i
)
1907 HTMLStartEndPos
*pPos
= nullptr;
1908 if (nCharBoxIndex
< m_aStartLst
.size())
1911 pPos
= m_aStartLst
[nCharBoxIndex
];
1912 else if( i
== nCharBoxIndex
)
1913 pPos
= m_aStartLst
[0];
1915 pPos
= m_aStartLst
[i
];
1918 pPos
= m_aStartLst
[i
];
1920 sal_Int32 nStart
= pPos
->GetStart();
1923 // this attribute, and all that follow, will be opened later on
1926 else if( nStart
== nPos
)
1928 // output the attribute
1929 sal_uInt16 nCSS1Script
= rWrt
.m_nCSS1Script
;
1930 sal_uInt16 nWhich
= pPos
->GetItem()->Which();
1931 if( RES_TXTATR_CHARFMT
== nWhich
||
1932 RES_TXTATR_INETFMT
== nWhich
||
1933 RES_PARATR_DROP
== nWhich
)
1935 rWrt
.m_nCSS1Script
= GetScriptAtPos( nPos
, nCSS1Script
);
1937 HTMLOutFuncs::FlushToAscii( rWrt
.Strm() ); // was one time only - do we still need it?
1938 Out( aHTMLAttrFnTab
, *pPos
->GetItem(), rWrt
);
1939 rWrt
.maStartedAttributes
[pPos
->GetItem()->Which()]++;
1940 rWrt
.m_nCSS1Script
= nCSS1Script
;
1945 void HTMLEndPosLst::OutEndAttrs( SwHTMLWriter
& rWrt
, sal_Int32 nPos
)
1947 rWrt
.m_bTagOn
= false;
1949 // the attributes in the End list are sorted in ascending order
1950 HTMLStartEndPositions::size_type i
{0};
1951 while (i
< m_aEndLst
.size())
1953 HTMLStartEndPos
* pPos
= m_aEndLst
[i
];
1954 sal_Int32 nEnd
= pPos
->GetEnd();
1956 if( SAL_MAX_INT32
== nPos
|| nEnd
== nPos
)
1958 HTMLOutFuncs::FlushToAscii( rWrt
.Strm() ); // was one time only - do we still need it?
1959 // Skip closing span if next character span has the same border (border merge)
1960 bool bSkipOut
= false;
1961 if( pPos
->GetItem()->Which() == RES_CHRATR_BOX
)
1963 HTMLStartEndPositions::iterator it
1964 = std::find(m_aStartLst
.begin(), m_aStartLst
.end(), pPos
);
1965 OSL_ENSURE(it
!= m_aStartLst
.end(), "Item not found in Start List!");
1966 if (it
!= m_aStartLst
.end())
1968 while (it
!= m_aStartLst
.end())
1970 HTMLStartEndPos
*pEndPos
= *it
;
1971 if( pEndPos
->GetItem()->Which() == RES_CHRATR_BOX
&&
1972 *static_cast<const SvxBoxItem
*>(pEndPos
->GetItem()) ==
1973 *static_cast<const SvxBoxItem
*>(pPos
->GetItem()) )
1975 pEndPos
->SetStart(pPos
->GetStart());
1984 Out( aHTMLAttrFnTab
, *pPos
->GetItem(), rWrt
);
1985 rWrt
.maStartedAttributes
[pPos
->GetItem()->Which()]--;
1989 else if( nEnd
> nPos
)
1991 // this attribute, and all that follow, are closed later on
1996 // The attribute is closed before the current position. This
1997 // is not allowed, but we can handle it anyway.
1998 OSL_ENSURE( nEnd
>= nPos
,
1999 "The attribute should've been closed a long time ago" );
2005 /* Output of the nodes*/
2006 SwHTMLWriter
& OutHTML_SwTextNode( SwHTMLWriter
& rWrt
, const SwContentNode
& rNode
)
2008 const SwTextNode
* pNd
= &static_cast<const SwTextNode
&>(rNode
);
2010 const OUString
& rStr
= pNd
->GetText();
2011 sal_Int32 nEnd
= rStr
.getLength();
2013 // special case: empty node and HR style (horizontal rule)
2014 // output a <HR>, only
2015 sal_uInt16 nPoolId
= pNd
->GetAnyFormatColl().GetPoolFormatId();
2017 // Handle horizontal rule <hr>
2019 (RES_POOLCOLL_HTML_HR
==nPoolId
|| pNd
->GetAnyFormatColl().GetName() == OOO_STRING_SVTOOLS_HTML_horzrule
))
2021 // then, the paragraph-anchored graphics/OLE objects in the paragraph
2022 // MIB 8.7.97: We enclose the line in a <PRE>. This means that the
2023 // spacings are wrong, but otherwise we get an empty paragraph
2024 // after the <HR> which is even uglier.
2025 rWrt
.ChangeParaToken( HtmlTokenId::NONE
);
2027 // Output all the nodes that are anchored to a frame
2028 rWrt
.OutFlyFrame( rNode
.GetIndex(), 0, HtmlPosition::Any
);
2030 if( rWrt
.m_bLFPossible
)
2031 rWrt
.OutNewLine(); // paragraph tag on a new line
2033 rWrt
.m_bLFPossible
= true;
2035 HtmlWriter
aHtml(rWrt
.Strm(), rWrt
.maNamespace
);
2036 aHtml
.prettyPrint(rWrt
.m_bPrettyPrint
);
2037 aHtml
.start(OOO_STRING_SVTOOLS_HTML_horzrule
);
2039 const SfxItemSet
* pItemSet
= pNd
->GetpSwAttrSet();
2042 aHtml
.endAttribute();
2045 if (pItemSet
->GetItemIfSet(RES_MARGIN_FIRSTLINE
, false)
2046 || pItemSet
->GetItemIfSet(RES_MARGIN_TEXTLEFT
, false)
2047 || pItemSet
->GetItemIfSet(RES_MARGIN_RIGHT
, false))
2049 SvxFirstLineIndentItem
const& rFirstLine(pItemSet
->Get(RES_MARGIN_FIRSTLINE
));
2050 SvxTextLeftMarginItem
const& rTextLeftMargin(pItemSet
->Get(RES_MARGIN_TEXTLEFT
));
2051 SvxRightMarginItem
const& rRightMargin(pItemSet
->Get(RES_MARGIN_RIGHT
));
2052 sal_Int32
const nLeft(rTextLeftMargin
.GetLeft(rFirstLine
));
2053 sal_Int32
const nRight(rRightMargin
.GetRight());
2054 if( nLeft
|| nRight
)
2056 const SwFrameFormat
& rPgFormat
=
2057 rWrt
.m_pDoc
->getIDocumentStylePoolAccess().GetPageDescFromPool
2058 ( RES_POOLPAGE_HTML
, false )->GetMaster();
2059 const SwFormatFrameSize
& rSz
= rPgFormat
.GetFrameSize();
2060 const SvxLRSpaceItem
& rLR
= rPgFormat
.GetLRSpace();
2061 const SwFormatCol
& rCol
= rPgFormat
.GetCol();
2063 tools::Long nPageWidth
= rSz
.GetWidth() - rLR
.GetLeft() - rLR
.GetRight();
2065 if( 1 < rCol
.GetNumCols() )
2066 nPageWidth
/= rCol
.GetNumCols();
2068 const SwTableNode
* pTableNd
= pNd
->FindTableNode();
2071 const SwTableBox
* pBox
= pTableNd
->GetTable().GetTableBox(
2072 pNd
->StartOfSectionIndex() );
2074 nPageWidth
= pBox
->GetFrameFormat()->GetFrameSize().GetWidth();
2077 OString sWidth
= OString::number(SwHTMLWriter::ToPixel(nPageWidth
- nLeft
- nRight
));
2078 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_width
, sWidth
);
2081 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_align
, OOO_STRING_SVTOOLS_HTML_AL_left
);
2083 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_align
, OOO_STRING_SVTOOLS_HTML_AL_right
);
2085 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_align
, OOO_STRING_SVTOOLS_HTML_AL_center
);
2089 if( const SvxBoxItem
* pBoxItem
= pItemSet
->GetItemIfSet( RES_BOX
, false ))
2091 const editeng::SvxBorderLine
* pBorderLine
= pBoxItem
->GetBottom();
2094 sal_uInt16 nWidth
= pBorderLine
->GetScaledWidth();
2095 OString sWidth
= OString::number(SwHTMLWriter::ToPixel(nWidth
));
2096 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_size
, sWidth
);
2098 const Color
& rBorderColor
= pBorderLine
->GetColor();
2099 if( !rBorderColor
.IsRGBEqual( COL_GRAY
) )
2101 HtmlWriterHelper::applyColor(aHtml
, OOO_STRING_SVTOOLS_HTML_O_color
, rBorderColor
);
2104 if( !pBorderLine
->GetInWidth() )
2106 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_noshade
, OOO_STRING_SVTOOLS_HTML_O_noshade
);
2114 // Do not export the empty nodes with 2pt fonts and standard style that
2115 // are inserted before tables and sections, but do export bookmarks
2116 // and paragraph anchored frames.
2117 if( !nEnd
&& (nPoolId
== RES_POOLCOLL_STANDARD
||
2118 nPoolId
== RES_POOLCOLL_TABLE
||
2119 nPoolId
== RES_POOLCOLL_TABLE_HDLN
) )
2121 // The current node is empty and contains the standard style ...
2122 const SvxFontHeightItem
* pFontHeightItem
;
2123 const SfxItemSet
* pItemSet
= pNd
->GetpSwAttrSet();
2124 if( pItemSet
&& pItemSet
->Count() &&
2125 (pFontHeightItem
= pItemSet
->GetItemIfSet( RES_CHRATR_FONTSIZE
, false )) &&
2126 40 == pFontHeightItem
->GetHeight() )
2128 // ... moreover, the 2pt font is set ...
2129 SwNodeOffset nNdPos
= rWrt
.m_pCurrentPam
->GetPoint()->GetNodeIndex();
2130 const SwNode
*pNextNd
= rWrt
.m_pDoc
->GetNodes()[nNdPos
+1];
2131 const SwNode
*pPrevNd
= rWrt
.m_pDoc
->GetNodes()[nNdPos
-1];
2132 bool bStdColl
= nPoolId
== RES_POOLCOLL_STANDARD
;
2133 if( ( bStdColl
&& (pNextNd
->IsTableNode() || pNextNd
->IsSectionNode()) ) ||
2135 pNextNd
->IsEndNode() &&
2136 pPrevNd
->IsStartNode() &&
2137 SwTableBoxStartNode
== pPrevNd
->GetStartNode()->GetStartNodeType() ) )
2139 // ... and it is located before a table or a section
2140 rWrt
.OutBookmarks();
2141 rWrt
.m_bLFPossible
= rWrt
.m_nLastParaToken
== HtmlTokenId::NONE
;
2143 // Output all frames that are anchored to this node
2144 rWrt
.OutFlyFrame( rNode
.GetIndex(), 0, HtmlPosition::Any
);
2145 rWrt
.m_bLFPossible
= false;
2152 // catch PageBreaks and PageDescs
2153 bool bPageBreakBehind
= false;
2154 if( rWrt
.m_bCfgFormFeed
&&
2155 !(rWrt
.m_bOutTable
|| rWrt
.m_bOutFlyFrame
) &&
2156 rWrt
.m_pStartNdIdx
->GetIndex() != rWrt
.m_pCurrentPam
->GetPoint()->GetNodeIndex() )
2158 bool bPageBreakBefore
= false;
2159 const SfxItemSet
* pItemSet
= pNd
->GetpSwAttrSet();
2163 const SwFormatPageDesc
* pPageDescItem
= pItemSet
->GetItemIfSet( RES_PAGEDESC
);
2164 if( pPageDescItem
&& pPageDescItem
->GetPageDesc() )
2166 bPageBreakBefore
= true;
2168 else if( const SvxFormatBreakItem
* pItem
= pItemSet
->GetItemIfSet( RES_BREAK
) )
2170 switch( pItem
->GetBreak() )
2172 case SvxBreak::PageBefore
:
2173 bPageBreakBefore
= true;
2175 case SvxBreak::PageAfter
:
2176 bPageBreakBehind
= true;
2178 case SvxBreak::PageBoth
:
2179 bPageBreakBefore
= true;
2180 bPageBreakBehind
= true;
2188 if( bPageBreakBefore
)
2189 rWrt
.Strm().WriteChar( '\f' );
2192 // if necessary, open a form
2195 // Output the page-anchored frames that are 'anchored' to this node
2196 bool bFlysLeft
= rWrt
.OutFlyFrame( rNode
.GetIndex(), 0, HtmlPosition::Prefix
);
2198 // Output all frames that are anchored to this node that are supposed to
2199 // be written before the paragraph tag.
2202 bFlysLeft
= rWrt
.OutFlyFrame( rNode
.GetIndex(), 0, HtmlPosition::Before
);
2205 if( rWrt
.m_pCurrentPam
->GetPoint()->GetNode() == rWrt
.m_pCurrentPam
->GetMark()->GetNode() )
2207 nEnd
= rWrt
.m_pCurrentPam
->GetMark()->GetContentIndex();
2210 // are there any hard attributes that must be written as options?
2211 rWrt
.m_bTagOn
= true;
2213 // now, output the tag of the paragraph
2214 const SwFormat
& rFormat
= pNd
->GetAnyFormatColl();
2215 SwHTMLTextCollOutputInfo aFormatInfo
;
2216 bool bOldLFPossible
= rWrt
.m_bLFPossible
;
2217 OutHTML_SwFormat( rWrt
, rFormat
, pNd
->GetpSwAttrSet(), aFormatInfo
);
2219 // If we didn't open a new line before the paragraph tag, we do that now
2220 rWrt
.m_bLFPossible
= rWrt
.m_nLastParaToken
== HtmlTokenId::NONE
;
2221 if( !bOldLFPossible
&& rWrt
.m_bLFPossible
)
2224 // then, the bookmarks (including end tag)
2225 rWrt
.m_bOutOpts
= false;
2226 rWrt
.OutBookmarks();
2228 // now it's a good opportunity again for an LF - if it is still allowed
2229 // FIXME: for LOK case we set rWrt.m_nWishLineLen as -1, for now keep old flow
2230 // when LOK side will be fixed - don't insert new line at the beginning
2231 if( rWrt
.m_bLFPossible
&& rWrt
.m_bPrettyPrint
&& rWrt
.m_nWishLineLen
>= 0 &&
2232 rWrt
.GetLineLen() >= rWrt
.m_nWishLineLen
)
2236 rWrt
.m_bLFPossible
= false;
2238 // find text that originates from an outline numbering
2239 sal_Int32 nOffset
= 0;
2240 OUString aOutlineText
;
2243 // export numbering string as plain text only for the outline numbering,
2244 // because the outline numbering isn't exported as a numbering - see <SwHTMLNumRuleInfo::Set(..)>
2245 if ( pNd
->IsOutline() &&
2246 pNd
->GetNumRule() == pNd
->GetDoc().GetOutlineNumRule() )
2248 aOutlineText
= pNd
->GetNumString();
2249 nOffset
= nOffset
+ aOutlineText
.getLength();
2250 aFullText
= aOutlineText
;
2252 OUString aFootEndNoteSym
;
2253 if( rWrt
.m_pFormatFootnote
)
2255 aFootEndNoteSym
= rWrt
.GetFootEndNoteSym( *rWrt
.m_pFormatFootnote
);
2256 nOffset
= nOffset
+ aFootEndNoteSym
.getLength();
2257 aFullText
+= aFootEndNoteSym
;
2260 // Table of Contents or other paragraph with dot leaders?
2261 sal_Int32 nIndexTab
= rWrt
.indexOfDotLeaders( nPoolId
, rStr
);
2263 // skip part after the tabulator (page number)
2266 // are there any hard attributes that must be written as tags?
2268 HTMLEndPosLst
aEndPosLst( rWrt
.m_pDoc
, rWrt
.m_xTemplate
.get(),
2269 rWrt
.m_xDfltColor
, rWrt
.m_bCfgOutStyles
,
2270 rWrt
.GetHTMLMode(), aFullText
,
2271 rWrt
.m_aScriptTextStyles
);
2272 if( aFormatInfo
.moItemSet
)
2274 aEndPosLst
.Insert( *aFormatInfo
.moItemSet
, 0, nEnd
+ nOffset
,
2275 rWrt
.m_CharFormatInfos
, false, true );
2278 if( !aOutlineText
.isEmpty() || rWrt
.m_pFormatFootnote
)
2280 // output paragraph attributes, so that the text gets the attributes of
2282 aEndPosLst
.OutStartAttrs( rWrt
, 0 );
2284 // Theoretically, we would have to consider the character style of
2285 // the numbering. Because it cannot be set via the UI, let's ignore
2288 if( !aOutlineText
.isEmpty() )
2289 HTMLOutFuncs::Out_String( rWrt
.Strm(), aOutlineText
);
2291 if( rWrt
.m_pFormatFootnote
)
2293 rWrt
.OutFootEndNoteSym( *rWrt
.m_pFormatFootnote
, aFootEndNoteSym
,
2294 aEndPosLst
.GetScriptAtPos( aOutlineText
.getLength(), rWrt
.m_nCSS1Script
) );
2295 rWrt
.m_pFormatFootnote
= nullptr;
2299 // for now, correct the start. I.e., if we only output part of the sentence,
2300 // the attributes must be correct there, as well!!
2301 rWrt
.m_bTextAttr
= true;
2303 size_t nAttrPos
= 0;
2304 sal_Int32 nStrPos
= rWrt
.m_pCurrentPam
->GetPoint()->GetContentIndex();
2305 const SwTextAttr
* pHt
= nullptr;
2306 const size_t nCntAttr
= pNd
->HasHints() ? pNd
->GetSwpHints().Count() : 0;
2307 if( nCntAttr
&& nStrPos
> ( pHt
= pNd
->GetSwpHints().Get(0) )->GetStart() )
2309 // Ok, there are earlier attributes that we must output
2311 aEndPosLst
.OutEndAttrs( rWrt
, nStrPos
+ nOffset
);
2314 if( pHt
->Which() == RES_TXTATR_FIELD
2315 || pHt
->Which() == RES_TXTATR_ANNOTATION
)
2318 if ( pHt
->End() && !pHt
->HasDummyChar() )
2320 const sal_Int32 nHtEnd
= *pHt
->End(),
2321 nHtStt
= pHt
->GetStart();
2322 if( !rWrt
.m_bWriteAll
&& nHtEnd
<= nStrPos
)
2325 // don't consider empty hints at the beginning - or should we ??
2326 if( nHtEnd
== nHtStt
)
2329 // add attribute to the list
2330 if( rWrt
.m_bWriteAll
)
2331 aEndPosLst
.Insert( pHt
->GetAttr(), nHtStt
+ nOffset
,
2333 rWrt
.m_CharFormatInfos
);
2336 sal_Int32 nTmpStt
= nHtStt
< nStrPos
? nStrPos
: nHtStt
;
2337 sal_Int32 nTmpEnd
= std::min(nHtEnd
, nEnd
);
2338 aEndPosLst
.Insert( pHt
->GetAttr(), nTmpStt
+ nOffset
,
2340 rWrt
.m_CharFormatInfos
);
2343 // but don't output it, that will be done later !!
2346 } while( nAttrPos
< nCntAttr
&& nStrPos
>
2347 ( pHt
= pNd
->GetSwpHints().Get( nAttrPos
) )->GetStart() );
2349 // so, let's output all collected attributes from the string pos on
2350 aEndPosLst
.OutEndAttrs( rWrt
, nStrPos
+ nOffset
);
2351 aEndPosLst
.OutStartAttrs( rWrt
, nStrPos
+ nOffset
);
2354 bool bWriteBreak
= (HtmlTokenId::PREFORMTXT_ON
!= rWrt
.m_nLastParaToken
);
2355 if (bWriteBreak
&& (pNd
->GetNumRule() || rWrt
.mbReqIF
))
2357 // One line-break is exactly one <br> in the ReqIF case.
2358 bWriteBreak
= false;
2362 // Tabs are leading till there is a non-tab since the start of the paragraph.
2363 bool bLeadingTab
= true;
2364 for( ; nStrPos
< nEnd
; nStrPos
++ )
2366 // output the frames that are anchored to the current position
2369 aEndPosLst
.OutEndAttrs( rWrt
, nStrPos
+ nOffset
);
2370 bFlysLeft
= rWrt
.OutFlyFrame( rNode
.GetIndex(),
2371 nStrPos
, HtmlPosition::Inside
);
2374 bool bOutChar
= true;
2375 const SwTextAttr
* pTextHt
= nullptr;
2376 if (nAttrPos
< nCntAttr
&& pHt
->GetStart() == nStrPos
)
2379 if ( pHt
->End() && !pHt
->HasDummyChar() )
2381 if( *pHt
->End() != nStrPos
)
2383 // insert hints with end, if they don't start
2384 // an empty range (hints that don't start a range
2386 aEndPosLst
.Insert( pHt
->GetAttr(), nStrPos
+ nOffset
,
2387 *pHt
->End() + nOffset
,
2388 rWrt
.m_CharFormatInfos
);
2393 // hints without an end are output last
2394 OSL_ENSURE( !pTextHt
, "Why is there already an attribute without an end?" );
2395 if( rWrt
.m_nTextAttrsToIgnore
>0 )
2397 rWrt
.m_nTextAttrsToIgnore
--;
2402 SwFieldIds nFieldWhich
;
2403 if( RES_TXTATR_FIELD
!= pHt
->Which()
2404 || ( SwFieldIds::Postit
!= (nFieldWhich
= static_cast<const SwFormatField
&>(pHt
->GetAttr()).GetField()->Which())
2405 && SwFieldIds::Script
!= nFieldWhich
) )
2407 bWriteBreak
= false;
2410 bOutChar
= false; // don't output 255
2412 } while( ++nAttrPos
< nCntAttr
&& nStrPos
==
2413 ( pHt
= pNd
->GetSwpHints().Get( nAttrPos
) )->GetStart() );
2416 // Additionally, some draw formats can bring attributes
2417 if( pTextHt
&& RES_TXTATR_FLYCNT
== pTextHt
->Which() )
2419 const SwFrameFormat
* pFrameFormat
=
2420 pTextHt
->GetAttr().StaticWhichCast(RES_TXTATR_FLYCNT
).GetFrameFormat();
2422 if( RES_DRAWFRMFMT
== pFrameFormat
->Which() )
2423 aEndPosLst
.Insert( *static_cast<const SwDrawFrameFormat
*>(pFrameFormat
),
2425 rWrt
.m_CharFormatInfos
);
2428 aEndPosLst
.OutEndAttrs( rWrt
, nStrPos
+ nOffset
);
2429 aEndPosLst
.OutStartAttrs( rWrt
, nStrPos
+ nOffset
);
2433 rWrt
.m_bLFPossible
= rWrt
.m_nLastParaToken
== HtmlTokenId::NONE
&&
2435 rStr
[nStrPos
-1] == ' ';
2436 sal_uInt16 nCSS1Script
= rWrt
.m_nCSS1Script
;
2437 rWrt
.m_nCSS1Script
= aEndPosLst
.GetScriptAtPos(
2438 nStrPos
+ nOffset
, nCSS1Script
);
2439 HTMLOutFuncs::FlushToAscii( rWrt
.Strm() );
2440 Out( aHTMLAttrFnTab
, pTextHt
->GetAttr(), rWrt
);
2441 rWrt
.m_nCSS1Script
= nCSS1Script
;
2442 rWrt
.m_bLFPossible
= false;
2447 sal_uInt32 c
= rStr
[nStrPos
];
2448 if( rtl::isHighSurrogate(c
) && nStrPos
< nEnd
- 1 )
2450 const sal_Unicode d
= rStr
[nStrPos
+ 1];
2451 if( rtl::isLowSurrogate(d
) )
2453 c
= rtl::combineSurrogates(c
, d
);
2458 // try to split a line after about 255 characters
2459 // at a space character unless in a PRE-context
2460 if( ' ' == c
&& rWrt
.m_nLastParaToken
== HtmlTokenId::NONE
)
2463 nLineLen
= rWrt
.GetLineLen();
2465 sal_Int32 nWordLen
= rStr
.indexOf( ' ', nStrPos
+1 );
2466 if( nWordLen
== -1 )
2468 nWordLen
-= nStrPos
;
2470 if( rWrt
.m_bPrettyPrint
&& rWrt
.m_nWishLineLen
>= 0 &&
2471 (nLineLen
>= rWrt
.m_nWishLineLen
||
2472 (nLineLen
+nWordLen
) >= rWrt
.m_nWishLineLen
) )
2474 HTMLOutFuncs::FlushToAscii( rWrt
.Strm() );
2484 HTMLOutFuncs::FlushToAscii( rWrt
.Strm() );
2485 HtmlWriter
aHtml(rWrt
.Strm(), rWrt
.maNamespace
);
2486 aHtml
.prettyPrint(rWrt
.m_bPrettyPrint
);
2487 aHtml
.single(OOO_STRING_SVTOOLS_HTML_linebreak
);
2489 else if (c
== CH_TXT_ATR_FORMELEMENT
)
2491 // Placeholder for a single-point fieldmark.
2493 SwPosition aMarkPos
= *rWrt
.m_pCurrentPam
->GetPoint();
2494 aMarkPos
.AdjustContent( nStrPos
- aMarkPos
.GetContentIndex() );
2495 rWrt
.OutPointFieldmarks(aMarkPos
);
2499 bool bConsumed
= false;
2502 if (bLeadingTab
&& rWrt
.m_nLeadingTabWidth
.has_value())
2504 // Consume a tab if it's leading and we know the number of NBSPs to
2505 // be used as a replacement.
2506 for (sal_Int32 i
= 0; i
< *rWrt
.m_nLeadingTabWidth
; ++i
)
2508 rWrt
.Strm().WriteOString(" ");
2515 // Not a tab -> later tabs are no longer leading.
2516 bLeadingTab
= false;
2521 HTMLOutFuncs::Out_Char(rWrt
.Strm(), c
);
2527 // if a paragraph's last character is a hard line break
2528 // then we need to add an extra <br>
2529 // because browsers like Mozilla wouldn't add a line for the next paragraph
2530 bWriteBreak
= (0x0a == c
) &&
2531 (HtmlTokenId::PREFORMTXT_ON
!= rWrt
.m_nLastParaToken
);
2536 HTMLOutFuncs::FlushToAscii( rWrt
.Strm() );
2539 aEndPosLst
.OutEndAttrs( rWrt
, SAL_MAX_INT32
);
2541 // Output the frames that are anchored to the last position
2543 bFlysLeft
= rWrt
.OutFlyFrame( rNode
.GetIndex(),
2544 nEnd
, HtmlPosition::Inside
);
2545 OSL_ENSURE( !bFlysLeft
, "Not all frames were saved!" );
2547 rWrt
.m_bTextAttr
= false;
2551 bool bEndOfCell
= rWrt
.m_bOutTable
&&
2552 rWrt
.m_pCurrentPam
->GetPoint()->GetNodeIndex() ==
2553 rWrt
.m_pCurrentPam
->GetMark()->GetNodeIndex();
2555 if( bEndOfCell
&& !nEnd
&&
2556 rWrt
.IsHTMLMode(HTMLMODE_NBSP_IN_TABLES
) )
2558 // If the last paragraph of a table cell is empty and we export
2559 // for the MS-IE, we write a instead of a <BR>
2560 rWrt
.Strm().WriteChar( '&' ).WriteOString( OOO_STRING_SVTOOLS_HTML_S_nbsp
).WriteChar( ';' );
2564 HtmlWriter
aHtml(rWrt
.Strm(), rWrt
.maNamespace
);
2565 aHtml
.prettyPrint(rWrt
.m_bPrettyPrint
);
2566 aHtml
.single(OOO_STRING_SVTOOLS_HTML_linebreak
);
2567 const SvxULSpaceItem
& rULSpace
= pNd
->GetSwAttrSet().Get(RES_UL_SPACE
);
2568 if (rULSpace
.GetLower() > 0 && !bEndOfCell
)
2570 aHtml
.single(OOO_STRING_SVTOOLS_HTML_linebreak
);
2572 rWrt
.m_bLFPossible
= true;
2576 if( rWrt
.m_bClearLeft
|| rWrt
.m_bClearRight
)
2578 const char* pString
;
2579 if( rWrt
.m_bClearLeft
)
2581 if( rWrt
.m_bClearRight
)
2582 pString
= OOO_STRING_SVTOOLS_HTML_AL_all
;
2584 pString
= OOO_STRING_SVTOOLS_HTML_AL_left
;
2588 pString
= OOO_STRING_SVTOOLS_HTML_AL_right
;
2591 HtmlWriter
aHtml(rWrt
.Strm(), rWrt
.maNamespace
);
2592 aHtml
.prettyPrint(rWrt
.m_bPrettyPrint
);
2593 aHtml
.start(OOO_STRING_SVTOOLS_HTML_linebreak
);
2594 aHtml
.attribute(OOO_STRING_SVTOOLS_HTML_O_clear
, pString
);
2597 rWrt
.m_bClearLeft
= false;
2598 rWrt
.m_bClearRight
= false;
2600 rWrt
.m_bLFPossible
= true;
2603 // if an LF is not allowed already, it is allowed once the paragraphs
2605 if( !rWrt
.m_bLFPossible
&&
2606 rWrt
.m_nLastParaToken
== HtmlTokenId::NONE
&&
2607 nEnd
> 0 && ' ' == rStr
[nEnd
-1] )
2608 rWrt
.m_bLFPossible
= true;
2610 // dot leaders: print the skipped page number in a different span element
2611 if (nIndexTab
> -1) {
2612 OString sOut
= OUStringToOString(rStr
.subView(nIndexTab
+ 1), RTL_TEXTENCODING_ASCII_US
);
2613 rWrt
.Strm().WriteOString( Concat2View("</span><span>" + sOut
+ "</span>") );
2616 rWrt
.m_bTagOn
= false;
2617 OutHTML_SwFormatOff( rWrt
, aFormatInfo
);
2619 // if necessary, close a form
2620 rWrt
.OutForm( false );
2622 if( bPageBreakBehind
)
2623 rWrt
.Strm().WriteChar( '\f' );
2628 // In CSS, "px" is 1/96 of inch: https://www.w3.org/TR/css3-values/#absolute-lengths
2629 sal_uInt32
SwHTMLWriter::ToPixel(sal_uInt32 nTwips
)
2631 // if there is a Twip, there should be a pixel as well
2633 ? std::max(o3tl::convert(nTwips
, o3tl::Length::twip
, o3tl::Length::px
), sal_Int64(1))
2637 Size
SwHTMLWriter::ToPixel(Size aTwips
)
2639 return Size(ToPixel(aTwips
.Width()), ToPixel(aTwips
.Height()));
2642 static SwHTMLWriter
& OutHTML_CSS1Attr( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2644 // if hints are currently written, we try to write the hint as an
2647 if( rWrt
.m_bCfgOutStyles
&& rWrt
.m_bTextAttr
)
2648 OutCSS1_HintSpanTag( rWrt
, rHt
);
2653 /* File CHRATR.HXX: */
2655 static SwHTMLWriter
& OutHTML_SvxColor( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2657 if( rWrt
.m_bOutOpts
)
2660 if( !rWrt
.m_bTextAttr
&& rWrt
.m_bCfgOutStyles
&& rWrt
.m_bCfgPreferStyles
)
2662 // don't write the font color as a tag, if styles are preferred to
2669 Color
aColor( static_cast<const SvxColorItem
&>(rHt
).GetValue() );
2670 if( COL_AUTO
== aColor
)
2675 OString sOut
= "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
2676 " " OOO_STRING_SVTOOLS_HTML_O_style
"=";
2677 rWrt
.Strm().WriteOString(sOut
);
2678 HTMLOutFuncs::Out_Color(rWrt
.Strm(), aColor
, /*bXHTML=*/true).WriteChar('>');
2682 OString sOut
= "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_font
" "
2683 OOO_STRING_SVTOOLS_HTML_O_color
"=";
2684 rWrt
.Strm().WriteOString( sOut
);
2685 HTMLOutFuncs::Out_Color( rWrt
.Strm(), aColor
).WriteChar( '>' );
2691 HTMLOutFuncs::Out_AsciiTag(
2692 rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
), false);
2694 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_font
), false );
2700 static SwHTMLWriter
& OutHTML_SwPosture( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2702 if( rWrt
.m_bOutOpts
)
2705 const FontItalic nPosture
= static_cast<const SvxPostureItem
&>(rHt
).GetPosture();
2706 if( ITALIC_NORMAL
== nPosture
)
2708 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_italic
), rWrt
.m_bTagOn
);
2710 else if( rWrt
.m_bCfgOutStyles
&& rWrt
.m_bTextAttr
)
2712 // maybe as CSS1 attribute?
2713 OutCSS1_HintSpanTag( rWrt
, rHt
);
2719 static SwHTMLWriter
& OutHTML_SvxFont( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2721 if( rWrt
.m_bOutOpts
)
2724 if (IgnorePropertyForReqIF(rWrt
.mbReqIF
, "font-family", ""))
2732 SwHTMLWriter::PrepareFontList( static_cast<const SvxFontItem
&>(rHt
), aNames
, 0,
2733 rWrt
.IsHTMLMode(HTMLMODE_FONT_GENERIC
) );
2736 OString sOut
= "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
2737 " " OOO_STRING_SVTOOLS_HTML_O_style
"=\"font-family: ";
2738 rWrt
.Strm().WriteOString(sOut
);
2739 HTMLOutFuncs::Out_String(rWrt
.Strm(), aNames
)
2740 .WriteOString("\">");
2744 OString sOut
= "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_font
" "
2745 OOO_STRING_SVTOOLS_HTML_O_face
"=\"";
2746 rWrt
.Strm().WriteOString( sOut
);
2747 HTMLOutFuncs::Out_String( rWrt
.Strm(), aNames
)
2748 .WriteOString( "\">" );
2754 HTMLOutFuncs::Out_AsciiTag(
2755 rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
), false);
2757 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_font
), false );
2763 static SwHTMLWriter
& OutHTML_SvxFontHeight( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2765 if( rWrt
.m_bOutOpts
)
2768 if (IgnorePropertyForReqIF(rWrt
.mbReqIF
, "font-size", ""))
2777 OString sOut
= "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
;
2779 sal_uInt32 nHeight
= static_cast<const SvxFontHeightItem
&>(rHt
).GetHeight();
2781 sal_uInt16 nSize
= nHeight
/ 20;
2782 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_style
"=\"font-size: "
2783 + OString::number(static_cast<sal_Int32
>(nSize
)) + "pt\"";
2784 rWrt
.Strm().WriteOString(sOut
);
2788 OString sOut
= "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_font
;
2790 sal_uInt32 nHeight
= static_cast<const SvxFontHeightItem
&>(rHt
).GetHeight();
2791 sal_uInt16 nSize
= rWrt
.GetHTMLFontSize( nHeight
);
2792 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_size
"=\"" +
2793 OString::number(static_cast<sal_Int32
>(nSize
)) + "\"";
2794 rWrt
.Strm().WriteOString( sOut
);
2796 if( rWrt
.m_bCfgOutStyles
&& rWrt
.m_bTextAttr
)
2798 // always export font size as CSS option, too
2799 OutCSS1_HintStyleOpt( rWrt
, rHt
);
2802 rWrt
.Strm().WriteChar( '>' );
2807 HTMLOutFuncs::Out_AsciiTag(
2808 rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
), false);
2810 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_font
), false );
2816 static SwHTMLWriter
& OutHTML_SvxLanguage( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2818 if( rWrt
.m_bOutOpts
)
2821 LanguageType eLang
= static_cast<const SvxLanguageItem
&>(rHt
).GetLanguage();
2822 if( LANGUAGE_DONTKNOW
== eLang
)
2827 OString sOut
= "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
;
2828 rWrt
.Strm().WriteOString( sOut
);
2829 rWrt
.OutLanguage( static_cast<const SvxLanguageItem
&>(rHt
).GetLanguage() );
2830 rWrt
.Strm().WriteChar( '>' );
2834 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span
), false );
2839 static SwHTMLWriter
& OutHTML_SwWeight( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2841 if( rWrt
.m_bOutOpts
)
2844 const FontWeight nBold
= static_cast<const SvxWeightItem
&>(rHt
).GetWeight();
2845 if( WEIGHT_BOLD
== nBold
)
2847 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_bold
), rWrt
.m_bTagOn
);
2849 else if( rWrt
.m_bCfgOutStyles
&& rWrt
.m_bTextAttr
)
2851 // maybe as CSS1 attribute ?
2852 OutCSS1_HintSpanTag( rWrt
, rHt
);
2858 static SwHTMLWriter
& OutHTML_SwCrossedOut( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2860 if( rWrt
.m_bOutOpts
)
2863 // Because of Netscape, we output STRIKE and not S!
2864 const FontStrikeout nStrike
= static_cast<const SvxCrossedOutItem
&>(rHt
).GetStrikeout();
2865 if( STRIKEOUT_NONE
!= nStrike
&& !rWrt
.mbReqIF
)
2867 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_strike
), rWrt
.m_bTagOn
);
2869 else if( rWrt
.m_bCfgOutStyles
&& rWrt
.m_bTextAttr
)
2871 // maybe as CSS1 attribute?
2872 OutCSS1_HintSpanTag( rWrt
, rHt
);
2878 static SwHTMLWriter
& OutHTML_SvxEscapement( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2880 if( rWrt
.m_bOutOpts
)
2883 const SvxEscapement eEscape
=
2884 static_cast<SvxEscapement
>(static_cast<const SvxEscapementItem
&>(rHt
).GetEnumValue());
2888 case SvxEscapement::Superscript
: aTag
= OOO_STRING_SVTOOLS_HTML_superscript
; break;
2889 case SvxEscapement::Subscript
: aTag
= OOO_STRING_SVTOOLS_HTML_subscript
; break;
2894 if( !aTag
.isEmpty() )
2896 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + aTag
), rWrt
.m_bTagOn
);
2898 else if( rWrt
.m_bCfgOutStyles
&& rWrt
.m_bTextAttr
)
2900 // maybe as CSS1 attribute?
2901 OutCSS1_HintSpanTag( rWrt
, rHt
);
2907 static SwHTMLWriter
& OutHTML_SwUnderline( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2909 if( rWrt
.m_bOutOpts
)
2912 const FontLineStyle eUnder
= static_cast<const SvxUnderlineItem
&>(rHt
).GetLineStyle();
2913 if( LINESTYLE_NONE
!= eUnder
&& !rWrt
.mbReqIF
)
2915 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_underline
), rWrt
.m_bTagOn
);
2917 else if( rWrt
.m_bCfgOutStyles
&& rWrt
.m_bTextAttr
)
2919 // maybe as CSS1 attribute?
2920 OutCSS1_HintSpanTag( rWrt
, rHt
);
2926 static SwHTMLWriter
& OutHTML_SwFlyCnt( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2928 const SwFormatFlyCnt
& rFlyCnt
= static_cast<const SwFormatFlyCnt
&>(rHt
);
2930 const SwFrameFormat
& rFormat
= *rFlyCnt
.GetFrameFormat();
2931 const SdrObject
*pSdrObj
= nullptr;
2933 SwHTMLFrameType eType
= rWrt
.GuessFrameType( rFormat
, pSdrObj
);
2934 AllHtmlFlags nMode
= aHTMLOutFrameAsCharTable
[eType
][rWrt
.m_nExportMode
];
2935 rWrt
.OutFrameFormat( nMode
, rFormat
, pSdrObj
);
2939 // This is now our Blink item. Blinking is activated by setting the item to
2941 static SwHTMLWriter
& OutHTML_SwBlink( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
2943 if( rWrt
.m_bOutOpts
)
2946 if( static_cast<const SvxBlinkItem
&>(rHt
).GetValue() )
2948 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_blink
), rWrt
.m_bTagOn
);
2950 else if( rWrt
.m_bCfgOutStyles
&& rWrt
.m_bTextAttr
)
2952 // maybe as CSS1 attribute?
2953 OutCSS1_HintSpanTag( rWrt
, rHt
);
2959 SwHTMLWriter
& OutHTML_INetFormat( SwHTMLWriter
& rWrt
, const SwFormatINetFormat
& rINetFormat
, bool bOn
)
2961 OUString
aURL( rINetFormat
.GetValue() );
2962 const SvxMacroTableDtor
*pMacTable
= rINetFormat
.GetMacroTable();
2963 bool bEvents
= pMacTable
!= nullptr && !pMacTable
->empty();
2965 // Anything to output at all?
2966 if( aURL
.isEmpty() && !bEvents
&& rINetFormat
.GetName().isEmpty() )
2969 // bOn controls if we are writing the opening or closing tag
2972 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor
), false );
2976 OString
sOut("<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor
);
2978 bool bScriptDependent
= false;
2980 const SwCharFormat
* pFormat
= rWrt
.m_pDoc
->getIDocumentStylePoolAccess().GetCharFormatFromPool(
2981 RES_POOLCHR_INET_NORMAL
);
2982 std::unique_ptr
<SwHTMLFormatInfo
> pFormatInfo(new SwHTMLFormatInfo(pFormat
));
2983 auto const it
= rWrt
.m_CharFormatInfos
.find( pFormatInfo
);
2984 if (it
!= rWrt
.m_CharFormatInfos
.end())
2986 bScriptDependent
= (*it
)->bScriptDependent
;
2989 if( !bScriptDependent
)
2991 const SwCharFormat
* pFormat
= rWrt
.m_pDoc
->getIDocumentStylePoolAccess().GetCharFormatFromPool(
2992 RES_POOLCHR_INET_VISIT
);
2993 std::unique_ptr
<SwHTMLFormatInfo
> pFormatInfo(new SwHTMLFormatInfo(pFormat
));
2994 auto const it
= rWrt
.m_CharFormatInfos
.find( pFormatInfo
);
2995 if (it
!= rWrt
.m_CharFormatInfos
.end())
2997 bScriptDependent
= (*it
)->bScriptDependent
;
3001 if( bScriptDependent
)
3003 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_class
"=\"";
3004 const char* pStr
= nullptr;
3005 switch( rWrt
.m_nCSS1Script
)
3007 case CSS1_OUTMODE_WESTERN
:
3010 case CSS1_OUTMODE_CJK
:
3013 case CSS1_OUTMODE_CTL
:
3017 sOut
+= pStr
+ OString::Concat("\"");
3020 rWrt
.Strm().WriteOString( sOut
);
3025 if( !aURL
.isEmpty() || bEvents
)
3027 OUString
sTmp( aURL
.toAsciiUpperCase() );
3028 sal_Int32 nPos
= sTmp
.indexOf( "\" REL=" );
3031 sRel
= aURL
.copy( nPos
+1 );
3032 aURL
= aURL
.copy( 0, nPos
);
3034 aURL
= comphelper::string::strip(aURL
, ' ');
3036 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_href
"=\"";
3037 rWrt
.Strm().WriteOString( sOut
);
3038 rWrt
.OutHyperlinkHRefValue( aURL
);
3042 if( !rINetFormat
.GetName().isEmpty() )
3044 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_name
"=\"";
3045 rWrt
.Strm().WriteOString( sOut
);
3046 HTMLOutFuncs::Out_String( rWrt
.Strm(), rINetFormat
.GetName() );
3050 const OUString
& rTarget
= rINetFormat
.GetTargetFrame();
3051 if( !rTarget
.isEmpty() )
3053 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_target
"=\"";
3054 rWrt
.Strm().WriteOString( sOut
);
3055 HTMLOutFuncs::Out_String( rWrt
.Strm(), rTarget
);
3059 if( !sRel
.isEmpty() )
3060 sOut
+= OUStringToOString(sRel
, RTL_TEXTENCODING_ASCII_US
);
3062 if( !sOut
.isEmpty() )
3063 rWrt
.Strm().WriteOString( sOut
);
3066 HTMLOutFuncs::Out_Events( rWrt
.Strm(), *pMacTable
, aAnchorEventTable
,
3067 rWrt
.m_bCfgStarBasic
);
3068 rWrt
.Strm().WriteOString( ">" );
3073 static SwHTMLWriter
& OutHTML_SwFormatINetFormat( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
3075 if( rWrt
.m_bOutOpts
)
3078 const SwFormatINetFormat
& rINetFormat
= static_cast<const SwFormatINetFormat
&>(rHt
);
3082 // if necessary, temporarily close an attribute that is still open
3083 if( !rWrt
.m_aINetFormats
.empty() )
3085 SwFormatINetFormat
*pINetFormat
=
3086 rWrt
.m_aINetFormats
.back();
3087 OutHTML_INetFormat( rWrt
, *pINetFormat
, false );
3090 // now, open the new one
3091 OutHTML_INetFormat( rWrt
, rINetFormat
, true );
3094 SwFormatINetFormat
*pINetFormat
= new SwFormatINetFormat( rINetFormat
);
3095 rWrt
.m_aINetFormats
.push_back( pINetFormat
);
3099 OutHTML_INetFormat( rWrt
, rINetFormat
, false );
3101 OSL_ENSURE( rWrt
.m_aINetFormats
.size(), "there must be a URL attribute missing" );
3102 if( !rWrt
.m_aINetFormats
.empty() )
3104 // get its own attribute from the stack
3105 SwFormatINetFormat
*pINetFormat
= rWrt
.m_aINetFormats
.back();
3106 rWrt
.m_aINetFormats
.pop_back();
3110 if( !rWrt
.m_aINetFormats
.empty() )
3112 // there is still an attribute on the stack that must be reopened
3113 SwFormatINetFormat
*pINetFormat
= rWrt
.m_aINetFormats
.back();
3114 OutHTML_INetFormat( rWrt
, *pINetFormat
, true );
3121 static SwHTMLWriter
& OutHTML_SwTextCharFormat( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
3123 if( rWrt
.m_bOutOpts
)
3126 const SwFormatCharFormat
& rChrFormat
= static_cast<const SwFormatCharFormat
&>(rHt
);
3127 const SwCharFormat
* pFormat
= rChrFormat
.GetCharFormat();
3134 std::unique_ptr
<SwHTMLFormatInfo
> pTmpInfo(new SwHTMLFormatInfo(pFormat
));
3135 SwHTMLFormatInfos::const_iterator it
= rWrt
.m_CharFormatInfos
.find(pTmpInfo
);
3136 if (it
== rWrt
.m_CharFormatInfos
.end())
3139 const SwHTMLFormatInfo
*pFormatInfo
= it
->get();
3140 OSL_ENSURE( pFormatInfo
, "Why is there no information about the character style?" );
3144 OString sOut
= "<" + rWrt
.GetNamespace();
3145 if( !pFormatInfo
->aToken
.isEmpty() )
3146 sOut
+= pFormatInfo
->aToken
;
3148 sOut
+= OOO_STRING_SVTOOLS_HTML_span
;
3150 if( rWrt
.m_bCfgOutStyles
&&
3151 (!pFormatInfo
->aClass
.isEmpty() || pFormatInfo
->bScriptDependent
) )
3153 sOut
+= " " OOO_STRING_SVTOOLS_HTML_O_class
"=\"";
3154 rWrt
.Strm().WriteOString( sOut
);
3155 OUString
aClass( pFormatInfo
->aClass
);
3156 if( pFormatInfo
->bScriptDependent
)
3158 if( !aClass
.isEmpty() )
3160 switch( rWrt
.m_nCSS1Script
)
3162 case CSS1_OUTMODE_WESTERN
:
3163 aClass
+= "western";
3165 case CSS1_OUTMODE_CJK
:
3168 case CSS1_OUTMODE_CTL
:
3173 HTMLOutFuncs::Out_String( rWrt
.Strm(), aClass
);
3177 rWrt
.Strm().WriteOString( sOut
);
3181 OString aTag
= !pFormatInfo
->aToken
.isEmpty() ? pFormatInfo
->aToken
.getStr()
3182 : OOO_STRING_SVTOOLS_HTML_span
;
3183 HTMLOutFuncs::Out_AsciiTag(rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + aTag
), false);
3189 static SwHTMLWriter
& OutHTML_SvxAdjust( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
3191 if( !rWrt
.m_bOutOpts
|| !rWrt
.m_bTagOn
)
3194 const SvxAdjustItem
& rAdjust
= static_cast<const SvxAdjustItem
&>(rHt
);
3195 const char* pStr
= nullptr;
3196 switch( rAdjust
.GetAdjust() )
3198 case SvxAdjust::Center
: pStr
= OOO_STRING_SVTOOLS_HTML_AL_center
; break;
3199 case SvxAdjust::Left
: pStr
= OOO_STRING_SVTOOLS_HTML_AL_left
; break;
3200 case SvxAdjust::Right
: pStr
= OOO_STRING_SVTOOLS_HTML_AL_right
; break;
3201 case SvxAdjust::Block
: pStr
= OOO_STRING_SVTOOLS_HTML_AL_justify
; break;
3207 OString sOut
= OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_align
"=\"") +
3209 rWrt
.Strm().WriteOString( sOut
);
3216 * here, define the table for the HTML function pointers to the output
3220 SwAttrFnTab aHTMLAttrFnTab
= {
3221 /* RES_CHRATR_CASEMAP */ OutHTML_CSS1Attr
,
3222 /* RES_CHRATR_CHARSETCOLOR */ nullptr,
3223 /* RES_CHRATR_COLOR */ OutHTML_SvxColor
,
3224 /* RES_CHRATR_CONTOUR */ nullptr,
3225 /* RES_CHRATR_CROSSEDOUT */ OutHTML_SwCrossedOut
,
3226 /* RES_CHRATR_ESCAPEMENT */ OutHTML_SvxEscapement
,
3227 /* RES_CHRATR_FONT */ OutHTML_SvxFont
,
3228 /* RES_CHRATR_FONTSIZE */ OutHTML_SvxFontHeight
,
3229 /* RES_CHRATR_KERNING */ OutHTML_CSS1Attr
,
3230 /* RES_CHRATR_LANGUAGE */ OutHTML_SvxLanguage
,
3231 /* RES_CHRATR_POSTURE */ OutHTML_SwPosture
,
3232 /* RES_CHRATR_UNUSED1*/ nullptr,
3233 /* RES_CHRATR_SHADOWED */ nullptr,
3234 /* RES_CHRATR_UNDERLINE */ OutHTML_SwUnderline
,
3235 /* RES_CHRATR_WEIGHT */ OutHTML_SwWeight
,
3236 /* RES_CHRATR_WORDLINEMODE */ nullptr,
3237 /* RES_CHRATR_AUTOKERN */ nullptr,
3238 /* RES_CHRATR_BLINK */ OutHTML_SwBlink
,
3239 /* RES_CHRATR_NOHYPHEN */ nullptr, // New: don't hyphenate
3240 /* RES_CHRATR_UNUSED2 */ nullptr,
3241 /* RES_CHRATR_BACKGROUND */ OutHTML_CSS1Attr
, // New: character background
3242 /* RES_CHRATR_CJK_FONT */ OutHTML_SvxFont
,
3243 /* RES_CHRATR_CJK_FONTSIZE */ OutHTML_SvxFontHeight
,
3244 /* RES_CHRATR_CJK_LANGUAGE */ OutHTML_SvxLanguage
,
3245 /* RES_CHRATR_CJK_POSTURE */ OutHTML_SwPosture
,
3246 /* RES_CHRATR_CJK_WEIGHT */ OutHTML_SwWeight
,
3247 /* RES_CHRATR_CTL_FONT */ OutHTML_SvxFont
,
3248 /* RES_CHRATR_CTL_FONTSIZE */ OutHTML_SvxFontHeight
,
3249 /* RES_CHRATR_CTL_LANGUAGE */ OutHTML_SvxLanguage
,
3250 /* RES_CHRATR_CTL_POSTURE */ OutHTML_SwPosture
,
3251 /* RES_CHRATR_CTL_WEIGHT */ OutHTML_SwWeight
,
3252 /* RES_CHRATR_ROTATE */ nullptr,
3253 /* RES_CHRATR_EMPHASIS_MARK */ nullptr,
3254 /* RES_CHRATR_TWO_LINES */ nullptr,
3255 /* RES_CHRATR_SCALEW */ nullptr,
3256 /* RES_CHRATR_RELIEF */ nullptr,
3257 /* RES_CHRATR_HIDDEN */ OutHTML_CSS1Attr
,
3258 /* RES_CHRATR_OVERLINE */ OutHTML_CSS1Attr
,
3259 /* RES_CHRATR_RSID */ nullptr,
3260 /* RES_CHRATR_BOX */ OutHTML_CSS1Attr
,
3261 /* RES_CHRATR_SHADOW */ nullptr,
3262 /* RES_CHRATR_HIGHLIGHT */ nullptr,
3263 /* RES_CHRATR_GRABBAG */ nullptr,
3264 /* RES_CHRATR_BIDIRTL */ nullptr,
3265 /* RES_CHRATR_IDCTHINT */ nullptr,
3267 /* RES_TXTATR_REFMARK */ nullptr,
3268 /* RES_TXTATR_TOXMARK */ nullptr,
3269 /* RES_TXTATR_META */ nullptr,
3270 /* RES_TXTATR_METAFIELD */ nullptr,
3271 /* RES_TXTATR_AUTOFMT */ nullptr,
3272 /* RES_TXTATR_INETFMT */ OutHTML_SwFormatINetFormat
,
3273 /* RES_TXTATR_CHARFMT */ OutHTML_SwTextCharFormat
,
3274 /* RES_TXTATR_CJK_RUBY */ nullptr,
3275 /* RES_TXTATR_UNKNOWN_CONTAINER */ nullptr,
3276 /* RES_TXTATR_INPUTFIELD */ OutHTML_SwFormatField
,
3277 /* RES_TXTATR_CONTENTCONTROL */ nullptr,
3279 /* RES_TXTATR_FIELD */ OutHTML_SwFormatField
,
3280 /* RES_TXTATR_FLYCNT */ OutHTML_SwFlyCnt
,
3281 /* RES_TXTATR_FTN */ OutHTML_SwFormatFootnote
,
3282 /* RES_TXTATR_ANNOTATION */ OutHTML_SwFormatField
,
3283 /* RES_TXTATR_LINEBREAK */ OutHTML_SwFormatLineBreak
,
3284 /* RES_TXTATR_DUMMY1 */ nullptr, // Dummy:
3286 /* RES_PARATR_LINESPACING */ nullptr,
3287 /* RES_PARATR_ADJUST */ OutHTML_SvxAdjust
,
3288 /* RES_PARATR_SPLIT */ nullptr,
3289 /* RES_PARATR_ORPHANS */ nullptr,
3290 /* RES_PARATR_WIDOWS */ nullptr,
3291 /* RES_PARATR_TABSTOP */ nullptr,
3292 /* RES_PARATR_HYPHENZONE*/ nullptr,
3293 /* RES_PARATR_DROP */ OutHTML_CSS1Attr
,
3294 /* RES_PARATR_REGISTER */ nullptr, // new: register-true
3295 /* RES_PARATR_NUMRULE */ nullptr, // Dummy:
3296 /* RES_PARATR_SCRIPTSPACE */ nullptr, // Dummy:
3297 /* RES_PARATR_HANGINGPUNCTUATION */ nullptr, // Dummy:
3298 /* RES_PARATR_FORBIDDEN_RULES */ nullptr, // new
3299 /* RES_PARATR_VERTALIGN */ nullptr, // new
3300 /* RES_PARATR_SNAPTOGRID*/ nullptr, // new
3301 /* RES_PARATR_CONNECT_TO_BORDER */ nullptr, // new
3302 /* RES_PARATR_OUTLINELEVEL */ nullptr,
3303 /* RES_PARATR_RSID */ nullptr,
3304 /* RES_PARATR_GRABBAG */ nullptr,
3306 /* RES_PARATR_LIST_ID */ nullptr, // new
3307 /* RES_PARATR_LIST_LEVEL */ nullptr, // new
3308 /* RES_PARATR_LIST_ISRESTART */ nullptr, // new
3309 /* RES_PARATR_LIST_RESTARTVALUE */ nullptr, // new
3310 /* RES_PARATR_LIST_ISCOUNTED */ nullptr, // new
3312 /* RES_FILL_ORDER */ nullptr,
3313 /* RES_FRM_SIZE */ nullptr,
3314 /* RES_PAPER_BIN */ nullptr,
3315 /* RES_MARGIN_FIRSTLINE */ nullptr,
3316 /* RES_MARGIN_TEXTLEFT */ nullptr,
3317 /* RES_MARGIN_RIGHT */ nullptr,
3318 /* RES_MARGIN_LEFT */ nullptr,
3319 /* RES_MARGIN_GUTTER */ nullptr,
3320 /* RES_MARGIN_GUTTER_RIGHT */ nullptr,
3321 /* RES_LR_SPACE */ nullptr,
3322 /* RES_UL_SPACE */ nullptr,
3323 /* RES_PAGEDESC */ nullptr,
3324 /* RES_BREAK */ nullptr,
3325 /* RES_CNTNT */ nullptr,
3326 /* RES_HEADER */ nullptr,
3327 /* RES_FOOTER */ nullptr,
3328 /* RES_PRINT */ nullptr,
3329 /* RES_OPAQUE */ nullptr,
3330 /* RES_PROTECT */ nullptr,
3331 /* RES_SURROUND */ nullptr,
3332 /* RES_VERT_ORIENT */ nullptr,
3333 /* RES_HORI_ORIENT */ nullptr,
3334 /* RES_ANCHOR */ nullptr,
3335 /* RES_BACKGROUND */ nullptr,
3336 /* RES_BOX */ nullptr,
3337 /* RES_SHADOW */ nullptr,
3338 /* RES_FRMMACRO */ nullptr,
3339 /* RES_COL */ nullptr,
3340 /* RES_KEEP */ nullptr,
3341 /* RES_URL */ nullptr,
3342 /* RES_EDIT_IN_READONLY */ nullptr,
3343 /* RES_LAYOUT_SPLIT */ nullptr,
3344 /* RES_CHAIN */ nullptr,
3345 /* RES_TEXTGRID */ nullptr,
3346 /* RES_LINENUMBER */ nullptr,
3347 /* RES_FTN_AT_TXTEND */ nullptr,
3348 /* RES_END_AT_TXTEND */ nullptr,
3349 /* RES_COLUMNBALANCE */ nullptr,
3350 /* RES_FRAMEDIR */ nullptr,
3351 /* RES_HEADER_FOOTER_EAT_SPACING */ nullptr,
3352 /* RES_ROW_SPLIT */ nullptr,
3353 /* RES_FLY_SPLIT */ nullptr,
3354 /* RES_FOLLOW_TEXT_FLOW */ nullptr,
3355 /* RES_COLLAPSING_BORDERS */ nullptr,
3356 /* RES_WRAP_INFLUENCE_ON_OBJPOS */ nullptr,
3357 /* RES_AUTO_STYLE */ nullptr,
3358 /* RES_FRMATR_STYLE_NAME */ nullptr,
3359 /* RES_FRMATR_CONDITIONAL_STYLE_NAME */ nullptr,
3360 /* RES_FRMATR_GRABBAG */ nullptr,
3361 /* RES_TEXT_VERT_ADJUST */ nullptr,
3362 /* RES_BACKGROUND_FULL_SIZE */ nullptr,
3363 /* RES_RTL_GUTTER */ nullptr,
3364 /* RES_DECORATIVE */ nullptr,
3366 /* RES_GRFATR_MIRRORGRF */ nullptr,
3367 /* RES_GRFATR_CROPGRF */ nullptr,
3368 /* RES_GRFATR_ROTATION */ nullptr,
3369 /* RES_GRFATR_LUMINANCE */ nullptr,
3370 /* RES_GRFATR_CONTRAST */ nullptr,
3371 /* RES_GRFATR_CHANNELR */ nullptr,
3372 /* RES_GRFATR_CHANNELG */ nullptr,
3373 /* RES_GRFATR_CHANNELB */ nullptr,
3374 /* RES_GRFATR_GAMMA */ nullptr,
3375 /* RES_GRFATR_INVERT */ nullptr,
3376 /* RES_GRFATR_TRANSPARENCY */ nullptr,
3377 /* RES_GRFATR_DRWAMODE */ nullptr,
3378 /* RES_GRFATR_DUMMY3 */ nullptr,
3379 /* RES_GRFATR_DUMMY4 */ nullptr,
3380 /* RES_GRFATR_DUMMY5 */ nullptr,
3382 /* RES_BOXATR_FORMAT */ nullptr,
3383 /* RES_BOXATR_FORMULA */ nullptr,
3384 /* RES_BOXATR_VALUE */ nullptr
3387 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */