android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / html / htmlftn.cxx
blob10b909d1df4168f0353fc8ff0c5ae3669b247556
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <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>
30 #include <fmtftn.hxx>
31 #include <txtftn.hxx>
32 #include <ftninfo.hxx>
33 #include <doc.hxx>
34 #include <ndtxt.hxx>
35 #include <charfmt.hxx>
37 #include "swhtml.hxx"
38 #include "wrthtml.hxx"
40 static sal_Int32 lcl_html_getNextPart( OUString& rPart, std::u16string_view aContent,
41 sal_Int32 nPos )
43 rPart.clear();
44 sal_Int32 nLen = aContent.size();
45 if( nPos >= nLen )
47 nPos = -1;
49 else
51 bool bQuoted = false, bDone = false;
52 for( ; nPos < nLen && !bDone; nPos++ )
54 sal_Unicode c = aContent[nPos];
55 switch( c )
57 case '\\':
58 if( bQuoted )
59 rPart += OUStringChar( c );
60 bQuoted = !bQuoted;
61 break;
63 case ';':
64 if( bQuoted )
65 rPart += OUStringChar( c );
66 else
67 bDone = true;
68 bQuoted = false;
69 break;
71 default:
72 rPart += OUStringChar( c );
73 bQuoted = false;
74 break;
79 return nPos;
82 static sal_Int32 lcl_html_getEndNoteInfo( SwEndNoteInfo& rInfo,
83 std::u16string_view aContent,
84 bool bEndNote )
86 sal_Int32 nStrPos = 0;
87 for( int nPart = 0; nPart < 4; ++nPart )
89 OUString aPart;
90 if( -1 != nStrPos )
91 nStrPos = lcl_html_getNextPart( aPart, aContent, nStrPos );
93 switch( nPart )
95 case 0:
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() ));
100 break;
102 case 1:
103 rInfo.m_nFootnoteOffset = aPart.isEmpty() ? 0 : o3tl::narrowing<sal_uInt16>(aPart.toInt32());
104 break;
106 case 2:
107 rInfo.SetPrefix( aPart );
108 break;
110 case 3:
111 rInfo.SetSuffix( aPart );
112 break;
116 return nStrPos;
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 )
134 OUString aPart;
135 if( -1 != nStrPos )
136 nStrPos = lcl_html_getNextPart( aPart, aContent, nStrPos );
138 switch( nPart )
140 case 4:
141 aInfo.m_eNum = FTNNUM_DOC;
142 if( !aPart.isEmpty() )
144 switch( aPart[0] )
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;
151 break;
153 case 5:
154 aInfo.m_ePos = FTNPOS_PAGE;
155 if( !aPart.isEmpty() )
157 switch( aPart[0] )
159 case 'C': aInfo.m_ePos = FTNPOS_CHAPTER; break;
160 case 'P': aInfo.m_ePos = FTNPOS_PAGE; break;
163 break;
165 case 6:
166 aInfo.m_aQuoVadis = aPart;
167 break;
169 case 7:
170 aInfo.m_aErgoSum = aPart;
171 break;
175 m_xDoc->SetFootnoteInfo( aInfo );
178 void SwHTMLParser::InsertFootEndNote( const OUString& rName, bool bEndNote,
179 bool bFixed )
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 )
196 return;
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.
207 if (pTextFootnote)
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();
240 break;
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");
258 break;
259 case SwLineBreakClear::LEFT:
260 aWriter.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, "left");
261 break;
262 case SwLineBreakClear::RIGHT:
263 aWriter.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, "right");
264 break;
265 case SwLineBreakClear::ALL:
266 aWriter.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, "all");
267 break;
269 aWriter.end();
270 return rWrt;
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();
277 if( !pTextFootnote )
278 return rWrt;
280 OUString sFootnoteName, sClass;
281 size_t nPos;
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) );
290 else
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 );
301 OStringBuffer sOut;
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 );
305 sOut.setLength(0);
306 HTMLOutFuncs::Out_String( rWrt.Strm(), sClass );
307 sOut.append("\" " OOO_STRING_SVTOOLS_HTML_O_name "=\"");
308 rWrt.Strm().WriteOString( sOut );
309 sOut.setLength(0);
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 );
314 sOut.setLength(0);
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);
319 sOut.append(">");
320 rWrt.Strm().WriteOString( sOut );
321 sOut.setLength(0);
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 );
328 return rWrt;
331 void SwHTMLWriter::OutFootEndNotes()
333 OSL_ENSURE( m_xFootEndNotes,
334 "SwHTMLWriter::OutFootEndNotes(): unnecessary call" );
335 if( !m_xFootEndNotes )
336 return;
338 #if OSL_DEBUG_LEVEL > 0
339 sal_uInt16 nFootnote = m_nFootNote, nEn = m_nEndNote;
340 #endif
341 m_nFootNote = 0;
342 m_nEndNote = 0;
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));
353 else
355 sFootnoteName = OOO_STRING_SVTOOLS_HTML_sdfootnote + OUString::number(static_cast<sal_Int32>(++m_nFootNote));
358 if( m_bLFPossible )
359 OutNewLine();
360 OString sOut =
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" );
374 if( pSttNdIdx )
376 HTMLSaveData aSaveData( *this, pSttNdIdx->GetIndex()+1,
377 pSttNdIdx->GetNode().EndOfSectionIndex(), false );
378 Out_SwDoc( m_pCurrentPam.get() );
381 DecIndentLevel(); // indent content of <DIV>
382 if( m_bLFPossible )
383 OutNewLine();
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() )
392 m_nEndNote++;
393 else
394 m_nFootNote++;
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" );
405 #endif
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();
418 OUString sRet;
419 if( pInfo )
420 sRet = pInfo->GetPrefix();
421 sRet += rFormatFootnote.GetViewNumStr(*m_pDoc, nullptr);
422 if( pInfo )
423 sRet += pInfo->GetSuffix();
425 return sRet;
428 void SwHTMLWriter::OutFootEndNoteSym( const SwFormatFootnote& rFormatFootnote,
429 const OUString& rNum,
430 sal_uInt16 nScript )
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();
442 else
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() ) )
453 switch( nScript )
455 case CSS1_OUTMODE_WESTERN:
456 sClass += "-western";
457 break;
458 case CSS1_OUTMODE_CJK:
459 sClass += "-cjk";
460 break;
461 case CSS1_OUTMODE_CTL:
462 sClass += "-ctl";
463 break;
467 OStringBuffer sOut("<"
468 + GetNamespace() + OOO_STRING_SVTOOLS_HTML_anchor " "
469 OOO_STRING_SVTOOLS_HTML_O_class "=\"");
470 Strm().WriteOString( sOut );
471 sOut.setLength(0);
472 HTMLOutFuncs::Out_String( Strm(), sClass );
473 sOut.append("\" " OOO_STRING_SVTOOLS_HTML_O_name "=\"");
474 Strm().WriteOString( sOut );
475 sOut.setLength(0);
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 );
480 sOut.setLength(0);
481 HTMLOutFuncs::Out_String( Strm(), sFootnoteName );
482 sOut.append(OOO_STRING_SVTOOLS_HTML_FTN_anchor "\">");
483 Strm().WriteOString( sOut );
484 sOut.setLength(0);
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,
491 OUString *pParts,
492 bool bEndNote )
494 int nParts = 0;
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 );
499 if( pStr )
501 pParts[0] = OUString::createFromAscii( pStr );
502 nParts = 1;
505 if( rInfo.m_nFootnoteOffset > 0 )
507 pParts[1] = OUString::number(rInfo.m_nFootnoteOffset);
508 nParts = 2;
510 if( !rInfo.GetPrefix().isEmpty() )
512 pParts[2] = rInfo.GetPrefix();
513 nParts = 3;
515 if( !rInfo.GetSuffix().isEmpty() )
517 pParts[3] = rInfo.GetSuffix();
518 nParts = 4;
521 return nParts;
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( ";", "\\;" );
533 if( i > 0 )
534 aContent.append(";");
535 aContent.append(aTmp);
538 rWrt.OutNewLine();
539 OString sOut =
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)
551 // Offset (0)
552 // Before it
553 // Behind it
554 // Doc/Page/Chap (D)
555 // Position (S)
556 // Next page
557 // Beginning
560 const SwFootnoteInfo& rInfo = m_pDoc->GetFootnoteInfo();
561 OUString aParts[8];
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" );
566 nParts = 5;
568 if( rInfo.m_ePos != FTNPOS_PAGE)
570 aParts[5] = "C";
571 nParts = 6;
573 if( !rInfo.m_aQuoVadis.isEmpty() )
575 aParts[6] = rInfo.m_aQuoVadis;
576 nParts = 7;
578 if( !rInfo.m_aErgoSum.isEmpty() )
580 aParts[7] = rInfo.m_aErgoSum;
581 nParts = 8;
583 if( nParts > 0 )
584 lcl_html_outFootEndNoteInfo( *this, aParts, nParts,
585 OOO_STRING_SVTOOLS_HTML_META_sdfootnote );
589 const SwEndNoteInfo& rInfo = m_pDoc->GetEndNoteInfo();
590 OUString aParts[4];
591 const int nParts = lcl_html_fillEndNoteInfo( rInfo, aParts, true );
592 if( nParts > 0 )
593 lcl_html_outFootEndNoteInfo( *this, aParts, nParts,
594 OOO_STRING_SVTOOLS_HTML_META_sdendnote );
598 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */