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 <sal/config.h>
22 #include <string_view>
24 #include <osl/diagnose.h>
25 #include <svtools/htmlout.hxx>
26 #include <svtools/htmlkywd.hxx>
27 #include <svtools/HtmlWriter.hxx>
28 #include <rtl/strbuf.hxx>
29 #include <ndindex.hxx>
32 #include <ftninfo.hxx>
35 #include <charfmt.hxx>
38 #include "wrthtml.hxx"
40 static sal_Int32
lcl_html_getNextPart( OUString
& rPart
, std::u16string_view aContent
,
44 sal_Int32 nLen
= aContent
.size();
51 bool bQuoted
= false, bDone
= false;
52 for( ; nPos
< nLen
&& !bDone
; nPos
++ )
54 sal_Unicode c
= aContent
[nPos
];
59 rPart
+= OUStringChar( c
);
65 rPart
+= OUStringChar( c
);
72 rPart
+= OUStringChar( c
);
82 static sal_Int32
lcl_html_getEndNoteInfo( SwEndNoteInfo
& rInfo
,
83 std::u16string_view aContent
,
86 sal_Int32 nStrPos
= 0;
87 for( int nPart
= 0; nPart
< 4; ++nPart
)
91 nStrPos
= lcl_html_getNextPart( aPart
, aContent
, nStrPos
);
96 rInfo
.m_aFormat
.SetNumberingType( bEndNote
? SVX_NUM_ROMAN_LOWER
: SVX_NUM_ARABIC
);
97 if( !aPart
.isEmpty() )
98 rInfo
.m_aFormat
.SetNumberingType(SwHTMLParser::GetNumType( aPart
,
99 rInfo
.m_aFormat
.GetNumberingType() ));
103 rInfo
.m_nFootnoteOffset
= aPart
.isEmpty() ? 0 : o3tl::narrowing
<sal_uInt16
>(aPart
.toInt32());
107 rInfo
.SetPrefix( aPart
);
111 rInfo
.SetSuffix( aPart
);
119 void SwHTMLParser::FillEndNoteInfo( std::u16string_view aContent
)
121 SwEndNoteInfo
aInfo( m_xDoc
->GetEndNoteInfo() );
122 lcl_html_getEndNoteInfo( aInfo
, aContent
, true );
123 m_xDoc
->SetEndNoteInfo( aInfo
);
126 void SwHTMLParser::FillFootNoteInfo( std::u16string_view aContent
)
128 SwFootnoteInfo
aInfo( m_xDoc
->GetFootnoteInfo() );
130 sal_Int32 nStrPos
= lcl_html_getEndNoteInfo( aInfo
, aContent
, false );
132 for( int nPart
= 4; nPart
< 8; ++nPart
)
136 nStrPos
= lcl_html_getNextPart( aPart
, aContent
, nStrPos
);
141 aInfo
.m_eNum
= FTNNUM_DOC
;
142 if( !aPart
.isEmpty() )
146 case 'D': aInfo
.m_eNum
= FTNNUM_DOC
; break;
147 case 'C': aInfo
.m_eNum
= FTNNUM_CHAPTER
; break;
148 case 'P': aInfo
.m_eNum
= FTNNUM_PAGE
; break;
154 aInfo
.m_ePos
= FTNPOS_PAGE
;
155 if( !aPart
.isEmpty() )
159 case 'C': aInfo
.m_ePos
= FTNPOS_CHAPTER
; break;
160 case 'P': aInfo
.m_ePos
= FTNPOS_PAGE
; break;
166 aInfo
.m_aQuoVadis
= aPart
;
170 aInfo
.m_aErgoSum
= aPart
;
175 m_xDoc
->SetFootnoteInfo( aInfo
);
178 void SwHTMLParser::InsertFootEndNote( const OUString
& rName
, bool bEndNote
,
181 if( !m_pFootEndNoteImpl
)
182 m_pFootEndNoteImpl
.reset(new SwHTMLFootEndNote_Impl
);
184 m_pFootEndNoteImpl
->sName
= rName
;
185 if( m_pFootEndNoteImpl
->sName
.getLength() > 3 )
186 m_pFootEndNoteImpl
->sName
= m_pFootEndNoteImpl
->sName
.copy( 0, m_pFootEndNoteImpl
->sName
.getLength() - 3 );
187 m_pFootEndNoteImpl
->sName
= m_pFootEndNoteImpl
->sName
.toAsciiUpperCase();
188 m_pFootEndNoteImpl
->bEndNote
= bEndNote
;
189 m_pFootEndNoteImpl
->bFixed
= bFixed
;
190 m_pFootEndNoteImpl
->sContent
.clear();
193 void SwHTMLParser::FinishFootEndNote()
195 if( !m_pFootEndNoteImpl
)
198 SwFormatFootnote
aFootnote( m_pFootEndNoteImpl
->bEndNote
);
199 if( m_pFootEndNoteImpl
->bFixed
)
200 aFootnote
.SetNumStr( m_pFootEndNoteImpl
->sContent
);
202 m_xDoc
->getIDocumentContentOperations().InsertPoolItem( *m_pPam
, aFootnote
);
203 SwTextFootnote
* const pTextFootnote
= static_cast<SwTextFootnote
*>(
204 m_pPam
->GetPointNode().GetTextNode()->GetTextAttrForCharAt(
205 m_pPam
->GetPoint()->GetContentIndex() - 1, RES_TXTATR_FTN
) );
206 // In header and footer no footnotes can be inserted.
208 m_pFootEndNoteImpl
->aTextFootnotes
.push_back(SwHTMLTextFootnote(m_pFootEndNoteImpl
->sName
,pTextFootnote
));
209 m_pFootEndNoteImpl
->sName
.clear();
210 m_pFootEndNoteImpl
->sContent
.clear();
211 m_pFootEndNoteImpl
->bFixed
= false;
214 void SwHTMLParser::InsertFootEndNoteText()
216 if( m_pFootEndNoteImpl
&& m_pFootEndNoteImpl
->bFixed
)
217 m_pFootEndNoteImpl
->sContent
+= aToken
;
220 SwNodeIndex
*SwHTMLParser::GetFootEndNoteSection( const OUString
& rName
)
222 SwNodeIndex
*pStartNodeIdx
= nullptr;
224 if (m_pFootEndNoteImpl
)
226 OUString
aName(rName
.toAsciiUpperCase());
228 size_t nCount
= m_pFootEndNoteImpl
->aTextFootnotes
.size();
229 for(size_t i
= 0; i
< nCount
; ++i
)
231 if (m_pFootEndNoteImpl
->aTextFootnotes
[i
].GetName() == aName
)
233 pStartNodeIdx
= const_cast<SwNodeIndex
*>(m_pFootEndNoteImpl
->aTextFootnotes
[i
].GetStartNode());
234 m_pFootEndNoteImpl
->aTextFootnotes
.erase( m_pFootEndNoteImpl
->aTextFootnotes
.begin() + i
);
235 if (m_pFootEndNoteImpl
->aTextFootnotes
.empty())
237 m_pFootEndNoteImpl
.reset();
245 return pStartNodeIdx
;
248 SwHTMLWriter
& OutHTML_SwFormatLineBreak(SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
250 const auto& rLineBreak
= static_cast<const SwFormatLineBreak
&>(rHt
);
252 HtmlWriter
aWriter(rWrt
.Strm(), rWrt
.maNamespace
);
253 aWriter
.start(OOO_STRING_SVTOOLS_HTML_linebreak
);
254 switch (rLineBreak
.GetValue())
256 case SwLineBreakClear::NONE
:
257 aWriter
.attribute(OOO_STRING_SVTOOLS_HTML_O_clear
, "none");
259 case SwLineBreakClear::LEFT
:
260 aWriter
.attribute(OOO_STRING_SVTOOLS_HTML_O_clear
, "left");
262 case SwLineBreakClear::RIGHT
:
263 aWriter
.attribute(OOO_STRING_SVTOOLS_HTML_O_clear
, "right");
265 case SwLineBreakClear::ALL
:
266 aWriter
.attribute(OOO_STRING_SVTOOLS_HTML_O_clear
, "all");
273 SwHTMLWriter
& OutHTML_SwFormatFootnote( SwHTMLWriter
& rWrt
, const SfxPoolItem
& rHt
)
275 SwFormatFootnote
& rFormatFootnote
= const_cast<SwFormatFootnote
&>(static_cast<const SwFormatFootnote
&>(rHt
));
276 SwTextFootnote
*pTextFootnote
= rFormatFootnote
.GetTextFootnote();
280 OUString sFootnoteName
, sClass
;
282 if( rFormatFootnote
.IsEndNote() )
284 nPos
= rWrt
.m_xFootEndNotes
? rWrt
.m_xFootEndNotes
->size() : 0;
285 OSL_ENSURE( nPos
== static_cast<size_t>(rWrt
.m_nFootNote
+ rWrt
.m_nEndNote
),
286 "OutHTML_SwFormatFootnote: wrong position" );
287 sClass
= OOO_STRING_SVTOOLS_HTML_sdendnote_anc
;
288 sFootnoteName
= OOO_STRING_SVTOOLS_HTML_sdendnote
+ OUString::number( static_cast<sal_Int32
>(++rWrt
.m_nEndNote
) );
292 nPos
= rWrt
.m_nFootNote
;
293 sClass
= OOO_STRING_SVTOOLS_HTML_sdfootnote_anc
;
294 sFootnoteName
= OOO_STRING_SVTOOLS_HTML_sdfootnote
+ OUString::number( static_cast<sal_Int32
>(++rWrt
.m_nFootNote
));
297 if( !rWrt
.m_xFootEndNotes
)
298 rWrt
.m_xFootEndNotes
.emplace();
299 rWrt
.m_xFootEndNotes
->insert( rWrt
.m_xFootEndNotes
->begin() + nPos
, pTextFootnote
);
302 OString aTag
= rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor
;
303 sOut
.append("<" + aTag
+ " " OOO_STRING_SVTOOLS_HTML_O_class
"=\"");
304 rWrt
.Strm().WriteOString( sOut
);
306 HTMLOutFuncs::Out_String( rWrt
.Strm(), sClass
);
307 sOut
.append("\" " OOO_STRING_SVTOOLS_HTML_O_name
"=\"");
308 rWrt
.Strm().WriteOString( sOut
);
310 HTMLOutFuncs::Out_String( rWrt
.Strm(), sFootnoteName
);
311 sOut
.append(OOO_STRING_SVTOOLS_HTML_FTN_anchor
"\" "
312 OOO_STRING_SVTOOLS_HTML_O_href
"=\"#");
313 rWrt
.Strm().WriteOString( sOut
);
315 HTMLOutFuncs::Out_String( rWrt
.Strm(), sFootnoteName
);
316 sOut
.append(OOO_STRING_SVTOOLS_HTML_FTN_symbol
"\"");
317 if( !rFormatFootnote
.GetNumStr().isEmpty() )
318 sOut
.append(" " OOO_STRING_SVTOOLS_HTML_O_sdfixed
);
320 rWrt
.Strm().WriteOString( sOut
);
322 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_superscript
));
324 HTMLOutFuncs::Out_String( rWrt
.Strm(), rFormatFootnote
.GetViewNumStr(*rWrt
.m_pDoc
, nullptr) );
325 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_superscript
), false );
326 HTMLOutFuncs::Out_AsciiTag( rWrt
.Strm(), Concat2View(rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor
), false );
331 void SwHTMLWriter::OutFootEndNotes()
333 OSL_ENSURE( m_xFootEndNotes
,
334 "SwHTMLWriter::OutFootEndNotes(): unnecessary call" );
335 if( !m_xFootEndNotes
)
338 #if OSL_DEBUG_LEVEL > 0
339 sal_uInt16 nFootnote
= m_nFootNote
, nEn
= m_nEndNote
;
344 for( auto *pTextFootnote
: *m_xFootEndNotes
)
346 m_pFormatFootnote
= &pTextFootnote
->GetFootnote();
348 OUString sFootnoteName
;
349 if( m_pFormatFootnote
->IsEndNote() )
351 sFootnoteName
= OOO_STRING_SVTOOLS_HTML_sdendnote
+ OUString::number(static_cast<sal_Int32
>(++m_nEndNote
));
355 sFootnoteName
= OOO_STRING_SVTOOLS_HTML_sdfootnote
+ OUString::number(static_cast<sal_Int32
>(++m_nFootNote
));
361 "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_division
362 " " OOO_STRING_SVTOOLS_HTML_O_id
"=\"";
363 Strm().WriteOString( sOut
);
364 HTMLOutFuncs::Out_String( Strm(), sFootnoteName
);
365 Strm().WriteOString( "\">" );
367 m_bLFPossible
= true;
368 IncIndentLevel(); // indent content of <DIV>
370 OSL_ENSURE( pTextFootnote
, "SwHTMLWriter::OutFootEndNotes: SwTextFootnote is missing" );
371 const SwNodeIndex
*pSttNdIdx
= pTextFootnote
->GetStartNode();
372 OSL_ENSURE( pSttNdIdx
,
373 "SwHTMLWriter::OutFootEndNotes: StartNode-Index is missing" );
376 HTMLSaveData
aSaveData( *this, pSttNdIdx
->GetIndex()+1,
377 pSttNdIdx
->GetNode().EndOfSectionIndex(), false );
378 Out_SwDoc( m_pCurrentPam
.get() );
381 DecIndentLevel(); // indent content of <DIV>
384 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division
), false );
385 m_bLFPossible
= true;
387 OSL_ENSURE( !m_pFormatFootnote
,
388 "SwHTMLWriter::OutFootEndNotes: Footnote was not output" );
389 if( m_pFormatFootnote
)
391 if( m_pFormatFootnote
->IsEndNote() )
396 m_pFormatFootnote
= nullptr;
400 #if OSL_DEBUG_LEVEL > 0
401 OSL_ENSURE( nFootnote
== m_nFootNote
,
402 "SwHTMLWriter::OutFootEndNotes: Number of footnotes does not match" );
403 OSL_ENSURE( nEn
== m_nEndNote
,
404 "SwHTMLWriter::OutFootEndNotes: Number of endnotes does not match" );
407 m_xFootEndNotes
.reset();
408 m_nFootNote
= m_nEndNote
= 0;
411 OUString
SwHTMLWriter::GetFootEndNoteSym( const SwFormatFootnote
& rFormatFootnote
)
413 const SwEndNoteInfo
* pInfo
= nullptr;
414 if( rFormatFootnote
.GetNumStr().isEmpty() )
415 pInfo
= rFormatFootnote
.IsEndNote() ? &m_pDoc
->GetEndNoteInfo()
416 : &m_pDoc
->GetFootnoteInfo();
420 sRet
= pInfo
->GetPrefix();
421 sRet
+= rFormatFootnote
.GetViewNumStr(*m_pDoc
, nullptr);
423 sRet
+= pInfo
->GetSuffix();
428 void SwHTMLWriter::OutFootEndNoteSym( const SwFormatFootnote
& rFormatFootnote
,
429 const OUString
& rNum
,
432 const SwEndNoteInfo
*pInfo
;
434 OUString sFootnoteName
, sClass
;
435 if( rFormatFootnote
.IsEndNote() )
437 sClass
= OOO_STRING_SVTOOLS_HTML_sdendnote_sym
;
438 sFootnoteName
= OOO_STRING_SVTOOLS_HTML_sdendnote
+
439 OUString::number(static_cast<sal_Int32
>(m_nEndNote
));
440 pInfo
= &m_pDoc
->GetEndNoteInfo();
444 sClass
= OOO_STRING_SVTOOLS_HTML_sdfootnote_sym
;
445 sFootnoteName
= OOO_STRING_SVTOOLS_HTML_sdfootnote
+
446 OUString::number(static_cast<sal_Int32
>(m_nFootNote
));
447 pInfo
= &m_pDoc
->GetFootnoteInfo();
450 const SwCharFormat
*pSymCharFormat
= pInfo
->GetCharFormat( *m_pDoc
);
451 if( pSymCharFormat
&& 0 != m_aScriptTextStyles
.count( pSymCharFormat
->GetName() ) )
455 case CSS1_OUTMODE_WESTERN
:
456 sClass
+= "-western";
458 case CSS1_OUTMODE_CJK
:
461 case CSS1_OUTMODE_CTL
:
467 OStringBuffer
sOut("<"
468 + GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor
" "
469 OOO_STRING_SVTOOLS_HTML_O_class
"=\"");
470 Strm().WriteOString( sOut
);
472 HTMLOutFuncs::Out_String( Strm(), sClass
);
473 sOut
.append("\" " OOO_STRING_SVTOOLS_HTML_O_name
"=\"");
474 Strm().WriteOString( sOut
);
476 HTMLOutFuncs::Out_String( Strm(), sFootnoteName
);
477 sOut
.append(OOO_STRING_SVTOOLS_HTML_FTN_symbol
"\" "
478 OOO_STRING_SVTOOLS_HTML_O_href
"=\"#");
479 Strm().WriteOString( sOut
);
481 HTMLOutFuncs::Out_String( Strm(), sFootnoteName
);
482 sOut
.append(OOO_STRING_SVTOOLS_HTML_FTN_anchor
"\">");
483 Strm().WriteOString( sOut
);
486 HTMLOutFuncs::Out_String( Strm(), rNum
);
487 HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor
), false );
490 static int lcl_html_fillEndNoteInfo( const SwEndNoteInfo
& rInfo
,
495 sal_Int16 eFormat
= rInfo
.m_aFormat
.GetNumberingType();
496 if( (bEndNote
? SVX_NUM_ROMAN_LOWER
: SVX_NUM_ARABIC
) != eFormat
)
498 const char *pStr
= SwHTMLWriter::GetNumFormat( eFormat
);
501 pParts
[0] = OUString::createFromAscii( pStr
);
505 if( rInfo
.m_nFootnoteOffset
> 0 )
507 pParts
[1] = OUString::number(rInfo
.m_nFootnoteOffset
);
510 if( !rInfo
.GetPrefix().isEmpty() )
512 pParts
[2] = rInfo
.GetPrefix();
515 if( !rInfo
.GetSuffix().isEmpty() )
517 pParts
[3] = rInfo
.GetSuffix();
524 static void lcl_html_outFootEndNoteInfo( SwHTMLWriter
& rWrt
, OUString
const *pParts
,
525 int nParts
, const char *pName
)
527 OUStringBuffer aContent
;
528 for( int i
=0; i
<nParts
; ++i
)
530 OUString
aTmp( pParts
[i
] );
531 aTmp
= aTmp
.replaceAll( "\\", "\\\\" );
532 aTmp
= aTmp
.replaceAll( ";", "\\;" );
534 aContent
.append(";");
535 aContent
.append(aTmp
);
540 "<" + rWrt
.GetNamespace() + OOO_STRING_SVTOOLS_HTML_meta
" "
541 OOO_STRING_SVTOOLS_HTML_O_name
"=\"" + pName
+
542 "\" " OOO_STRING_SVTOOLS_HTML_O_content
"=\"";
543 rWrt
.Strm().WriteOString( sOut
);
544 HTMLOutFuncs::Out_String( rWrt
.Strm(), aContent
.makeStringAndClear() );
545 rWrt
.Strm().WriteOString( "\">" );
548 void SwHTMLWriter::OutFootEndNoteInfo()
550 // Number type (1 or i)
560 const SwFootnoteInfo
& rInfo
= m_pDoc
->GetFootnoteInfo();
562 int nParts
= lcl_html_fillEndNoteInfo( rInfo
, aParts
, false );
563 if( rInfo
.m_eNum
!= FTNNUM_DOC
)
565 aParts
[4] = rInfo
.m_eNum
== FTNNUM_CHAPTER
? std::u16string_view( u
"C" ) : std::u16string_view( u
"P" );
568 if( rInfo
.m_ePos
!= FTNPOS_PAGE
)
573 if( !rInfo
.m_aQuoVadis
.isEmpty() )
575 aParts
[6] = rInfo
.m_aQuoVadis
;
578 if( !rInfo
.m_aErgoSum
.isEmpty() )
580 aParts
[7] = rInfo
.m_aErgoSum
;
584 lcl_html_outFootEndNoteInfo( *this, aParts
, nParts
,
585 OOO_STRING_SVTOOLS_HTML_META_sdfootnote
);
589 const SwEndNoteInfo
& rInfo
= m_pDoc
->GetEndNoteInfo();
591 const int nParts
= lcl_html_fillEndNoteInfo( rInfo
, aParts
, true );
593 lcl_html_outFootEndNoteInfo( *this, aParts
, nParts
,
594 OOO_STRING_SVTOOLS_HTML_META_sdendnote
);
598 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */