android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / html / htmlsect.cxx
blob26a1ec8d0e1976d41dc2b382049d74aa7cb78723
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 <com/sun/star/text/HoriOrientation.hpp>
21 #include <com/sun/star/text/VertOrientation.hpp>
22 #include <rtl/uri.hxx>
24 #include <svl/urihelper.hxx>
25 #include <vcl/svapp.hxx>
26 #include <editeng/adjustitem.hxx>
27 #include <editeng/ulspitem.hxx>
28 #include <editeng/formatbreakitem.hxx>
29 #include <svtools/htmltokn.h>
30 #include <svtools/htmlkywd.hxx>
31 #include <sfx2/linkmgr.hxx>
32 #include <osl/diagnose.h>
34 #include <hintids.hxx>
35 #include <fmthdft.hxx>
36 #include <fmtcntnt.hxx>
37 #include <fmtclds.hxx>
38 #include <fmtanchr.hxx>
39 #include <fmtpdsc.hxx>
40 #include <frmatr.hxx>
41 #include <doc.hxx>
42 #include <pam.hxx>
43 #include <ndtxt.hxx>
44 #include <shellio.hxx>
45 #include <section.hxx>
46 #include <poolfmt.hxx>
47 #include <pagedesc.hxx>
48 #include <swtable.hxx>
49 #include "swcss1.hxx"
50 #include "swhtml.hxx"
53 using namespace ::com::sun::star;
55 void SwHTMLParser::NewDivision( HtmlTokenId nToken )
57 OUString aId, aHRef;
58 OUString aStyle, aLang, aDir;
59 OUString aClass;
60 SvxAdjust eAdjust = HtmlTokenId::CENTER_ON==nToken ? SvxAdjust::Center
61 : SvxAdjust::End;
63 bool bHeader=false, bFooter=false;
64 const HTMLOptions& rHTMLOptions = GetOptions();
65 for (size_t i = rHTMLOptions.size(); i; )
67 const HTMLOption& rOption = rHTMLOptions[--i];
68 switch( rOption.GetToken() )
70 case HtmlOptionId::ID:
71 aId = rOption.GetString();
72 break;
73 case HtmlOptionId::ALIGN:
74 if( HtmlTokenId::DIVISION_ON==nToken )
75 eAdjust = rOption.GetEnum( aHTMLPAlignTable, eAdjust );
76 break;
77 case HtmlOptionId::STYLE:
78 aStyle = rOption.GetString();
79 break;
80 case HtmlOptionId::CLASS:
81 aClass = rOption.GetString();
82 break;
83 case HtmlOptionId::LANG:
84 aLang = rOption.GetString();
85 break;
86 case HtmlOptionId::DIR:
87 aDir = rOption.GetString();
88 break;
89 case HtmlOptionId::HREF:
90 aHRef = rOption.GetString();
91 break;
92 case HtmlOptionId::TITLE:
94 const OUString& rType = rOption.GetString();
95 if( rType.equalsIgnoreAsciiCase("header") )
96 bHeader = true;
97 else if( rType.equalsIgnoreAsciiCase("footer") )
98 bFooter = true;
100 break;
101 default: break;
105 bool bAppended = false;
106 if( m_pPam->GetPoint()->GetContentIndex() )
108 AppendTextNode( bHeader||bFooter||!aId.isEmpty()|| !aHRef.isEmpty() ? AM_NORMAL
109 : AM_NOSPACE );
110 bAppended = true;
113 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken));
115 bool bStyleParsed = false, bPositioned = false;
116 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
117 SvxCSS1PropertyInfo aPropInfo;
118 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
120 bStyleParsed = ParseStyleOptions( aStyle, aId, aClass,
121 aItemSet, aPropInfo, &aLang, &aDir );
122 if( bStyleParsed )
124 if ( aPropInfo.m_nColumnCount >= 2 )
126 xCntxt.reset();
127 NewMultiCol( aPropInfo.m_nColumnCount );
128 return;
130 bPositioned = HtmlTokenId::DIVISION_ON == nToken && !aClass.isEmpty() &&
131 CreateContainer(aClass, aItemSet, aPropInfo,
132 xCntxt.get());
133 if( !bPositioned )
135 if (aPropInfo.m_bVisible && m_aContexts.size())
137 const std::unique_ptr<HTMLAttrContext>& pParent
138 = m_aContexts[m_aContexts.size() - 1];
139 if (!pParent->IsVisible())
141 // If the parent context is hidden, we are not visible, either.
142 aPropInfo.m_bVisible = false;
145 bPositioned = DoPositioning(aItemSet, aPropInfo, xCntxt.get());
150 if (!bPositioned && (bHeader || bFooter) && IsNewDoc() && !m_bReadingHeaderOrFooter)
152 m_bReadingHeaderOrFooter = true;
153 xCntxt->SetHeaderOrFooter(true);
155 SwPageDesc *pPageDesc = m_pCSS1Parser->GetMasterPageDesc();
156 SwFrameFormat& rPageFormat = pPageDesc->GetMaster();
158 SwFrameFormat *pHdFtFormat;
159 bool bNew = false;
160 HtmlContextFlags nFlags = HtmlContextFlags::MultiColMask;
161 if( bHeader )
163 pHdFtFormat = const_cast<SwFrameFormat*>(rPageFormat.GetHeader().GetHeaderFormat());
164 if( !pHdFtFormat )
166 // still no header, then create one
167 rPageFormat.SetFormatAttr( SwFormatHeader( true ));
168 pHdFtFormat = const_cast<SwFrameFormat*>(rPageFormat.GetHeader().GetHeaderFormat());
169 bNew = true;
171 nFlags |= HtmlContextFlags::HeaderDist;
173 else
175 pHdFtFormat = const_cast<SwFrameFormat*>(rPageFormat.GetFooter().GetFooterFormat());
176 if( !pHdFtFormat )
178 // still no footer, then create one
179 rPageFormat.SetFormatAttr( SwFormatFooter( true ));
180 pHdFtFormat = const_cast<SwFrameFormat*>(rPageFormat.GetFooter().GetFooterFormat());
181 bNew = true;
183 nFlags |= HtmlContextFlags::FooterDist;
186 const SwFormatContent& rFlyContent = pHdFtFormat->GetContent();
187 const SwNodeIndex& rContentStIdx = *rFlyContent.GetContentIdx();
189 if( !bNew )
191 // Our own html export only exports one "header" at most (and one "footer")
193 // Create a new node at the beginning of the section if a duplicate arises
194 // and hide the original header/footers content by putting it into a hidden
195 // document-level section
196 SwNodeIndex aSttIdx( rContentStIdx, 1 );
197 m_xDoc->GetNodes().MakeTextNode( aSttIdx.GetNode(),
198 m_pCSS1Parser->GetTextCollFromPool(RES_POOLCOLL_TEXT));
200 // delete the current content of the section
201 SwPaM aDelPam( aSttIdx );
202 aDelPam.SetMark();
204 const SwStartNode *pStNd =
205 static_cast<const SwStartNode *>( &rContentStIdx.GetNode() );
206 aDelPam.GetPoint()->Assign( pStNd->EndOfSectionIndex() );
208 SwSectionData aSection(SectionType::Content, m_xDoc->GetUniqueSectionName());
209 if (SwSection* pOldContent = m_xDoc->InsertSwSection(aDelPam, aSection, nullptr, nullptr, false))
210 pOldContent->SetHidden(true);
212 // update page style
213 for( size_t i=0; i < m_xDoc->GetPageDescCnt(); i++ )
215 if( RES_POOLPAGE_HTML == m_xDoc->GetPageDesc(i).GetPoolFormatId() )
217 m_xDoc->ChgPageDesc( i, *pPageDesc );
218 break;
223 SwPosition aNewPos( rContentStIdx, SwNodeOffset(1) );
224 SaveDocContext(xCntxt.get(), nFlags, &aNewPos);
226 else if( !bPositioned && aId.getLength() > 9 &&
227 (aId[0] == 's' || aId[0] == 'S' ) &&
228 (aId[1] == 'd' || aId[1] == 'D' ) )
230 bool bEndNote = false, bFootNote = false;
231 if( aId.startsWithIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdendnote ) )
232 bEndNote = true;
233 else if( aId.startsWithIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdfootnote ) )
234 bFootNote = true;
235 if( bFootNote || bEndNote )
237 SwNodeIndex *pStartNdIdx = GetFootEndNoteSection( aId );
238 if( pStartNdIdx )
240 SwContentNode *pCNd =
241 m_xDoc->GetNodes()[pStartNdIdx->GetIndex()+1]->GetContentNode();
242 SwNodeIndex aTmpSwNodeIndex(*pCNd);
243 SwPosition aNewPos( aTmpSwNodeIndex, pCNd, 0 );
244 SaveDocContext(xCntxt.get(), HtmlContextFlags::MultiColMask, &aNewPos);
245 aId.clear();
246 aPropInfo.m_aId.clear();
251 // We only insert sections into frames if the section is linked.
252 if( (!aId.isEmpty() && !bPositioned) || !aHRef.isEmpty() )
254 // Insert section (has to be done before setting of attributes,
255 // because the section is inserted before the PaM position.
257 // If we are in the first node of a section, we insert the section
258 // before the current section and not in the current section.
259 // Therefore we have to add a node and delete it again!
260 if( !bAppended )
262 SwNodeIndex aPrvNdIdx( m_pPam->GetPoint()->GetNode(), -1 );
263 if (aPrvNdIdx.GetNode().IsSectionNode())
265 AppendTextNode();
266 bAppended = true;
269 std::unique_ptr<std::deque<std::unique_ptr<HTMLAttr>>> pPostIts(bAppended ? nullptr : new std::deque<std::unique_ptr<HTMLAttr>>);
270 SetAttr( true, true, pPostIts.get() );
272 // make name of section unique
273 const OUString aName( m_xDoc->GetUniqueSectionName( !aId.isEmpty() ? &aId : nullptr ) );
275 if( !aHRef.isEmpty() )
277 sal_Unicode cDelim = 255U;
278 sal_Int32 nPos = aHRef.lastIndexOf( cDelim );
279 sal_Int32 nPos2 = -1;
280 if( nPos != -1 )
282 nPos2 = aHRef.lastIndexOf( cDelim, nPos );
283 if( nPos2 != -1 )
284 std::swap( nPos, nPos2 );
286 OUString aURL;
287 if( nPos == -1 )
289 aURL = URIHelper::SmartRel2Abs(INetURLObject( m_sBaseURL ), aHRef, Link<OUString *, bool>(), false);
291 else
293 aURL = URIHelper::SmartRel2Abs(INetURLObject( m_sBaseURL ), aHRef.copy( 0, nPos ), Link<OUString *, bool>(), false )
294 + OUStringChar(sfx2::cTokenSeparator);
295 if( nPos2 == -1 )
297 aURL += aHRef.subView( nPos+1 );
299 else
301 aURL += aHRef.subView( nPos+1, nPos2 - (nPos+1) )
302 + OUStringChar(sfx2::cTokenSeparator)
303 + rtl::Uri::decode( aHRef.copy( nPos2+1 ),
304 rtl_UriDecodeWithCharset,
305 RTL_TEXTENCODING_ISO_8859_1 );
308 aHRef = aURL;
311 SwSectionData aSection( (!aHRef.isEmpty()) ? SectionType::FileLink
312 : SectionType::Content, aName );
313 if( !aHRef.isEmpty() )
315 aSection.SetLinkFileName( aHRef );
316 aSection.SetProtectFlag(true);
319 SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameItemSet( m_xDoc->GetAttrPool() );
320 if( !IsNewDoc() )
321 Reader::ResetFrameFormatAttrs(aFrameItemSet );
323 if( const SvxBrushItem* pItem = aItemSet.GetItemIfSet( RES_BACKGROUND, false ) )
325 aFrameItemSet.Put( *pItem );
326 aItemSet.ClearItem( RES_BACKGROUND );
328 if( const SvxFrameDirectionItem* pItem = aItemSet.GetItemIfSet( RES_FRAMEDIR, false ) )
330 aFrameItemSet.Put( *pItem );
331 aItemSet.ClearItem( RES_FRAMEDIR );
334 m_xDoc->InsertSwSection( *m_pPam, aSection, nullptr, &aFrameItemSet, false );
336 // maybe jump to section
337 if( JumpToMarks::Region == m_eJumpTo && aName == m_sJmpMark )
339 m_bChkJumpMark = true;
340 m_eJumpTo = JumpToMarks::NONE;
343 SwTextNode* pOldTextNd =
344 bAppended ? nullptr : m_pPam->GetPoint()->GetNode().GetTextNode();
346 m_pPam->Move( fnMoveBackward );
348 // move PageDesc and SwFormatBreak attribute from current node into
349 // (first) node of the section
350 if( pOldTextNd )
351 MovePageDescAttrs( pOldTextNd, m_pPam->GetPoint()->GetNodeIndex(),
352 true );
354 if( pPostIts )
356 // move still existing PostIts in the first paragraph of the table
357 InsertAttrs( std::move(*pPostIts) );
358 pPostIts.reset();
361 xCntxt->SetSpansSection( true );
363 // don't insert Bookmarks with same name as sections
364 if( !aPropInfo.m_aId.isEmpty() && aPropInfo.m_aId==aName )
365 aPropInfo.m_aId.clear();
367 else
369 xCntxt->SetAppendMode( AM_NOSPACE );
372 if( SvxAdjust::End != eAdjust )
374 InsertAttr(&m_xAttrTab->pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST), xCntxt.get());
377 // parse style
378 if( bStyleParsed )
379 InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true );
381 xCntxt->SetVisible(aPropInfo.m_bVisible);
382 PushContext(xCntxt);
385 void SwHTMLParser::EndDivision()
387 // search for the stack entry of the token (because we still have the div stack
388 // we don't make a difference between DIV and CENTER)
389 std::unique_ptr<HTMLAttrContext> xCntxt;
390 auto nPos = m_aContexts.size();
391 while (!xCntxt && nPos>m_nContextStMin)
393 switch( m_aContexts[--nPos]->GetToken() )
395 case HtmlTokenId::CENTER_ON:
396 case HtmlTokenId::DIVISION_ON:
397 xCntxt = std::move(m_aContexts[nPos]);
398 m_aContexts.erase( m_aContexts.begin() + nPos );
399 break;
400 default: break;
404 if (xCntxt)
406 // close attribute
407 EndContext(xCntxt.get());
408 SetAttr(); // set paragraph attributes really fast because of JavaScript
409 if (xCntxt->IsHeaderOrFooter())
410 m_bReadingHeaderOrFooter = false;
414 void SwHTMLParser::FixHeaderFooterDistance( bool bHeader,
415 const SwPosition *pOldPos )
417 SwPageDesc *pPageDesc = m_pCSS1Parser->GetMasterPageDesc();
418 SwFrameFormat& rPageFormat = pPageDesc->GetMaster();
420 SwFrameFormat *pHdFtFormat =
421 bHeader ? const_cast<SwFrameFormat*>(rPageFormat.GetHeader().GetHeaderFormat())
422 : const_cast<SwFrameFormat*>(rPageFormat.GetFooter().GetFooterFormat());
423 OSL_ENSURE( pHdFtFormat, "No header or footer" );
425 const SwFormatContent& rFlyContent = pHdFtFormat->GetContent();
426 const SwNodeIndex& rContentStIdx = *rFlyContent.GetContentIdx();
428 SwNodeOffset nPrvNxtIdx;
429 if( bHeader )
431 nPrvNxtIdx = rContentStIdx.GetNode().EndOfSectionIndex()-1;
433 else
435 nPrvNxtIdx = pOldPos->GetNodeIndex() - 1;
438 sal_uInt16 nSpace = 0;
439 SwTextNode *pTextNode = m_xDoc->GetNodes()[nPrvNxtIdx]->GetTextNode();
440 if( pTextNode )
442 const SvxULSpaceItem& rULSpace =
443 pTextNode->SwContentNode::GetAttr( RES_UL_SPACE );
445 // The bottom paragraph padding becomes the padding
446 // to header or footer
447 nSpace = rULSpace.GetLower();
449 // and afterwards set to a valid value
450 const SvxULSpaceItem& rCollULSpace =
451 pTextNode->GetAnyFormatColl().GetULSpace();
452 if( rCollULSpace.GetUpper() == rULSpace.GetUpper() )
453 pTextNode->ResetAttr( RES_UL_SPACE );
454 else
455 pTextNode->SetAttr(
456 SvxULSpaceItem( rULSpace.GetUpper(),
457 rCollULSpace.GetLower(), RES_UL_SPACE ) );
460 if( bHeader )
462 nPrvNxtIdx = pOldPos->GetNodeIndex();
464 else
466 nPrvNxtIdx = rContentStIdx.GetIndex() + 1;
469 pTextNode = m_xDoc->GetNodes()[nPrvNxtIdx]
470 ->GetTextNode();
471 if( pTextNode )
473 const SvxULSpaceItem& rULSpace =
474 pTextNode->SwContentNode::GetAttr( RES_UL_SPACE );
476 // The top paragraph padding becomes the padding
477 // to headline or footer if it is greater than the
478 // bottom padding of the paragraph beforehand
479 if( rULSpace.GetUpper() > nSpace )
480 nSpace = rULSpace.GetUpper();
482 // and afterwards set to a valid value
483 const SvxULSpaceItem& rCollULSpace =
484 pTextNode->GetAnyFormatColl().GetULSpace();
485 if( rCollULSpace.GetLower() == rULSpace.GetLower() )
486 pTextNode->ResetAttr( RES_UL_SPACE );
487 else
488 pTextNode->SetAttr(
489 SvxULSpaceItem( rCollULSpace.GetUpper(),
490 rULSpace.GetLower(), RES_UL_SPACE ) );
493 SvxULSpaceItem aULSpace( RES_UL_SPACE );
494 if( bHeader )
495 aULSpace.SetLower( nSpace );
496 else
497 aULSpace.SetUpper( nSpace );
499 pHdFtFormat->SetFormatAttr( aULSpace );
502 bool SwHTMLParser::EndSection( bool bLFStripped )
504 SwEndNode *pEndNd = m_xDoc->GetNodes()[m_pPam->GetPoint()->GetNodeIndex()+1]
505 ->GetEndNode();
506 if( pEndNd && pEndNd->StartOfSectionNode()->IsSectionNode() )
508 // close the section
509 if( !bLFStripped )
510 StripTrailingPara();
511 m_pPam->Move( fnMoveForward );
512 return true;
515 OSL_ENSURE( false, "Wrong PaM position at end of section" );
517 return false;
520 bool SwHTMLParser::EndSections( bool bLFStripped )
522 bool bSectionClosed = false;
523 auto nPos = m_aContexts.size();
524 while( nPos>m_nContextStMin )
526 HTMLAttrContext *pCntxt = m_aContexts[--nPos].get();
527 if( pCntxt->GetSpansSection() && EndSection( bLFStripped ) )
529 bSectionClosed = true;
530 pCntxt->SetSpansSection( false );
531 bLFStripped = false;
535 return bSectionClosed;
538 void SwHTMLParser::NewMultiCol( sal_uInt16 columnsFromCss )
540 OUString aId;
541 OUString aStyle, aClass, aLang, aDir;
542 tools::Long nWidth = 100;
543 sal_uInt16 nCols = columnsFromCss, nGutter = 10;
544 bool bPercentWidth = true;
546 const HTMLOptions& rHTMLOptions = GetOptions();
547 for (size_t i = rHTMLOptions.size(); i; )
549 const HTMLOption& rOption = rHTMLOptions[--i];
550 switch( rOption.GetToken() )
552 case HtmlOptionId::ID:
553 aId = rOption.GetString();
554 break;
555 case HtmlOptionId::STYLE:
556 aStyle = rOption.GetString();
557 break;
558 case HtmlOptionId::CLASS:
559 aClass = rOption.GetString();
560 break;
561 case HtmlOptionId::LANG:
562 aLang = rOption.GetString();
563 break;
564 case HtmlOptionId::DIR:
565 aDir = rOption.GetString();
566 break;
567 case HtmlOptionId::COLS:
568 nCols = o3tl::narrowing<sal_uInt16>(rOption.GetNumber());
569 break;
570 case HtmlOptionId::WIDTH:
571 nWidth = rOption.GetNumber();
572 bPercentWidth = (rOption.GetString().indexOf('%') != -1);
573 if( bPercentWidth && nWidth>100 )
574 nWidth = 100;
575 break;
576 case HtmlOptionId::GUTTER:
577 nGutter = o3tl::narrowing<sal_uInt16>(rOption.GetNumber());
578 break;
579 default: break;
583 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(HtmlTokenId::MULTICOL_ON));
585 //.is the multicol element contained in a container? That may be the
586 // case for 5.0 documents.
587 bool bInCntnr = false;
588 auto i = m_aContexts.size();
589 while( !bInCntnr && i > m_nContextStMin )
590 bInCntnr = nullptr != m_aContexts[--i]->GetFrameItemSet();
592 // Parse style sheets, but don't position anything by now.
593 bool bStyleParsed = false;
594 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
595 SvxCSS1PropertyInfo aPropInfo;
596 if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
597 bStyleParsed = ParseStyleOptions( aStyle, aId, aClass,
598 aItemSet, aPropInfo, &aLang, &aDir );
600 // Calculate width.
601 sal_uInt8 nPercentWidth = bPercentWidth ? static_cast<sal_uInt8>(nWidth) : 0;
602 SwTwips nTwipWidth = 0;
603 if( !bPercentWidth && nWidth )
605 nTwipWidth = o3tl::convert(nWidth, o3tl::Length::px, o3tl::Length::twip);
608 if( !nPercentWidth && nTwipWidth < MINFLY )
609 nTwipWidth = MINFLY;
611 // Do positioning.
612 bool bPositioned = false;
613 if( bInCntnr || SwCSS1Parser::MayBePositioned( aPropInfo, true ) )
615 SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameItemSet( m_xDoc->GetAttrPool() );
616 if( !IsNewDoc() )
617 Reader::ResetFrameFormatAttrs(aFrameItemSet );
619 SetAnchorAndAdjustment( text::VertOrientation::NONE, text::HoriOrientation::NONE, aPropInfo,
620 aFrameItemSet );
622 // The width is either the WIDTH attribute's value or contained
623 // in some style option.
624 SetVarSize( aPropInfo, aFrameItemSet, nTwipWidth, nPercentWidth );
626 SetSpace( Size(0,0), aItemSet, aPropInfo, aFrameItemSet );
628 // Set some other frame attributes. If the background is set, its
629 // it will be cleared here. That for, it won't be set at the section,
630 // too.
631 SetFrameFormatAttrs( aItemSet,
632 HtmlFrameFormatFlags::Box|HtmlFrameFormatFlags::Background|HtmlFrameFormatFlags::Padding|HtmlFrameFormatFlags::Direction,
633 aFrameItemSet );
635 // Insert fly frame. If the are columns, the fly frame's name is not
636 // the sections name but a generated one.
637 OUString aFlyName;
638 if( nCols < 2 )
640 aFlyName = aId;
641 aPropInfo.m_aId.clear();
644 InsertFlyFrame(aFrameItemSet, xCntxt.get(), aFlyName);
646 xCntxt->SetPopStack( true );
647 bPositioned = true;
650 bool bAppended = false;
651 if( !bPositioned )
653 if( m_pPam->GetPoint()->GetContentIndex() )
655 AppendTextNode( AM_SPACE );
656 bAppended = true;
658 else
660 AddParSpace();
664 // If there are less than 2 columns, no section is inserted.
665 if( nCols >= 2 )
667 if( !bAppended )
669 // If the pam is at the start of a section, an additional text
670 // node must be inserted. Otherwise, the new section will be
671 // inserted in front of the old one.
672 SwNodeIndex aPrvNdIdx( m_pPam->GetPoint()->GetNode(), -1 );
673 if (aPrvNdIdx.GetNode().IsSectionNode())
675 AppendTextNode();
676 bAppended = true;
679 std::unique_ptr<std::deque<std::unique_ptr<HTMLAttr>>> pPostIts(bAppended ? nullptr : new std::deque<std::unique_ptr<HTMLAttr>>);
680 SetAttr( true, true, pPostIts.get() );
682 // Make section name unique.
683 OUString aName( m_xDoc->GetUniqueSectionName( !aId.isEmpty() ? &aId : nullptr ) );
684 SwSectionData aSection( SectionType::Content, aName );
686 SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameItemSet( m_xDoc->GetAttrPool() );
687 if( !IsNewDoc() )
688 Reader::ResetFrameFormatAttrs(aFrameItemSet );
690 if( nGutter )
692 nGutter = o3tl::convert(nGutter, o3tl::Length::px, o3tl::Length::twip);
695 SwFormatCol aFormatCol;
697 aFormatCol.Init( nCols, nGutter, USHRT_MAX );
698 aFrameItemSet.Put( aFormatCol );
700 if( const SvxBrushItem* pItem = aItemSet.GetItemIfSet( RES_BACKGROUND, false) )
702 aFrameItemSet.Put( *pItem );
703 aItemSet.ClearItem( RES_BACKGROUND );
705 if( const SvxFrameDirectionItem* pItem = aItemSet.GetItemIfSet( RES_FRAMEDIR, false ) )
707 aFrameItemSet.Put( *pItem );
708 aItemSet.ClearItem( RES_FRAMEDIR );
710 m_xDoc->InsertSwSection( *m_pPam, aSection, nullptr, &aFrameItemSet, false );
712 // Jump to section, if this is requested.
713 if( JumpToMarks::Region == m_eJumpTo && aName == m_sJmpMark )
715 m_bChkJumpMark = true;
716 m_eJumpTo = JumpToMarks::NONE;
719 SwTextNode* pOldTextNd =
720 bAppended ? nullptr : m_pPam->GetPoint()->GetNode().GetTextNode();
722 m_pPam->Move( fnMoveBackward );
724 // Move PageDesc and SwFormatBreak attributes of the current node
725 // to the section's first node.
726 if( pOldTextNd )
727 MovePageDescAttrs( pOldTextNd, m_pPam->GetPoint()->GetNodeIndex(),
728 true );
730 if( pPostIts )
732 // Move pending PostIts into the section.
733 InsertAttrs( std::move(*pPostIts) );
734 pPostIts.reset();
737 xCntxt->SetSpansSection( true );
739 // Insert a bookmark if its name differs from the section's name only.
740 if( !aPropInfo.m_aId.isEmpty() && aPropInfo.m_aId==aName )
741 aPropInfo.m_aId.clear();
744 // Additional attributes must be set as hard ones.
745 if( bStyleParsed )
746 InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true );
748 PushContext(xCntxt);
751 void SwHTMLParser::InsertFlyFrame( const SfxItemSet& rItemSet,
752 HTMLAttrContext *pCntxt,
753 const OUString& rName )
755 RndStdIds eAnchorId =
756 rItemSet.Get( RES_ANCHOR ).GetAnchorId();
758 // create frame
759 SwFlyFrameFormat* pFlyFormat = m_xDoc->MakeFlySection( eAnchorId, m_pPam->GetPoint(),
760 &rItemSet );
761 if( !rName.isEmpty() )
762 pFlyFormat->SetFormatName( rName );
764 RegisterFlyFrame( pFlyFormat );
766 const SwFormatContent& rFlyContent = pFlyFormat->GetContent();
767 const SwNodeIndex& rFlyCntIdx = *rFlyContent.GetContentIdx();
769 SwPosition aNewPos( rFlyCntIdx, SwNodeOffset(1) );
770 const HtmlContextFlags nFlags = HtmlContextFlags::ProtectStack|HtmlContextFlags::StripPara;
771 SaveDocContext( pCntxt, nFlags, &aNewPos );
774 void SwHTMLParser::MovePageDescAttrs( SwNode *pSrcNd,
775 SwNodeOffset nDestIdx,
776 bool bFormatBreak )
778 SwContentNode* pDestContentNd =
779 m_xDoc->GetNodes()[nDestIdx]->GetContentNode();
781 OSL_ENSURE( pDestContentNd, "Why is the target not a Content-Node?" );
783 if( pSrcNd->IsContentNode() )
785 SwContentNode* pSrcContentNd = pSrcNd->GetContentNode();
787 const SwFormatPageDesc* pFormatPageDesc =
788 pSrcContentNd->GetSwAttrSet().GetItemIfSet( RES_PAGEDESC, false );
789 if( pFormatPageDesc && pFormatPageDesc->GetPageDesc() )
791 pDestContentNd->SetAttr( *pFormatPageDesc );
792 pSrcContentNd->ResetAttr( RES_PAGEDESC );
794 if( const SvxFormatBreakItem* pItem = pSrcContentNd->GetSwAttrSet()
795 .GetItemIfSet( RES_BREAK, false ) )
797 switch( pItem->GetBreak() )
799 case SvxBreak::PageBefore:
800 case SvxBreak::PageAfter:
801 case SvxBreak::PageBoth:
802 if( bFormatBreak )
803 pDestContentNd->SetAttr( *pItem );
804 pSrcContentNd->ResetAttr( RES_BREAK );
805 break;
806 default:
807 break;
811 else if( pSrcNd->IsTableNode() )
813 SwFrameFormat *pFrameFormat = pSrcNd->GetTableNode()->GetTable().GetFrameFormat();
815 if( const SwFormatPageDesc* pItem = pFrameFormat->GetAttrSet().
816 GetItemIfSet( RES_PAGEDESC, false ) )
818 if (pDestContentNd)
819 pDestContentNd->SetAttr(*pItem);
820 pFrameFormat->ResetFormatAttr( RES_PAGEDESC );
825 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */