diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/filter/html/htmlplug.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/filter/html/htmlplug.cxx')
-rw-r--r-- | sw/source/filter/html/htmlplug.cxx | 1765 |
1 files changed, 1765 insertions, 0 deletions
diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx new file mode 100644 index 0000000000..8b2ff71cd3 --- /dev/null +++ b/sw/source/filter/html/htmlplug.cxx @@ -0,0 +1,1765 @@ +/* -*- 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 <config_java.h> + +#include <hintids.hxx> +#include <rtl/strbuf.hxx> +#include <sal/log.hxx> +#include <svl/urihelper.hxx> +#include <vcl/svapp.hxx> +#include <sfx2/frmhtml.hxx> +#include <sfx2/frmhtmlw.hxx> +#include <sfx2/frmdescr.hxx> +#include <sot/storage.hxx> +#include <svx/xoutbmp.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/htmlkywd.hxx> +#include <svtools/htmltokn.h> +#include <comphelper/diagnose_ex.hxx> +#include <IDocumentContentOperations.hxx> +#include <SwAppletImpl.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include <fmtsrnd.hxx> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <frmfmt.hxx> + +#include <svl/ownlist.hxx> +#include <unotools/mediadescriptor.hxx> +#include <unotools/streamwrap.hxx> +#include <pam.hxx> +#include <doc.hxx> +#include <swerror.h> +#include <ndole.hxx> +#include <docsh.hxx> +#include "swhtml.hxx" +#include "wrthtml.hxx" +#include "htmlfly.hxx" +#include "swcss1.hxx" +#include "htmlreqifreader.hxx" +#include <unoframe.hxx> +#include <com/sun/star/embed/XClassifiedObject.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/io/XActiveDataStreamer.hpp> +#include <com/sun/star/embed/XEmbedPersist2.hpp> +#include <com/sun/star/lang/XInitialization.hpp> + +#include <comphelper/embeddedobjectcontainer.hxx> +#include <comphelper/classids.hxx> +#include <rtl/uri.hxx> +#include <comphelper/storagehelper.hxx> +#include <vcl/graphicfilter.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <comphelper/propertysequence.hxx> +#include <filter/msfilter/msoleexp.hxx> +#include <comphelper/fileurl.hxx> +#include <o3tl/safeint.hxx> +#include <osl/file.hxx> +#include <comphelper/propertyvalue.hxx> +#include <svtools/HtmlWriter.hxx> + +using namespace com::sun::star; + + +#define HTML_DFLT_EMBED_WIDTH (o3tl::toTwips(125, o3tl::Length::mm10)) +#define HTML_DFLT_EMBED_HEIGHT (o3tl::toTwips(125, o3tl::Length::mm10)) + +#define HTML_DFLT_APPLET_WIDTH (o3tl::toTwips(125, o3tl::Length::mm10)) +#define HTML_DFLT_APPLET_HEIGHT (o3tl::toTwips(125, o3tl::Length::mm10)) + + +const HtmlFrmOpts HTML_FRMOPTS_EMBED_ALL = + HtmlFrmOpts::Alt | + HtmlFrmOpts::Size | + HtmlFrmOpts::Name; +const HtmlFrmOpts HTML_FRMOPTS_EMBED_CNTNR = + HTML_FRMOPTS_EMBED_ALL | + HtmlFrmOpts::AbsSize; +const HtmlFrmOpts HTML_FRMOPTS_EMBED = + HTML_FRMOPTS_EMBED_ALL | + HtmlFrmOpts::Align | + HtmlFrmOpts::Space | + HtmlFrmOpts::BrClear | + HtmlFrmOpts::Name; +const HtmlFrmOpts HTML_FRMOPTS_HIDDEN_EMBED = + HtmlFrmOpts::Alt | + HtmlFrmOpts::Name; + +const HtmlFrmOpts HTML_FRMOPTS_APPLET_ALL = + HtmlFrmOpts::Alt | + HtmlFrmOpts::Size; +const HtmlFrmOpts HTML_FRMOPTS_APPLET_CNTNR = + HTML_FRMOPTS_APPLET_ALL | + HtmlFrmOpts::AbsSize; +const HtmlFrmOpts HTML_FRMOPTS_APPLET = + HTML_FRMOPTS_APPLET_ALL | + HtmlFrmOpts::Align | + HtmlFrmOpts::Space | + HtmlFrmOpts::BrClear; + +const HtmlFrmOpts HTML_FRMOPTS_IFRAME_ALL = + HtmlFrmOpts::Alt | + HtmlFrmOpts::Size; +const HtmlFrmOpts HTML_FRMOPTS_IFRAME_CNTNR = + HTML_FRMOPTS_IFRAME_ALL | + HtmlFrmOpts::AbsSize; +const HtmlFrmOpts HTML_FRMOPTS_IFRAME = + HTML_FRMOPTS_IFRAME_ALL | + HtmlFrmOpts::Align | + HtmlFrmOpts::Space | + HtmlFrmOpts::Border | + HtmlFrmOpts::BrClear; + +const HtmlFrmOpts HTML_FRMOPTS_OLE_CSS1 = + HtmlFrmOpts::SAlign | + HtmlFrmOpts::SSpace; + +namespace +{ +/** + * Calculates a filename for an image, provided the HTML file name, the image + * itself and a wanted extension. + */ +OUString lcl_CalculateFileName(const OUString* pOrigFileName, const Graphic& rGraphic, + std::u16string_view rExtension) +{ + OUString aFileName; + + if (pOrigFileName) + aFileName = *pOrigFileName; + INetURLObject aURL(aFileName); + OUString aName = aURL.getBase() + "_" + + aURL.getExtension() + "_" + + OUString::number(rGraphic.GetChecksum(), 16); + aURL.setBase(aName); + aURL.setExtension(rExtension); + aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + + return aFileName; +} +} + +void SwHTMLParser::SetFixSize( const Size& rPixSize, + const Size& rTwipDfltSize, + bool bPercentWidth, bool bPercentHeight, + SvxCSS1PropertyInfo const & rCSS1PropInfo, + SfxItemSet& rFlyItemSet ) +{ + // convert absolute size values into Twip + sal_uInt8 nPercentWidth = 0, nPercentHeight = 0; + Size aTwipSz( bPercentWidth || USHRT_MAX==rPixSize.Width() ? 0 : rPixSize.Width(), + bPercentHeight || USHRT_MAX==rPixSize.Height() ? 0 : rPixSize.Height() ); + if( aTwipSz.Width() || aTwipSz.Height() ) + { + aTwipSz = o3tl::convert(aTwipSz, o3tl::Length::px, o3tl::Length::twip); + } + + // process width + if( SVX_CSS1_LTYPE_PERCENTAGE == rCSS1PropInfo.m_eWidthType ) + { + nPercentWidth = static_cast<sal_uInt8>(rCSS1PropInfo.m_nWidth); + aTwipSz.setWidth( rTwipDfltSize.Width() ); + } + else if( SVX_CSS1_LTYPE_TWIP== rCSS1PropInfo.m_eWidthType ) + { + aTwipSz.setWidth( rCSS1PropInfo.m_nWidth ); + } + else if( bPercentWidth && rPixSize.Width() ) + { + nPercentWidth = static_cast<sal_uInt8>(rPixSize.Width()); + if (nPercentWidth > 100 && nPercentWidth != SwFormatFrameSize::SYNCED) + nPercentWidth = 100; + + aTwipSz.setWidth( rTwipDfltSize.Width() ); + } + else if( USHRT_MAX==rPixSize.Width() ) + { + aTwipSz.setWidth( rTwipDfltSize.Width() ); + } + if( aTwipSz.Width() < MINFLY ) + { + aTwipSz.setWidth( MINFLY ); + } + + // process height + if( SVX_CSS1_LTYPE_PERCENTAGE == rCSS1PropInfo.m_eHeightType ) + { + nPercentHeight = static_cast<sal_uInt8>(rCSS1PropInfo.m_nHeight); + aTwipSz.setHeight( rTwipDfltSize.Height() ); + } + else if( SVX_CSS1_LTYPE_TWIP== rCSS1PropInfo.m_eHeightType ) + { + aTwipSz.setHeight( rCSS1PropInfo.m_nHeight ); + } + else if( bPercentHeight && rPixSize.Height() ) + { + nPercentHeight = static_cast<sal_uInt8>(rPixSize.Height()); + if (nPercentHeight > 100 && nPercentHeight != SwFormatFrameSize::SYNCED) + nPercentHeight = 100; + + aTwipSz.setHeight( rTwipDfltSize.Height() ); + } + else if( USHRT_MAX==rPixSize.Height() ) + { + aTwipSz.setHeight( rTwipDfltSize.Height() ); + } + if( aTwipSz.Height() < MINFLY ) + { + aTwipSz.setHeight( MINFLY ); + } + + // set size + SwFormatFrameSize aFrameSize( SwFrameSize::Fixed, aTwipSz.Width(), aTwipSz.Height() ); + aFrameSize.SetWidthPercent( nPercentWidth ); + aFrameSize.SetHeightPercent( nPercentHeight ); + rFlyItemSet.Put( aFrameSize ); +} + +void SwHTMLParser::SetSpace( const Size& rPixSpace, + SfxItemSet& rCSS1ItemSet, + SvxCSS1PropertyInfo& rCSS1PropInfo, + SfxItemSet& rFlyItemSet ) +{ + sal_Int32 nLeftSpace = 0, nRightSpace = 0; + sal_uInt16 nUpperSpace = 0, nLowerSpace = 0; + if( rPixSpace.Width() || rPixSpace.Height() ) + { + nLeftSpace = nRightSpace = o3tl::convert(rPixSpace.Width(), o3tl::Length::px, o3tl::Length::twip); + nUpperSpace = nLowerSpace = o3tl::convert(rPixSpace.Height(), o3tl::Length::px, o3tl::Length::twip); + } + + // set left/right margin + // note: parser never creates SvxLeftMarginItem! must be converted + if (const SvxTextLeftMarginItem *const pLeft = rCSS1ItemSet.GetItemIfSet(RES_MARGIN_TEXTLEFT)) + { + if( rCSS1PropInfo.m_bLeftMargin ) + { + // should be SvxLeftMarginItem... "cast" it + nLeftSpace = pLeft->GetTextLeft(); + rCSS1PropInfo.m_bLeftMargin = false; + } + rCSS1ItemSet.ClearItem(RES_MARGIN_TEXTLEFT); + } + if (const SvxRightMarginItem *const pRight = rCSS1ItemSet.GetItemIfSet(RES_MARGIN_RIGHT)) + { + if( rCSS1PropInfo.m_bRightMargin ) + { + nRightSpace = pRight->GetRight(); + rCSS1PropInfo.m_bRightMargin = false; + } + rCSS1ItemSet.ClearItem(RES_MARGIN_RIGHT); + } + if( nLeftSpace > 0 || nRightSpace > 0 ) + { + SvxLRSpaceItem aLRItem( RES_LR_SPACE ); + aLRItem.SetLeft( std::max<sal_Int32>(nLeftSpace, 0) ); + aLRItem.SetRight( std::max<sal_Int32>(nRightSpace, 0) ); + rFlyItemSet.Put( aLRItem ); + if( nLeftSpace ) + { + const SwFormatHoriOrient& rHoriOri = + rFlyItemSet.Get( RES_HORI_ORIENT ); + if( text::HoriOrientation::NONE == rHoriOri.GetHoriOrient() ) + { + SwFormatHoriOrient aHoriOri( rHoriOri ); + aHoriOri.SetPos( aHoriOri.GetPos() + nLeftSpace ); + rFlyItemSet.Put( aHoriOri ); + } + } + } + + // set top/bottom margin + if( const SvxULSpaceItem *pULItem = rCSS1ItemSet.GetItemIfSet( RES_UL_SPACE ) ) + { + // if applicable remove the first line indent + if( rCSS1PropInfo.m_bTopMargin ) + { + nUpperSpace = pULItem->GetUpper(); + rCSS1PropInfo.m_bTopMargin = false; + } + if( rCSS1PropInfo.m_bBottomMargin ) + { + nLowerSpace = pULItem->GetLower(); + rCSS1PropInfo.m_bBottomMargin = false; + } + rCSS1ItemSet.ClearItem( RES_UL_SPACE ); + } + if( !(nUpperSpace || nLowerSpace) ) + return; + + SvxULSpaceItem aULItem( RES_UL_SPACE ); + aULItem.SetUpper( nUpperSpace ); + aULItem.SetLower( nLowerSpace ); + rFlyItemSet.Put( aULItem ); + if( nUpperSpace ) + { + const SwFormatVertOrient& rVertOri = + rFlyItemSet.Get( RES_VERT_ORIENT ); + if( text::VertOrientation::NONE == rVertOri.GetVertOrient() ) + { + SwFormatVertOrient aVertOri( rVertOri ); + aVertOri.SetPos( aVertOri.GetPos() + nUpperSpace ); + rFlyItemSet.Put( aVertOri ); + } + } +} + +OUString SwHTMLParser::StripQueryFromPath(std::u16string_view rBase, const OUString& rPath) +{ + if (!comphelper::isFileUrl(rBase)) + return rPath; + + sal_Int32 nIndex = rPath.indexOf('?'); + + if (nIndex != -1) + return rPath.copy(0, nIndex); + + return rPath; +} + +bool SwHTMLParser::InsertEmbed() +{ + OUString aURL, aType, aName, aAlt, aId, aStyle, aClass; + OUString aData; + Size aSize( USHRT_MAX, USHRT_MAX ); + Size aSpace( USHRT_MAX, USHRT_MAX ); + bool bPercentWidth = false, bPercentHeight = false, bHidden = false; + sal_Int16 eVertOri = text::VertOrientation::NONE; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + SvCommandList aCmdLst; + const HTMLOptions& rHTMLOptions = GetOptions(); + + // The options are read forwards, because the plug-ins expect them in this + // order. Still only the first value of an option may be regarded. + for (const auto & rOption : rHTMLOptions) + { + 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::NAME: + aName = rOption.GetString(); + break; + case HtmlOptionId::SRC: + if( aURL.isEmpty() ) + aURL = rOption.GetString(); + break; + case HtmlOptionId::ALT: + aAlt = rOption.GetString(); + break; + case HtmlOptionId::TYPE: + if( aType.isEmpty() ) + aType = rOption.GetString(); + break; + case HtmlOptionId::ALIGN: + if( eVertOri==text::VertOrientation::NONE && eHoriOri==text::HoriOrientation::NONE ) + { + eVertOri = rOption.GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = rOption.GetEnum( aHTMLImgHAlignTable, eHoriOri ); + } + break; + case HtmlOptionId::WIDTH: + if( USHRT_MAX==aSize.Width() ) + { + bPercentWidth = (rOption.GetString().indexOf('%') != -1); + aSize.setWidth( static_cast<tools::Long>(rOption.GetNumber()) ); + } + break; + case HtmlOptionId::HEIGHT: + if( USHRT_MAX==aSize.Height() ) + { + bPercentHeight = (rOption.GetString().indexOf('%') != -1); + aSize.setHeight( static_cast<tools::Long>(rOption.GetNumber()) ); + } + break; + case HtmlOptionId::HSPACE: + if( USHRT_MAX==aSpace.Width() ) + aSpace.setWidth( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::VSPACE: + if( USHRT_MAX==aSpace.Height() ) + aSpace.setHeight( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::DATA: + if (m_bXHTML && aURL.isEmpty()) + aData = rOption.GetString(); + break; + case HtmlOptionId::UNKNOWN: + if (rOption.GetTokenString().equalsIgnoreAsciiCase( + OOO_STRING_SW_HTML_O_Hidden)) + { + bHidden = !rOption.GetString().equalsIgnoreAsciiCase( + "FALSE"); + } + break; + default: break; + } + + // All parameters are passed to the plug-in. + aCmdLst.Append( rOption.GetTokenString(), rOption.GetString() ); + } + + static const std::set<std::u16string_view> vAllowlist = { + u"image/png", + u"image/gif", + u"image/x-MS-bmp", + u"image/jpeg", + u"image/x-wmf", + u"image/svg+xml", + u"image/tiff", + u"image/x-emf", + u"image/bmp", + u"image/tif", + u"image/wmf", + }; + + if (vAllowlist.find(aType) != vAllowlist.end() && m_aEmbeds.empty()) + { + // Toplevel <object> for an image format -> that's an image, not an OLE object. + m_aEmbeds.push(nullptr); + return false; + } + + SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + // Convert the default values (except height/width, which is done by SetFrameSize()) + if( eVertOri==text::VertOrientation::NONE && eHoriOri==text::HoriOrientation::NONE ) + eVertOri = text::VertOrientation::TOP; + if( USHRT_MAX==aSpace.Width() ) + aSpace.setWidth( 0 ); + if( USHRT_MAX==aSpace.Height() ) + aSpace.setHeight( 0 ); + if( bHidden ) + { + // Size (0,0) will be changed to (MINFLY, MINFLY) in SetFrameSize() + aSize.setWidth( 0 ); aSize.setHeight( 0 ); + aSpace.setWidth( 0 ); aSpace.setHeight( 0 ); + bPercentWidth = bPercentHeight = false; + } + + // prepare the URL + INetURLObject aURLObj; + bool bHasURL = !aURL.isEmpty() && + aURLObj.SetURL( + URIHelper::SmartRel2Abs( + INetURLObject(m_sBaseURL), aURL, + URIHelper::GetMaybeFileHdl()) ); + bool bHasData = !aData.isEmpty(); + + try + { + // Strip query and everything after that for file:// URLs, browsers do + // the same. + aURLObj.SetURL(rtl::Uri::convertRelToAbs( + m_sBaseURL, SwHTMLParser::StripQueryFromPath(m_sBaseURL, aData))); + } + catch (const rtl::MalformedUriException& /*rException*/) + { + bHasData = false; + } + + // do not insert plugin if it has neither URL nor type + bool bHasType = !aType.isEmpty(); + if( !bHasURL && !bHasType && !bHasData ) + return true; + + if (!m_aEmbeds.empty()) + { + // Nested XHTML <object> element: points to replacement graphic. + SwOLENode* pOLENode = m_aEmbeds.top(); + if (!pOLENode) + { + // <object> is mapped to an image -> ignore replacement graphic. + return true; + } + + svt::EmbeddedObjectRef& rObj = pOLENode->GetOLEObj().GetObject(); + Graphic aGraphic; + if (GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aURLObj) != ERRCODE_NONE) + return true; + + rObj.SetGraphic(aGraphic, aType); + + // Set the size of the OLE frame to the size of the graphic. + SwFrameFormat* pFormat = pOLENode->GetFlyFormat(); + if (!pFormat) + return true; + SwAttrSet aAttrSet(pFormat->GetAttrSet()); + aAttrSet.ClearItem(RES_CNTNT); + Size aDefaultTwipSize(o3tl::convert(aGraphic.GetSizePixel(), o3tl::Length::px, o3tl::Length::twip)); + + if (aSize.Width() == USHRT_MAX && bPercentHeight) + { + // Height is relative, width is not set: keep aspect ratio. + aSize.setWidth(SwFormatFrameSize::SYNCED); + bPercentWidth = true; + } + if (aSize.Height() == USHRT_MAX && bPercentWidth) + { + // Width is relative, height is not set: keep aspect ratio. + aSize.setHeight(SwFormatFrameSize::SYNCED); + bPercentHeight = true; + } + + SetFixSize(aSize, aDefaultTwipSize, bPercentWidth, bPercentHeight, aPropInfo, aAttrSet); + pOLENode->GetDoc().SetFlyFrameAttr(*pFormat, aAttrSet); + return true; + } + + // create the plug-in + comphelper::EmbeddedObjectContainer aCnt; + OUString aObjName; + uno::Reference < embed::XEmbeddedObject > xObj; + if (!bHasData) + { + xObj = aCnt.CreateEmbeddedObject( SvGlobalName( SO3_PLUGIN_CLASSID ).GetByteSequence(), aObjName ); + if ( svt::EmbeddedObjectRef::TryRunningState( xObj ) ) + { + uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY ); + if ( xSet.is() ) + { + if( bHasURL ) + xSet->setPropertyValue("PluginURL", uno::Any( aURL ) ); + if( bHasType ) + xSet->setPropertyValue("PluginMimeType", uno::Any( aType ) ); + + uno::Sequence < beans::PropertyValue > aProps; + aCmdLst.FillSequence( aProps ); + xSet->setPropertyValue("PluginCommands", uno::Any( aProps ) ); + + } + } + } + else if (SwDocShell* pDocSh = m_xDoc->GetDocShell()) + { + // Has non-empty data attribute in XHTML: map that to an OLE object. + uno::Reference<embed::XStorage> xStorage = pDocSh->GetStorage(); + aCnt.SwitchPersistence(xStorage); + aObjName = aCnt.CreateUniqueObjectName(); + { + OUString aEmbedURL = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE); + SvFileStream aFileStream(aEmbedURL, StreamMode::READ); + uno::Reference<io::XInputStream> xInStream; + SvMemoryStream aMemoryStream; + + // Allow any MIME type that starts with magic, unless a set of allowed types are + // specified. + auto it = m_aAllowedRTFOLEMimeTypes.find(aType); + if (m_aAllowedRTFOLEMimeTypes.empty() || it != m_aAllowedRTFOLEMimeTypes.end()) + { + OString aMagic("{\\object"_ostr); + OString aHeader(read_uInt8s_ToOString(aFileStream, aMagic.getLength())); + aFileStream.Seek(0); + if (aHeader == aMagic) + { + // OLE2 wrapped in RTF: either own format or real OLE2 embedding. + bool bOwnFormat = false; + if (SwReqIfReader::ExtractOleFromRtf(aFileStream, aMemoryStream, bOwnFormat)) + { + xInStream.set(new utl::OStreamWrapper(aMemoryStream)); + } + + if (bOwnFormat) + { + uno::Sequence<beans::PropertyValue> aMedium = comphelper::InitPropertySequence( + { { "InputStream", uno::Any(xInStream) }, + { "URL", uno::Any(OUString("private:stream")) }, + { "DocumentBaseURL", uno::Any(m_sBaseURL) } }); + xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &m_sBaseURL); + } + else + { + // The type is now an OLE2 container, not the original XHTML type. + aType = "application/vnd.sun.star.oleobject"; + } + } + } + + if (!xInStream.is()) + { + // Object data is neither OLE2 in RTF, nor an image. Then map this to an URL that + // will be set on the inner image. + m_aEmbedURL = aEmbedURL; + // Signal success, so the outer object won't fall back to the image handler. + return true; + } + + if (!xObj.is()) + { + uno::Reference<io::XStream> xOutStream + = xStorage->openStreamElement(aObjName, embed::ElementModes::READWRITE); + if (aFileStream.IsOpen()) + comphelper::OStorageHelper::CopyInputToOutput(xInStream, + xOutStream->getOutputStream()); + + if (!aType.isEmpty()) + { + // Set media type of the native data. + uno::Reference<beans::XPropertySet> xOutStreamProps(xOutStream, uno::UNO_QUERY); + if (xOutStreamProps.is()) + xOutStreamProps->setPropertyValue("MediaType", uno::Any(aType)); + } + } + xObj = aCnt.GetEmbeddedObject(aObjName); + } + } + + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameSet( m_xDoc->GetAttrPool() ); + if( !IsNewDoc() ) + Reader::ResetFrameFormatAttrs( aFrameSet ); + + // set the anchor + if( !bHidden ) + { + SetAnchorAndAdjustment( eVertOri, eHoriOri, aPropInfo, aFrameSet ); + } + else + { + SwFormatAnchor aAnchor( RndStdIds::FLY_AT_PARA ); + aAnchor.SetAnchor( m_pPam->GetPoint() ); + aFrameSet.Put( aAnchor ); + aFrameSet.Put( SwFormatHoriOrient( 0, text::HoriOrientation::LEFT, text::RelOrientation::FRAME) ); + aFrameSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) ); + aFrameSet.Put( SwFormatVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::PRINT_AREA ) ); + } + + // and the size of the frame + Size aDfltSz( HTML_DFLT_EMBED_WIDTH, HTML_DFLT_EMBED_HEIGHT ); + SetFixSize( aSize, aDfltSz, bPercentWidth, bPercentHeight, aPropInfo, aFrameSet ); + SetSpace( aSpace, aItemSet, aPropInfo, aFrameSet ); + + // and insert into the document + uno::Reference<lang::XInitialization> xObjInitialization(xObj, uno::UNO_QUERY); + if (xObjInitialization.is()) + { + // Request that the native data of the embedded object is not modified + // during parsing. + uno::Sequence<beans::PropertyValue> aValues{ comphelper::makePropertyValue("StreamReadOnly", + true) }; + uno::Sequence<uno::Any> aArguments{ uno::Any(aValues) }; + xObjInitialization->initialize(aArguments); + } + SwFrameFormat* pFlyFormat = + m_xDoc->getIDocumentContentOperations().InsertEmbObject(*m_pPam, + ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT), + &aFrameSet); + if (xObjInitialization.is()) + { + uno::Sequence<beans::PropertyValue> aValues{ comphelper::makePropertyValue("StreamReadOnly", + false) }; + uno::Sequence<uno::Any> aArguments{ uno::Any(aValues) }; + xObjInitialization->initialize(aArguments); + } + + // set name at FrameFormat + if( !aName.isEmpty() ) + pFlyFormat->SetFormatName( aName ); + + // set the alternative text + SwNoTextNode *pNoTextNd = + m_xDoc->GetNodes()[ pFlyFormat->GetContent().GetContentIdx() + ->GetIndex()+1 ]->GetNoTextNode(); + pNoTextNd->SetTitle( aAlt ); + + // if applicable create frames and register auto-bound frames + if( !bHidden ) + { + // HIDDEN plug-ins should stay paragraph-bound. Since RegisterFlyFrame() + // will change paragraph-bound frames with wrap-through into a + // character-bound frame, here we must create the frames by hand. + RegisterFlyFrame( pFlyFormat ); + } + + if (!bHasData) + return true; + + SwOLENode* pOLENode = pNoTextNd->GetOLENode(); + if (!pOLENode) + return true; + + m_aEmbeds.push(pOLENode); + + return true; +} + +#if HAVE_FEATURE_JAVA +void SwHTMLParser::NewObject() +{ + OUString aClassID; + OUString aStandBy, aId, aStyle, aClass; + Size aSize( USHRT_MAX, USHRT_MAX ); + Size aSpace( 0, 0 ); + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + + bool bPercentWidth = false, bPercentHeight = false, + bDeclare = false; + // create a new Command list + m_pAppletImpl.reset(new SwApplet_Impl( m_xDoc->GetAttrPool() )); + + const HTMLOptions& rHTMLOptions = GetOptions(); + for (size_t i = rHTMLOptions.size(); i; ) + { + const HTMLOption& rOption = rHTMLOptions[--i]; + switch( rOption.GetToken() ) + { + case HtmlOptionId::ID: + aId = rOption.GetString(); + break; + case HtmlOptionId::STYLE: + aStyle = rOption.GetString(); + break; + case HtmlOptionId::CLASS: + aClass = rOption.GetString(); + break; + case HtmlOptionId::DECLARE: + bDeclare = true; + break; + case HtmlOptionId::CLASSID: + aClassID = rOption.GetString(); + break; + case HtmlOptionId::CODEBASE: + break; + case HtmlOptionId::DATA: + break; + case HtmlOptionId::TYPE: + break; + case HtmlOptionId::CODETYPE: + break; + case HtmlOptionId::ARCHIVE: + case HtmlOptionId::UNKNOWN: + break; + case HtmlOptionId::STANDBY: + aStandBy = rOption.GetString(); + break; + case HtmlOptionId::WIDTH: + bPercentWidth = (rOption.GetString().indexOf('%') != -1); + aSize.setWidth( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::HEIGHT: + bPercentHeight = (rOption.GetString().indexOf('%') != -1); + aSize.setHeight( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::ALIGN: + eVertOri = rOption.GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = rOption.GetEnum( aHTMLImgHAlignTable, eHoriOri ); + break; + case HtmlOptionId::USEMAP: + break; + case HtmlOptionId::NAME: + break; + case HtmlOptionId::HSPACE: + aSpace.setWidth( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::VSPACE: + aSpace.setHeight( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::BORDER: + break; + + case HtmlOptionId::SDONCLICK: + case HtmlOptionId::ONCLICK: + case HtmlOptionId::SDONMOUSEOVER: + case HtmlOptionId::ONMOUSEOVER: + case HtmlOptionId::SDONMOUSEOUT: + case HtmlOptionId::ONMOUSEOUT: + break; + default: break; + } + // All parameters are passed to the applet. + m_pAppletImpl->AppendParam( rOption.GetTokenString(), + rOption.GetString() ); + + } + + // Objects that are declared only are not evaluated. Moreover, only + // Java applets are supported. + bool bIsApplet = false; + + if( !bDeclare && aClassID.getLength() == 42 && + aClassID.startsWith("clsid:") ) + { + aClassID = aClassID.copy(6); + SvGlobalName aCID; + if( aCID.MakeId( aClassID ) ) + { + SvGlobalName aJavaCID( 0x8AD9C840UL, 0x044EU, 0x11D1U, 0xB3U, 0xE9U, + 0x00U, 0x80U, 0x5FU, 0x49U, 0x9DU, 0x93U ); + + bIsApplet = aJavaCID == aCID; + } + } + + if( !bIsApplet ) + { + m_pAppletImpl.reset(); + return; + } + + m_pAppletImpl->SetAltText( aStandBy ); + + SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + SfxItemSet& rFrameSet = m_pAppletImpl->GetItemSet(); + if( !IsNewDoc() ) + Reader::ResetFrameFormatAttrs( rFrameSet ); + + // set the anchor and the adjustment + SetAnchorAndAdjustment( eVertOri, eHoriOri, aPropInfo, rFrameSet ); + + // and still the size of the frame + Size aDfltSz( HTML_DFLT_APPLET_WIDTH, HTML_DFLT_APPLET_HEIGHT ); + SetFixSize( aSize, aDfltSz, bPercentWidth, bPercentHeight, aPropInfo, rFrameSet ); + SetSpace( aSpace, aItemSet, aPropInfo, rFrameSet ); +} +#endif + +void SwHTMLParser::EndObject() +{ +#if HAVE_FEATURE_JAVA + if( !m_pAppletImpl ) + return; + if( !m_pAppletImpl->CreateApplet( m_sBaseURL ) ) + return; + + m_pAppletImpl->FinishApplet(); + + // and insert into the document + SwFrameFormat* pFlyFormat = + m_xDoc->getIDocumentContentOperations().InsertEmbObject(*m_pPam, + ::svt::EmbeddedObjectRef( m_pAppletImpl->GetApplet(), embed::Aspects::MSOLE_CONTENT ), + &m_pAppletImpl->GetItemSet() ); + + // set the alternative name + SwNoTextNode *pNoTextNd = + m_xDoc->GetNodes()[ pFlyFormat->GetContent().GetContentIdx() + ->GetIndex()+1 ]->GetNoTextNode(); + pNoTextNd->SetTitle( m_pAppletImpl->GetAltText() ); + + // if applicable create frames and register auto-bound frames + RegisterFlyFrame( pFlyFormat ); + + m_pAppletImpl.reset(); +#else + (void) this; // Silence loplugin:staticmethods +#endif +} + +#if HAVE_FEATURE_JAVA +void SwHTMLParser::InsertApplet() +{ + OUString aCodeBase, aCode, aName, aAlt, aId, aStyle, aClass; + Size aSize( USHRT_MAX, USHRT_MAX ); + Size aSpace( 0, 0 ); + bool bPercentWidth = false, bPercentHeight = false, bMayScript = false; + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + + // create a new Command list + m_pAppletImpl.reset(new SwApplet_Impl( m_xDoc->GetAttrPool() )); + + const HTMLOptions& rHTMLOptions = GetOptions(); + for (size_t i = rHTMLOptions.size(); i; ) + { + const HTMLOption& rOption = rHTMLOptions[--i]; + switch( rOption.GetToken() ) + { + case HtmlOptionId::ID: + aId = rOption.GetString(); + break; + case HtmlOptionId::STYLE: + aStyle = rOption.GetString(); + break; + case HtmlOptionId::CLASS: + aClass = rOption.GetString(); + break; + case HtmlOptionId::CODEBASE: + aCodeBase = rOption.GetString(); + break; + case HtmlOptionId::CODE: + aCode = rOption.GetString(); + break; + case HtmlOptionId::NAME: + aName = rOption.GetString(); + break; + case HtmlOptionId::ALT: + aAlt = rOption.GetString(); + break; + case HtmlOptionId::ALIGN: + eVertOri = rOption.GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = rOption.GetEnum( aHTMLImgHAlignTable, eHoriOri ); + break; + case HtmlOptionId::WIDTH: + bPercentWidth = (rOption.GetString().indexOf('%') != -1); + aSize.setWidth( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::HEIGHT: + bPercentHeight = (rOption.GetString().indexOf('%') != -1); + aSize.setHeight( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::HSPACE: + aSpace.setWidth( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::VSPACE: + aSpace.setHeight( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::MAYSCRIPT: + bMayScript = true; + break; + default: break; + } + + // All parameters are passed to the applet. + m_pAppletImpl->AppendParam( rOption.GetTokenString(), + rOption.GetString() ); + } + + if( aCode.isEmpty() ) + { + m_pAppletImpl.reset(); + return; + } + + if ( !aCodeBase.isEmpty() ) + aCodeBase = INetURLObject::GetAbsURL( m_sBaseURL, aCodeBase ); + m_pAppletImpl->CreateApplet( aCode, aName, bMayScript, aCodeBase, m_sBaseURL );//, aAlt ); + m_pAppletImpl->SetAltText( aAlt ); + + SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + SfxItemSet& rFrameSet = m_pAppletImpl->GetItemSet(); + if( !IsNewDoc() ) + Reader::ResetFrameFormatAttrs( rFrameSet ); + + // set the anchor and the adjustment + SetAnchorAndAdjustment( eVertOri, eHoriOri, aPropInfo, rFrameSet ); + + // and still the size or the frame + Size aDfltSz( HTML_DFLT_APPLET_WIDTH, HTML_DFLT_APPLET_HEIGHT ); + SetFixSize( aSize, aDfltSz, bPercentWidth, bPercentHeight, aPropInfo, rFrameSet ); + SetSpace( aSpace, aItemSet, aPropInfo, rFrameSet ); +} +#endif + +void SwHTMLParser::EndApplet() +{ +#if HAVE_FEATURE_JAVA + if( !m_pAppletImpl ) + return; + + m_pAppletImpl->FinishApplet(); + + // and insert into the document + SwFrameFormat* pFlyFormat = + m_xDoc->getIDocumentContentOperations().InsertEmbObject(*m_pPam, + ::svt::EmbeddedObjectRef( m_pAppletImpl->GetApplet(), embed::Aspects::MSOLE_CONTENT ), + &m_pAppletImpl->GetItemSet()); + + // set the alternative name + SwNoTextNode *pNoTextNd = + m_xDoc->GetNodes()[ pFlyFormat->GetContent().GetContentIdx() + ->GetIndex()+1 ]->GetNoTextNode(); + pNoTextNd->SetTitle( m_pAppletImpl->GetAltText() ); + + // if applicable create frames and register auto-bound frames + RegisterFlyFrame( pFlyFormat ); + + m_pAppletImpl.reset(); +#else + (void) this; +#endif +} + +void SwHTMLParser::InsertParam() +{ +#if HAVE_FEATURE_JAVA + if( !m_pAppletImpl ) + return; + + OUString aName, aValue; + + const HTMLOptions& rHTMLOptions = GetOptions(); + for (size_t i = rHTMLOptions.size(); i; ) + { + const HTMLOption& rOption = rHTMLOptions[--i]; + switch( rOption.GetToken() ) + { + case HtmlOptionId::NAME: + aName = rOption.GetString(); + break; + case HtmlOptionId::VALUE: + aValue = rOption.GetString(); + break; + default: break; + } + } + + if( aName.isEmpty() ) + return; + + m_pAppletImpl->AppendParam( aName, aValue ); +#else + (void) this; +#endif +} + +void SwHTMLParser::InsertFloatingFrame() +{ + OUString aAlt, aId, aStyle, aClass; + Size aSize( USHRT_MAX, USHRT_MAX ); + Size aSpace( 0, 0 ); + bool bPercentWidth = false, bPercentHeight = false; + sal_Int16 eVertOri = text::VertOrientation::TOP; + sal_Int16 eHoriOri = text::HoriOrientation::NONE; + + const HTMLOptions& rHTMLOptions = GetOptions(); + + // First fetch the options of the Writer-Frame-Format + for (const auto & rOption : rHTMLOptions) + { + 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::ALT: + aAlt = rOption.GetString(); + break; + case HtmlOptionId::ALIGN: + eVertOri = rOption.GetEnum( aHTMLImgVAlignTable, eVertOri ); + eHoriOri = rOption.GetEnum( aHTMLImgHAlignTable, eHoriOri ); + break; + case HtmlOptionId::WIDTH: + bPercentWidth = (rOption.GetString().indexOf('%') != -1); + aSize.setWidth( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::HEIGHT: + bPercentHeight = (rOption.GetString().indexOf('%') != -1); + aSize.setHeight( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::HSPACE: + aSpace.setWidth( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + case HtmlOptionId::VSPACE: + aSpace.setHeight( static_cast<tools::Long>(rOption.GetNumber()) ); + break; + default: break; + } + } + + // and now the ones for the SfxFrame + SfxFrameDescriptor aFrameDesc; + + SfxFrameHTMLParser::ParseFrameOptions( &aFrameDesc, rHTMLOptions, m_sBaseURL ); + + // create a floating frame + comphelper::EmbeddedObjectContainer aCnt; + OUString aObjName; + uno::Reference < embed::XEmbeddedObject > xObj = aCnt.CreateEmbeddedObject( SvGlobalName( SO3_IFRAME_CLASSID ).GetByteSequence(), aObjName ); + + try + { + // TODO/MBA: testing + if ( svt::EmbeddedObjectRef::TryRunningState( xObj ) ) + { + uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY ); + if ( xSet.is() ) + { + const OUString& aName = aFrameDesc.GetName(); + ScrollingMode eScroll = aFrameDesc.GetScrollingMode(); + bool bHasBorder = aFrameDesc.HasFrameBorder(); + Size aMargin = aFrameDesc.GetMargin(); + + OUString sHRef = aFrameDesc.GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + if (INetURLObject(sHRef).IsExoticProtocol()) + NotifyMacroEventRead(); + + xSet->setPropertyValue("FrameURL", uno::Any( sHRef ) ); + xSet->setPropertyValue("FrameName", uno::Any( aName ) ); + + if ( eScroll == ScrollingMode::Auto ) + xSet->setPropertyValue("FrameIsAutoScroll", + uno::Any( true ) ); + else + xSet->setPropertyValue("FrameIsScrollingMode", + uno::Any( eScroll == ScrollingMode::Yes ) ); + + xSet->setPropertyValue("FrameIsBorder", + uno::Any( bHasBorder ) ); + + xSet->setPropertyValue("FrameMarginWidth", + uno::Any( sal_Int32( aMargin.Width() ) ) ); + + xSet->setPropertyValue("FrameMarginHeight", + uno::Any( sal_Int32( aMargin.Height() ) ) ); + } + } + } + catch ( uno::Exception& ) + { + } + + SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() ); + SvxCSS1PropertyInfo aPropInfo; + if( HasStyleOptions( aStyle, aId, aClass ) ) + ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo ); + + // fetch the ItemSet + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameSet( m_xDoc->GetAttrPool() ); + if( !IsNewDoc() ) + Reader::ResetFrameFormatAttrs( aFrameSet ); + + // set the anchor and the adjustment + SetAnchorAndAdjustment( eVertOri, eHoriOri, aPropInfo, aFrameSet ); + + // and still the size of the frame + Size aDfltSz( HTML_DFLT_APPLET_WIDTH, HTML_DFLT_APPLET_HEIGHT ); + SetFixSize( aSize, aDfltSz, bPercentWidth, bPercentHeight, aPropInfo, aFrameSet ); + SetSpace( aSpace, aItemSet, aPropInfo, aFrameSet ); + + // and insert into the document + SwFrameFormat* pFlyFormat = + m_xDoc->getIDocumentContentOperations().InsertEmbObject(*m_pPam, + ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT), + &aFrameSet); + + // set the alternative name + SwNoTextNode *pNoTextNd = + m_xDoc->GetNodes()[ pFlyFormat->GetContent().GetContentIdx() + ->GetIndex()+1 ]->GetNoTextNode(); + pNoTextNd->SetTitle( aAlt ); + + // if applicable create frames and register auto-bound frames + RegisterFlyFrame( pFlyFormat ); + + m_bInFloatingFrame = true; + + ++m_nFloatingFrames; +} + +SwHTMLFrameType SwHTMLWriter::GuessOLENodeFrameType( const SwNode& rNode ) +{ + SwHTMLFrameType eType = HTML_FRMTYPE_OLE; + + SwOLENode* pOLENode = const_cast<SwOLENode*>(rNode.GetOLENode()); + assert(pOLENode && "must exist"); + SwOLEObj& rObj = pOLENode->GetOLEObj(); + + uno::Reference < embed::XClassifiedObject > xClass = rObj.GetOleRef(); + SvGlobalName aClass( xClass->getClassID() ); + if( aClass == SvGlobalName( SO3_PLUGIN_CLASSID ) ) + { + eType = HTML_FRMTYPE_PLUGIN; + } + else if( aClass == SvGlobalName( SO3_IFRAME_CLASSID ) ) + { + eType = HTML_FRMTYPE_IFRAME; + } +#if HAVE_FEATURE_JAVA + else if( aClass == SvGlobalName( SO3_APPLET_CLASSID ) ) + { + eType = HTML_FRMTYPE_APPLET; + } +#endif + + return eType; +} + +SwHTMLWriter& OutHTML_FrameFormatOLENode( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat, + bool bInCntnr ) +{ + const SwFormatContent& rFlyContent = rFrameFormat.GetContent(); + SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex()+1; + SwOLENode *pOLENd = rWrt.m_pDoc->GetNodes()[ nStt ]->GetOLENode(); + + OSL_ENSURE( pOLENd, "OLE-Node expected" ); + if( !pOLENd ) + return rWrt; + + SwOLEObj &rObj = pOLENd->GetOLEObj(); + + uno::Reference < embed::XEmbeddedObject > xObj( rObj.GetOleRef() ); + if ( !svt::EmbeddedObjectRef::TryRunningState( xObj ) ) + return rWrt; + + uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY ); + bool bHiddenEmbed = false; + + if( !xSet.is() ) + { + OSL_FAIL("Unknown Object" ); + return rWrt; + } + + HtmlFrmOpts nFrameOpts; + + // if possible output a line break before the "object" + if (rWrt.IsLFPossible()) + rWrt.OutNewLine( true ); + + if( !rFrameFormat.GetName().isEmpty() ) + rWrt.OutImplicitMark( rFrameFormat.GetName(), + "ole" ); + uno::Any aAny; + SvGlobalName aGlobName( xObj->getClassID() ); + OStringBuffer sOut("<"); + if( aGlobName == SvGlobalName( SO3_PLUGIN_CLASSID ) ) + { + // first the plug-in specifics + sOut.append(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_embed); + + OUString aStr; + OUString aURL; + aAny = xSet->getPropertyValue("PluginURL"); + if( (aAny >>= aStr) && !aStr.isEmpty() ) + { + aURL = URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), + aStr); + } + + if( !aURL.isEmpty() ) + { + sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_src "=\""); + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + HTMLOutFuncs::Out_String( rWrt.Strm(), aURL ); + sOut.append('\"'); + } + + OUString aType; + aAny = xSet->getPropertyValue("PluginMimeType"); + if( (aAny >>= aType) && !aType.isEmpty() ) + { + sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_type "=\""); + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + HTMLOutFuncs::Out_String( rWrt.Strm(), aType ); + sOut.append('\"'); + } + + if ((RndStdIds::FLY_AT_PARA == rFrameFormat.GetAnchor().GetAnchorId()) && + css::text::WrapTextMode_THROUGH == rFrameFormat.GetSurround().GetSurround() ) + { + // A HIDDEN plug-in + sOut.append(" " OOO_STRING_SW_HTML_O_Hidden); + nFrameOpts = HTML_FRMOPTS_HIDDEN_EMBED; + bHiddenEmbed = true; + } + else + { + nFrameOpts = bInCntnr ? HTML_FRMOPTS_EMBED_CNTNR + : HTML_FRMOPTS_EMBED; + } + } + else if( aGlobName == SvGlobalName( SO3_APPLET_CLASSID ) ) + { + // or the applet specifics + + sOut.append(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_applet); + + // CODEBASE + OUString aCd; + aAny = xSet->getPropertyValue("AppletCodeBase"); + if( (aAny >>= aCd) && !aCd.isEmpty() ) + { + OUString sCodeBase( URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), aCd) ); + if( !sCodeBase.isEmpty() ) + { + sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_codebase "=\""); + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + HTMLOutFuncs::Out_String( rWrt.Strm(), sCodeBase ); + sOut.append('\"'); + } + } + + // CODE + OUString aClass; + aAny = xSet->getPropertyValue("AppletCode"); + aAny >>= aClass; + sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_code "=\""); + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + HTMLOutFuncs::Out_String( rWrt.Strm(), aClass ); + sOut.append('\"'); + + // NAME + OUString aAppletName; + aAny = xSet->getPropertyValue("AppletName"); + aAny >>= aAppletName; + if( !aAppletName.isEmpty() ) + { + sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_name "=\""); + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + HTMLOutFuncs::Out_String( rWrt.Strm(), aAppletName ); + sOut.append('\"'); + } + + bool bScript = false; + aAny = xSet->getPropertyValue("AppletIsScript"); + aAny >>= bScript; + if( bScript ) + sOut.append(" " OOO_STRING_SVTOOLS_HTML_O_mayscript); + + nFrameOpts = bInCntnr ? HTML_FRMOPTS_APPLET_CNTNR + : HTML_FRMOPTS_APPLET; + } + else + { + // or the Floating-Frame specifics + + sOut.append(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_iframe); + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + + SfxFrameHTMLWriter::Out_FrameDescriptor( rWrt.Strm(), rWrt.GetBaseURL(), + xSet ); + + nFrameOpts = bInCntnr ? HTML_FRMOPTS_IFRAME_CNTNR + : HTML_FRMOPTS_IFRAME; + } + + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + + // ALT, WIDTH, HEIGHT, HSPACE, VSPACE, ALIGN + if( rWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bHiddenEmbed ) + nFrameOpts |= HTML_FRMOPTS_OLE_CSS1; + OString aEndTags = rWrt.OutFrameFormatOptions( rFrameFormat, pOLENd->GetTitle(), nFrameOpts ); + if( rWrt.IsHTMLMode( HTMLMODE_ABS_POS_FLY ) && !bHiddenEmbed ) + rWrt.OutCSS1_FrameFormatOptions( rFrameFormat, nFrameOpts ); + + if( aGlobName == SvGlobalName( SO3_APPLET_CLASSID ) ) + { + // output the parameters of applets as separate tags + // and write a </APPLET> + + uno::Sequence < beans::PropertyValue > aProps; + aAny = xSet->getPropertyValue("AppletCommands"); + aAny >>= aProps; + + SvCommandList aCommands; + aCommands.FillFromSequence( aProps ); + std::vector<sal_uLong> aParams; + size_t i = aCommands.size(); + while( i > 0 ) + { + const SvCommand& rCommand = aCommands[ --i ]; + const OUString& rName = rCommand.GetCommand(); + SwHtmlOptType nType = SwApplet_Impl::GetOptionType( rName, true ); + if( SwHtmlOptType::TAG == nType ) + { + const OUString& rValue = rCommand.GetArgument(); + rWrt.Strm().WriteChar( ' ' ); + HTMLOutFuncs::Out_String( rWrt.Strm(), rName ); + rWrt.Strm().WriteOString( "=\"" ); + HTMLOutFuncs::Out_String( rWrt.Strm(), rValue ).WriteChar( '\"' ); + } + else if( SwHtmlOptType::PARAM == nType ) + { + aParams.push_back( i ); + } + } + + rWrt.Strm().WriteChar( '>' ); + + rWrt.IncIndentLevel(); // indent the applet content + + size_t ii = aParams.size(); + while( ii > 0 ) + { + const SvCommand& rCommand = aCommands[ aParams[--ii] ]; + const OUString& rName = rCommand.GetCommand(); + const OUString& rValue = rCommand.GetArgument(); + rWrt.OutNewLine(); + sOut.append( + "<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_param + " " OOO_STRING_SVTOOLS_HTML_O_name + "=\""); + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + HTMLOutFuncs::Out_String( rWrt.Strm(), rName ); + sOut.append("\" " OOO_STRING_SVTOOLS_HTML_O_value "=\""); + rWrt.Strm().WriteOString( sOut ); + sOut.setLength(0); + HTMLOutFuncs::Out_String( rWrt.Strm(), rValue ).WriteOString( "\">" ); + } + + rWrt.DecIndentLevel(); // indent the applet content + if( aCommands.size() ) + rWrt.OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_applet), false ); + } + else if( aGlobName == SvGlobalName( SO3_PLUGIN_CLASSID ) ) + { + // write plug-ins parameters as options + + uno::Sequence < beans::PropertyValue > aProps; + aAny = xSet->getPropertyValue("PluginCommands"); + aAny >>= aProps; + + SvCommandList aCommands; + aCommands.FillFromSequence( aProps ); + for( size_t i = 0; i < aCommands.size(); i++ ) + { + const SvCommand& rCommand = aCommands[ i ]; + const OUString& rName = rCommand.GetCommand(); + + if( SwApplet_Impl::GetOptionType( rName, false ) == SwHtmlOptType::TAG ) + { + const OUString& rValue = rCommand.GetArgument(); + rWrt.Strm().WriteChar( ' ' ); + HTMLOutFuncs::Out_String( rWrt.Strm(), rName ); + rWrt.Strm().WriteOString( "=\"" ); + HTMLOutFuncs::Out_String( rWrt.Strm(), rValue ).WriteChar( '\"' ); + } + } + rWrt.Strm().WriteChar( '>' ); + } + else + { + // and for Floating-Frames just output another </IFRAME> + + rWrt.Strm().WriteChar( '>' ); + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_iframe), false ); + } + + if( !aEndTags.isEmpty() ) + rWrt.Strm().WriteOString( aEndTags ); + + return rWrt; +} + +static void OutHTMLGraphic(SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat, SwOLENode* pOLENd, + const Graphic& rGraphic, bool bObjectOpened, bool bInCntnr) +{ + OUString aGraphicURL; + OUString aMimeType; + if (!rWrt.mbEmbedImages) + { + const OUString* pTempFileName = rWrt.GetOrigFileName(); + if (pTempFileName) + aGraphicURL = *pTempFileName; + + OUString aFilterName(u"JPG"_ustr); + XOutFlags nFlags = XOutFlags::UseGifIfPossible | XOutFlags::UseNativeIfPossible; + + if (bObjectOpened) + { + aFilterName = u"PNG"_ustr; + nFlags = XOutFlags::NONE; + aMimeType = u"image/png"_ustr; + + if (rGraphic.GetType() == GraphicType::NONE) + { + // The OLE Object has no replacement image, write a stub. + aGraphicURL = lcl_CalculateFileName(rWrt.GetOrigFileName(), rGraphic, u"png"); + osl::File aFile(aGraphicURL); + aFile.open(osl_File_OpenFlag_Create); + aFile.close(); + } + } + + ErrCode nErr = XOutBitmap::WriteGraphic(rGraphic, aGraphicURL, aFilterName, nFlags); + if (nErr) // error, don't write anything + { + rWrt.m_nWarn = WARN_SWG_POOR_LOAD; + if (bObjectOpened) // Still at least close the tag. + rWrt.Strm().WriteOString( + Concat2View("</" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object ">")); + return; + } + aGraphicURL = URIHelper::SmartRel2Abs(INetURLObject(rWrt.GetBaseURL()), aGraphicURL, + URIHelper::GetMaybeFileHdl()); + } + HtmlFrmOpts nFlags = bInCntnr ? HtmlFrmOpts::GenImgAllMask : HtmlFrmOpts::GenImgMask; + if (bObjectOpened) + nFlags |= HtmlFrmOpts::Replacement; + HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace); + OutHTML_ImageStart(aHtml, rWrt, rFrameFormat, aGraphicURL, rGraphic, pOLENd->GetTitle(), + pOLENd->GetTwipSize(), nFlags, "ole", nullptr, aMimeType); + OutHTML_ImageEnd(aHtml, rWrt); +} + +static void OutHTMLStartObject(SwHTMLWriter& rWrt, const OUString& rFileName, const OUString& rFileType) +{ + OUString aFileName = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), rFileName); + + if (rWrt.IsLFPossible()) + rWrt.OutNewLine(); + rWrt.Strm().WriteOString( + Concat2View("<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object)); + rWrt.Strm().WriteOString(Concat2View(" data=\"" + aFileName.toUtf8() + "\"")); + if (!rFileType.isEmpty()) + rWrt.Strm().WriteOString(Concat2View(" type=\"" + rFileType.toUtf8() + "\"")); + rWrt.Strm().WriteOString(">"); + rWrt.SetLFPossible(true); +} + +static void OutHTMLEndObject(SwHTMLWriter& rWrt) +{ + rWrt.Strm().WriteOString( + Concat2View("</" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object ">")); +} + +static bool TrySaveFormulaAsPDF(SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat, + SwOLENode* pOLENd, bool bWriteReplacementGraphic, bool bInCntnr) +{ + if (!rWrt.mbReqIF) + return false; + if (!rWrt.m_bExportFormulasAsPDF) + return false; + + auto xTextContent = SwXTextEmbeddedObject::CreateXTextEmbeddedObject( + *rWrt.m_pDoc, const_cast<SwFrameFormat*>(&rFrameFormat)); + uno::Reference<frame::XStorable> xStorable(xTextContent->getEmbeddedObject(), uno::UNO_QUERY); + uno::Reference<lang::XServiceInfo> xServiceInfo(xStorable, uno::UNO_QUERY); + if (!xServiceInfo) + return false; + if (!xServiceInfo->supportsService(u"com.sun.star.formula.FormulaProperties"_ustr)) + return false; + + Graphic aGraphic(xTextContent->getReplacementGraphic()); + OUString aFileName = lcl_CalculateFileName(rWrt.GetOrigFileName(), aGraphic, u"pdf"); + + utl::MediaDescriptor aDescr; + aDescr[u"FilterName"_ustr] <<= u"math_pdf_Export"_ustr; + // Properties from starmath/inc/unomodel.hxx + aDescr[u"FilterData"_ustr] <<= comphelper::InitPropertySequence({ + { u"TitleRow"_ustr, css::uno::Any(false) }, + { u"FormulaText"_ustr, css::uno::Any(false) }, + { u"Border"_ustr, css::uno::Any(false) }, + { u"PrintFormat"_ustr, css::uno::Any(sal_Int32(1)) }, // PRINT_SIZE_SCALED + }); + xStorable->storeToURL(aFileName, aDescr.getAsConstPropertyValueList()); + + OutHTMLStartObject(rWrt, aFileName, u"application/pdf"_ustr); + + if (bWriteReplacementGraphic) + OutHTMLGraphic(rWrt, rFrameFormat, pOLENd, aGraphic, true, bInCntnr); + + OutHTMLEndObject(rWrt); + + return true; +} + +SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat, + bool bInCntnr, bool bWriteReplacementGraphic ) +{ + const SwFormatContent& rFlyContent = rFrameFormat.GetContent(); + SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex()+1; + SwOLENode *pOLENd = rWrt.m_pDoc->GetNodes()[ nStt ]->GetOLENode(); + + OSL_ENSURE( pOLENd, "OLE-Node expected" ); + if( !pOLENd ) + return rWrt; + + if (rWrt.mbSkipImages) + { + // If we skip images, embedded objects would be completely lost. + // Instead, try to use the HTML export of the embedded object. + auto xTextContent = SwXTextEmbeddedObject::CreateXTextEmbeddedObject(*rWrt.m_pDoc, const_cast<SwFrameFormat*>(&rFrameFormat)); + uno::Reference<frame::XStorable> xStorable(xTextContent->getEmbeddedObject(), uno::UNO_QUERY); + SAL_WARN_IF(!xStorable.is(), "sw.html", "OutHTML_FrameFormatOLENodeGrf: no embedded object"); + + // Figure out what is the filter name of the embedded object. + OUString aFilter; + if (uno::Reference<lang::XServiceInfo> xServiceInfo{ xStorable, uno::UNO_QUERY }) + { + if (xServiceInfo->supportsService("com.sun.star.sheet.SpreadsheetDocument")) + aFilter = "HTML (StarCalc)"; + else if (xServiceInfo->supportsService("com.sun.star.text.TextDocument")) + aFilter = "HTML (StarWriter)"; + } + + if (!aFilter.isEmpty()) + { + try + { + // FIXME: exception for the simplest test document, too + SvMemoryStream aStream; + uno::Reference<io::XOutputStream> xOutputStream(new utl::OStreamWrapper(aStream)); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= aFilter; + aMediaDescriptor["FilterOptions"] <<= OUString("SkipHeaderFooter"); + aMediaDescriptor["OutputStream"] <<= xOutputStream; + xStorable->storeToURL("private:stream", aMediaDescriptor.getAsConstPropertyValueList()); + SAL_WARN_IF(aStream.GetSize()>=o3tl::make_unsigned(SAL_MAX_INT32), "sw.html", "Stream can't fit in OString"); + OString aData(static_cast<const char*>(aStream.GetData()), static_cast<sal_Int32>(aStream.GetSize())); + // Wrap output in a <span> tag to avoid 'HTML parser error: Unexpected end tag: p' + HTMLOutFuncs::Out_AsciiTag(rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span)); + rWrt.Strm().WriteOString(aData); + HTMLOutFuncs::Out_AsciiTag(rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false); + } + catch ( uno::Exception& ) + { + } + } + + return rWrt; + } + + if (TrySaveFormulaAsPDF(rWrt, rFrameFormat, pOLENd, bWriteReplacementGraphic, bInCntnr)) + return rWrt; + + if ( !pOLENd->GetGraphic() ) + { + SAL_WARN("sw.html", "Unexpected missing OLE fallback graphic"); + return rWrt; + } + + Graphic aGraphic( *pOLENd->GetGraphic() ); + + SwDocShell* pDocSh = rWrt.m_pDoc->GetDocShell(); + bool bObjectOpened = false; + OUString aRTFType = "text/rtf"; + if (!rWrt.m_aRTFOLEMimeType.isEmpty()) + { + aRTFType = rWrt.m_aRTFOLEMimeType; + } + + if (rWrt.mbXHTML && pDocSh) + { + // Map native data to an outer <object> element. + + // Calculate the file name, which is meant to be the same as the + // replacement image, just with a .ole extension. + OUString aFileName = lcl_CalculateFileName(rWrt.GetOrigFileName(), aGraphic, u"ole"); + + // Write the data. + SwOLEObj& rOLEObj = pOLENd->GetOLEObj(); + uno::Reference<embed::XEmbeddedObject> xEmbeddedObject = rOLEObj.GetOleRef(); + OUString aFileType; + SvFileStream aOutStream(aFileName, StreamMode::WRITE); + uno::Reference<io::XActiveDataStreamer> xStreamProvider; + uno::Reference<embed::XEmbedPersist2> xOwnEmbedded; + if (xEmbeddedObject.is()) + { + xStreamProvider.set(xEmbeddedObject, uno::UNO_QUERY); + xOwnEmbedded.set(xEmbeddedObject, uno::UNO_QUERY); + } + if (xStreamProvider.is()) + { + // Real OLE2 case: OleEmbeddedObject. + uno::Reference<io::XInputStream> xStream(xStreamProvider->getStream(), uno::UNO_QUERY); + if (xStream.is()) + { + std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xStream)); + if (SwReqIfReader::WrapOleInRtf(*pStream, aOutStream, *pOLENd, rFrameFormat)) + { + // Data always wrapped in RTF. + aFileType = aRTFType; + } + } + } + else if (xOwnEmbedded.is()) + { + // Our own embedded object: OCommonEmbeddedObject. + SvxMSExportOLEObjects aOLEExp(0); + // Trigger the load of the OLE object if needed, otherwise we can't + // export it. + pOLENd->GetTwipSize(); + SvMemoryStream aMemory; + tools::SvRef<SotStorage> pStorage = new SotStorage(aMemory); + aOLEExp.ExportOLEObject(rOLEObj.GetObject(), *pStorage); + pStorage->Commit(); + aMemory.Seek(0); + if (SwReqIfReader::WrapOleInRtf(aMemory, aOutStream, *pOLENd, rFrameFormat)) + { + // Data always wrapped in RTF. + aFileType = aRTFType; + } + } + else + { + // Otherwise the native data is just a grab-bag: ODummyEmbeddedObject. + const OUString& aStreamName = rOLEObj.GetCurrentPersistName(); + uno::Reference<embed::XStorage> xStorage = pDocSh->GetStorage(); + uno::Reference<io::XStream> xInStream; + try + { + // Even the native data may be missing. + xInStream = xStorage->openStreamElement(aStreamName, embed::ElementModes::READ); + } catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("sw.html", "OutHTML_FrameFormatOLENodeGrf: failed to open stream element"); + } + if (xInStream.is()) + { + uno::Reference<io::XStream> xOutStream(new utl::OStreamWrapper(aOutStream)); + comphelper::OStorageHelper::CopyInputToOutput(xInStream->getInputStream(), + xOutStream->getOutputStream()); + } + + uno::Reference<beans::XPropertySet> xOutStreamProps(xInStream, uno::UNO_QUERY); + if (xOutStreamProps.is()) + xOutStreamProps->getPropertyValue("MediaType") >>= aFileType; + if (!aRTFType.isEmpty()) + { + aFileType = aRTFType; + } + } + + // Refer to this data. + OutHTMLStartObject(rWrt, aFileName, aFileType); + bObjectOpened = true; + } + + if (!bObjectOpened || bWriteReplacementGraphic) + OutHTMLGraphic(rWrt, rFrameFormat, pOLENd, aGraphic, bObjectOpened, bInCntnr); + + if (bObjectOpened) + // Close native data. + OutHTMLEndObject(rWrt); + + return rWrt; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |