summaryrefslogtreecommitdiffstats
path: root/sw/source/filter/html/htmlflywriter.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/html/htmlflywriter.cxx')
-rw-r--r--sw/source/filter/html/htmlflywriter.cxx2257
1 files changed, 2257 insertions, 0 deletions
diff --git a/sw/source/filter/html/htmlflywriter.cxx b/sw/source/filter/html/htmlflywriter.cxx
new file mode 100644
index 0000000000..ef3e4b19c3
--- /dev/null
+++ b/sw/source/filter/html/htmlflywriter.cxx
@@ -0,0 +1,2257 @@
+/* -*- 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 <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <hintids.hxx>
+#include <tools/fract.hxx>
+#include <svl/urihelper.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/event.hxx>
+#include <svtools/htmlkywd.hxx>
+#include <svtools/htmlout.hxx>
+#include <svtools/htmltokn.h>
+#include <vcl/imap.hxx>
+#include <vcl/imapobj.hxx>
+#include <svtools/htmlcfg.hxx>
+#include <svtools/HtmlWriter.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/xoutbmp.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <svx/svdograf.hxx>
+#include <comphelper/xmlencode.hxx>
+
+#include <fmtanchr.hxx>
+#include <fmtornt.hxx>
+#include <fmturl.hxx>
+#include <fmtfsize.hxx>
+#include <fmtclds.hxx>
+#include <fmtcntnt.hxx>
+#include <fmtsrnd.hxx>
+#include <fmtinfmt.hxx>
+#include <txtinet.hxx>
+#include <frmatr.hxx>
+#include <grfatr.hxx>
+#include <flypos.hxx>
+#include <ndgrf.hxx>
+
+#include <doc.hxx>
+#include <ndtxt.hxx>
+#include <pam.hxx>
+#include <swerror.h>
+#include <frmfmt.hxx>
+#include "wrthtml.hxx"
+#include "htmlatr.hxx"
+#include "htmlfly.hxx"
+#include "htmlreqifreader.hxx"
+
+using namespace css;
+
+const HtmlFrmOpts HTML_FRMOPTS_IMG_ALL =
+ HtmlFrmOpts::Alt |
+ HtmlFrmOpts::Size |
+ HtmlFrmOpts::AnySize |
+ HtmlFrmOpts::Border |
+ HtmlFrmOpts::Name;
+const HtmlFrmOpts HTML_FRMOPTS_IMG_CNTNR =
+ HTML_FRMOPTS_IMG_ALL |
+ HtmlFrmOpts::AbsSize;
+const HtmlFrmOpts HTML_FRMOPTS_IMG =
+ HTML_FRMOPTS_IMG_ALL |
+ HtmlFrmOpts::Align |
+ HtmlFrmOpts::Space |
+ HtmlFrmOpts::BrClear;
+const HtmlFrmOpts HTML_FRMOPTS_IMG_CSS1 =
+ HtmlFrmOpts::SAlign |
+ HtmlFrmOpts::SSpace;
+
+const HtmlFrmOpts HTML_FRMOPTS_DIV =
+ HtmlFrmOpts::Id |
+ HtmlFrmOpts::SAlign |
+ HtmlFrmOpts::SSize |
+ HtmlFrmOpts::AnySize |
+ HtmlFrmOpts::AbsSize |
+ HtmlFrmOpts::SSpace |
+ HtmlFrmOpts::SBorder |
+ HtmlFrmOpts::SBackground |
+ HtmlFrmOpts::BrClear |
+ HtmlFrmOpts::Dir;
+
+const HtmlFrmOpts HTML_FRMOPTS_MULTICOL =
+ HtmlFrmOpts::Id |
+ HtmlFrmOpts::Width |
+ HtmlFrmOpts::AnySize |
+ HtmlFrmOpts::AbsSize |
+ HtmlFrmOpts::Dir;
+
+const HtmlFrmOpts HTML_FRMOPTS_MULTICOL_CSS1 =
+ HtmlFrmOpts::SAlign |
+ HtmlFrmOpts::SSize |
+ HtmlFrmOpts::SSpace |
+ HtmlFrmOpts::SBorder|
+ HtmlFrmOpts::SBackground;
+
+const HtmlFrmOpts HTML_FRMOPTS_SPACER =
+ HtmlFrmOpts::Align |
+ HtmlFrmOpts::Size |
+ HtmlFrmOpts::AnySize |
+ HtmlFrmOpts::BrClear |
+ HtmlFrmOpts::MarginSize |
+ HtmlFrmOpts::AbsSize;
+
+const HtmlFrmOpts HTML_FRMOPTS_CNTNR =
+ HtmlFrmOpts::SAlign |
+ HtmlFrmOpts::SSpace |
+ HtmlFrmOpts::SWidth |
+ HtmlFrmOpts::AnySize |
+ HtmlFrmOpts::AbsSize |
+ HtmlFrmOpts::SPixSize;
+
+static SwHTMLWriter& OutHTML_FrameFormatTableNode( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat );
+static SwHTMLWriter& OutHTML_FrameFormatAsMulticol( SwHTMLWriter& rWrt, const SwFrameFormat& rFormat,
+ bool bInCntnr );
+static SwHTMLWriter& OutHTML_FrameFormatAsSpacer( SwHTMLWriter& rWrt, const SwFrameFormat& rFormat );
+static SwHTMLWriter& OutHTML_FrameFormatAsDivOrSpan( SwHTMLWriter& rWrt,
+ const SwFrameFormat& rFrameFormat, bool bSpan );
+static SwHTMLWriter& OutHTML_FrameFormatAsImage( SwHTMLWriter& rWrt, const SwFrameFormat& rFormat, bool bPNGFallback );
+
+static SwHTMLWriter& OutHTML_FrameFormatGrfNode( SwHTMLWriter& rWrt, const SwFrameFormat& rFormat,
+ bool bInCntnr, bool bPNGFallback );
+
+static SwHTMLWriter& OutHTML_FrameFormatAsMarquee( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat,
+ const SdrObject& rSdrObj );
+
+HTMLOutEvent const aImageEventTable[] =
+{
+ { OOO_STRING_SVTOOLS_HTML_O_SDonload, OOO_STRING_SVTOOLS_HTML_O_onload, SvMacroItemId::OnImageLoadDone },
+ { OOO_STRING_SVTOOLS_HTML_O_SDonabort, OOO_STRING_SVTOOLS_HTML_O_onabort, SvMacroItemId::OnImageLoadCancel },
+ { OOO_STRING_SVTOOLS_HTML_O_SDonerror, OOO_STRING_SVTOOLS_HTML_O_onerror, SvMacroItemId::OnImageLoadError },
+ { nullptr, nullptr, SvMacroItemId::NONE }
+};
+
+HTMLOutEvent const aIMapEventTable[] =
+{
+ { OOO_STRING_SVTOOLS_HTML_O_SDonmouseover, OOO_STRING_SVTOOLS_HTML_O_onmouseover, SvMacroItemId::OnMouseOver },
+ { OOO_STRING_SVTOOLS_HTML_O_SDonmouseout, OOO_STRING_SVTOOLS_HTML_O_onmouseout, SvMacroItemId::OnMouseOut },
+ { nullptr, nullptr, SvMacroItemId::NONE }
+};
+
+SwHTMLFrameType SwHTMLWriter::GuessFrameType( const SwFrameFormat& rFrameFormat,
+ const SdrObject*& rpSdrObj )
+{
+ SwHTMLFrameType eType;
+
+ if( RES_DRAWFRMFMT == rFrameFormat.Which() )
+ {
+ // use an arbitrary draw object as the default value
+ eType = HTML_FRMTYPE_DRAW;
+
+ const SdrObject *pObj =
+ SwHTMLWriter::GetMarqueeTextObj( static_cast<const SwDrawFrameFormat &>(rFrameFormat) );
+ if( pObj )
+ {
+ // scrolling text
+ rpSdrObj = pObj;
+ eType = HTML_FRMTYPE_MARQUEE;
+ }
+ else
+ {
+ pObj = GetHTMLControl( static_cast<const SwDrawFrameFormat &>(rFrameFormat) );
+
+ if( pObj )
+ {
+ // Form control
+ rpSdrObj = pObj;
+ eType = HTML_FRMTYPE_CONTROL;
+ }
+ }
+ }
+ else
+ {
+ // use a text frame as the default value
+ eType = HTML_FRMTYPE_TEXT;
+
+ const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
+ SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex()+1;
+ const SwNode* pNd = m_pDoc->GetNodes()[ nStt ];
+
+ if( pNd->IsGrfNode() )
+ {
+ // graphic node
+ eType = HTML_FRMTYPE_GRF;
+ }
+ else if( pNd->IsOLENode() )
+ {
+ // applet, plugin, floating frame
+ eType = GuessOLENodeFrameType( *pNd );
+ }
+ else
+ {
+ SwNodeOffset nEnd = m_pDoc->GetNodes()[nStt-1]->EndOfSectionIndex();
+
+ const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
+ const SwFormatCol* pFormatCol = rItemSet.GetItemIfSet( RES_COL );
+ if( pFormatCol && pFormatCol->GetNumCols() > 1 )
+ {
+ // frame with columns
+ eType = HTML_FRMTYPE_MULTICOL;
+ }
+ else if( pNd->IsTableNode() )
+ {
+ const SwTableNode *pTableNd = pNd->GetTableNode();
+ SwNodeOffset nTableEnd = pTableNd->EndOfSectionIndex();
+
+ if( nTableEnd+1 == nEnd )
+ {
+ // table
+ eType = HTML_FRMTYPE_TABLE;
+ }
+ else if( nTableEnd+2 == nEnd )
+ {
+ // table with caption
+ eType = HTML_FRMTYPE_TABLE_CAP;
+ }
+ }
+ else if( pNd->IsTextNode() )
+ {
+ const SwTextNode *pTextNd = pNd->GetTextNode();
+
+ bool bEmpty = false;
+ if( nStt==nEnd-1 && !pTextNd->Len() )
+ {
+ // empty frame? Only if no frame is
+ // anchored to the text or start node.
+ bEmpty = true;
+ for( auto & pHTMLPosFlyFrame : m_aHTMLPosFlyFrames )
+ {
+ SwNodeOffset nIdx = pHTMLPosFlyFrame->GetNdIndex().GetIndex();
+ bEmpty = (nIdx != nStt) && (nIdx != nStt-1);
+ if( !bEmpty || nIdx > nStt )
+ break;
+ }
+ }
+ if( bEmpty )
+ {
+ std::unique_ptr<SvxBrushItem> aBrush = rFrameFormat.makeBackgroundBrushItem();
+ /// background is not empty, if it has a background graphic
+ /// or its background color is not "no fill"/"auto fill".
+ if( GPOS_NONE != aBrush->GetGraphicPos() ||
+ aBrush->GetColor() != COL_TRANSPARENT )
+ {
+ bEmpty = false;
+ }
+ }
+ if( bEmpty )
+ {
+ // empty frame
+ eType = HTML_FRMTYPE_EMPTY;
+ }
+ else if( m_pDoc->GetNodes()[nStt+1]->IsTableNode() )
+ {
+ const SwTableNode *pTableNd =
+ m_pDoc->GetNodes()[nStt+1]->GetTableNode();
+ if( pTableNd->EndOfSectionIndex()+1 == nEnd )
+ {
+ // table with heading
+ eType = HTML_FRMTYPE_TABLE_CAP;
+ }
+ }
+ }
+ }
+ }
+
+ return eType;
+}
+
+void SwHTMLWriter::CollectFlyFrames()
+{
+ SwPosFlyFrames aFlyPos(
+ m_pDoc->GetAllFlyFormats(m_bWriteAll ? nullptr : m_pCurrentPam.get(), true));
+
+ for(const SwPosFlyFrame& rItem : aFlyPos)
+ {
+ const SwFrameFormat& rFrameFormat = rItem.GetFormat();
+ const SdrObject *pSdrObj = nullptr;
+ const SwNode *pAnchorNode;
+ const SwContentNode *pACNd;
+ SwHTMLFrameType eType = GuessFrameType( rFrameFormat, pSdrObj );
+
+ AllHtmlFlags nMode;
+ const SwFormatAnchor& rAnchor = rFrameFormat.GetAnchor();
+ sal_Int16 eHoriRel = rFrameFormat.GetHoriOrient().GetRelationOrient();
+ switch( rAnchor.GetAnchorId() )
+ {
+ case RndStdIds::FLY_AT_PAGE:
+ case RndStdIds::FLY_AT_FLY:
+ nMode = getHTMLOutFramePageFlyTable(eType, m_nExportMode);
+ break;
+
+ case RndStdIds::FLY_AT_PARA:
+ // frames that are anchored to a paragraph are only placed
+ // before the paragraph, if the paragraph has a
+ // spacing.
+ if( text::RelOrientation::FRAME == eHoriRel &&
+ (pAnchorNode = rAnchor.GetAnchorNode()) != nullptr &&
+ (pACNd = pAnchorNode->GetContentNode()) != nullptr )
+ {
+ const SvxTextLeftMarginItem& rTextLeftMargin =
+ pACNd->GetAttr(RES_MARGIN_TEXTLEFT);
+ const SvxRightMarginItem& rRightMargin =
+ pACNd->GetAttr(RES_MARGIN_RIGHT);
+ if (rTextLeftMargin.GetTextLeft() || rRightMargin.GetRight())
+ {
+ nMode = getHTMLOutFrameParaFrameTable(eType, m_nExportMode);
+ break;
+ }
+ }
+ nMode = getHTMLOutFrameParaPrtAreaTable(eType, m_nExportMode);
+ break;
+
+ case RndStdIds::FLY_AT_CHAR:
+ if( text::RelOrientation::FRAME == eHoriRel || text::RelOrientation::PRINT_AREA == eHoriRel )
+ nMode = getHTMLOutFrameParaPrtAreaTable(eType, m_nExportMode);
+ else
+ nMode = getHTMLOutFrameParaOtherTable(eType, m_nExportMode);
+ break;
+
+ default:
+ nMode = getHTMLOutFrameParaPrtAreaTable(eType, m_nExportMode);
+ break;
+ }
+
+ m_aHTMLPosFlyFrames.insert( std::make_unique<SwHTMLPosFlyFrame>(rItem, pSdrObj, nMode) );
+ }
+}
+
+bool SwHTMLWriter::OutFlyFrame( SwNodeOffset nNdIdx, sal_Int32 nContentIdx, HtmlPosition nPos )
+{
+ bool bFlysLeft = false; // Are there still Flys left at the current node position?
+
+ // OutFlyFrame can be called recursively. Thus, sometimes it is
+ // necessary to start over after a Fly was returned.
+ bool bRestart = true;
+ while( !m_aHTMLPosFlyFrames.empty() && bRestart )
+ {
+ bFlysLeft = bRestart = false;
+
+ // search for the beginning of the FlyFrames
+ size_t i {0};
+
+ for( ; i < m_aHTMLPosFlyFrames.size() &&
+ m_aHTMLPosFlyFrames[i]->GetNdIndex().GetIndex() < nNdIdx; i++ )
+ ;
+ for( ; !bRestart && i < m_aHTMLPosFlyFrames.size() &&
+ m_aHTMLPosFlyFrames[i]->GetNdIndex().GetIndex() == nNdIdx; i++ )
+ {
+ SwHTMLPosFlyFrame *pPosFly = m_aHTMLPosFlyFrames[i].get();
+ if( ( HtmlPosition::Any == nPos ||
+ pPosFly->GetOutPos() == nPos ) &&
+ pPosFly->GetContentIndex() == nContentIdx )
+ {
+ // It is important to remove it first, because additional
+ // elements or the whole array could be deleted on
+ // deeper recursion levels.
+ std::unique_ptr<SwHTMLPosFlyFrame> flyHolder = m_aHTMLPosFlyFrames.erase_extract(i);
+ i--;
+ if( m_aHTMLPosFlyFrames.empty() )
+ {
+ bRestart = true; // not really, only exit the loop
+ }
+
+ HTMLOutFuncs::FlushToAscii(Strm()); // it was one time only; do we still need it?
+
+ OutFrameFormat( pPosFly->GetOutMode(), pPosFly->GetFormat(),
+ pPosFly->GetSdrObject() );
+ switch( pPosFly->GetOutFn() )
+ {
+ case HtmlOut::Div:
+ case HtmlOut::Span:
+ case HtmlOut::MultiCol:
+ case HtmlOut::TableNode:
+ bRestart = true; // It could become recursive here
+ break;
+ default: break;
+ }
+ }
+ else
+ {
+ bFlysLeft = true;
+ }
+ }
+ }
+
+ return bFlysLeft;
+}
+
+void SwHTMLWriter::OutFrameFormat( AllHtmlFlags nMode, const SwFrameFormat& rFrameFormat,
+ const SdrObject *pSdrObject )
+{
+ HtmlContainerFlags nCntnrMode = nMode.nContainer;
+ HtmlOut nOutMode = nMode.nOut;
+ OString aContainerStr;
+ if( HtmlContainerFlags::NONE != nCntnrMode )
+ {
+
+ if (IsLFPossible() && HtmlContainerFlags::Div == nCntnrMode)
+ OutNewLine();
+
+ OStringBuffer sOut;
+ aContainerStr = (HtmlContainerFlags::Div == nCntnrMode)
+ ? OOO_STRING_SVTOOLS_HTML_division
+ : OOO_STRING_SVTOOLS_HTML_span;
+ sOut.append("<" + GetNamespace() + aContainerStr + " "
+ OOO_STRING_SVTOOLS_HTML_O_class "=\""
+ "sd-abs-pos\"");
+ Strm().WriteOString( sOut );
+ sOut.setLength(0);
+
+ // Output a width for non-draw objects
+ HtmlFrmOpts nFrameFlags = HTML_FRMOPTS_CNTNR;
+
+ // For frames with columns we can also output the background
+ if( HtmlOut::MultiCol == nOutMode )
+ nFrameFlags |= HtmlFrmOpts::SBackground|HtmlFrmOpts::SBorder;
+
+ if( IsHTMLMode( HTMLMODE_BORDER_NONE ) )
+ nFrameFlags |= HtmlFrmOpts::SNoBorder;
+ OutCSS1_FrameFormatOptions( rFrameFormat, nFrameFlags, pSdrObject );
+ Strm().WriteChar( '>' );
+
+ if( HtmlContainerFlags::Div == nCntnrMode )
+ {
+ IncIndentLevel();
+ SetLFPossible(true);
+ }
+ }
+
+ switch( nOutMode )
+ {
+ case HtmlOut::TableNode: // OK
+ OSL_ENSURE( aContainerStr.isEmpty(), "Table: Container is not supposed to be here" );
+ OutHTML_FrameFormatTableNode( *this, rFrameFormat );
+ break;
+ case HtmlOut::GraphicNode: // OK
+ OutHTML_FrameFormatGrfNode( *this, rFrameFormat, !aContainerStr.isEmpty(), /*bPNGFallback=*/true );
+ break;
+ case HtmlOut::OleNode: // OK
+ OutHTML_FrameFormatOLENode( *this, rFrameFormat, !aContainerStr.isEmpty() );
+ break;
+ case HtmlOut::OleGraphic: // OK
+ OutHTML_FrameFormatOLENodeGrf( *this, rFrameFormat, !aContainerStr.isEmpty() );
+ break;
+ case HtmlOut::Div:
+ case HtmlOut::Span:
+ OSL_ENSURE( aContainerStr.isEmpty(), "Div: Container is not supposed to be here" );
+ OutHTML_FrameFormatAsDivOrSpan( *this, rFrameFormat, HtmlOut::Span==nOutMode );
+ break;
+ case HtmlOut::MultiCol: // OK
+ OutHTML_FrameFormatAsMulticol( *this, rFrameFormat, !aContainerStr.isEmpty() );
+ break;
+ case HtmlOut::Spacer: // OK
+ OSL_ENSURE( aContainerStr.isEmpty(), "Spacer: Container is not supposed to be here" );
+ OutHTML_FrameFormatAsSpacer( *this, rFrameFormat );
+ break;
+ case HtmlOut::Control: // OK
+ OutHTML_DrawFrameFormatAsControl( *this,
+ static_cast<const SwDrawFrameFormat &>(rFrameFormat), dynamic_cast<const SdrUnoObj&>(*pSdrObject),
+ !aContainerStr.isEmpty() );
+ break;
+ case HtmlOut::AMarquee:
+ OutHTML_FrameFormatAsMarquee( *this, rFrameFormat, *pSdrObject );
+ break;
+ case HtmlOut::Marquee:
+ OSL_ENSURE( aContainerStr.isEmpty(), "Marquee: Container is not supposed to be here" );
+ OutHTML_DrawFrameFormatAsMarquee( *this,
+ static_cast<const SwDrawFrameFormat &>(rFrameFormat), *pSdrObject );
+ break;
+ case HtmlOut::GraphicFrame:
+ OutHTML_FrameFormatAsImage( *this, rFrameFormat, /*bPNGFallback=*/true );
+ break;
+ }
+
+ if( HtmlContainerFlags::Div == nCntnrMode )
+ {
+ DecIndentLevel();
+ if (IsLFPossible())
+ OutNewLine();
+ HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
+ SetLFPossible(true);
+ }
+ else if( HtmlContainerFlags::Span == nCntnrMode )
+ HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false );
+}
+
+OString SwHTMLWriter::OutFrameFormatOptions( const SwFrameFormat &rFrameFormat,
+ const OUString& rAlternateText,
+ HtmlFrmOpts nFrameOpts )
+{
+ OString sRetEndTags;
+ OStringBuffer sOut;
+ const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
+
+ // Name
+ if( (nFrameOpts & (HtmlFrmOpts::Id|HtmlFrmOpts::Name)) &&
+ !rFrameFormat.GetName().isEmpty() )
+ {
+ const char *pStr =
+ (nFrameOpts & HtmlFrmOpts::Id) ? OOO_STRING_SVTOOLS_HTML_O_id : OOO_STRING_SVTOOLS_HTML_O_name;
+ sOut.append(OString::Concat(" ") + pStr + "=\"");
+ Strm().WriteOString( sOut );
+ sOut.setLength(0);
+ HTMLOutFuncs::Out_String( Strm(), rFrameFormat.GetName() );
+ sOut.append('\"');
+ }
+
+ // Name
+ if( nFrameOpts & HtmlFrmOpts::Dir )
+ {
+ SvxFrameDirection nDir = GetHTMLDirection( rItemSet );
+ Strm().WriteOString( sOut );
+ sOut.setLength(0);
+ OutDirection( nDir );
+ }
+
+ // ALT
+ if( (nFrameOpts & HtmlFrmOpts::Alt) && !rAlternateText.isEmpty() )
+ {
+ sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_alt "=\"");
+ Strm().WriteOString( sOut );
+ sOut.setLength(0);
+ HTMLOutFuncs::Out_String( Strm(), rAlternateText );
+ sOut.append('\"');
+ }
+
+ // ALIGN
+ const char *pStr = nullptr;
+ RndStdIds eAnchorId = rFrameFormat.GetAnchor().GetAnchorId();
+ if( (nFrameOpts & HtmlFrmOpts::Align) &&
+ ((RndStdIds::FLY_AT_PARA == eAnchorId) || (RndStdIds::FLY_AT_CHAR == eAnchorId)) )
+ {
+ // MIB 12.3.98: Wouldn't it be more clever to left-align frames that
+ // are anchored to a paragraph if necessary, instead of inserting them
+ // as being anchored to characters?
+ const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient();
+ if( !(nFrameOpts & HtmlFrmOpts::SAlign) ||
+ text::RelOrientation::FRAME == rHoriOri.GetRelationOrient() ||
+ text::RelOrientation::PRINT_AREA == rHoriOri.GetRelationOrient() )
+ {
+ pStr = text::HoriOrientation::RIGHT == rHoriOri.GetHoriOrient()
+ ? OOO_STRING_SVTOOLS_HTML_AL_right
+ : OOO_STRING_SVTOOLS_HTML_AL_left;
+ }
+ }
+ const SwFormatVertOrient* pVertOrient;
+ if( (nFrameOpts & HtmlFrmOpts::Align) && !pStr &&
+ ( !(nFrameOpts & HtmlFrmOpts::SAlign) ||
+ (RndStdIds::FLY_AS_CHAR == eAnchorId) ) &&
+ (pVertOrient = rItemSet.GetItemIfSet( RES_VERT_ORIENT )) )
+ {
+ switch( pVertOrient->GetVertOrient() )
+ {
+ case text::VertOrientation::LINE_TOP: pStr = OOO_STRING_SVTOOLS_HTML_VA_top; break;
+ case text::VertOrientation::CHAR_TOP:
+ case text::VertOrientation::BOTTOM: pStr = OOO_STRING_SVTOOLS_HTML_VA_texttop; break; // not possible
+ case text::VertOrientation::LINE_CENTER:
+ case text::VertOrientation::CHAR_CENTER: pStr = OOO_STRING_SVTOOLS_HTML_VA_absmiddle; break; // not possible
+ case text::VertOrientation::CENTER: pStr = OOO_STRING_SVTOOLS_HTML_VA_middle; break;
+ case text::VertOrientation::LINE_BOTTOM:
+ case text::VertOrientation::CHAR_BOTTOM: pStr = OOO_STRING_SVTOOLS_HTML_VA_absbottom; break; // not possible
+ case text::VertOrientation::TOP: pStr = OOO_STRING_SVTOOLS_HTML_VA_bottom; break;
+ case text::VertOrientation::NONE: break;
+ }
+ }
+ if( pStr )
+ {
+ sOut.append(OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_align "=\"") +
+ pStr + "\"");
+ }
+
+ // HSPACE and VSPACE
+ Size aTwipSpc( 0, 0 );
+ const SvxLRSpaceItem* pLRSpaceItem;
+ if( (nFrameOpts & (HtmlFrmOpts::Space|HtmlFrmOpts::MarginSize)) &&
+ (pLRSpaceItem = rItemSet.GetItemIfSet( RES_LR_SPACE )) )
+ {
+ aTwipSpc.setWidth(
+ ( pLRSpaceItem->GetLeft() + pLRSpaceItem->GetRight() ) / 2 );
+ m_nDfltLeftMargin = m_nDfltRightMargin = aTwipSpc.Width();
+ }
+ const SvxULSpaceItem* pULSpaceItem;
+ if( (nFrameOpts & (HtmlFrmOpts::Space|HtmlFrmOpts::MarginSize)) &&
+ (pULSpaceItem = rItemSet.GetItemIfSet( RES_UL_SPACE )) )
+ {
+ aTwipSpc.setHeight(
+ ( pULSpaceItem->GetUpper() + pULSpaceItem->GetLower() ) / 2 );
+ m_nDfltTopMargin = m_nDfltBottomMargin = o3tl::narrowing<sal_uInt16>(aTwipSpc.Height());
+ }
+
+ if( (nFrameOpts & HtmlFrmOpts::Space) &&
+ (aTwipSpc.Width() || aTwipSpc.Height()) &&
+ !mbReqIF )
+ {
+ Size aPixelSpc = SwHTMLWriter::ToPixel(aTwipSpc);
+
+ if( aPixelSpc.Width() )
+ {
+ sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_hspace
+ "=\"" + OString::number(aPixelSpc.Width()) + "\"");
+ }
+
+ if( aPixelSpc.Height() )
+ {
+ sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_vspace
+ "=\"" + OString::number(aPixelSpc.Height()) + "\"");
+ }
+ }
+
+ // The spacing must be considered for the size, if the corresponding flag
+ // is set.
+ if( nFrameOpts & HtmlFrmOpts::MarginSize )
+ {
+ aTwipSpc.setWidth( aTwipSpc.Width() * -2 );
+ aTwipSpc.setHeight( aTwipSpc.Height() * -2 );
+ }
+ else
+ {
+ aTwipSpc.setWidth( 0 );
+ aTwipSpc.setHeight( 0 );
+ }
+
+ const SvxBoxItem* pBoxItem;
+ if( !(nFrameOpts & HtmlFrmOpts::AbsSize) &&
+ (pBoxItem = rItemSet.GetItemIfSet( RES_BOX )) )
+ {
+ aTwipSpc.AdjustWidth(pBoxItem->CalcLineSpace( SvxBoxItemLine::LEFT ) );
+ aTwipSpc.AdjustWidth(pBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT ) );
+ aTwipSpc.AdjustHeight(pBoxItem->CalcLineSpace( SvxBoxItemLine::TOP ) );
+ aTwipSpc.AdjustHeight(pBoxItem->CalcLineSpace( SvxBoxItemLine::BOTTOM ) );
+ }
+
+ // WIDTH and/or HEIGHT
+ // Output SwFrameSize::Variable/SwFrameSize::Minimum only, if ANYSIZE is set
+ const SwFormatFrameSize *pFSItem;
+ if( (nFrameOpts & HtmlFrmOpts::Size) &&
+ (pFSItem = rItemSet.GetItemIfSet( RES_FRM_SIZE )) &&
+ ( (nFrameOpts & HtmlFrmOpts::AnySize) ||
+ SwFrameSize::Fixed == pFSItem->GetHeightSizeType()) )
+ {
+ sal_uInt8 nPercentWidth = pFSItem->GetWidthPercent();
+ sal_uInt8 nPercentHeight = pFSItem->GetHeightPercent();
+
+ // Size of the object in Twips without margins
+ Size aTwipSz( (nPercentWidth ? 0
+ : pFSItem->GetWidth()-aTwipSpc.Width()),
+ (nPercentHeight ? 0
+ : pFSItem->GetHeight()-aTwipSpc.Height()) );
+
+ OSL_ENSURE( aTwipSz.Width() >= 0 && aTwipSz.Height() >= 0, "Frame size minus spacing < 0!!!???" );
+ if( aTwipSz.Width() < 0 )
+ aTwipSz.setWidth( 0 );
+ if( aTwipSz.Height() < 0 )
+ aTwipSz.setHeight( 0 );
+
+ Size aPixelSz(SwHTMLWriter::ToPixel(aTwipSz));
+
+ if( (nFrameOpts & HtmlFrmOpts::Width) &&
+ ((nPercentWidth && nPercentWidth!=255) || aPixelSz.Width()) )
+ {
+ sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_width "=\"");
+ if( nPercentWidth )
+ sOut.append(OString::number(static_cast<sal_Int32>(nPercentWidth)) + "%");
+ else
+ sOut.append(static_cast<sal_Int32>(aPixelSz.Width()));
+ sOut.append("\"");
+ }
+
+ if( (nFrameOpts & HtmlFrmOpts::Height) &&
+ ((nPercentHeight && nPercentHeight!=255) || aPixelSz.Height()) )
+ {
+ sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_height "=\"");
+ if( nPercentHeight )
+ sOut.append(OString::number(static_cast<sal_Int32>(nPercentHeight)) + "%");
+ else
+ sOut.append(static_cast<sal_Int32>(aPixelSz.Height()));
+ sOut.append("\"");
+ }
+ }
+
+ if (!sOut.isEmpty())
+ {
+ Strm().WriteOString( sOut );
+ sOut.setLength(0);
+ }
+
+ if (!mbReqIF)
+ {
+ // Insert wrap for graphics that are anchored to a paragraph as
+ // <BR CLEAR=...> in the string
+ const SwFormatSurround* pSurround;
+ if( (nFrameOpts & HtmlFrmOpts::BrClear) &&
+ ((RndStdIds::FLY_AT_PARA == rFrameFormat.GetAnchor().GetAnchorId()) ||
+ (RndStdIds::FLY_AT_CHAR == rFrameFormat.GetAnchor().GetAnchorId())) &&
+ (pSurround = rItemSet.GetItemIfSet( RES_SURROUND )) )
+ {
+ sal_Int16 eHoriOri = rFrameFormat.GetHoriOrient().GetHoriOrient();
+ pStr = nullptr;
+ css::text::WrapTextMode eSurround = pSurround->GetSurround();
+ bool bAnchorOnly = pSurround->IsAnchorOnly();
+ switch( eHoriOri )
+ {
+ case text::HoriOrientation::RIGHT:
+ {
+ switch( eSurround )
+ {
+ case css::text::WrapTextMode_NONE:
+ case css::text::WrapTextMode_RIGHT:
+ pStr = OOO_STRING_SVTOOLS_HTML_AL_right;
+ break;
+ case css::text::WrapTextMode_LEFT:
+ case css::text::WrapTextMode_PARALLEL:
+ if( bAnchorOnly )
+ m_bClearRight = true;
+ break;
+ default:
+ ;
+ }
+ }
+ break;
+
+ default:
+ // If a frame is centered, it gets left aligned. This
+ // should be taken into account here, too.
+ {
+ switch( eSurround )
+ {
+ case css::text::WrapTextMode_NONE:
+ case css::text::WrapTextMode_LEFT:
+ pStr = OOO_STRING_SVTOOLS_HTML_AL_left;
+ break;
+ case css::text::WrapTextMode_RIGHT:
+ case css::text::WrapTextMode_PARALLEL:
+ if( bAnchorOnly )
+ m_bClearLeft = true;
+ break;
+ default:
+ ;
+ }
+ }
+ break;
+
+ }
+
+ if( pStr )
+ {
+ sOut.append("<" OOO_STRING_SVTOOLS_HTML_linebreak
+ " " OOO_STRING_SVTOOLS_HTML_O_clear
+ "=\"" + OString::Concat(pStr) + "\">");
+ sRetEndTags = sOut.makeStringAndClear();
+ }
+ }
+ }
+ return sRetEndTags;
+}
+
+void SwHTMLWriter::writeFrameFormatOptions(HtmlWriter& aHtml, const SwFrameFormat& rFrameFormat, const OUString& rAlternateText, HtmlFrmOpts nFrameOptions)
+{
+ bool bReplacement = (nFrameOptions & HtmlFrmOpts::Replacement) || mbReqIF;
+ const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
+
+ // Name
+ if( (nFrameOptions & (HtmlFrmOpts::Id|HtmlFrmOpts::Name)) &&
+ !rFrameFormat.GetName().isEmpty() && !bReplacement)
+ {
+ const char* pAttributeName = (nFrameOptions & HtmlFrmOpts::Id) ? OOO_STRING_SVTOOLS_HTML_O_id : OOO_STRING_SVTOOLS_HTML_O_name;
+ aHtml.attribute(pAttributeName, rFrameFormat.GetName());
+ }
+
+ // Name
+ if (nFrameOptions & HtmlFrmOpts::Dir)
+ {
+ SvxFrameDirection nCurrentDirection = GetHTMLDirection(rItemSet);
+ OString sDirection = convertDirection(nCurrentDirection);
+ aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_dir, sDirection);
+ }
+
+ // alt
+ if( (nFrameOptions & HtmlFrmOpts::Alt) && !rAlternateText.isEmpty() && !bReplacement )
+ {
+ aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_alt, rAlternateText);
+ }
+
+ // align
+ std::string_view pAlignString;
+ RndStdIds eAnchorId = rFrameFormat.GetAnchor().GetAnchorId();
+ if( (nFrameOptions & HtmlFrmOpts::Align) &&
+ ((RndStdIds::FLY_AT_PARA == eAnchorId) || (RndStdIds::FLY_AT_CHAR == eAnchorId)) && !bReplacement)
+ {
+ const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient();
+ if( !(nFrameOptions & HtmlFrmOpts::SAlign) ||
+ text::RelOrientation::FRAME == rHoriOri.GetRelationOrient() ||
+ text::RelOrientation::PRINT_AREA == rHoriOri.GetRelationOrient() )
+ {
+ pAlignString = text::HoriOrientation::RIGHT == rHoriOri.GetHoriOrient()
+ ? std::string_view(OOO_STRING_SVTOOLS_HTML_AL_right)
+ : std::string_view(OOO_STRING_SVTOOLS_HTML_AL_left);
+ }
+ }
+ const SwFormatVertOrient* pVertOrient;
+ if( (nFrameOptions & HtmlFrmOpts::Align) && pAlignString.empty() &&
+ ( !(nFrameOptions & HtmlFrmOpts::SAlign) ||
+ (RndStdIds::FLY_AS_CHAR == eAnchorId) ) &&
+ (pVertOrient = rItemSet.GetItemIfSet( RES_VERT_ORIENT )) )
+ {
+ switch( pVertOrient->GetVertOrient() )
+ {
+ case text::VertOrientation::LINE_TOP: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_top; break;
+ case text::VertOrientation::CHAR_TOP:
+ case text::VertOrientation::BOTTOM: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_texttop; break;
+ case text::VertOrientation::LINE_CENTER:
+ case text::VertOrientation::CHAR_CENTER: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_absmiddle; break;
+ case text::VertOrientation::CENTER: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_middle; break;
+ case text::VertOrientation::LINE_BOTTOM:
+ case text::VertOrientation::CHAR_BOTTOM: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_absbottom; break;
+ case text::VertOrientation::TOP: pAlignString = OOO_STRING_SVTOOLS_HTML_VA_bottom; break;
+ case text::VertOrientation::NONE: break;
+ }
+ }
+ if (!pAlignString.empty() && !bReplacement)
+ {
+ aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_align, pAlignString);
+ }
+
+ // hspace and vspace
+ Size aTwipSpc( 0, 0 );
+ const SvxLRSpaceItem* pLRSpaceItem;
+ if( (nFrameOptions & (HtmlFrmOpts::Space | HtmlFrmOpts::MarginSize)) &&
+ (pLRSpaceItem = rItemSet.GetItemIfSet( RES_LR_SPACE )) )
+ {
+ aTwipSpc.setWidth(
+ ( pLRSpaceItem->GetLeft() + pLRSpaceItem->GetRight() ) / 2 );
+ m_nDfltLeftMargin = m_nDfltRightMargin = aTwipSpc.Width();
+ }
+ const SvxULSpaceItem* pULSpaceItem;
+ if( (nFrameOptions & (HtmlFrmOpts::Space|HtmlFrmOpts::MarginSize)) &&
+ (pULSpaceItem = rItemSet.GetItemIfSet( RES_UL_SPACE )) )
+ {
+ aTwipSpc.setHeight(
+ ( pULSpaceItem->GetUpper() + pULSpaceItem->GetLower() ) / 2 );
+ m_nDfltTopMargin = m_nDfltBottomMargin = o3tl::narrowing<sal_uInt16>(aTwipSpc.Height());
+ }
+
+ if( (nFrameOptions & HtmlFrmOpts::Space) &&
+ (aTwipSpc.Width() || aTwipSpc.Height()) &&
+ !mbReqIF )
+ {
+ Size aPixelSpc = SwHTMLWriter::ToPixel(aTwipSpc);
+
+ if (aPixelSpc.Width())
+ {
+ aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_hspace, static_cast<sal_Int32>(aPixelSpc.Width()));
+ }
+
+ if (aPixelSpc.Height())
+ {
+ aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_vspace, static_cast<sal_Int32>(aPixelSpc.Height()));
+ }
+ }
+
+ // The spacing must be considered for the size, if the corresponding flag
+ // is set.
+ if( nFrameOptions & HtmlFrmOpts::MarginSize )
+ {
+ aTwipSpc.setWidth( aTwipSpc.Width() * -2 );
+ aTwipSpc.setHeight( aTwipSpc.Height() * -2 );
+ }
+ else
+ {
+ aTwipSpc.setWidth( 0 );
+ aTwipSpc.setHeight( 0 );
+ }
+
+ const SvxBoxItem* pBoxItem;
+ if( !(nFrameOptions & HtmlFrmOpts::AbsSize) &&
+ (pBoxItem = rItemSet.GetItemIfSet( RES_BOX )) )
+ {
+ aTwipSpc.AdjustWidth(pBoxItem->CalcLineSpace( SvxBoxItemLine::LEFT ) );
+ aTwipSpc.AdjustWidth(pBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT ) );
+ aTwipSpc.AdjustHeight(pBoxItem->CalcLineSpace( SvxBoxItemLine::TOP ) );
+ aTwipSpc.AdjustHeight(pBoxItem->CalcLineSpace( SvxBoxItemLine::BOTTOM ) );
+ }
+
+ // "width" and/or "height"
+ // Only output SwFrameSize::Variable/SwFrameSize::Minimum if ANYSIZE is set
+ std::optional<SwFormatFrameSize> aFrameSize;
+ const SwFormatFrameSize* pFSItem = rItemSet.GetItemIfSet( RES_FRM_SIZE );
+ const SdrObject* pObject;
+ if (!pFSItem && (pObject = rFrameFormat.FindSdrObject()))
+ {
+ // Write size for Draw shapes as well.
+ const tools::Rectangle& rSnapRect = pObject->GetSnapRect();
+ aFrameSize.emplace();
+ aFrameSize->SetWidthSizeType(SwFrameSize::Fixed);
+ aFrameSize->SetWidth(rSnapRect.getOpenWidth());
+ aFrameSize->SetHeightSizeType(SwFrameSize::Fixed);
+ aFrameSize->SetHeight(rSnapRect.getOpenHeight());
+ pFSItem = &*aFrameSize;
+ }
+ if( (nFrameOptions & HtmlFrmOpts::Size) &&
+ pFSItem &&
+ ( (nFrameOptions & HtmlFrmOpts::AnySize) ||
+ SwFrameSize::Fixed == pFSItem->GetHeightSizeType()) )
+ {
+ sal_uInt8 nPercentWidth = pFSItem->GetWidthPercent();
+ sal_uInt8 nPercentHeight = pFSItem->GetHeightPercent();
+
+ // Size of the object in Twips without margins
+ Size aTwipSz( (nPercentWidth && nPercentWidth != 255 ? 0
+ : pFSItem->GetWidth()-aTwipSpc.Width()),
+ (nPercentHeight && nPercentHeight != 255 ? 0
+ : pFSItem->GetHeight()-aTwipSpc.Height()) );
+
+ OSL_ENSURE( aTwipSz.Width() >= 0 && aTwipSz.Height() >= 0, "Frame size minus spacing < 0!!!???" );
+ if( aTwipSz.Width() < 0 )
+ aTwipSz.setWidth( 0 );
+ if( aTwipSz.Height() < 0 )
+ aTwipSz.setHeight( 0 );
+
+ Size aPixelSz(SwHTMLWriter::ToPixel(aTwipSz));
+
+ if( (nFrameOptions & HtmlFrmOpts::Width) &&
+ ((nPercentWidth && nPercentWidth!=255) || aPixelSz.Width()) )
+ {
+ OString sWidth;
+ if (nPercentWidth)
+ {
+ if (nPercentWidth == 255)
+ {
+ if (nPercentHeight)
+ {
+ sWidth = "auto"_ostr;
+ }
+ else
+ {
+ sWidth = OString::number(static_cast<sal_Int32>(aPixelSz.Width()));
+ }
+ }
+ else
+ {
+ sWidth = OString::number(static_cast<sal_Int32>(nPercentWidth)) + "%";
+ }
+ }
+ else
+ sWidth = OString::number(static_cast<sal_Int32>(aPixelSz.Width()));
+ if (!mbXHTML || sWidth != "auto")
+ {
+ aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_width, sWidth);
+ }
+ }
+
+ if( (nFrameOptions & HtmlFrmOpts::Height) &&
+ ((nPercentHeight && nPercentHeight!=255) || aPixelSz.Height()) )
+ {
+ OString sHeight;
+ if (nPercentHeight)
+ {
+ if (nPercentHeight == 255)
+ {
+ if (nPercentWidth)
+ {
+ sHeight = "auto"_ostr;
+ }
+ else
+ {
+ sHeight = OString::number(static_cast<sal_Int32>(aPixelSz.Height()));
+ }
+ }
+ else
+ {
+ sHeight = OString::number(static_cast<sal_Int32>(nPercentHeight)) + "%";
+ }
+ }
+ else
+ sHeight = OString::number(static_cast<sal_Int32>(aPixelSz.Height()));
+ if (!mbXHTML || sHeight != "auto")
+ {
+ aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_height, sHeight);
+ }
+ }
+ }
+
+ if (mbReqIF)
+ return;
+
+ // Insert wrap for graphics that are anchored to a paragraph as
+ // <BR CLEAR=...> in the string
+
+ if( !(nFrameOptions & HtmlFrmOpts::BrClear) )
+ return;
+ RndStdIds nAnchorId = rFrameFormat.GetAnchor().GetAnchorId();
+ if (RndStdIds::FLY_AT_PARA != nAnchorId && RndStdIds::FLY_AT_CHAR != nAnchorId)
+ return;
+ const SwFormatSurround* pSurround = rItemSet.GetItemIfSet( RES_SURROUND );
+ if (!pSurround)
+ return;
+
+ std::string_view pSurroundString;
+
+ sal_Int16 eHoriOri = rFrameFormat.GetHoriOrient().GetHoriOrient();
+ css::text::WrapTextMode eSurround = pSurround->GetSurround();
+ bool bAnchorOnly = pSurround->IsAnchorOnly();
+ switch( eHoriOri )
+ {
+ case text::HoriOrientation::RIGHT:
+ {
+ switch( eSurround )
+ {
+ case css::text::WrapTextMode_NONE:
+ case css::text::WrapTextMode_RIGHT:
+ pSurroundString = OOO_STRING_SVTOOLS_HTML_AL_right;
+ break;
+ case css::text::WrapTextMode_LEFT:
+ case css::text::WrapTextMode_PARALLEL:
+ if( bAnchorOnly )
+ m_bClearRight = true;
+ break;
+ default:
+ ;
+ }
+ }
+ break;
+
+ default:
+ // If a frame is centered, it gets left aligned. This
+ // should be taken into account here, too.
+ {
+ switch( eSurround )
+ {
+ case css::text::WrapTextMode_NONE:
+ case css::text::WrapTextMode_LEFT:
+ pSurroundString = OOO_STRING_SVTOOLS_HTML_AL_left;
+ break;
+ case css::text::WrapTextMode_RIGHT:
+ case css::text::WrapTextMode_PARALLEL:
+ if( bAnchorOnly )
+ m_bClearLeft = true;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ if (!pSurroundString.empty())
+ {
+ aHtml.start(OOO_STRING_SVTOOLS_HTML_linebreak ""_ostr);
+ aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, pSurroundString);
+ aHtml.end();
+ }
+}
+
+namespace
+{
+
+OUString lclWriteOutImap(SwHTMLWriter& rWrt, const SfxItemSet& rItemSet, const SwFrameFormat& rFrameFormat,
+ const Size& rRealSize, const ImageMap* pAltImgMap, const SwFormatURL*& pURLItem)
+{
+ OUString aIMapName;
+
+ // Only consider the URL attribute if no ImageMap was supplied
+ if (!pAltImgMap)
+ pURLItem = rItemSet.GetItemIfSet( RES_URL );
+
+ // write ImageMap
+ const ImageMap* pIMap = pAltImgMap;
+ if( !pIMap && pURLItem )
+ {
+ pIMap = pURLItem->GetMap();
+ }
+
+ if (pIMap)
+ {
+ // make the name unique
+ aIMapName = pIMap->GetName();
+ OUString aNameBase;
+ if (!aIMapName.isEmpty())
+ aNameBase = aIMapName;
+ else
+ aNameBase = OOO_STRING_SVTOOLS_HTML_map;
+
+ if (aIMapName.isEmpty())
+ aIMapName = aNameBase + OUString::number(rWrt.m_nImgMapCnt);
+
+ bool bFound;
+ do
+ {
+ bFound = false;
+ for (const OUString & rImgMapName : rWrt.m_aImgMapNames)
+ {
+ // TODO: Unicode: Comparison is case insensitive for ASCII
+ // characters only now!
+ if (aIMapName.equalsIgnoreAsciiCase(rImgMapName))
+ {
+ bFound = true;
+ break;
+ }
+ }
+ if (bFound)
+ {
+ rWrt.m_nImgMapCnt++;
+ aIMapName = aNameBase + OUString::number( rWrt.m_nImgMapCnt );
+ }
+ } while (bFound);
+
+ bool bScale = false;
+ Fraction aScaleX(1, 1);
+ Fraction aScaleY(1, 1);
+
+ const SwFormatFrameSize& rFrameSize = rFrameFormat.GetFrameSize();
+ const SvxBoxItem& rBox = rFrameFormat.GetBox();
+
+ if (!rFrameSize.GetWidthPercent() && rRealSize.Width())
+ {
+ SwTwips nWidth = rFrameSize.GetWidth();
+ nWidth -= rBox.CalcLineSpace(SvxBoxItemLine::LEFT) + rBox.CalcLineSpace(SvxBoxItemLine::RIGHT);
+
+ OSL_ENSURE( nWidth > 0, "Are there any graphics that are 0 twip wide!?" );
+ if (nWidth <= 0) // should not happen
+ nWidth = 1;
+
+ if (rRealSize.Width() != nWidth)
+ {
+ aScaleX = Fraction(nWidth, rRealSize.Width());
+ bScale = true;
+ }
+ }
+
+ if (!rFrameSize.GetHeightPercent() && rRealSize.Height())
+ {
+ SwTwips nHeight = rFrameSize.GetHeight();
+
+ nHeight -= rBox.CalcLineSpace(SvxBoxItemLine::TOP) + rBox.CalcLineSpace(SvxBoxItemLine::BOTTOM);
+
+ OSL_ENSURE( nHeight > 0, "Are there any graphics that are 0 twip high!?" );
+ if (nHeight <= 0)
+ nHeight = 1;
+
+ if (rRealSize.Height() != nHeight)
+ {
+ aScaleY = Fraction(nHeight, rRealSize.Height());
+ bScale = true;
+ }
+ }
+
+ rWrt.m_aImgMapNames.push_back(aIMapName);
+
+ OString aIndMap, aIndArea;
+ const char *pIndArea = nullptr, *pIndMap = nullptr;
+
+ if (rWrt.IsLFPossible())
+ {
+ rWrt.OutNewLine( true );
+ aIndMap = rWrt.GetIndentString();
+ aIndArea = rWrt.GetIndentString(1);
+ pIndArea = aIndArea.getStr();
+ pIndMap = aIndMap.getStr();
+ }
+
+ if (bScale)
+ {
+ ImageMap aScaledIMap(*pIMap);
+ aScaledIMap.Scale(aScaleX, aScaleY);
+ HTMLOutFuncs::Out_ImageMap( rWrt.Strm(), rWrt.GetBaseURL(), aScaledIMap, aIMapName,
+ aIMapEventTable,
+ rWrt.m_bCfgStarBasic,
+ SAL_NEWLINE_STRING, pIndArea, pIndMap );
+ }
+ else
+ {
+ HTMLOutFuncs::Out_ImageMap( rWrt.Strm(), rWrt.GetBaseURL(), *pIMap, aIMapName,
+ aIMapEventTable,
+ rWrt.m_bCfgStarBasic,
+ SAL_NEWLINE_STRING, pIndArea, pIndMap );
+ }
+ }
+ return aIMapName;
+}
+
+OUString getFrameFormatText(const SwFrameFormat& rFrameFormat)
+{
+ const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
+ const SwNodeIndex* pSttIx = rFlyContent.GetContentIdx();
+ if (!pSttIx)
+ return {};
+
+ const SwNodeOffset nStt = pSttIx->GetIndex();
+ const auto& nodes = rFrameFormat.GetDoc()->GetNodes();
+ const SwNodeOffset nEnd = nodes[nStt]->EndOfSectionIndex();
+
+ OUStringBuffer result;
+ for (SwNodeOffset i = nStt + 1; i < nEnd; ++i)
+ {
+ if (const auto* pTextNd = nodes[i]->GetTextNode())
+ {
+ if (!result.isEmpty())
+ result.append("\n");
+ result.append(comphelper::string::encodeForXml(pTextNd->GetExpandText(
+ nullptr, 0, -1, true, true, false,
+ ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::HideDeletions
+ | ExpandMode::HideFieldmarkCommands)));
+ }
+ }
+
+ return result.makeStringAndClear();
+}
+
+}
+
+SwHTMLWriter& OutHTML_ImageStart( HtmlWriter& rHtml, SwHTMLWriter& rWrt, const SwFrameFormat &rFrameFormat,
+ const OUString& rGraphicURL,
+ Graphic const & rGraphic, const OUString& rAlternateText,
+ const Size &rRealSize, HtmlFrmOpts nFrameOpts,
+ const char *pMarkType,
+ const ImageMap *pAltImgMap,
+ const OUString& rMimeType )
+{
+ // <object data="..."> instead of <img src="...">
+ bool bReplacement = (nFrameOpts & HtmlFrmOpts::Replacement) || rWrt.mbReqIF;
+
+ if (rWrt.mbSkipImages)
+ return rWrt;
+
+ // if necessary, temporarily close an open attribute
+ if( !rWrt.m_aINetFormats.empty() )
+ {
+ SwFormatINetFormat* pINetFormat = rWrt.m_aINetFormats.back();
+ OutHTML_INetFormat( rWrt, *pINetFormat, false );
+ }
+
+ OUString aGraphicURL( rGraphicURL );
+ if( !rWrt.mbEmbedImages && !HTMLOutFuncs::PrivateURLToInternalImg(aGraphicURL) && !rWrt.mpTempBaseURL )
+ aGraphicURL = URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), aGraphicURL);
+
+ const SfxItemSet& rItemSet = rFrameFormat.GetAttrSet();
+
+ const SwFormatURL* pURLItem = nullptr;
+ OUString aIMapName = lclWriteOutImap(rWrt, rItemSet, rFrameFormat, rRealSize, pAltImgMap, pURLItem);
+
+ // put img into new line
+ if (rWrt.IsLFPossible())
+ rWrt.OutNewLine( true );
+
+ // <a name=...></a>...<img ...>
+ if( pMarkType && !rFrameFormat.GetName().isEmpty() )
+ {
+ rWrt.OutImplicitMark( rFrameFormat.GetName(), pMarkType );
+ }
+
+ // URL -> <a>...<img ... >...</a>
+ const SvxMacroItem *pMacItem = rItemSet.GetItemIfSet(RES_FRMMACRO);
+
+ if (pURLItem || pMacItem)
+ {
+ OUString aMapURL;
+ OUString aName;
+ OUString aTarget;
+
+ if(pURLItem)
+ {
+ aMapURL = pURLItem->GetURL();
+ aName = pURLItem->GetName();
+ aTarget = pURLItem->GetTargetFrameName();
+ }
+
+ bool bEvents = pMacItem && !pMacItem->GetMacroTable().empty();
+
+ if( !aMapURL.isEmpty() || !aName.isEmpty() || !aTarget.isEmpty() || bEvents )
+ {
+ rHtml.start(OOO_STRING_SVTOOLS_HTML_anchor ""_ostr);
+
+ // Output "href" element if a link or macro exists
+ if( !aMapURL.isEmpty() || bEvents )
+ {
+ rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_href, rWrt.convertHyperlinkHRefValue(aMapURL));
+ }
+
+ if( !aName.isEmpty() )
+ {
+ rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_name, aName);
+ }
+
+ if( !aTarget.isEmpty() )
+ {
+ rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_target, aTarget);
+ }
+
+ if( pMacItem )
+ {
+ const SvxMacroTableDtor& rMacTable = pMacItem->GetMacroTable();
+ if (!rMacTable.empty())
+ {
+ HtmlWriterHelper::applyEvents(rHtml, rMacTable, aAnchorEventTable, rWrt.m_bCfgStarBasic);
+ }
+ }
+ }
+ }
+
+ // <font color = ...>...<img ... >...</font>
+ sal_uInt16 nBorderWidth = 0;
+ const SvxBoxItem* pBoxItem;
+ if( (nFrameOpts & HtmlFrmOpts::Border) &&
+ (pBoxItem = rItemSet.GetItemIfSet( RES_BOX )) )
+ {
+ Size aTwipBorder( 0, 0 );
+ const ::editeng::SvxBorderLine *pColBorderLine = nullptr;
+ const ::editeng::SvxBorderLine *pBorderLine = pBoxItem->GetLeft();
+ if( pBorderLine )
+ {
+ pColBorderLine = pBorderLine;
+ aTwipBorder.AdjustWidth(pBorderLine->GetOutWidth() );
+ }
+
+ pBorderLine = pBoxItem->GetRight();
+ if( pBorderLine )
+ {
+ pColBorderLine = pBorderLine;
+ aTwipBorder.AdjustWidth(pBorderLine->GetOutWidth() );
+ }
+
+ pBorderLine = pBoxItem->GetTop();
+ if( pBorderLine )
+ {
+ pColBorderLine = pBorderLine;
+ aTwipBorder.AdjustHeight(pBorderLine->GetOutWidth() );
+ }
+
+ pBorderLine = pBoxItem->GetBottom();
+ if( pBorderLine )
+ {
+ pColBorderLine = pBorderLine;
+ aTwipBorder.AdjustHeight(pBorderLine->GetOutWidth() );
+ }
+
+ aTwipBorder.setWidth( aTwipBorder.Width() / 2 );
+ aTwipBorder.setHeight( aTwipBorder.Height() / 2 );
+
+ if( (aTwipBorder.Width() || aTwipBorder.Height()) &&
+ Application::GetDefaultDevice() )
+ {
+ Size aPixelBorder = SwHTMLWriter::ToPixel(aTwipBorder);
+
+ if( aPixelBorder.Width() )
+ aPixelBorder.setHeight( 0 );
+
+ nBorderWidth =
+ o3tl::narrowing<sal_uInt16>(aPixelBorder.Width() + aPixelBorder.Height());
+ }
+
+ if( pColBorderLine )
+ {
+ rHtml.start(OOO_STRING_SVTOOLS_HTML_font ""_ostr);
+ HtmlWriterHelper::applyColor(rHtml, OOO_STRING_SVTOOLS_HTML_O_color, pColBorderLine->GetColor());
+ }
+ }
+
+ OString aTag(OOO_STRING_SVTOOLS_HTML_image ""_ostr);
+ if (bReplacement)
+ // Write replacement graphic of OLE object as <object>.
+ aTag = OOO_STRING_SVTOOLS_HTML_object ""_ostr;
+ rHtml.start(aTag);
+
+ if(rWrt.mbEmbedImages)
+ {
+ OUString aGraphicInBase64;
+ if (XOutBitmap::GraphicToBase64(rGraphic, aGraphicInBase64))
+ {
+ OString sBuffer(OString::Concat(OOO_STRING_SVTOOLS_HTML_O_data)
+ + ":"
+ + OUStringToOString(aGraphicInBase64, RTL_TEXTENCODING_UTF8));
+ rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_src, sBuffer);
+ }
+ else
+ rWrt.m_nWarn = WARN_SWG_POOR_LOAD;
+ }
+ else
+ {
+ OString sBuffer(OUStringToOString(aGraphicURL, RTL_TEXTENCODING_UTF8));
+ OString aAttribute(OOO_STRING_SVTOOLS_HTML_O_src ""_ostr);
+ if (bReplacement)
+ aAttribute = OOO_STRING_SVTOOLS_HTML_O_data ""_ostr;
+ rHtml.attribute(aAttribute, sBuffer);
+ }
+
+ if (bReplacement)
+ {
+ // Handle XHTML type attribute for OLE replacement images.
+ if (!rMimeType.isEmpty())
+ rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_type, rMimeType);
+ }
+
+ // Events
+ if (const SvxMacroItem* pMacroItem = rItemSet.GetItemIfSet(RES_FRMMACRO))
+ {
+ const SvxMacroTableDtor& rMacTable = pMacroItem->GetMacroTable();
+ if (!rMacTable.empty())
+ {
+ HtmlWriterHelper::applyEvents(rHtml, rMacTable, aImageEventTable, rWrt.m_bCfgStarBasic);
+ }
+ }
+
+ // alt, align, width, height, hspace, vspace
+ rWrt.writeFrameFormatOptions(rHtml, rFrameFormat, rAlternateText, nFrameOpts);
+ if( rWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) )
+ rWrt.OutCSS1_FrameFormatOptions( rFrameFormat, nFrameOpts );
+
+ if ((nFrameOpts & HtmlFrmOpts::Border) && !bReplacement)
+ {
+ rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_border, nBorderWidth);
+ }
+
+ if( pURLItem && pURLItem->IsServerMap() )
+ {
+ rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_ismap);
+ }
+
+ if( !aIMapName.isEmpty() )
+ {
+ rHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_usemap, "#" + aIMapName);
+ }
+
+ if (bReplacement)
+ {
+ OUString aAltText = rAlternateText;
+ // In ReqIF mode, output text from the frame instead
+ if (rWrt.mbReqIF)
+ if (OUString aFrameText = getFrameFormatText(rFrameFormat); !aFrameText.isEmpty())
+ aAltText = aFrameText;
+
+ // XHTML object replacement image's alternate text doesn't use the
+ // "alt" attribute.
+ if (aAltText.isEmpty())
+ // Empty alternate text is not valid.
+ rHtml.characters(" ");
+ else
+ rHtml.characters(aAltText.toUtf8());
+ }
+
+ return rWrt;
+}
+
+SwHTMLWriter& OutHTML_ImageEnd( HtmlWriter& rHtml, SwHTMLWriter& rWrt )
+{
+ rHtml.flushStack();
+
+ if( !rWrt.m_aINetFormats.empty() )
+ {
+ // There is still an attribute on the stack that has to be reopened
+ SwFormatINetFormat *pINetFormat = rWrt.m_aINetFormats.back();
+ OutHTML_INetFormat( rWrt, *pINetFormat, true );
+ }
+
+ return rWrt;
+}
+
+SwHTMLWriter& OutHTML_BulletImage( SwHTMLWriter& rWrt,
+ const char *pTag,
+ const SvxBrushItem* pBrush,
+ const OUString &rGraphicURL)
+{
+ OUString aGraphicInBase64;
+ OUString aLink;
+ if( pBrush )
+ {
+ aLink = pBrush->GetGraphicLink();
+ if(rWrt.mbEmbedImages || aLink.isEmpty())
+ {
+ const Graphic* pGrf = pBrush->GetGraphic();
+ if( pGrf )
+ {
+ if( !XOutBitmap::GraphicToBase64(*pGrf, aGraphicInBase64) )
+ {
+ rWrt.m_nWarn = WARN_SWG_POOR_LOAD;
+ }
+ }
+ }
+ else if(!aLink.isEmpty())
+ {
+ if( rWrt.m_bCfgCpyLinkedGrfs )
+ {
+ rWrt.CopyLocalFileToINet( aLink );
+ }
+
+ }
+ }
+ else if(!rWrt.mbEmbedImages)
+ {
+ aLink = rGraphicURL;
+ }
+ if(!aLink.isEmpty())
+ {
+ if( !HTMLOutFuncs::PrivateURLToInternalImg(aLink) )
+ aLink = URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), aLink);
+ }
+
+ OStringBuffer sOut;
+ if( pTag )
+ sOut.append(OString::Concat("<") + pTag);
+
+ sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_style "=\"");
+ if(!aLink.isEmpty())
+ {
+ sOut.append(OOO_STRING_SVTOOLS_HTML_O_src "=\"");
+ rWrt.Strm().WriteOString( sOut );
+ sOut.setLength(0);
+ HTMLOutFuncs::Out_String( rWrt.Strm(), aLink );
+ }
+ else
+ {
+ sOut.append("list-style-image: url("
+ OOO_STRING_SVTOOLS_HTML_O_data ":");
+ rWrt.Strm().WriteOString( sOut );
+ sOut.setLength(0);
+ HTMLOutFuncs::Out_String( rWrt.Strm(), aGraphicInBase64 );
+ sOut.append(");");
+ }
+ sOut.append('\"');
+
+ if (pTag)
+ sOut.append('>');
+ rWrt.Strm().WriteOString( sOut );
+
+ return rWrt;
+}
+
+static SwHTMLWriter& OutHTML_FrameFormatTableNode( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat )
+{
+ const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
+ SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex()+1;
+ SwNodeOffset nEnd = rWrt.m_pDoc->GetNodes()[nStt-1]->EndOfSectionIndex();
+
+ OUString aCaption;
+ bool bTopCaption = false;
+
+ // Not const, because GetTable won't be const sometime later
+ SwNode *pNd = rWrt.m_pDoc->GetNodes()[ nStt ];
+ SwTableNode *pTableNd = pNd->GetTableNode();
+ const SwTextNode *pTextNd = pNd->GetTextNode();
+ if( !pTableNd && pTextNd )
+ {
+ // Table with heading
+ bTopCaption = true;
+ pTableNd = rWrt.m_pDoc->GetNodes()[nStt+1]->GetTableNode();
+ }
+ OSL_ENSURE( pTableNd, "Frame does not contain a table" );
+ if( pTableNd )
+ {
+ SwNodeOffset nTableEnd = pTableNd->EndOfSectionIndex();
+ OSL_ENSURE( nTableEnd == nEnd - 1 ||
+ (nTableEnd == nEnd - 2 && !bTopCaption),
+ "Invalid frame content for a table" );
+
+ if( nTableEnd == nEnd - 2 )
+ pTextNd = rWrt.m_pDoc->GetNodes()[nTableEnd+1]->GetTextNode();
+ }
+ if( pTextNd )
+ aCaption = pTextNd->GetText();
+
+ if( pTableNd )
+ {
+ HTMLSaveData aSaveData( rWrt, pTableNd->GetIndex()+1,
+ pTableNd->EndOfSectionIndex(),
+ true, &rFrameFormat );
+ rWrt.m_bOutFlyFrame = true;
+ OutHTML_SwTableNode( rWrt, *pTableNd, &rFrameFormat, &aCaption,
+ bTopCaption );
+ }
+
+ return rWrt;
+}
+
+static SwHTMLWriter & OutHTML_FrameFormatAsMulticol( SwHTMLWriter& rWrt,
+ const SwFrameFormat& rFrameFormat,
+ bool bInCntnr )
+{
+ rWrt.ChangeParaToken( HtmlTokenId::NONE );
+
+ // Close the current <DL>!
+ rWrt.OutAndSetDefList( 0 );
+
+ // output as Multicol
+ if (rWrt.IsLFPossible())
+ rWrt.OutNewLine();
+
+ OStringBuffer sOut("<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_multicol);
+
+ const SwFormatCol& rFormatCol = rFrameFormat.GetCol();
+
+ // output the number of columns as COLS
+ sal_uInt16 nCols = rFormatCol.GetNumCols();
+ if( nCols )
+ {
+ sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_cols
+ "=\"" + OString::number(nCols) + "\"");
+ }
+
+ // the Gutter width (minimum value) as GUTTER
+ sal_uInt16 nGutter = rFormatCol.GetGutterWidth( true );
+ if( nGutter!=USHRT_MAX )
+ {
+ nGutter = SwHTMLWriter::ToPixel(nGutter);
+ sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_gutter
+ "=\"" + OString::number(nGutter) + "\"");
+ }
+
+ rWrt.Strm().WriteOString( sOut );
+ sOut.setLength(0);
+
+ // WIDTH
+ HtmlFrmOpts nFrameFlags = HTML_FRMOPTS_MULTICOL;
+ if( rWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr )
+ nFrameFlags |= HTML_FRMOPTS_MULTICOL_CSS1;
+ rWrt.OutFrameFormatOptions(rFrameFormat, OUString(), nFrameFlags);
+ if( rWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr )
+ rWrt.OutCSS1_FrameFormatOptions( rFrameFormat, nFrameFlags );
+
+ rWrt.Strm().WriteChar( '>' );
+
+ rWrt.SetLFPossible(true);
+ rWrt.IncIndentLevel(); // indent the content of Multicol
+
+ const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
+ SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex();
+ const SwStartNode* pSttNd = rWrt.m_pDoc->GetNodes()[nStt]->GetStartNode();
+ OSL_ENSURE( pSttNd, "Where is the start node" );
+
+ {
+ // in a block, so that the old state can be restored in time
+ // before the end
+ HTMLSaveData aSaveData( rWrt, nStt+1,
+ pSttNd->EndOfSectionIndex(),
+ true, &rFrameFormat );
+ rWrt.m_bOutFlyFrame = true;
+ rWrt.Out_SwDoc( rWrt.m_pCurrentPam.get() );
+ }
+
+ rWrt.DecIndentLevel(); // indent the content of Multicol;
+ if (rWrt.IsLFPossible())
+ rWrt.OutNewLine();
+ HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_multicol), false );
+ rWrt.SetLFPossible(true);
+
+ return rWrt;
+}
+
+static SwHTMLWriter& OutHTML_FrameFormatAsSpacer( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat )
+{
+ // if possible, output a line break before the graphic
+ if (rWrt.IsLFPossible())
+ rWrt.OutNewLine( true );
+
+ OString sOut =
+ "<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_spacer " "
+ OOO_STRING_SVTOOLS_HTML_O_type "=\""
+ OOO_STRING_SVTOOLS_HTML_SPTYPE_block "\"";
+ rWrt.Strm().WriteOString( sOut );
+
+ // ALIGN, WIDTH, HEIGHT
+ OString aEndTags = rWrt.OutFrameFormatOptions(rFrameFormat, OUString(), HTML_FRMOPTS_SPACER);
+
+ rWrt.Strm().WriteChar( '>' );
+ if( !aEndTags.isEmpty() )
+ rWrt.Strm().WriteOString( aEndTags );
+
+ return rWrt;
+}
+
+static SwHTMLWriter& OutHTML_FrameFormatAsDivOrSpan( SwHTMLWriter& rWrt,
+ const SwFrameFormat& rFrameFormat, bool bSpan)
+{
+ OString aTag;
+ if( !bSpan )
+ {
+ rWrt.ChangeParaToken( HtmlTokenId::NONE );
+
+ // Close the current <DL>!
+ rWrt.OutAndSetDefList( 0 );
+ aTag = OOO_STRING_SVTOOLS_HTML_division ""_ostr;
+ }
+ else
+ aTag = OOO_STRING_SVTOOLS_HTML_span ""_ostr;
+
+ // output as DIV
+ if (rWrt.IsLFPossible())
+ rWrt.OutNewLine();
+
+ OStringBuffer sOut("<" + rWrt.GetNamespace() + aTag);
+
+ rWrt.Strm().WriteOString( sOut );
+ sOut.setLength(0);
+ HtmlFrmOpts nFrameFlags = HTML_FRMOPTS_DIV;
+ if( rWrt.IsHTMLMode( HTMLMODE_BORDER_NONE ) )
+ nFrameFlags |= HtmlFrmOpts::SNoBorder;
+ OString aEndTags = rWrt.OutFrameFormatOptions(rFrameFormat, OUString(), nFrameFlags);
+ rWrt.OutCSS1_FrameFormatOptions( rFrameFormat, nFrameFlags );
+ rWrt.Strm().WriteChar( '>' );
+
+ rWrt.IncIndentLevel(); // indent the content
+ rWrt.SetLFPossible(true);
+
+ const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
+ SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex();
+
+ // Output frame-anchored frames that are anchored to the start node
+ rWrt.OutFlyFrame( nStt, 0, HtmlPosition::Any );
+
+ const SwStartNode* pSttNd = rWrt.m_pDoc->GetNodes()[nStt]->GetStartNode();
+ OSL_ENSURE( pSttNd, "Where is the start node" );
+
+ {
+ // in a block, so that the old state can be restored in time
+ // before the end
+ HTMLSaveData aSaveData( rWrt, nStt+1,
+ pSttNd->EndOfSectionIndex(),
+ true, &rFrameFormat );
+ rWrt.m_bOutFlyFrame = true;
+ rWrt.Out_SwDoc( rWrt.m_pCurrentPam.get() );
+ }
+
+ rWrt.DecIndentLevel(); // indent the content of Multicol;
+ if (rWrt.IsLFPossible())
+ rWrt.OutNewLine();
+ HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + aTag), false );
+
+ if( !aEndTags.isEmpty() )
+ rWrt.Strm().WriteOString( aEndTags );
+
+ return rWrt;
+}
+
+/// Starts the OLE version of an image in the ReqIF + OLE case.
+static void OutHTML_ImageOLEStart(SwHTMLWriter& rWrt, const Graphic& rGraphic,
+ const SwFrameFormat& rFrameFormat)
+{
+ if (!rWrt.mbReqIF || !rWrt.m_bExportImagesAsOLE)
+ return;
+
+ // Write the original image as an RTF fragment.
+ OUString aFileName;
+ if (rWrt.GetOrigFileName())
+ aFileName = *rWrt.GetOrigFileName();
+ INetURLObject aURL(aFileName);
+ OUString aName = aURL.getBase() + "_" + aURL.getExtension() + "_"
+ + OUString::number(rGraphic.GetChecksum(), 16);
+ aURL.setBase(aName);
+ aURL.setExtension(u"ole");
+ aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+
+ SvFileStream aOutStream(aFileName, StreamMode::WRITE);
+ if (!SwReqIfReader::WrapGraphicInRtf(rGraphic, rFrameFormat, aOutStream))
+ SAL_WARN("sw.html", "SwReqIfReader::WrapGraphicInRtf() failed");
+
+ // Refer to this data.
+ aFileName = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), aFileName);
+ rWrt.Strm().WriteOString(
+ Concat2View("<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object));
+ rWrt.Strm().WriteOString(Concat2View(" data=\"" + aFileName.toUtf8() + "\""));
+ rWrt.Strm().WriteOString(" type=\"text/rtf\"");
+ rWrt.Strm().WriteOString(">");
+ rWrt.OutNewLine();
+}
+
+/// Ends the OLE version of an image in the ReqIF + OLE case.
+static void OutHTML_ImageOLEEnd(SwHTMLWriter& rWrt)
+{
+ if (rWrt.mbReqIF && rWrt.m_bExportImagesAsOLE)
+ {
+ rWrt.Strm().WriteOString(
+ Concat2View("</" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object ">"));
+ }
+}
+
+static SwHTMLWriter & OutHTML_FrameFormatAsImage( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat, bool bPNGFallback)
+{
+ bool bWritePNGFallback = rWrt.mbReqIF && !rWrt.m_bExportImagesAsOLE && bPNGFallback;
+
+ if (rWrt.mbSkipImages)
+ return rWrt;
+
+ ImageMap aIMap;
+ std::optional<Size> aDPI;
+ if (rWrt.m_nShapeDPI.has_value())
+ {
+ aDPI.emplace(*rWrt.m_nShapeDPI, *rWrt.m_nShapeDPI);
+ }
+ Graphic aGraphic( const_cast<SwFrameFormat &>(rFrameFormat).MakeGraphic( &aIMap, /*nMaximumQuadraticPixels=*/2100000, aDPI ) );
+
+ if (rWrt.mbReqIF)
+ {
+ // ImageMap doesn't seem to be allowed in reqif.
+ if (auto pGrafObj = dynamic_cast<const SdrGrafObj*>(rFrameFormat.FindSdrObject()))
+ {
+ aGraphic = pGrafObj->GetGraphic();
+ }
+ else
+ {
+ // We only have a bitmap, write that as PNG without any fallback.
+ bWritePNGFallback = false;
+ }
+ }
+
+ Size aSz( 0, 0 );
+ OUString GraphicURL;
+ OUString aMimeType("image/jpeg");
+ if(!rWrt.mbEmbedImages)
+ {
+ if( rWrt.GetOrigFileName() )
+ GraphicURL = *rWrt.GetOrigFileName();
+
+ OUString aFilterName("JPG");
+ XOutFlags nFlags = XOutFlags::UseGifIfPossible | XOutFlags::UseNativeIfPossible;
+
+ if (rWrt.mbReqIF && !bWritePNGFallback)
+ {
+ // Writing image without fallback PNG in ReqIF mode: force PNG output.
+ aFilterName = "PNG";
+ nFlags = XOutFlags::NONE;
+ aMimeType = "image/png";
+ }
+ else if (rWrt.mbReqIF)
+ {
+ // Original format is wanted, don't force JPG.
+ aFilterName.clear();
+ aMimeType.clear();
+ }
+
+ if( aGraphic.GetType() == GraphicType::NONE ||
+ XOutBitmap::WriteGraphic( aGraphic, GraphicURL,
+ aFilterName,
+ nFlags ) != ERRCODE_NONE )
+ {
+ // empty or incorrect, because there is nothing to output
+ rWrt.m_nWarn = WARN_SWG_POOR_LOAD;
+ return rWrt;
+ }
+
+ GraphicURL = URIHelper::SmartRel2Abs(
+ INetURLObject(rWrt.GetBaseURL()), GraphicURL,
+ URIHelper::GetMaybeFileHdl() );
+
+ }
+ uno::Reference<beans::XPropertySet> xGraphic(aGraphic.GetXGraphic(), uno::UNO_QUERY);
+ if (xGraphic.is() && aMimeType.isEmpty())
+ xGraphic->getPropertyValue("MimeType") >>= aMimeType;
+
+ OutHTML_ImageOLEStart(rWrt, aGraphic, rFrameFormat);
+
+ HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace);
+ OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, GraphicURL, aGraphic, rFrameFormat.GetName(), aSz,
+ HtmlFrmOpts::GenImgMask, "frame",
+ aIMap.GetIMapObjectCount() ? &aIMap : nullptr, aMimeType );
+
+ GfxLink aLink = aGraphic.GetGfxLink();
+ if (bWritePNGFallback && aLink.GetType() != GfxLinkType::NativePng)
+ {
+ OutHTML_FrameFormatAsImage( rWrt, rFrameFormat, /*bPNGFallback=*/false);
+ }
+
+ OutHTML_ImageEnd(aHtml, rWrt);
+
+ OutHTML_ImageOLEEnd(rWrt);
+
+ return rWrt;
+}
+
+static SwHTMLWriter& OutHTML_FrameFormatGrfNode( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat,
+ bool bInCntnr, bool bPNGFallback )
+{
+ bool bWritePNGFallback = rWrt.mbReqIF && !rWrt.m_bExportImagesAsOLE && bPNGFallback;
+
+ if (rWrt.mbSkipImages)
+ return rWrt;
+
+ const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
+ SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex()+1;
+ SwGrfNode *pGrfNd = rWrt.m_pDoc->GetNodes()[ nStt ]->GetGrfNode();
+ OSL_ENSURE( pGrfNd, "Grf node expected" );
+ if( !pGrfNd )
+ return rWrt;
+
+ HtmlFrmOpts nFrameFlags = bInCntnr ? HTML_FRMOPTS_IMG_CNTNR : HTML_FRMOPTS_IMG;
+ if( rWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bInCntnr )
+ nFrameFlags |= HTML_FRMOPTS_IMG_CSS1;
+
+ Graphic aGraphic = pGrfNd->GetGraphic();
+
+ if (aGraphic.GetType() == GraphicType::GdiMetafile)
+ {
+ // We only have a metafile, write that as PNG without any fallback.
+ bWritePNGFallback = false;
+ }
+
+ OUString aGraphicURL;
+ OUString aMimeType;
+ if(!rWrt.mbEmbedImages)
+ {
+ const SwMirrorGrf& rMirror = pGrfNd->GetSwAttrSet().GetMirrorGrf();
+
+ if( !pGrfNd->IsLinkedFile() || MirrorGraph::Dont != rMirror.GetValue() )
+ {
+ // create a (mirrored) jpeg file
+ if( rWrt.GetOrigFileName() )
+ aGraphicURL = *rWrt.GetOrigFileName();
+ else
+ aGraphicURL = rWrt.GetBaseURL();
+ pGrfNd->GetGrf( true );
+
+ XOutFlags nFlags = XOutFlags::UseGifIfSensible |
+ XOutFlags::UseNativeIfPossible;
+ switch( rMirror.GetValue() )
+ {
+ case MirrorGraph::Vertical: nFlags = XOutFlags::MirrorHorz; break;
+ case MirrorGraph::Horizontal: nFlags = XOutFlags::MirrorVert; break;
+ case MirrorGraph::Both:
+ nFlags = XOutFlags::MirrorVert | XOutFlags::MirrorHorz;
+ break;
+ default: break;
+ }
+
+ const SwFormatFrameSize& rSize = rFrameFormat.GetFrameSize();
+ Size aMM100Size = o3tl::convert( rSize.GetSize(),
+ o3tl::Length::twip, o3tl::Length::mm100 );
+
+ OUString aFilterName;
+
+ if (rWrt.mbReqIF)
+ {
+ // In ReqIF mode, do not try to write GIF for other image types
+ nFlags &= ~XOutFlags::UseGifIfSensible;
+ if (!bWritePNGFallback)
+ {
+ // Writing image without fallback PNG in ReqIF mode: force PNG
+ // output.
+ // But don't force it when writing the original format and we'll write PNG inside
+ // that.
+ aFilterName = "PNG";
+ nFlags &= ~XOutFlags::UseNativeIfPossible;
+ }
+ }
+
+ const Graphic& rGraphic = pGrfNd->GetGrf();
+
+ // So that Graphic::IsTransparent() can report true.
+ if (!rGraphic.isAvailable())
+ const_cast<Graphic&>(rGraphic).makeAvailable();
+
+ if (rWrt.mbReqIF && bWritePNGFallback)
+ {
+ // ReqIF: force native data if possible.
+ const std::shared_ptr<VectorGraphicData>& pVectorGraphicData = rGraphic.getVectorGraphicData();
+ if (pVectorGraphicData && pVectorGraphicData->getType() == VectorGraphicDataType::Svg)
+ {
+ aFilterName = "svg";
+ }
+ else if (rGraphic.GetGfxLink().IsEMF())
+ {
+ aFilterName = "emf";
+ }
+ else if (pVectorGraphicData && pVectorGraphicData->getType() == VectorGraphicDataType::Wmf)
+ {
+ aFilterName = "wmf";
+ }
+ else if (rGraphic.GetGfxLink().GetType() == GfxLinkType::NativeTif)
+ {
+ aFilterName = "tif";
+ }
+ }
+
+ ErrCode nErr = XOutBitmap::WriteGraphic( rGraphic, aGraphicURL,
+ aFilterName, nFlags, &aMM100Size, nullptr, &aMimeType );
+ if( nErr )
+ {
+ rWrt.m_nWarn = WARN_SWG_POOR_LOAD;
+ return rWrt;
+ }
+ aGraphicURL = URIHelper::SmartRel2Abs(
+ INetURLObject(rWrt.GetBaseURL()), aGraphicURL,
+ URIHelper::GetMaybeFileHdl() );
+ }
+ else
+ {
+ pGrfNd->GetFileFilterNms( &aGraphicURL, nullptr );
+ if( rWrt.m_bCfgCpyLinkedGrfs )
+ rWrt.CopyLocalFileToINet( aGraphicURL );
+ }
+
+ }
+ uno::Reference<beans::XPropertySet> xGraphic(aGraphic.GetXGraphic(), uno::UNO_QUERY);
+ if (xGraphic.is() && aMimeType.isEmpty())
+ xGraphic->getPropertyValue("MimeType") >>= aMimeType;
+
+ OutHTML_ImageOLEStart(rWrt, aGraphic, rFrameFormat);
+
+ HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace);
+ OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, aGraphicURL, aGraphic, pGrfNd->GetTitle(),
+ pGrfNd->GetTwipSize(), nFrameFlags, "graphic", nullptr, aMimeType );
+
+ GfxLink aLink = aGraphic.GetGfxLink();
+ if (bWritePNGFallback && aLink.GetType() != GfxLinkType::NativePng)
+ {
+ // Not OLE mode, outer format is not PNG: write inner PNG.
+ OutHTML_FrameFormatGrfNode( rWrt, rFrameFormat,
+ bInCntnr, /*bPNGFallback=*/false );
+ }
+
+ OutHTML_ImageEnd(aHtml, rWrt);
+
+ OutHTML_ImageOLEEnd(rWrt);
+
+ return rWrt;
+}
+
+static SwHTMLWriter& OutHTML_FrameFormatAsMarquee( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat,
+ const SdrObject& rSdrObj )
+{
+ // get the edit engine attributes of the object as SW attributes and
+ // sort them as Hints
+ const SfxItemSet& rFormatItemSet = rFrameFormat.GetAttrSet();
+ SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> aItemSet( *rFormatItemSet.GetPool() );
+ SwHTMLWriter::GetEEAttrsFromDrwObj( aItemSet, &rSdrObj );
+ bool bCfgOutStylesOld = rWrt.m_bCfgOutStyles;
+ rWrt.m_bCfgOutStyles = false;
+ rWrt.m_bTextAttr = true;
+ rWrt.m_bTagOn = true;
+ Out_SfxItemSet( aHTMLAttrFnTab, rWrt, aItemSet, false );
+ rWrt.m_bTextAttr = false;
+
+ OutHTML_DrawFrameFormatAsMarquee( rWrt,
+ static_cast<const SwDrawFrameFormat &>(rFrameFormat),
+ rSdrObj );
+ rWrt.m_bTextAttr = true;
+ rWrt.m_bTagOn = false;
+ Out_SfxItemSet( aHTMLAttrFnTab, rWrt, aItemSet, false );
+ rWrt.m_bTextAttr = false;
+ rWrt.m_bCfgOutStyles = bCfgOutStylesOld;
+
+ return rWrt;
+}
+
+SwHTMLWriter& OutHTML_HeaderFooter( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat,
+ bool bHeader )
+{
+ // output as Multicol
+ rWrt.OutNewLine();
+ OStringBuffer sOut;
+ sOut.append(OOO_STRING_SVTOOLS_HTML_division " "
+ OOO_STRING_SVTOOLS_HTML_O_title "=\"")
+ .append( bHeader ? "header" : "footer" ).append("\"");
+ HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + sOut) );
+
+ rWrt.IncIndentLevel(); // indent the content of Multicol;
+
+ // Piece a spacer for the spacing together. Because the
+ // <DL> or </DL> always produces a space between paragraphs, it is
+ // subtracted if necessary.
+ const SvxULSpaceItem& rULSpace = rFrameFormat.GetULSpace();
+ sal_uInt16 nSize = bHeader ? rULSpace.GetLower() : rULSpace.GetUpper();
+ rWrt.m_nHeaderFooterSpace = nSize;
+
+ OString aSpacer;
+ if( rWrt.IsHTMLMode(HTMLMODE_VERT_SPACER) &&
+ nSize > HTML_PARSPACE )
+ {
+ nSize -= HTML_PARSPACE;
+ nSize = SwHTMLWriter::ToPixel(nSize);
+
+ aSpacer = OOO_STRING_SVTOOLS_HTML_spacer
+ " " OOO_STRING_SVTOOLS_HTML_O_type
+ "=\"" OOO_STRING_SVTOOLS_HTML_SPTYPE_vertical "\""
+ " " OOO_STRING_SVTOOLS_HTML_O_size
+ "=\"" + OString::number(nSize) + "\"";
+ }
+
+ const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
+ SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex();
+ const SwStartNode* pSttNd = rWrt.m_pDoc->GetNodes()[nStt]->GetStartNode();
+ OSL_ENSURE( pSttNd, "Where is the start node" );
+
+ if( !bHeader && !aSpacer.isEmpty() )
+ {
+ rWrt.OutNewLine();
+ HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + aSpacer) );
+ }
+
+ {
+ // in a block, so that the old state can be restored in time
+ // before the end. pFlyFormat doesn't need to be set here, because
+ // PageDesc attributes cannot occur here
+ HTMLSaveData aSaveData( rWrt, nStt+1,
+ pSttNd->EndOfSectionIndex() );
+
+ if( bHeader )
+ rWrt.m_bOutHeader = true;
+ else
+ rWrt.m_bOutFooter = true;
+
+ rWrt.Out_SwDoc( rWrt.m_pCurrentPam.get() );
+ }
+
+ if( bHeader && !aSpacer.isEmpty() )
+ {
+ rWrt.OutNewLine();
+ HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + aSpacer) );
+ }
+
+ rWrt.DecIndentLevel(); // indent the content of Multicol;
+ rWrt.OutNewLine();
+ HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
+
+ rWrt.m_nHeaderFooterSpace = 0;
+
+ return rWrt;
+}
+
+void SwHTMLWriter::AddLinkTarget( std::u16string_view aURL )
+{
+ if( aURL.empty() || aURL[0] != '#' )
+ return;
+
+ // There might be a '|' as delimiter (if the link has been inserted
+ // freshly) or a '%7c' or a '%7C' if the document has been saved and
+ // loaded already.
+ sal_Int32 nPos = aURL.size();
+ bool bFound = false, bEncoded = false;
+ while( !bFound && nPos > 0 )
+ {
+ sal_Unicode c = aURL[ --nPos ];
+ switch( c )
+ {
+ case cMarkSeparator:
+ bFound = true;
+ break;
+ case '%':
+ bFound = (aURL.size() - nPos) >=3 && aURL[ nPos+1 ] == '7';
+ if(bFound)
+ {
+ c = aURL[ nPos+2 ];
+ bFound = (c == 'C' || c == 'c');
+ }
+ if( bFound )
+ bEncoded = true;
+ }
+ }
+ if( !bFound || nPos < 2 ) // at least "#a|..."
+ return;
+
+ aURL = aURL.substr( 1 );
+
+ // nPos-1+1/3 (-1 because of Erase)
+ OUString sCmp = OUString(aURL.substr(bEncoded ? nPos+2 : nPos)).replaceAll(" ","");
+ if( sCmp.isEmpty() )
+ return;
+
+ sCmp = sCmp.toAsciiLowerCase();
+
+ if( sCmp == "region" ||
+ sCmp == "frame" ||
+ sCmp == "graphic" ||
+ sCmp == "ole" ||
+ sCmp == "table" )
+ {
+ // Just remember it in a sorted array
+ OUString aURL2(aURL);
+ if( bEncoded )
+ {
+ aURL2 = aURL2.replaceAt( nPos - 1, 3, rtl::OUStringChar(cMarkSeparator) );
+ }
+ m_aImplicitMarks.insert( aURL2 );
+ }
+ else if( sCmp == "outline" )
+ {
+ // Here, we need position and name. That's why we sort a
+ // sal_uInt16 and a string array ourselves.
+ OUString aOutline( aURL.substr( 0, nPos-1 ) );
+ SwPosition aPos( *m_pCurrentPam->GetPoint() );
+ if( m_pDoc->GotoOutline( aPos, aOutline ) )
+ {
+ SwNodeOffset nIdx = aPos.GetNodeIndex();
+
+ decltype(m_aOutlineMarkPoss)::size_type nIns=0;
+ while( nIns < m_aOutlineMarkPoss.size() &&
+ m_aOutlineMarkPoss[nIns] < nIdx )
+ nIns++;
+
+ m_aOutlineMarkPoss.insert( m_aOutlineMarkPoss.begin()+nIns, nIdx );
+ OUString aURL2(aURL);
+ if( bEncoded )
+ {
+ aURL2 = aURL2.replaceAt( nPos - 1, 3, rtl::OUStringChar(cMarkSeparator) );
+ }
+ m_aOutlineMarks.insert( m_aOutlineMarks.begin()+nIns, aURL2 );
+ }
+ }
+}
+
+void SwHTMLWriter::CollectLinkTargets()
+{
+ const SwTextINetFormat* pTextAttr;
+
+ for (const SfxPoolItem* pItem : m_pDoc->GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT))
+ {
+ auto pINetFormat = dynamic_cast<const SwFormatINetFormat*>(pItem);
+ const SwTextNode* pTextNd;
+
+ if( pINetFormat &&
+ nullptr != ( pTextAttr = pINetFormat->GetTextINetFormat()) &&
+ nullptr != ( pTextNd = pTextAttr->GetpTextNode() ) &&
+ pTextNd->GetNodes().IsDocNodes() )
+ {
+ AddLinkTarget( pINetFormat->GetValue() );
+ }
+ }
+
+ for (const SfxPoolItem* pItem : m_pDoc->GetAttrPool().GetItemSurrogates(RES_URL))
+ {
+ auto pURL = dynamic_cast<const SwFormatURL*>(pItem);
+ if( pURL )
+ {
+ AddLinkTarget( pURL->GetURL() );
+ const ImageMap *pIMap = pURL->GetMap();
+ if( pIMap )
+ {
+ for( size_t i=0; i<pIMap->GetIMapObjectCount(); ++i )
+ {
+ const IMapObject* pObj = pIMap->GetIMapObject( i );
+ if( pObj )
+ {
+ AddLinkTarget( pObj->GetURL() );
+ }
+ }
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */