diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/filter/html/htmlsect.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/filter/html/htmlsect.cxx')
-rw-r--r-- | sw/source/filter/html/htmlsect.cxx | 825 |
1 files changed, 825 insertions, 0 deletions
diff --git a/sw/source/filter/html/htmlsect.cxx b/sw/source/filter/html/htmlsect.cxx new file mode 100644 index 0000000000..26a1ec8d0e --- /dev/null +++ b/sw/source/filter/html/htmlsect.cxx @@ -0,0 +1,825 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <rtl/uri.hxx> + +#include <svl/urihelper.hxx> +#include <vcl/svapp.hxx> +#include <editeng/adjustitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/formatbreakitem.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <sfx2/linkmgr.hxx> +#include <osl/diagnose.h> + +#include <hintids.hxx> +#include <fmthdft.hxx> +#include <fmtcntnt.hxx> +#include <fmtclds.hxx> +#include <fmtanchr.hxx> +#include <fmtpdsc.hxx> +#include <frmatr.hxx> +#include <doc.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <shellio.hxx> +#include <section.hxx> +#include <poolfmt.hxx> +#include <pagedesc.hxx> +#include <swtable.hxx> +#include "swcss1.hxx" +#include "swhtml.hxx" + + +using namespace ::com::sun::star; + +void SwHTMLParser::NewDivision( HtmlTokenId nToken ) +{ + OUString aId, aHRef; + OUString aStyle, aLang, aDir; + OUString aClass; + SvxAdjust eAdjust = HtmlTokenId::CENTER_ON==nToken ? SvxAdjust::Center + : SvxAdjust::End; + + bool bHeader=false, bFooter=false; + const HTMLOptions& rHTMLOptions = GetOptions(); + for (size_t i = rHTMLOptions.size(); i; ) + { + const HTMLOption& rOption = rHTMLOptions[--i]; + switch( rOption.GetToken() ) + { + case HtmlOptionId::ID: + aId = rOption.GetString(); + break; + case HtmlOptionId::ALIGN: + if( HtmlTokenId::DIVISION_ON==nToken ) + eAdjust = rOption.GetEnum( aHTMLPAlignTable, eAdjust ); + break; + case HtmlOptionId::STYLE: + aStyle = rOption.GetString(); + break; + case HtmlOptionId::CLASS: + aClass = rOption.GetString(); + break; + case HtmlOptionId::LANG: + aLang = rOption.GetString(); + break; + case HtmlOptionId::DIR: + aDir = rOption.GetString(); + break; + case HtmlOptionId::HREF: + aHRef = rOption.GetString(); + break; + case HtmlOptionId::TITLE: + { + const OUString& rType = rOption.GetString(); + if( rType.equalsIgnoreAsciiCase("header") ) + bHeader = true; + else if( rType.equalsIgnoreAsciiCase("footer") ) + bFooter = true; + } + break; + default: break; + } + } + + bool bAppended = false; + if( m_pPam->GetPoint()->GetContentIndex() ) + { + AppendTextNode( bHeader||bFooter||!aId.isEmpty()|| !aHRef.isEmpty() ? AM_NORMAL + : AM_NOSPACE ); + bAppended = true; + } + + std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken)); + + bool bStyleParsed = false, bPositioned = false; + SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + { + bStyleParsed = ParseStyleOptions( aStyle, aId, aClass, + aItemSet, aPropInfo, &aLang, &aDir ); + if( bStyleParsed ) + { + if ( aPropInfo.m_nColumnCount >= 2 ) + { + xCntxt.reset(); + NewMultiCol( aPropInfo.m_nColumnCount ); + return; + } + bPositioned = HtmlTokenId::DIVISION_ON == nToken && !aClass.isEmpty() && + CreateContainer(aClass, aItemSet, aPropInfo, + xCntxt.get()); + if( !bPositioned ) + { + if (aPropInfo.m_bVisible && m_aContexts.size()) + { + const std::unique_ptr<HTMLAttrContext>& pParent + = m_aContexts[m_aContexts.size() - 1]; + if (!pParent->IsVisible()) + { + // If the parent context is hidden, we are not visible, either. + aPropInfo.m_bVisible = false; + } + } + bPositioned = DoPositioning(aItemSet, aPropInfo, xCntxt.get()); + } + } + } + + if (!bPositioned && (bHeader || bFooter) && IsNewDoc() && !m_bReadingHeaderOrFooter) + { + m_bReadingHeaderOrFooter = true; + xCntxt->SetHeaderOrFooter(true); + + SwPageDesc *pPageDesc = m_pCSS1Parser->GetMasterPageDesc(); + SwFrameFormat& rPageFormat = pPageDesc->GetMaster(); + + SwFrameFormat *pHdFtFormat; + bool bNew = false; + HtmlContextFlags nFlags = HtmlContextFlags::MultiColMask; + if( bHeader ) + { + pHdFtFormat = const_cast<SwFrameFormat*>(rPageFormat.GetHeader().GetHeaderFormat()); + if( !pHdFtFormat ) + { + // still no header, then create one + rPageFormat.SetFormatAttr( SwFormatHeader( true )); + pHdFtFormat = const_cast<SwFrameFormat*>(rPageFormat.GetHeader().GetHeaderFormat()); + bNew = true; + } + nFlags |= HtmlContextFlags::HeaderDist; + } + else + { + pHdFtFormat = const_cast<SwFrameFormat*>(rPageFormat.GetFooter().GetFooterFormat()); + if( !pHdFtFormat ) + { + // still no footer, then create one + rPageFormat.SetFormatAttr( SwFormatFooter( true )); + pHdFtFormat = const_cast<SwFrameFormat*>(rPageFormat.GetFooter().GetFooterFormat()); + bNew = true; + } + nFlags |= HtmlContextFlags::FooterDist; + } + + const SwFormatContent& rFlyContent = pHdFtFormat->GetContent(); + const SwNodeIndex& rContentStIdx = *rFlyContent.GetContentIdx(); + + if( !bNew ) + { + // Our own html export only exports one "header" at most (and one "footer") + + // Create a new node at the beginning of the section if a duplicate arises + // and hide the original header/footers content by putting it into a hidden + // document-level section + SwNodeIndex aSttIdx( rContentStIdx, 1 ); + m_xDoc->GetNodes().MakeTextNode( aSttIdx.GetNode(), + m_pCSS1Parser->GetTextCollFromPool(RES_POOLCOLL_TEXT)); + + // delete the current content of the section + SwPaM aDelPam( aSttIdx ); + aDelPam.SetMark(); + + const SwStartNode *pStNd = + static_cast<const SwStartNode *>( &rContentStIdx.GetNode() ); + aDelPam.GetPoint()->Assign( pStNd->EndOfSectionIndex() ); + + SwSectionData aSection(SectionType::Content, m_xDoc->GetUniqueSectionName()); + if (SwSection* pOldContent = m_xDoc->InsertSwSection(aDelPam, aSection, nullptr, nullptr, false)) + pOldContent->SetHidden(true); + + // update page style + for( size_t i=0; i < m_xDoc->GetPageDescCnt(); i++ ) + { + if( RES_POOLPAGE_HTML == m_xDoc->GetPageDesc(i).GetPoolFormatId() ) + { + m_xDoc->ChgPageDesc( i, *pPageDesc ); + break; + } + } + } + + SwPosition aNewPos( rContentStIdx, SwNodeOffset(1) ); + SaveDocContext(xCntxt.get(), nFlags, &aNewPos); + } + else if( !bPositioned && aId.getLength() > 9 && + (aId[0] == 's' || aId[0] == 'S' ) && + (aId[1] == 'd' || aId[1] == 'D' ) ) + { + bool bEndNote = false, bFootNote = false; + if( aId.startsWithIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdendnote ) ) + bEndNote = true; + else if( aId.startsWithIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdfootnote ) ) + bFootNote = true; + if( bFootNote || bEndNote ) + { + SwNodeIndex *pStartNdIdx = GetFootEndNoteSection( aId ); + if( pStartNdIdx ) + { + SwContentNode *pCNd = + m_xDoc->GetNodes()[pStartNdIdx->GetIndex()+1]->GetContentNode(); + SwNodeIndex aTmpSwNodeIndex(*pCNd); + SwPosition aNewPos( aTmpSwNodeIndex, pCNd, 0 ); + SaveDocContext(xCntxt.get(), HtmlContextFlags::MultiColMask, &aNewPos); + aId.clear(); + aPropInfo.m_aId.clear(); + } + } + } + + // We only insert sections into frames if the section is linked. + if( (!aId.isEmpty() && !bPositioned) || !aHRef.isEmpty() ) + { + // Insert section (has to be done before setting of attributes, + // because the section is inserted before the PaM position. + + // If we are in the first node of a section, we insert the section + // before the current section and not in the current section. + // Therefore we have to add a node and delete it again! + if( !bAppended ) + { + SwNodeIndex aPrvNdIdx( m_pPam->GetPoint()->GetNode(), -1 ); + if (aPrvNdIdx.GetNode().IsSectionNode()) + { + AppendTextNode(); + bAppended = true; + } + } + std::unique_ptr<std::deque<std::unique_ptr<HTMLAttr>>> pPostIts(bAppended ? nullptr : new std::deque<std::unique_ptr<HTMLAttr>>); + SetAttr( true, true, pPostIts.get() ); + + // make name of section unique + const OUString aName( m_xDoc->GetUniqueSectionName( !aId.isEmpty() ? &aId : nullptr ) ); + + if( !aHRef.isEmpty() ) + { + sal_Unicode cDelim = 255U; + sal_Int32 nPos = aHRef.lastIndexOf( cDelim ); + sal_Int32 nPos2 = -1; + if( nPos != -1 ) + { + nPos2 = aHRef.lastIndexOf( cDelim, nPos ); + if( nPos2 != -1 ) + std::swap( nPos, nPos2 ); + } + OUString aURL; + if( nPos == -1 ) + { + aURL = URIHelper::SmartRel2Abs(INetURLObject( m_sBaseURL ), aHRef, Link<OUString *, bool>(), false); + } + else + { + aURL = URIHelper::SmartRel2Abs(INetURLObject( m_sBaseURL ), aHRef.copy( 0, nPos ), Link<OUString *, bool>(), false ) + + OUStringChar(sfx2::cTokenSeparator); + if( nPos2 == -1 ) + { + aURL += aHRef.subView( nPos+1 ); + } + else + { + aURL += aHRef.subView( nPos+1, nPos2 - (nPos+1) ) + + OUStringChar(sfx2::cTokenSeparator) + + rtl::Uri::decode( aHRef.copy( nPos2+1 ), + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_ISO_8859_1 ); + } + } + aHRef = aURL; + } + + SwSectionData aSection( (!aHRef.isEmpty()) ? SectionType::FileLink + : SectionType::Content, aName ); + if( !aHRef.isEmpty() ) + { + aSection.SetLinkFileName( aHRef ); + aSection.SetProtectFlag(true); + } + + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameItemSet( m_xDoc->GetAttrPool() ); + if( !IsNewDoc() ) + Reader::ResetFrameFormatAttrs(aFrameItemSet ); + + if( const SvxBrushItem* pItem = aItemSet.GetItemIfSet( RES_BACKGROUND, false ) ) + { + aFrameItemSet.Put( *pItem ); + aItemSet.ClearItem( RES_BACKGROUND ); + } + if( const SvxFrameDirectionItem* pItem = aItemSet.GetItemIfSet( RES_FRAMEDIR, false ) ) + { + aFrameItemSet.Put( *pItem ); + aItemSet.ClearItem( RES_FRAMEDIR ); + } + + m_xDoc->InsertSwSection( *m_pPam, aSection, nullptr, &aFrameItemSet, false ); + + // maybe jump to section + if( JumpToMarks::Region == m_eJumpTo && aName == m_sJmpMark ) + { + m_bChkJumpMark = true; + m_eJumpTo = JumpToMarks::NONE; + } + + SwTextNode* pOldTextNd = + bAppended ? nullptr : m_pPam->GetPoint()->GetNode().GetTextNode(); + + m_pPam->Move( fnMoveBackward ); + + // move PageDesc and SwFormatBreak attribute from current node into + // (first) node of the section + if( pOldTextNd ) + MovePageDescAttrs( pOldTextNd, m_pPam->GetPoint()->GetNodeIndex(), + true ); + + if( pPostIts ) + { + // move still existing PostIts in the first paragraph of the table + InsertAttrs( std::move(*pPostIts) ); + pPostIts.reset(); + } + + xCntxt->SetSpansSection( true ); + + // don't insert Bookmarks with same name as sections + if( !aPropInfo.m_aId.isEmpty() && aPropInfo.m_aId==aName ) + aPropInfo.m_aId.clear(); + } + else + { + xCntxt->SetAppendMode( AM_NOSPACE ); + } + + if( SvxAdjust::End != eAdjust ) + { + InsertAttr(&m_xAttrTab->pAdjust, SvxAdjustItem(eAdjust, RES_PARATR_ADJUST), xCntxt.get()); + } + + // parse style + if( bStyleParsed ) + InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true ); + + xCntxt->SetVisible(aPropInfo.m_bVisible); + PushContext(xCntxt); +} + +void SwHTMLParser::EndDivision() +{ + // search for the stack entry of the token (because we still have the div stack + // we don't make a difference between DIV and CENTER) + std::unique_ptr<HTMLAttrContext> xCntxt; + auto nPos = m_aContexts.size(); + while (!xCntxt && nPos>m_nContextStMin) + { + switch( m_aContexts[--nPos]->GetToken() ) + { + case HtmlTokenId::CENTER_ON: + case HtmlTokenId::DIVISION_ON: + xCntxt = std::move(m_aContexts[nPos]); + m_aContexts.erase( m_aContexts.begin() + nPos ); + break; + default: break; + } + } + + if (xCntxt) + { + // close attribute + EndContext(xCntxt.get()); + SetAttr(); // set paragraph attributes really fast because of JavaScript + if (xCntxt->IsHeaderOrFooter()) + m_bReadingHeaderOrFooter = false; + } +} + +void SwHTMLParser::FixHeaderFooterDistance( bool bHeader, + const SwPosition *pOldPos ) +{ + SwPageDesc *pPageDesc = m_pCSS1Parser->GetMasterPageDesc(); + SwFrameFormat& rPageFormat = pPageDesc->GetMaster(); + + SwFrameFormat *pHdFtFormat = + bHeader ? const_cast<SwFrameFormat*>(rPageFormat.GetHeader().GetHeaderFormat()) + : const_cast<SwFrameFormat*>(rPageFormat.GetFooter().GetFooterFormat()); + OSL_ENSURE( pHdFtFormat, "No header or footer" ); + + const SwFormatContent& rFlyContent = pHdFtFormat->GetContent(); + const SwNodeIndex& rContentStIdx = *rFlyContent.GetContentIdx(); + + SwNodeOffset nPrvNxtIdx; + if( bHeader ) + { + nPrvNxtIdx = rContentStIdx.GetNode().EndOfSectionIndex()-1; + } + else + { + nPrvNxtIdx = pOldPos->GetNodeIndex() - 1; + } + + sal_uInt16 nSpace = 0; + SwTextNode *pTextNode = m_xDoc->GetNodes()[nPrvNxtIdx]->GetTextNode(); + if( pTextNode ) + { + const SvxULSpaceItem& rULSpace = + pTextNode->SwContentNode::GetAttr( RES_UL_SPACE ); + + // The bottom paragraph padding becomes the padding + // to header or footer + nSpace = rULSpace.GetLower(); + + // and afterwards set to a valid value + const SvxULSpaceItem& rCollULSpace = + pTextNode->GetAnyFormatColl().GetULSpace(); + if( rCollULSpace.GetUpper() == rULSpace.GetUpper() ) + pTextNode->ResetAttr( RES_UL_SPACE ); + else + pTextNode->SetAttr( + SvxULSpaceItem( rULSpace.GetUpper(), + rCollULSpace.GetLower(), RES_UL_SPACE ) ); + } + + if( bHeader ) + { + nPrvNxtIdx = pOldPos->GetNodeIndex(); + } + else + { + nPrvNxtIdx = rContentStIdx.GetIndex() + 1; + } + + pTextNode = m_xDoc->GetNodes()[nPrvNxtIdx] + ->GetTextNode(); + if( pTextNode ) + { + const SvxULSpaceItem& rULSpace = + pTextNode->SwContentNode::GetAttr( RES_UL_SPACE ); + + // The top paragraph padding becomes the padding + // to headline or footer if it is greater than the + // bottom padding of the paragraph beforehand + if( rULSpace.GetUpper() > nSpace ) + nSpace = rULSpace.GetUpper(); + + // and afterwards set to a valid value + const SvxULSpaceItem& rCollULSpace = + pTextNode->GetAnyFormatColl().GetULSpace(); + if( rCollULSpace.GetLower() == rULSpace.GetLower() ) + pTextNode->ResetAttr( RES_UL_SPACE ); + else + pTextNode->SetAttr( + SvxULSpaceItem( rCollULSpace.GetUpper(), + rULSpace.GetLower(), RES_UL_SPACE ) ); + } + + SvxULSpaceItem aULSpace( RES_UL_SPACE ); + if( bHeader ) + aULSpace.SetLower( nSpace ); + else + aULSpace.SetUpper( nSpace ); + + pHdFtFormat->SetFormatAttr( aULSpace ); +} + +bool SwHTMLParser::EndSection( bool bLFStripped ) +{ + SwEndNode *pEndNd = m_xDoc->GetNodes()[m_pPam->GetPoint()->GetNodeIndex()+1] + ->GetEndNode(); + if( pEndNd && pEndNd->StartOfSectionNode()->IsSectionNode() ) + { + // close the section + if( !bLFStripped ) + StripTrailingPara(); + m_pPam->Move( fnMoveForward ); + return true; + } + + OSL_ENSURE( false, "Wrong PaM position at end of section" ); + + return false; +} + +bool SwHTMLParser::EndSections( bool bLFStripped ) +{ + bool bSectionClosed = false; + auto nPos = m_aContexts.size(); + while( nPos>m_nContextStMin ) + { + HTMLAttrContext *pCntxt = m_aContexts[--nPos].get(); + if( pCntxt->GetSpansSection() && EndSection( bLFStripped ) ) + { + bSectionClosed = true; + pCntxt->SetSpansSection( false ); + bLFStripped = false; + } + } + + return bSectionClosed; +} + +void SwHTMLParser::NewMultiCol( sal_uInt16 columnsFromCss ) +{ + OUString aId; + OUString aStyle, aClass, aLang, aDir; + tools::Long nWidth = 100; + sal_uInt16 nCols = columnsFromCss, nGutter = 10; + bool bPercentWidth = true; + + const HTMLOptions& rHTMLOptions = GetOptions(); + for (size_t i = rHTMLOptions.size(); i; ) + { + const HTMLOption& rOption = rHTMLOptions[--i]; + switch( rOption.GetToken() ) + { + case HtmlOptionId::ID: + aId = rOption.GetString(); + break; + case HtmlOptionId::STYLE: + aStyle = rOption.GetString(); + break; + case HtmlOptionId::CLASS: + aClass = rOption.GetString(); + break; + case HtmlOptionId::LANG: + aLang = rOption.GetString(); + break; + case HtmlOptionId::DIR: + aDir = rOption.GetString(); + break; + case HtmlOptionId::COLS: + nCols = o3tl::narrowing<sal_uInt16>(rOption.GetNumber()); + break; + case HtmlOptionId::WIDTH: + nWidth = rOption.GetNumber(); + bPercentWidth = (rOption.GetString().indexOf('%') != -1); + if( bPercentWidth && nWidth>100 ) + nWidth = 100; + break; + case HtmlOptionId::GUTTER: + nGutter = o3tl::narrowing<sal_uInt16>(rOption.GetNumber()); + break; + default: break; + } + } + + std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(HtmlTokenId::MULTICOL_ON)); + + //.is the multicol element contained in a container? That may be the + // case for 5.0 documents. + bool bInCntnr = false; + auto i = m_aContexts.size(); + while( !bInCntnr && i > m_nContextStMin ) + bInCntnr = nullptr != m_aContexts[--i]->GetFrameItemSet(); + + // Parse style sheets, but don't position anything by now. + bool bStyleParsed = false; + SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) + bStyleParsed = ParseStyleOptions( aStyle, aId, aClass, + aItemSet, aPropInfo, &aLang, &aDir ); + + // Calculate width. + sal_uInt8 nPercentWidth = bPercentWidth ? static_cast<sal_uInt8>(nWidth) : 0; + SwTwips nTwipWidth = 0; + if( !bPercentWidth && nWidth ) + { + nTwipWidth = o3tl::convert(nWidth, o3tl::Length::px, o3tl::Length::twip); + } + + if( !nPercentWidth && nTwipWidth < MINFLY ) + nTwipWidth = MINFLY; + + // Do positioning. + bool bPositioned = false; + if( bInCntnr || SwCSS1Parser::MayBePositioned( aPropInfo, true ) ) + { + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameItemSet( m_xDoc->GetAttrPool() ); + if( !IsNewDoc() ) + Reader::ResetFrameFormatAttrs(aFrameItemSet ); + + SetAnchorAndAdjustment( text::VertOrientation::NONE, text::HoriOrientation::NONE, aPropInfo, + aFrameItemSet ); + + // The width is either the WIDTH attribute's value or contained + // in some style option. + SetVarSize( aPropInfo, aFrameItemSet, nTwipWidth, nPercentWidth ); + + SetSpace( Size(0,0), aItemSet, aPropInfo, aFrameItemSet ); + + // Set some other frame attributes. If the background is set, its + // it will be cleared here. That for, it won't be set at the section, + // too. + SetFrameFormatAttrs( aItemSet, + HtmlFrameFormatFlags::Box|HtmlFrameFormatFlags::Background|HtmlFrameFormatFlags::Padding|HtmlFrameFormatFlags::Direction, + aFrameItemSet ); + + // Insert fly frame. If the are columns, the fly frame's name is not + // the sections name but a generated one. + OUString aFlyName; + if( nCols < 2 ) + { + aFlyName = aId; + aPropInfo.m_aId.clear(); + } + + InsertFlyFrame(aFrameItemSet, xCntxt.get(), aFlyName); + + xCntxt->SetPopStack( true ); + bPositioned = true; + } + + bool bAppended = false; + if( !bPositioned ) + { + if( m_pPam->GetPoint()->GetContentIndex() ) + { + AppendTextNode( AM_SPACE ); + bAppended = true; + } + else + { + AddParSpace(); + } + } + + // If there are less than 2 columns, no section is inserted. + if( nCols >= 2 ) + { + if( !bAppended ) + { + // If the pam is at the start of a section, an additional text + // node must be inserted. Otherwise, the new section will be + // inserted in front of the old one. + SwNodeIndex aPrvNdIdx( m_pPam->GetPoint()->GetNode(), -1 ); + if (aPrvNdIdx.GetNode().IsSectionNode()) + { + AppendTextNode(); + bAppended = true; + } + } + std::unique_ptr<std::deque<std::unique_ptr<HTMLAttr>>> pPostIts(bAppended ? nullptr : new std::deque<std::unique_ptr<HTMLAttr>>); + SetAttr( true, true, pPostIts.get() ); + + // Make section name unique. + OUString aName( m_xDoc->GetUniqueSectionName( !aId.isEmpty() ? &aId : nullptr ) ); + SwSectionData aSection( SectionType::Content, aName ); + + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameItemSet( m_xDoc->GetAttrPool() ); + if( !IsNewDoc() ) + Reader::ResetFrameFormatAttrs(aFrameItemSet ); + + if( nGutter ) + { + nGutter = o3tl::convert(nGutter, o3tl::Length::px, o3tl::Length::twip); + } + + SwFormatCol aFormatCol; + + aFormatCol.Init( nCols, nGutter, USHRT_MAX ); + aFrameItemSet.Put( aFormatCol ); + + if( const SvxBrushItem* pItem = aItemSet.GetItemIfSet( RES_BACKGROUND, false) ) + { + aFrameItemSet.Put( *pItem ); + aItemSet.ClearItem( RES_BACKGROUND ); + } + if( const SvxFrameDirectionItem* pItem = aItemSet.GetItemIfSet( RES_FRAMEDIR, false ) ) + { + aFrameItemSet.Put( *pItem ); + aItemSet.ClearItem( RES_FRAMEDIR ); + } + m_xDoc->InsertSwSection( *m_pPam, aSection, nullptr, &aFrameItemSet, false ); + + // Jump to section, if this is requested. + if( JumpToMarks::Region == m_eJumpTo && aName == m_sJmpMark ) + { + m_bChkJumpMark = true; + m_eJumpTo = JumpToMarks::NONE; + } + + SwTextNode* pOldTextNd = + bAppended ? nullptr : m_pPam->GetPoint()->GetNode().GetTextNode(); + + m_pPam->Move( fnMoveBackward ); + + // Move PageDesc and SwFormatBreak attributes of the current node + // to the section's first node. + if( pOldTextNd ) + MovePageDescAttrs( pOldTextNd, m_pPam->GetPoint()->GetNodeIndex(), + true ); + + if( pPostIts ) + { + // Move pending PostIts into the section. + InsertAttrs( std::move(*pPostIts) ); + pPostIts.reset(); + } + + xCntxt->SetSpansSection( true ); + + // Insert a bookmark if its name differs from the section's name only. + if( !aPropInfo.m_aId.isEmpty() && aPropInfo.m_aId==aName ) + aPropInfo.m_aId.clear(); + } + + // Additional attributes must be set as hard ones. + if( bStyleParsed ) + InsertAttrs( aItemSet, aPropInfo, xCntxt.get(), true ); + + PushContext(xCntxt); +} + +void SwHTMLParser::InsertFlyFrame( const SfxItemSet& rItemSet, + HTMLAttrContext *pCntxt, + const OUString& rName ) +{ + RndStdIds eAnchorId = + rItemSet.Get( RES_ANCHOR ).GetAnchorId(); + + // create frame + SwFlyFrameFormat* pFlyFormat = m_xDoc->MakeFlySection( eAnchorId, m_pPam->GetPoint(), + &rItemSet ); + if( !rName.isEmpty() ) + pFlyFormat->SetFormatName( rName ); + + RegisterFlyFrame( pFlyFormat ); + + const SwFormatContent& rFlyContent = pFlyFormat->GetContent(); + const SwNodeIndex& rFlyCntIdx = *rFlyContent.GetContentIdx(); + + SwPosition aNewPos( rFlyCntIdx, SwNodeOffset(1) ); + const HtmlContextFlags nFlags = HtmlContextFlags::ProtectStack|HtmlContextFlags::StripPara; + SaveDocContext( pCntxt, nFlags, &aNewPos ); +} + +void SwHTMLParser::MovePageDescAttrs( SwNode *pSrcNd, + SwNodeOffset nDestIdx, + bool bFormatBreak ) +{ + SwContentNode* pDestContentNd = + m_xDoc->GetNodes()[nDestIdx]->GetContentNode(); + + OSL_ENSURE( pDestContentNd, "Why is the target not a Content-Node?" ); + + if( pSrcNd->IsContentNode() ) + { + SwContentNode* pSrcContentNd = pSrcNd->GetContentNode(); + + const SwFormatPageDesc* pFormatPageDesc = + pSrcContentNd->GetSwAttrSet().GetItemIfSet( RES_PAGEDESC, false ); + if( pFormatPageDesc && pFormatPageDesc->GetPageDesc() ) + { + pDestContentNd->SetAttr( *pFormatPageDesc ); + pSrcContentNd->ResetAttr( RES_PAGEDESC ); + } + if( const SvxFormatBreakItem* pItem = pSrcContentNd->GetSwAttrSet() + .GetItemIfSet( RES_BREAK, false ) ) + { + switch( pItem->GetBreak() ) + { + case SvxBreak::PageBefore: + case SvxBreak::PageAfter: + case SvxBreak::PageBoth: + if( bFormatBreak ) + pDestContentNd->SetAttr( *pItem ); + pSrcContentNd->ResetAttr( RES_BREAK ); + break; + default: + break; + } + } + } + else if( pSrcNd->IsTableNode() ) + { + SwFrameFormat *pFrameFormat = pSrcNd->GetTableNode()->GetTable().GetFrameFormat(); + + if( const SwFormatPageDesc* pItem = pFrameFormat->GetAttrSet(). + GetItemIfSet( RES_PAGEDESC, false ) ) + { + if (pDestContentNd) + pDestContentNd->SetAttr(*pItem); + pFrameFormat->ResetFormatAttr( RES_PAGEDESC ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |