summaryrefslogtreecommitdiffstats
path: root/sw/source/filter/html/htmlgrin.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/filter/html/htmlgrin.cxx
parentInitial commit. (diff)
downloadlibreoffice-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/htmlgrin.cxx')
-rw-r--r--sw/source/filter/html/htmlgrin.cxx1574
1 files changed, 1574 insertions, 0 deletions
diff --git a/sw/source/filter/html/htmlgrin.cxx b/sw/source/filter/html/htmlgrin.cxx
new file mode 100644
index 0000000000..072b8945d2
--- /dev/null
+++ b/sw/source/filter/html/htmlgrin.cxx
@@ -0,0 +1,1574 @@
+/* -*- 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 <memory>
+#include <hintids.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/documentinfo.hxx>
+#include <vcl/svapp.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <svl/stritem.hxx>
+#include <svl/urihelper.hxx>
+#include <svl/languageoptions.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/langitem.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/event.hxx>
+#include <vcl/imap.hxx>
+#include <svtools/htmltokn.h>
+#include <svtools/htmlkywd.hxx>
+#include <unotools/eventcfg.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+#include <fmtornt.hxx>
+#include <fmturl.hxx>
+#include <fmtsrnd.hxx>
+#include <fmtinfmt.hxx>
+#include <fmtcntnt.hxx>
+#include <fmtanchr.hxx>
+#include <fmtfsize.hxx>
+#include <charatr.hxx>
+#include <frmfmt.hxx>
+#include <charfmt.hxx>
+#include <docsh.hxx>
+#include <pam.hxx>
+#include <doc.hxx>
+#include <ndtxt.hxx>
+#include <shellio.hxx>
+#include <poolfmt.hxx>
+#include <IMark.hxx>
+#include <ndgrf.hxx>
+#include "htmlnum.hxx"
+#include "swcss1.hxx"
+#include "swhtml.hxx"
+#include <numrule.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <frameformats.hxx>
+
+#include <vcl/graphicfilter.hxx>
+#include <tools/UnitConversion.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/securityoptions.hxx>
+
+using namespace ::com::sun::star;
+
+HTMLOptionEnum<sal_Int16> const aHTMLImgHAlignTable[] =
+{
+ { OOO_STRING_SVTOOLS_HTML_AL_left, text::HoriOrientation::LEFT },
+ { OOO_STRING_SVTOOLS_HTML_AL_right, text::HoriOrientation::RIGHT },
+ { nullptr, 0 }
+};
+
+HTMLOptionEnum<sal_Int16> const aHTMLImgVAlignTable[] =
+{
+ { OOO_STRING_SVTOOLS_HTML_VA_top, text::VertOrientation::LINE_TOP },
+ { OOO_STRING_SVTOOLS_HTML_VA_texttop, text::VertOrientation::CHAR_TOP },
+ { OOO_STRING_SVTOOLS_HTML_VA_middle, text::VertOrientation::CENTER },
+ { OOO_STRING_SVTOOLS_HTML_AL_center, text::VertOrientation::CENTER },
+ { OOO_STRING_SVTOOLS_HTML_VA_absmiddle, text::VertOrientation::LINE_CENTER },
+ { OOO_STRING_SVTOOLS_HTML_VA_bottom, text::VertOrientation::TOP },
+ { OOO_STRING_SVTOOLS_HTML_VA_baseline, text::VertOrientation::TOP },
+ { OOO_STRING_SVTOOLS_HTML_VA_absbottom, text::VertOrientation::LINE_BOTTOM },
+ { nullptr, 0 }
+};
+
+ImageMap *SwHTMLParser::FindImageMap( std::u16string_view rName ) const
+{
+ OSL_ENSURE( rName[0] != '#', "FindImageMap: name begins with '#'!" );
+
+ if (m_pImageMaps)
+ {
+ for (const auto &rpIMap : *m_pImageMaps)
+ {
+ if (o3tl::equalsIgnoreAsciiCase(rName, rpIMap->GetName()))
+ {
+ return rpIMap.get();
+ }
+ }
+ }
+ return nullptr;
+}
+
+void SwHTMLParser::ConnectImageMaps()
+{
+ SwNodes& rNds = m_xDoc->GetNodes();
+ // on the first node of section #1
+ SwNodeOffset nIdx = rNds.GetEndOfAutotext().StartOfSectionIndex() + 1;
+ SwNodeOffset nEndIdx = rNds.GetEndOfAutotext().GetIndex();
+
+ SwGrfNode* pGrfNd;
+ while( m_nMissingImgMaps > 0 && nIdx < nEndIdx )
+ {
+ SwNode *pNd = rNds[nIdx + 1];
+ pGrfNd = pNd->GetGrfNode();
+ if( nullptr != pGrfNd )
+ {
+ SwFrameFormat *pFormat = pGrfNd->GetFlyFormat();
+ SwFormatURL aURL( pFormat->GetURL() );
+ const ImageMap *pIMap = aURL.GetMap();
+ if( pIMap && pIMap->GetIMapObjectCount()==0 )
+ {
+ // The (empty) image map of the node will be either
+ // replaced with found image map or deleted.
+ ImageMap *pNewIMap =
+ FindImageMap( pIMap->GetName() );
+ aURL.SetMap( pNewIMap );
+ pFormat->SetFormatAttr( aURL );
+ if( !pGrfNd->IsScaleImageMap() )
+ {
+ // meanwhile the graphic size is known or the
+ // graphic don't need scaling
+ pGrfNd->ScaleImageMap();
+ }
+ m_nMissingImgMaps--; // search a map less
+ }
+ }
+ nIdx = rNds[nIdx]->EndOfSectionIndex() + 1;
+ }
+}
+
+void SwHTMLParser::SetAnchorAndAdjustment( sal_Int16 eVertOri,
+ sal_Int16 eHoriOri,
+ const SvxCSS1PropertyInfo &rCSS1PropInfo,
+ SfxItemSet& rFrameItemSet )
+{
+ const SfxItemSet *pCntnrItemSet = nullptr;
+ auto i = m_aContexts.size();
+ while( !pCntnrItemSet && i > m_nContextStMin )
+ pCntnrItemSet = m_aContexts[--i]->GetFrameItemSet();
+
+ if( pCntnrItemSet )
+ {
+ // If we are in a container then the anchoring of the container is used.
+ rFrameItemSet.Put( *pCntnrItemSet );
+ }
+ else if( SwCSS1Parser::MayBePositioned( rCSS1PropInfo, true ) )
+ {
+ // If the alignment can be set via CSS1 options we use them.
+ SetAnchorAndAdjustment( rCSS1PropInfo, rFrameItemSet );
+ }
+ else
+ {
+ // Otherwise the alignment is set correspondingly the normal HTML options.
+ SetAnchorAndAdjustment( eVertOri, eHoriOri, rFrameItemSet );
+ }
+}
+
+void SwHTMLParser::SetAnchorAndAdjustment( sal_Int16 eVertOri,
+ sal_Int16 eHoriOri,
+ SfxItemSet& rFrameSet,
+ bool bDontAppend )
+{
+ bool bMoveBackward = false;
+ SwFormatAnchor aAnchor( RndStdIds::FLY_AS_CHAR );
+ sal_Int16 eVertRel = text::RelOrientation::FRAME;
+
+ if( text::HoriOrientation::NONE != eHoriOri )
+ {
+ // determine paragraph indent
+ sal_uInt16 nLeftSpace = 0, nRightSpace = 0;
+ short nIndent = 0;
+ GetMarginsFromContextWithNumberBullet( nLeftSpace, nRightSpace, nIndent );
+
+ // determine horizontal alignment and wrapping
+ sal_Int16 eHoriRel;
+ css::text::WrapTextMode eSurround;
+ switch( eHoriOri )
+ {
+ case text::HoriOrientation::LEFT:
+ eHoriRel = nLeftSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME;
+ eSurround = css::text::WrapTextMode_RIGHT;
+ break;
+ case text::HoriOrientation::RIGHT:
+ eHoriRel = nRightSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME;
+ eSurround = css::text::WrapTextMode_LEFT;
+ break;
+ case text::HoriOrientation::CENTER: // for tables
+ eHoriRel = text::RelOrientation::FRAME;
+ eSurround = css::text::WrapTextMode_NONE;
+ break;
+ default:
+ eHoriRel = text::RelOrientation::FRAME;
+ eSurround = css::text::WrapTextMode_PARALLEL;
+ break;
+ }
+
+ // Create a new paragraph, if the current one has frames
+ // anchored at paragraph/at char without wrapping.
+ if( !bDontAppend && HasCurrentParaFlys( true ) )
+ {
+ // When the paragraph only contains graphics then there
+ // is no need for bottom margin. Since here also with use of
+ // styles no margin should be created, set attributes to
+ // override!
+ sal_uInt16 nUpper=0, nLower=0;
+ GetULSpaceFromContext( nUpper, nLower );
+ InsertAttr( SvxULSpaceItem( nUpper, 0, RES_UL_SPACE ), true );
+
+ AppendTextNode( AM_NOSPACE );
+
+ if( nUpper )
+ {
+ NewAttr(m_xAttrTab, &m_xAttrTab->pULSpace, SvxULSpaceItem(0, nLower, RES_UL_SPACE));
+ m_aParaAttrs.push_back( m_xAttrTab->pULSpace );
+ EndAttr( m_xAttrTab->pULSpace, false );
+ }
+ }
+
+ // determine vertical alignment and anchoring
+ const sal_Int32 nContent = m_pPam->GetPoint()->GetContentIndex();
+ if( nContent )
+ {
+ aAnchor.SetType( RndStdIds::FLY_AT_CHAR );
+ bMoveBackward = true;
+ eVertOri = text::VertOrientation::CHAR_BOTTOM;
+ eVertRel = text::RelOrientation::CHAR;
+ }
+ else
+ {
+ aAnchor.SetType( RndStdIds::FLY_AT_PARA );
+ eVertOri = text::VertOrientation::TOP;
+ eVertRel = text::RelOrientation::PRINT_AREA;
+ }
+
+ rFrameSet.Put( SwFormatHoriOrient( 0, eHoriOri, eHoriRel) );
+
+ rFrameSet.Put( SwFormatSurround( eSurround ) );
+ }
+ rFrameSet.Put( SwFormatVertOrient( 0, eVertOri, eVertRel) );
+
+ if( bMoveBackward )
+ m_pPam->Move( fnMoveBackward );
+
+ if (aAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR && !m_pPam->GetPointNode().GetTextNode())
+ {
+ eState = SvParserState::Error;
+ return;
+ }
+
+ aAnchor.SetAnchor( m_pPam->GetPoint() );
+
+ if( bMoveBackward )
+ m_pPam->Move( fnMoveForward );
+
+ rFrameSet.Put( aAnchor );
+}
+
+void SwHTMLParser::RegisterFlyFrame( SwFrameFormat *pFlyFormat )
+{
+ // automatically anchored frames must be moved forward by one position
+ if( RES_DRAWFRMFMT != pFlyFormat->Which() &&
+ (RndStdIds::FLY_AT_PARA == pFlyFormat->GetAnchor().GetAnchorId()) &&
+ css::text::WrapTextMode_THROUGH == pFlyFormat->GetSurround().GetSurround() )
+ {
+ m_aMoveFlyFrames.emplace_back(std::make_unique<SwHTMLFrameFormatListener>(pFlyFormat));
+ m_aMoveFlyCnts.push_back( m_pPam->GetPoint()->GetContentIndex() );
+ }
+}
+
+/* */
+
+void SwHTMLParser::GetDefaultScriptType( ScriptType& rType,
+ OUString& rTypeStr ) const
+{
+ SwDocShell *pDocSh = m_xDoc->GetDocShell();
+ SvKeyValueIterator* pHeaderAttrs = pDocSh ? pDocSh->GetHeaderAttributes()
+ : nullptr;
+ rType = GetScriptType( pHeaderAttrs );
+ rTypeStr = GetScriptTypeString( pHeaderAttrs );
+}
+
+namespace
+{
+ bool allowAccessLink(const SwDoc& rDoc)
+ {
+ OUString sReferer;
+ SfxObjectShell * sh = rDoc.GetPersist();
+ if (sh != nullptr && sh->HasName())
+ {
+ sReferer = sh->GetMedium()->GetName();
+ }
+ return !SvtSecurityOptions::isUntrustedReferer(sReferer);
+ }
+}
+
+/* */
+
+void SwHTMLParser::InsertImage()
+{
+ // and now analyze
+ OUString sAltNm, aId, aClass, aStyle, aMap, sHTMLGrfName;
+ OUString sGrfNm;
+ OUString aGraphicData;
+ sal_Int16 eVertOri = text::VertOrientation::TOP;
+ sal_Int16 eHoriOri = text::HoriOrientation::NONE;
+ bool bWidthProvided=false, bHeightProvided=false;
+ tools::Long nWidth=0, nHeight=0;
+ tools::Long nVSpace=0, nHSpace=0;
+
+ sal_uInt16 nBorder = (m_xAttrTab->pINetFormat ? 1 : 0);
+ bool bIsMap = false;
+ bool bPercentWidth = false;
+ bool bPercentHeight = false;
+ OUString sWidthAsString, sHeightAsString;
+ SvxMacroItem aMacroItem(RES_FRMMACRO);
+
+ ScriptType eDfltScriptType;
+ OUString sDfltScriptType;
+ GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
+
+ const HTMLOptions& rHTMLOptions = GetOptions();
+ for (size_t i = rHTMLOptions.size(); i; )
+ {
+ SvMacroItemId nEvent = SvMacroItemId::NONE;
+ ScriptType eScriptType2 = eDfltScriptType;
+ 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::SRC:
+ sGrfNm = rOption.GetString();
+ if( !InternalImgToPrivateURL(sGrfNm) )
+ sGrfNm = INetURLObject::GetAbsURL( m_sBaseURL, sGrfNm );
+ break;
+ case HtmlOptionId::DATA:
+ aGraphicData = rOption.GetString();
+ if (!InternalImgToPrivateURL(aGraphicData))
+ aGraphicData = INetURLObject::GetAbsURL(
+ m_sBaseURL, SwHTMLParser::StripQueryFromPath(m_sBaseURL, aGraphicData));
+ break;
+ case HtmlOptionId::ALIGN:
+ eVertOri =
+ rOption.GetEnum( aHTMLImgVAlignTable,
+ text::VertOrientation::TOP );
+ eHoriOri =
+ rOption.GetEnum( aHTMLImgHAlignTable );
+ break;
+ case HtmlOptionId::WIDTH:
+ // for now only store as pixel value!
+ nWidth = rOption.GetNumber();
+ sWidthAsString = rOption.GetString();
+ bPercentWidth = (sWidthAsString.indexOf('%') != -1);
+ if( bPercentWidth && nWidth>100 )
+ nWidth = 100;
+ // width|height = "auto" means viewing app decides the size
+ // i.e. proceed as if no particular size was provided
+ bWidthProvided = (sWidthAsString != "auto");
+ break;
+ case HtmlOptionId::HEIGHT:
+ // for now only store as pixel value!
+ nHeight = rOption.GetNumber();
+ sHeightAsString = rOption.GetString();
+ bPercentHeight = (sHeightAsString.indexOf('%') != -1);
+ if( bPercentHeight && nHeight>100 )
+ nHeight = 100;
+ // the same as above w/ HtmlOptionId::WIDTH
+ bHeightProvided = (sHeightAsString != "auto");
+ break;
+ case HtmlOptionId::VSPACE:
+ nVSpace = rOption.GetNumber();
+ break;
+ case HtmlOptionId::HSPACE:
+ nHSpace = rOption.GetNumber();
+ break;
+ case HtmlOptionId::ALT:
+ sAltNm = rOption.GetString();
+ break;
+ case HtmlOptionId::BORDER:
+ nBorder = o3tl::narrowing<sal_uInt16>(rOption.GetNumber());
+ break;
+ case HtmlOptionId::ISMAP:
+ bIsMap = true;
+ break;
+ case HtmlOptionId::USEMAP:
+ aMap = rOption.GetString();
+ break;
+ case HtmlOptionId::NAME:
+ sHTMLGrfName = rOption.GetString();
+ break;
+
+ case HtmlOptionId::SDONLOAD:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONLOAD:
+ nEvent = SvMacroItemId::OnImageLoadDone;
+ goto IMAGE_SETEVENT;
+
+ case HtmlOptionId::SDONABORT:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONABORT:
+ nEvent = SvMacroItemId::OnImageLoadCancel;
+ goto IMAGE_SETEVENT;
+
+ case HtmlOptionId::SDONERROR:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONERROR:
+ nEvent = SvMacroItemId::OnImageLoadError;
+ goto IMAGE_SETEVENT;
+IMAGE_SETEVENT:
+ {
+ OUString sTmp( rOption.GetString() );
+ if( !sTmp.isEmpty() )
+ {
+ sTmp = convertLineEnd(sTmp, GetSystemLineEnd());
+ OUString sScriptType;
+ if( EXTENDED_STYPE == eScriptType2 )
+ sScriptType = sDfltScriptType;
+ aMacroItem.SetMacro( nEvent,
+ SvxMacro( sTmp, sScriptType, eScriptType2 ));
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (sGrfNm.isEmpty() && !aGraphicData.isEmpty())
+ sGrfNm = aGraphicData;
+
+ if( sGrfNm.isEmpty() )
+ return;
+
+ // When we are in an ordered list and the paragraph is still empty and not
+ // numbered, it may be a graphic for a bullet list.
+ if( !m_pPam->GetPoint()->GetContentIndex() &&
+ GetNumInfo().GetDepth() > 0 && GetNumInfo().GetDepth() <= MAXLEVEL &&
+ !m_aBulletGrfs[GetNumInfo().GetDepth()-1].isEmpty() &&
+ m_aBulletGrfs[GetNumInfo().GetDepth()-1]==sGrfNm )
+ {
+ SwTextNode* pTextNode = m_pPam->GetPointNode().GetTextNode();
+
+ if( pTextNode && ! pTextNode->IsCountedInList())
+ {
+ OSL_ENSURE( pTextNode->GetActualListLevel() == GetNumInfo().GetLevel(),
+ "Numbering level is wrong" );
+
+ pTextNode->SetCountedInList( true );
+
+ // It's necessary to invalidate the rule, because between the reading
+ // of LI and the graphic an EndAction could be called.
+ if( GetNumInfo().GetNumRule() )
+ GetNumInfo().GetNumRule()->SetInvalidRule( true );
+
+ // Set the style again, so that indent of the first line is correct.
+ SetTextCollAttrs();
+
+ return;
+ }
+ }
+
+ Graphic aGraphic;
+ INetURLObject aGraphicURL( sGrfNm );
+ if( aGraphicURL.GetProtocol() == INetProtocol::Data )
+ {
+ std::unique_ptr<SvMemoryStream> const pStream(aGraphicURL.getData());
+ if (pStream)
+ {
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ aGraphic = rFilter.ImportUnloadedGraphic(*pStream);
+ sGrfNm.clear();
+
+ if (!sGrfNm.isEmpty())
+ {
+ if (ERRCODE_NONE == rFilter.ImportGraphic(aGraphic, u"", *pStream))
+ sGrfNm.clear();
+ }
+ }
+ }
+ else if (m_sBaseURL.isEmpty() || !aGraphicData.isEmpty())
+ {
+ // sBaseURL is empty if the source is clipboard
+ // aGraphicData is non-empty for <object data="..."> -> not a linked graphic.
+ if (ERRCODE_NONE == GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aGraphicURL))
+ sGrfNm.clear();
+ }
+
+ if (!sGrfNm.isEmpty())
+ {
+ aGraphic.SetDefaultType();
+ }
+
+ if (!nHeight || !nWidth)
+ {
+ Size aPixelSize = aGraphic.GetSizePixel(Application::GetDefaultDevice());
+ if (!bWidthProvided)
+ nWidth = aPixelSize.Width();
+ if (!bHeightProvided)
+ nHeight = aPixelSize.Height();
+ // tdf#142781 - calculate the width/height keeping the aspect ratio
+ if (bWidthProvided && !bHeightProvided && aPixelSize.Width())
+ {
+ if (bPercentWidth)
+ {
+ nHeight = SwFormatFrameSize::SYNCED;
+ bPercentHeight = true;
+ }
+ else
+ {
+ nHeight = nWidth * aPixelSize.Height() / aPixelSize.Width();
+ }
+ }
+ else if (!bWidthProvided && bHeightProvided && aPixelSize.Height())
+ {
+ if (bPercentHeight)
+ {
+ nWidth = SwFormatFrameSize::SYNCED;
+ bPercentWidth = true;
+ }
+ else
+ {
+ nWidth = nHeight * aPixelSize.Width() / aPixelSize.Height();
+ }
+ }
+ }
+
+ SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
+ SvxCSS1PropertyInfo aPropInfo;
+ if( HasStyleOptions( aStyle, aId, aClass ) )
+ ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo );
+
+ SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameSet( m_xDoc->GetAttrPool() );
+ if( !IsNewDoc() )
+ Reader::ResetFrameFormatAttrs( aFrameSet );
+
+ // set the border
+ tools::Long nHBorderWidth = 0, nVBorderWidth = 0;
+ if( nBorder )
+ {
+ nHBorderWidth = static_cast<tools::Long>(nBorder);
+ nVBorderWidth = static_cast<tools::Long>(nBorder);
+ SvxCSS1Parser::PixelToTwip( nVBorderWidth, nHBorderWidth );
+
+ ::editeng::SvxBorderLine aHBorderLine( nullptr, nHBorderWidth );
+ ::editeng::SvxBorderLine aVBorderLine( nullptr, nVBorderWidth );
+
+ if( m_xAttrTab->pINetFormat )
+ {
+ const OUString& rURL =
+ static_cast<const SwFormatINetFormat&>(m_xAttrTab->pINetFormat->GetItem()).GetValue();
+
+ m_pCSS1Parser->SetATagStyles();
+ sal_uInt16 nPoolId = static_cast< sal_uInt16 >(m_xDoc->IsVisitedURL( rURL )
+ ? RES_POOLCHR_INET_VISIT
+ : RES_POOLCHR_INET_NORMAL);
+ const SwCharFormat *pCharFormat = m_pCSS1Parser->GetCharFormatFromPool( nPoolId );
+ aHBorderLine.SetColor( pCharFormat->GetColor().GetValue() );
+ aVBorderLine.SetColor( aHBorderLine.GetColor() );
+ }
+ else
+ {
+ const SvxColorItem& rColorItem = m_xAttrTab->pFontColor ?
+ static_cast<const SvxColorItem &>(m_xAttrTab->pFontColor->GetItem()) :
+ m_xDoc->GetDefault(RES_CHRATR_COLOR);
+ aHBorderLine.SetColor( rColorItem.GetValue() );
+ aVBorderLine.SetColor( aHBorderLine.GetColor() );
+ }
+
+ SvxBoxItem aBoxItem( RES_BOX );
+ aBoxItem.SetLine( &aHBorderLine, SvxBoxItemLine::TOP );
+ aBoxItem.SetLine( &aHBorderLine, SvxBoxItemLine::BOTTOM );
+ aBoxItem.SetLine( &aVBorderLine, SvxBoxItemLine::LEFT );
+ aBoxItem.SetLine( &aVBorderLine, SvxBoxItemLine::RIGHT );
+ aFrameSet.Put( aBoxItem );
+ }
+
+ SetAnchorAndAdjustment( eVertOri, eHoriOri, aPropInfo, aFrameSet );
+
+ SetSpace( Size( nHSpace, nVSpace), aItemSet, aPropInfo, aFrameSet );
+
+ // set other CSS1 attributes
+ SetFrameFormatAttrs( aItemSet, HtmlFrameFormatFlags::Box, aFrameSet );
+
+ Size aTwipSz( bPercentWidth ? 0 : nWidth, bPercentHeight ? 0 : nHeight );
+ if( aTwipSz.Width() || aTwipSz.Height() )
+ {
+ if (bWidthProvided || bHeightProvided || // attributes imply pixel!
+ aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ {
+ aTwipSz = o3tl::convert(aTwipSz, o3tl::Length::px, o3tl::Length::twip);
+ }
+ else
+ { // some bitmaps may have a size in metric units (e.g. PNG); use that
+ assert(aGraphic.GetPrefMapMode().GetMapUnit() < MapUnit::MapPixel);
+ aTwipSz = o3tl::convert(aGraphic.GetPrefSize(),
+ MapToO3tlLength(aGraphic.GetPrefMapMode().GetMapUnit()),
+ o3tl::Length::twip);
+ }
+ }
+
+ // convert CSS1 size to "normal" size
+ switch( aPropInfo.m_eWidthType )
+ {
+ case SVX_CSS1_LTYPE_TWIP:
+ aTwipSz.setWidth( aPropInfo.m_nWidth );
+ nWidth = 1; // != 0
+ bPercentWidth = false;
+ break;
+ case SVX_CSS1_LTYPE_PERCENTAGE:
+ aTwipSz.setWidth( 0 );
+ nWidth = aPropInfo.m_nWidth;
+ bPercentWidth = true;
+ break;
+ default:
+ ;
+ }
+ switch( aPropInfo.m_eHeightType )
+ {
+ case SVX_CSS1_LTYPE_TWIP:
+ aTwipSz.setHeight( aPropInfo.m_nHeight );
+ nHeight = 1; // != 0
+ bPercentHeight = false;
+ break;
+ case SVX_CSS1_LTYPE_PERCENTAGE:
+ aTwipSz.setHeight( 0 );
+ nHeight = aPropInfo.m_nHeight;
+ bPercentHeight = true;
+ break;
+ default:
+ ;
+ }
+
+ Size aGrfSz( 0, 0 );
+ bool bSetTwipSize = true; // Set Twip-Size on Node?
+ bool bChangeFrameSize = false; // Change frame format later?
+ bool bRequestGrfNow = false;
+ bool bSetScaleImageMap = false;
+ sal_uInt8 nPercentWidth = 0, nPercentHeight = 0;
+
+ // bPercentWidth / bPercentHeight means we have a percent size. If that's not the case and we have no
+ // size from nWidth / nHeight either, then inspect the image header.
+ bool bRelWidthScale = bPercentWidth && nWidth == SwFormatFrameSize::SYNCED;
+ bool bNeedWidth = (!bPercentWidth && !nWidth) || bRelWidthScale;
+ bool bRelHeightScale = bPercentHeight && nHeight == SwFormatFrameSize::SYNCED;
+ bool bNeedHeight = (!bPercentHeight && !nHeight) || bRelHeightScale;
+ if ((bNeedWidth || bNeedHeight) && !bFuzzing && allowAccessLink(*m_xDoc))
+ {
+ GraphicDescriptor aDescriptor(aGraphicURL);
+ if (aDescriptor.Detect(/*bExtendedInfo=*/true))
+ {
+ // Try to use size info from the image header before defaulting to
+ // HTML_DFLT_IMG_WIDTH/HEIGHT.
+ aTwipSz
+ = o3tl::convert(aDescriptor.GetSizePixel(), o3tl::Length::px, o3tl::Length::twip);
+ if (!bPercentWidth && !nWidth)
+ {
+ nWidth = aTwipSz.getWidth();
+ }
+ if (!bPercentHeight && !nHeight)
+ {
+ nHeight = aTwipSz.getHeight();
+ }
+ }
+ }
+
+ if( !(nWidth && !bRelWidthScale) || !(nHeight && !bRelHeightScale) )
+ {
+ // When the graphic is in a table, it will be requested immediately,
+ // so that it is available before the table is layouted.
+ if (m_xTable && !nWidth)
+ {
+ bRequestGrfNow = true;
+ IncGrfsThatResizeTable();
+ }
+
+ // The frame size is set later
+ bChangeFrameSize = true;
+ aGrfSz = aTwipSz;
+ if( !nWidth && !nHeight )
+ {
+ aTwipSz.setWidth( HTML_DFLT_IMG_WIDTH );
+ aTwipSz.setHeight( HTML_DFLT_IMG_HEIGHT );
+ }
+ else if( nWidth )
+ {
+ // a percentage value
+ if( bPercentWidth )
+ {
+ nPercentWidth = static_cast<sal_uInt8>(nWidth);
+ nPercentHeight = 255;
+ }
+ else
+ {
+ aTwipSz.setHeight( HTML_DFLT_IMG_HEIGHT );
+ }
+ }
+ else if( nHeight )
+ {
+ if( bPercentHeight )
+ {
+ nPercentHeight = static_cast<sal_uInt8>(nHeight);
+ nPercentWidth = 255;
+ }
+ else
+ {
+ aTwipSz.setWidth( HTML_DFLT_IMG_WIDTH );
+ }
+ }
+ }
+ else
+ {
+ // Width and height were given and don't need to be set
+ bSetTwipSize = false;
+
+ if( bPercentWidth )
+ nPercentWidth = static_cast<sal_uInt8>(nWidth);
+
+ if( bPercentHeight )
+ nPercentHeight = static_cast<sal_uInt8>(nHeight);
+ }
+
+ // set image map
+ aMap = comphelper::string::stripEnd(aMap, ' ');
+ if( !aMap.isEmpty() )
+ {
+ // Since we only know local image maps we just use everything
+ // after # as name
+ sal_Int32 nPos = aMap.indexOf( '#' );
+ OUString aName;
+ if ( -1 == nPos )
+ aName = aMap ;
+ else
+ aName = aMap.copy(nPos+1);
+
+ ImageMap *pImgMap = FindImageMap( aName );
+ if( pImgMap )
+ {
+ SwFormatURL aURL; aURL.SetMap( pImgMap );// is copied
+
+ bSetScaleImageMap = !nPercentWidth || !nPercentHeight;
+ aFrameSet.Put( aURL );
+ }
+ else
+ {
+ ImageMap aEmptyImgMap( aName );
+ SwFormatURL aURL; aURL.SetMap( &aEmptyImgMap );// is copied
+ aFrameSet.Put( aURL );
+ m_nMissingImgMaps++; // image maps are missing
+
+ // the graphic has to scaled during SetTwipSize, if we didn't
+ // set a size on the node or the size doesn't match the graphic size.
+ bSetScaleImageMap = true;
+ }
+ }
+
+ // observe minimum values !!
+ bool bRelSizeScale = bRelWidthScale || bRelHeightScale;
+ if( nPercentWidth )
+ {
+ OSL_ENSURE( !aTwipSz.Width() || bRelSizeScale,
+ "Why is a width set if we already have percentage value?" );
+ aTwipSz.setWidth( aGrfSz.Width() ? aGrfSz.Width()
+ : HTML_DFLT_IMG_WIDTH );
+ }
+ else
+ {
+ aTwipSz.AdjustWidth(2*nVBorderWidth );
+ if( aTwipSz.Width() < MINFLY )
+ aTwipSz.setWidth( MINFLY );
+ }
+ if( nPercentHeight )
+ {
+ OSL_ENSURE( !aTwipSz.Height() || bRelSizeScale,
+ "Why is a height set if we already have percentage value?" );
+ aTwipSz.setHeight( aGrfSz.Height() ? aGrfSz.Height()
+ : HTML_DFLT_IMG_HEIGHT );
+ }
+ else
+ {
+ aTwipSz.AdjustHeight(2*nHBorderWidth );
+ if( aTwipSz.Height() < MINFLY )
+ aTwipSz.setHeight( MINFLY );
+ }
+
+ SwFormatFrameSize aFrameSize( SwFrameSize::Fixed, aTwipSz.Width(), aTwipSz.Height() );
+ aFrameSize.SetWidthPercent( nPercentWidth );
+ aFrameSize.SetHeightPercent( nPercentHeight );
+ aFrameSet.Put( aFrameSize );
+
+ const SwNodeType eNodeType = m_pPam->GetPointNode().GetNodeType();
+ if (eNodeType != SwNodeType::Text && eNodeType != SwNodeType::Table)
+ return;
+
+ // passing empty sGrfNm here, means we don't want the graphic to be linked
+ SwFrameFormat *const pFlyFormat =
+ m_xDoc->getIDocumentContentOperations().InsertGraphic(
+ *m_pPam, sGrfNm, OUString(), &aGraphic,
+ &aFrameSet, nullptr, nullptr);
+ SwGrfNode *pGrfNd = m_xDoc->GetNodes()[ pFlyFormat->GetContent().GetContentIdx()
+ ->GetIndex()+1 ]->GetGrfNode();
+
+ if( !sHTMLGrfName.isEmpty() )
+ {
+ pFlyFormat->SetFormatName( sHTMLGrfName );
+
+ // maybe jump to graphic
+ if( JumpToMarks::Graphic == m_eJumpTo && sHTMLGrfName == m_sJmpMark )
+ {
+ m_bChkJumpMark = true;
+ m_eJumpTo = JumpToMarks::NONE;
+ }
+ }
+
+ if (pGrfNd)
+ {
+ if( !sAltNm.isEmpty() )
+ pGrfNd->SetTitle( sAltNm );
+
+ if( bSetTwipSize )
+ pGrfNd->SetTwipSize( aGrfSz );
+
+ pGrfNd->SetChgTwipSize( bChangeFrameSize );
+
+ if( bSetScaleImageMap )
+ pGrfNd->SetScaleImageMap( true );
+ }
+
+ if( m_xAttrTab->pINetFormat )
+ {
+ const SwFormatINetFormat &rINetFormat =
+ static_cast<const SwFormatINetFormat&>(m_xAttrTab->pINetFormat->GetItem());
+
+ SwFormatURL aURL( pFlyFormat->GetURL() );
+
+ aURL.SetURL( rINetFormat.GetValue(), bIsMap );
+ aURL.SetTargetFrameName( rINetFormat.GetTargetFrame() );
+ aURL.SetName( rINetFormat.GetName() );
+ pFlyFormat->SetFormatAttr( aURL );
+
+ {
+ static const SvMacroItemId aEvents[] = {
+ SvMacroItemId::OnMouseOver,
+ SvMacroItemId::OnClick,
+ SvMacroItemId::OnMouseOut };
+
+ for( SvMacroItemId id : aEvents )
+ {
+ const SvxMacro *pMacro = rINetFormat.GetMacro( id );
+ if( nullptr != pMacro )
+ aMacroItem.SetMacro( id, *pMacro );
+ }
+ }
+
+ if ((RndStdIds::FLY_AS_CHAR == pFlyFormat->GetAnchor().GetAnchorId()) &&
+ m_xAttrTab->pINetFormat->GetStartParagraph() ==
+ m_pPam->GetPoint()->GetNode() &&
+ m_xAttrTab->pINetFormat->GetStartContent() ==
+ m_pPam->GetPoint()->GetContentIndex() - 1 )
+ {
+ // the attribute was insert right before as-character anchored
+ // graphic, therefore we move it
+ m_xAttrTab->pINetFormat->SetStart( *m_pPam->GetPoint() );
+
+ // When the attribute is also an anchor, we'll insert
+ // a bookmark before the graphic, because SwFormatURL
+ // isn't an anchor.
+ if( !rINetFormat.GetName().isEmpty() )
+ {
+ m_pPam->Move( fnMoveBackward );
+ InsertBookmark( rINetFormat.GetName() );
+ m_pPam->Move( fnMoveForward );
+ }
+ }
+
+ }
+ else if (!m_aEmbedURL.isEmpty())
+ {
+ // This is an inner <object> image and the outer <object> has a URL for us. Set that on the
+ // image.
+ SwFormatURL aURL(pFlyFormat->GetURL());
+ aURL.SetURL(m_aEmbedURL, bIsMap);
+ m_aEmbedURL.clear();
+ pFlyFormat->SetFormatAttr(aURL);
+ }
+
+ if( !aMacroItem.GetMacroTable().empty() )
+ {
+ NotifyMacroEventRead();
+ pFlyFormat->SetFormatAttr( aMacroItem );
+ }
+
+ // tdf#87083 If the graphic has not been loaded yet, then load it now.
+ // Otherwise it may be loaded during the first paint of the object and it
+ // will be too late to adapt the size of the graphic at that point.
+ if (bRequestGrfNow && pGrfNd)
+ {
+ Size aUpdatedSize = pGrfNd->GetTwipSize(); //trigger a swap-in
+ SAL_WARN_IF(!aUpdatedSize.Width() || !aUpdatedSize.Height(), "sw.html", "html image with no width or height");
+ }
+
+ // maybe create frames and register auto bound frames
+ RegisterFlyFrame( pFlyFormat );
+
+ if( !aId.isEmpty() )
+ InsertBookmark( aId );
+}
+
+/* */
+
+void SwHTMLParser::InsertBodyOptions()
+{
+ m_xDoc->SetTextFormatColl( *m_pPam,
+ m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_TEXT ) );
+
+ OUString aBackGround, aId, aStyle, aLang, aDir;
+ Color aBGColor, aTextColor, aLinkColor, aVLinkColor;
+ bool bBGColor=false, bTextColor=false;
+ bool bLinkColor=false, bVLinkColor=false;
+
+ ScriptType eDfltScriptType;
+ OUString sDfltScriptType;
+ GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
+
+ const HTMLOptions& rHTMLOptions = GetOptions();
+ for (size_t i = rHTMLOptions.size(); i; )
+ {
+ const HTMLOption& rOption = rHTMLOptions[--i];
+ ScriptType eScriptType2 = eDfltScriptType;
+ OUString aEvent;
+ bool bSetEvent = false;
+
+ switch( rOption.GetToken() )
+ {
+ case HtmlOptionId::ID:
+ aId = rOption.GetString();
+ break;
+ case HtmlOptionId::BACKGROUND:
+ aBackGround = rOption.GetString();
+ break;
+ case HtmlOptionId::BGCOLOR:
+ rOption.GetColor( aBGColor );
+ bBGColor = true;
+ break;
+ case HtmlOptionId::TEXT:
+ rOption.GetColor( aTextColor );
+ bTextColor = true;
+ break;
+ case HtmlOptionId::LINK:
+ rOption.GetColor( aLinkColor );
+ bLinkColor = true;
+ break;
+ case HtmlOptionId::VLINK:
+ rOption.GetColor( aVLinkColor );
+ bVLinkColor = true;
+ break;
+
+ case HtmlOptionId::SDONLOAD:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONLOAD:
+ aEvent = GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC );
+ bSetEvent = true;
+ break;
+
+ case HtmlOptionId::SDONUNLOAD:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONUNLOAD:
+ aEvent = GlobalEventConfig::GetEventName( GlobalEventId::PREPARECLOSEDOC );
+ bSetEvent = true;
+ break;
+
+ case HtmlOptionId::SDONFOCUS:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONFOCUS:
+ aEvent = GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC );
+ bSetEvent = true;
+ break;
+
+ case HtmlOptionId::SDONBLUR:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONBLUR:
+ aEvent = GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC );
+ bSetEvent = true;
+ break;
+
+ case HtmlOptionId::ONERROR:
+ break;
+
+ case HtmlOptionId::STYLE:
+ aStyle = rOption.GetString();
+ bTextColor = true;
+ break;
+ case HtmlOptionId::LANG:
+ aLang = rOption.GetString();
+ break;
+ case HtmlOptionId::DIR:
+ aDir = rOption.GetString();
+ break;
+ default: break;
+ }
+
+ if( bSetEvent )
+ {
+ const OUString& rEvent = rOption.GetString();
+ if( !rEvent.isEmpty() )
+ InsertBasicDocEvent( aEvent, rEvent, eScriptType2,
+ sDfltScriptType );
+ }
+ }
+
+ if( bTextColor && !m_pCSS1Parser->IsBodyTextSet() )
+ {
+ // The font colour is set in the default style
+ m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_STANDARD )
+ ->SetFormatAttr( SvxColorItem(aTextColor, RES_CHRATR_COLOR) );
+ m_pCSS1Parser->SetBodyTextSet();
+ }
+
+ // Prepare the items for the page style (background, frame)
+ // If BrushItem already set values must remain!
+ std::unique_ptr<SvxBrushItem> aBrushItem( m_pCSS1Parser->makePageDescBackground() );
+ bool bSetBrush = false;
+
+ if( bBGColor && !m_pCSS1Parser->IsBodyBGColorSet() )
+ {
+ // background colour from "BGCOLOR"
+ OUString aLink;
+ if( !aBrushItem->GetGraphicLink().isEmpty() )
+ aLink = aBrushItem->GetGraphicLink();
+ SvxGraphicPosition ePos = aBrushItem->GetGraphicPos();
+
+ aBrushItem->SetColor( aBGColor );
+
+ if( !aLink.isEmpty() )
+ {
+ aBrushItem->SetGraphicLink( aLink );
+ aBrushItem->SetGraphicPos( ePos );
+ }
+ bSetBrush = true;
+ m_pCSS1Parser->SetBodyBGColorSet();
+ }
+
+ if( !aBackGround.isEmpty() && !m_pCSS1Parser->IsBodyBackgroundSet() )
+ {
+ // background graphic from "BACKGROUND"
+ aBrushItem->SetGraphicLink( INetURLObject::GetAbsURL( m_sBaseURL, aBackGround ) );
+ aBrushItem->SetGraphicPos( GPOS_TILED );
+ bSetBrush = true;
+ m_pCSS1Parser->SetBodyBackgroundSet();
+ }
+
+ if( !aStyle.isEmpty() || !aDir.isEmpty() )
+ {
+ SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
+ SvxCSS1PropertyInfo aPropInfo;
+ OUString aDummy;
+ ParseStyleOptions( aStyle, aDummy, aDummy, aItemSet, aPropInfo, nullptr, &aDir );
+
+ // Some attributes have to set on the page style, in fact the ones
+ // which aren't inherited
+ m_pCSS1Parser->SetPageDescAttrs( bSetBrush ? aBrushItem.get() : nullptr,
+ &aItemSet );
+
+ static const TypedWhichId<SvxFontHeightItem> aWhichIds[3] = { RES_CHRATR_FONTSIZE,
+ RES_CHRATR_CJK_FONTSIZE,
+ RES_CHRATR_CTL_FONTSIZE };
+ for(auto const & i : aWhichIds)
+ {
+ const SvxFontHeightItem *pItem = aItemSet.GetItemIfSet( i, false );
+ if( pItem && pItem->GetProp() != 100)
+ {
+ sal_uInt32 nHeight =
+ ( m_aFontHeights[2] * pItem->GetProp() ) / 100;
+ SvxFontHeightItem aNewItem( nHeight, 100, i );
+ aItemSet.Put( aNewItem );
+ }
+ }
+
+ // all remaining options can be set on the default style
+ m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_STANDARD )
+ ->SetFormatAttr( aItemSet );
+ }
+ else if( bSetBrush )
+ {
+ m_pCSS1Parser->SetPageDescAttrs( aBrushItem.get() );
+ }
+
+ if( bLinkColor && !m_pCSS1Parser->IsBodyLinkSet() )
+ {
+ SwCharFormat *pCharFormat =
+ m_pCSS1Parser->GetCharFormatFromPool(RES_POOLCHR_INET_NORMAL);
+ pCharFormat->SetFormatAttr( SvxColorItem(aLinkColor, RES_CHRATR_COLOR) );
+ m_pCSS1Parser->SetBodyLinkSet();
+ }
+ if( bVLinkColor && !m_pCSS1Parser->IsBodyVLinkSet() )
+ {
+ SwCharFormat *pCharFormat =
+ m_pCSS1Parser->GetCharFormatFromPool(RES_POOLCHR_INET_VISIT);
+ pCharFormat->SetFormatAttr( SvxColorItem(aVLinkColor, RES_CHRATR_COLOR) );
+ m_pCSS1Parser->SetBodyVLinkSet();
+ }
+ if( !aLang.isEmpty() )
+ {
+ LanguageType eLang = LanguageTag::convertToLanguageTypeWithFallback( aLang );
+ if( LANGUAGE_DONTKNOW != eLang )
+ {
+ TypedWhichId<SvxLanguageItem> nWhich(0);
+ switch( SvtLanguageOptions::GetScriptTypeOfLanguage( eLang ) )
+ {
+ case SvtScriptType::LATIN:
+ nWhich = RES_CHRATR_LANGUAGE;
+ break;
+ case SvtScriptType::ASIAN:
+ nWhich = RES_CHRATR_CJK_LANGUAGE;
+ break;
+ case SvtScriptType::COMPLEX:
+ nWhich = RES_CHRATR_CTL_LANGUAGE;
+ break;
+ default: break;
+ }
+ if( nWhich )
+ {
+ SvxLanguageItem aLanguage( eLang, nWhich );
+ aLanguage.SetWhich( nWhich );
+ m_xDoc->SetDefault( aLanguage );
+ }
+ }
+ }
+
+ if( !aId.isEmpty() )
+ InsertBookmark( aId );
+}
+
+/* */
+
+void SwHTMLParser::NewAnchor()
+{
+ // end previous link if there was one
+ std::unique_ptr<HTMLAttrContext> xOldCntxt(PopContext(HtmlTokenId::ANCHOR_ON));
+ if (xOldCntxt)
+ {
+ // and maybe end attributes
+ EndContext(xOldCntxt.get());
+ }
+
+ SvxMacroTableDtor aMacroTable;
+ OUString sHRef, aName, sTarget;
+ OUString aId, aStyle, aClass, aLang, aDir;
+ bool bHasHRef = false, bFixed = false;
+
+ ScriptType eDfltScriptType;
+ OUString sDfltScriptType;
+ GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
+
+ const HTMLOptions& rHTMLOptions = GetOptions();
+ for (size_t i = rHTMLOptions.size(); i; )
+ {
+ SvMacroItemId nEvent = SvMacroItemId::NONE;
+ ScriptType eScriptType2 = eDfltScriptType;
+ const HTMLOption& rOption = rHTMLOptions[--i];
+ switch( rOption.GetToken() )
+ {
+ case HtmlOptionId::NAME:
+ aName = rOption.GetString();
+ break;
+
+ case HtmlOptionId::HREF:
+ sHRef = rOption.GetString();
+ bHasHRef = true;
+ break;
+ case HtmlOptionId::TARGET:
+ sTarget = rOption.GetString();
+ break;
+
+ case HtmlOptionId::STYLE:
+ aStyle = rOption.GetString();
+ break;
+ case HtmlOptionId::ID:
+ aId = rOption.GetString();
+ break;
+ case HtmlOptionId::CLASS:
+ aClass = rOption.GetString();
+ break;
+ case HtmlOptionId::SDFIXED:
+ bFixed = true;
+ break;
+ case HtmlOptionId::LANG:
+ aLang = rOption.GetString();
+ break;
+ case HtmlOptionId::DIR:
+ aDir = rOption.GetString();
+ break;
+
+ case HtmlOptionId::SDONCLICK:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONCLICK:
+ nEvent = SvMacroItemId::OnClick;
+ goto ANCHOR_SETEVENT;
+
+ case HtmlOptionId::SDONMOUSEOVER:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONMOUSEOVER:
+ nEvent = SvMacroItemId::OnMouseOver;
+ goto ANCHOR_SETEVENT;
+
+ case HtmlOptionId::SDONMOUSEOUT:
+ eScriptType2 = STARBASIC;
+ [[fallthrough]];
+ case HtmlOptionId::ONMOUSEOUT:
+ nEvent = SvMacroItemId::OnMouseOut;
+ goto ANCHOR_SETEVENT;
+ANCHOR_SETEVENT:
+ {
+ OUString sTmp( rOption.GetString() );
+ if( !sTmp.isEmpty() )
+ {
+ sTmp = convertLineEnd(sTmp, GetSystemLineEnd());
+ OUString sScriptType;
+ if( EXTENDED_STYPE == eScriptType2 )
+ sScriptType = sDfltScriptType;
+ aMacroTable.Insert( nEvent, SvxMacro( sTmp, sScriptType, eScriptType2 ));
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+
+ // Jump targets, which match our implicit targets,
+ // here we throw out rigorously.
+ if( !aName.isEmpty() )
+ {
+ OUString sDecoded( INetURLObject::decode( aName,
+ INetURLObject::DecodeMechanism::Unambiguous ));
+ sal_Int32 nPos = sDecoded.lastIndexOf( cMarkSeparator );
+ if( nPos != -1 )
+ {
+ OUString sCmp= sDecoded.copy(nPos+1).replaceAll(" ","");
+ if( !sCmp.isEmpty() )
+ {
+ sCmp = sCmp.toAsciiLowerCase();
+ if( sCmp == "region" ||
+ sCmp == "frame" ||
+ sCmp == "graphic" ||
+ sCmp == "ole" ||
+ sCmp == "table" ||
+ sCmp == "outline" ||
+ sCmp == "text" )
+ {
+ aName.clear();
+ }
+ }
+ }
+ }
+
+ // create a new context
+ std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(HtmlTokenId::ANCHOR_ON));
+
+ bool bEnAnchor = false, bFootnoteAnchor = false, bFootnoteEnSymbol = false;
+ OUString aFootnoteName;
+ OUString aStrippedClass( aClass );
+ SwCSS1Parser::GetScriptFromClass( aStrippedClass, false );
+ if( aStrippedClass.getLength() >=9 && bHasHRef && sHRef.getLength() > 1 &&
+ ('s' == aStrippedClass[0] || 'S' == aStrippedClass[0]) &&
+ ('d' == aStrippedClass[1] || 'D' == aStrippedClass[1]) )
+ {
+ if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdendnote_anc ) )
+ bEnAnchor = true;
+ else if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdfootnote_anc ) )
+ bFootnoteAnchor = true;
+ else if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdendnote_sym ) ||
+ aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdfootnote_sym ) )
+ bFootnoteEnSymbol = true;
+ if( bEnAnchor || bFootnoteAnchor || bFootnoteEnSymbol )
+ {
+ aFootnoteName = sHRef.copy( 1 );
+ aClass.clear();
+ aStrippedClass.clear();
+ aName.clear();
+ bHasHRef = false;
+ }
+ }
+
+ // Styles parsen
+ if( HasStyleOptions( aStyle, aId, aStrippedClass, &aLang, &aDir ) )
+ {
+ SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
+ SvxCSS1PropertyInfo aPropInfo;
+
+ if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
+ {
+ DoPositioning(aItemSet, aPropInfo, xCntxt.get());
+ InsertAttrs(aItemSet, aPropInfo, xCntxt.get(), true);
+ }
+ }
+
+ if( bHasHRef )
+ {
+ if( !sHRef.isEmpty() )
+ {
+ sHRef = URIHelper::SmartRel2Abs( INetURLObject(m_sBaseURL), sHRef, Link<OUString *, bool>(), false );
+ }
+ else
+ {
+ // use directory if empty URL
+ INetURLObject aURLObj( m_aPathToFile );
+ sHRef = aURLObj.GetPartBeforeLastName();
+ }
+
+ m_pCSS1Parser->SetATagStyles();
+ SwFormatINetFormat aINetFormat( sHRef, sTarget );
+ aINetFormat.SetName( aName );
+
+ if( !aMacroTable.empty() )
+ {
+ NotifyMacroEventRead();
+ aINetFormat.SetMacroTable( &aMacroTable );
+ }
+
+ // set the default attribute
+ InsertAttr(&m_xAttrTab->pINetFormat, aINetFormat, xCntxt.get());
+ }
+ else if( !aName.isEmpty() )
+ {
+ InsertBookmark( aName );
+ }
+
+ if( bEnAnchor || bFootnoteAnchor )
+ {
+ InsertFootEndNote( aFootnoteName, bEnAnchor, bFixed );
+ m_bInFootEndNoteAnchor = m_bCallNextToken = true;
+ }
+ else if( bFootnoteEnSymbol )
+ {
+ m_bInFootEndNoteSymbol = m_bCallNextToken = true;
+ }
+
+ // save context
+ PushContext(xCntxt);
+}
+
+void SwHTMLParser::EndAnchor()
+{
+ if( m_bInFootEndNoteAnchor )
+ {
+ FinishFootEndNote();
+ m_bInFootEndNoteAnchor = false;
+ }
+ else if( m_bInFootEndNoteSymbol )
+ {
+ m_bInFootEndNoteSymbol = false;
+ }
+
+ EndTag( HtmlTokenId::ANCHOR_OFF );
+}
+
+/* */
+
+void SwHTMLParser::InsertBookmark( const OUString& rName )
+{
+ HTMLAttr* pTmp = new HTMLAttr( *m_pPam->GetPoint(),
+ SfxStringItem(RES_FLTR_BOOKMARK, rName), nullptr, std::shared_ptr<HTMLAttrTable>());
+ m_aSetAttrTab.push_back( pTmp );
+}
+
+bool SwHTMLParser::HasCurrentParaBookmarks( bool bIgnoreStack ) const
+{
+ bool bHasMarks = false;
+ SwNodeOffset nNodeIdx = m_pPam->GetPoint()->GetNodeIndex();
+
+ // first step: are there still bookmark in the attribute-stack?
+ // bookmarks are added to the end of the stack - thus we only have
+ // to check the last bookmark
+ if( !bIgnoreStack )
+ {
+ for( auto i = m_aSetAttrTab.size(); i; )
+ {
+ HTMLAttr* pAttr = m_aSetAttrTab[ --i ];
+ if( RES_FLTR_BOOKMARK == pAttr->m_pItem->Which() )
+ {
+ if( pAttr->GetStartParagraphIdx() == nNodeIdx )
+ bHasMarks = true;
+ break;
+ }
+ }
+ }
+
+ if( !bHasMarks )
+ {
+ // second step: when we didn't find a bookmark, check if there is one set already
+ IDocumentMarkAccess* const pMarkAccess = m_xDoc->getIDocumentMarkAccess();
+ for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
+ ppMark != pMarkAccess->getAllMarksEnd();
+ ++ppMark)
+ {
+ const ::sw::mark::IMark* pBookmark = *ppMark;
+
+ const SwNodeOffset nBookNdIdx = pBookmark->GetMarkPos().GetNodeIndex();
+ if( nBookNdIdx==nNodeIdx )
+ {
+ bHasMarks = true;
+ break;
+ }
+ else if( nBookNdIdx > nNodeIdx )
+ break;
+ }
+ }
+
+ return bHasMarks;
+}
+
+/* */
+
+void SwHTMLParser::StripTrailingPara()
+{
+ bool bSetSmallFont = false;
+
+ SwContentNode* pCNd = m_pPam->GetPointContentNode();
+ SwNodeOffset nNodeIdx = m_pPam->GetPoint()->GetNodeIndex();
+ if( !m_pPam->GetPoint()->GetContentIndex() )
+ {
+ if( pCNd && pCNd->StartOfSectionIndex() + 2 <
+ pCNd->EndOfSectionIndex() && CanRemoveNode(nNodeIdx))
+ {
+
+ for(sw::SpzFrameFormat* pSpz: *m_xDoc->GetSpzFrameFormats())
+ {
+ SwFormatAnchor const*const pAnchor = &pSpz->GetAnchor();
+ SwNode const*const pAnchorNode = pAnchor->GetAnchorNode();
+ if (pAnchorNode &&
+ ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
+ (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
+ pAnchorNode->GetIndex() == nNodeIdx )
+
+ return; // we can't delete the node
+ }
+
+ SetAttr( false ); // the still open attributes must be
+ // closed before the node is deleted,
+ // otherwise the last index is dangling
+
+ if( pCNd->Len() && pCNd->IsTextNode() )
+ {
+ // fields were inserted into the node, now they have
+ // to be moved
+ SwTextNode *pPrvNd = m_xDoc->GetNodes()[nNodeIdx-1]->GetTextNode();
+ if( pPrvNd )
+ {
+ SwContentIndex aSrc( pCNd, 0 );
+ pCNd->GetTextNode()->CutText( pPrvNd, aSrc, pCNd->Len() );
+ }
+ }
+
+ // now we have to move maybe existing bookmarks
+ IDocumentMarkAccess* const pMarkAccess = m_xDoc->getIDocumentMarkAccess();
+ for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
+ ppMark != pMarkAccess->getAllMarksEnd();
+ ++ppMark)
+ {
+ ::sw::mark::IMark* pMark = *ppMark;
+
+ SwNodeOffset nBookNdIdx = pMark->GetMarkPos().GetNodeIndex();
+ if(nBookNdIdx==nNodeIdx)
+ {
+ SwNodeIndex nNewNdIdx(m_pPam->GetPoint()->GetNode());
+ SwContentNode* pNd = SwNodes::GoPrevious(&nNewNdIdx);
+ if(!pNd)
+ {
+ OSL_ENSURE(false, "Oops, where is my predecessor node?");
+ return;
+ }
+ // #i81002# - refactoring
+ // Do not directly manipulate member of <SwBookmark>
+ {
+ const SwPaM aPaM(*pNd, pNd->Len());
+ pMarkAccess->repositionMark(*ppMark, aPaM);
+ }
+ }
+ else if( nBookNdIdx > nNodeIdx )
+ break;
+ }
+
+ SwNode& rDelNode = m_pPam->GetPoint()->GetNode();
+ m_pPam->Move( fnMoveBackward, GoInNode );
+ m_pPam->SetMark();
+ m_pPam->DeleteMark();
+ m_xDoc->GetNodes().Delete( rDelNode );
+ }
+ else if (pCNd && pCNd->IsTextNode() && m_xTable)
+ {
+ // In empty cells we set a small font, so that the cell doesn't
+ // get higher than the graphic resp. as low as possible.
+ bSetSmallFont = true;
+ }
+ }
+ else if( pCNd && pCNd->IsTextNode() && m_xTable &&
+ pCNd->StartOfSectionIndex()+2 ==
+ pCNd->EndOfSectionIndex() )
+ {
+ // When the cell contains only as-character anchored graphics/frames,
+ // then we also set a small font.
+ bSetSmallFont = true;
+ SwTextNode* pTextNd = pCNd->GetTextNode();
+
+ sal_Int32 nPos = m_pPam->GetPoint()->GetContentIndex();
+ while( bSetSmallFont && nPos>0 )
+ {
+ --nPos;
+ bSetSmallFont =
+ (CH_TXTATR_BREAKWORD == pTextNd->GetText()[nPos]) &&
+ (nullptr != pTextNd->GetTextAttrForCharAt( nPos, RES_TXTATR_FLYCNT ));
+ }
+ }
+
+ if( bSetSmallFont )
+ {
+ // Added default to CJK and CTL
+ SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
+ pCNd->SetAttr( aFontHeight );
+ SvxFontHeightItem aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE );
+ pCNd->SetAttr( aFontHeightCJK );
+ SvxFontHeightItem aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE );
+ pCNd->SetAttr( aFontHeightCTL );
+ }
+}
+
+void SwHTMLParser::NotifyMacroEventRead()
+{
+ if (m_bNotifyMacroEventRead)
+ return;
+ SwDocShell *pDocSh = m_xDoc->GetDocShell();
+ if (!pDocSh)
+ return;
+ uno::Reference<frame::XModel> const xModel(pDocSh->GetBaseModel());
+ comphelper::DocumentInfo::notifyMacroEventRead(xModel);
+ m_bNotifyMacroEventRead = true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */