/* -*- 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 ) )
(void)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(u"PluginURL"_ustr, uno::Any( aURL ) );
if( bHasType )
xSet->setPropertyValue(u"PluginMimeType"_ustr, uno::Any( aType ) );
uno::Sequence < beans::PropertyValue > aProps;
aCmdLst.FillSequence( aProps );
xSet->setPropertyValue(u"PluginCommands"_ustr, 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(u"private:stream"_ustr) },
{ "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(u"MediaType"_ustr, 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(u"StreamReadOnly"_ustr,
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(u"StreamReadOnly"_ustr,
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 ) )
(void)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 ) )
(void)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(u"FrameURL"_ustr, uno::Any( sHRef ) );
xSet->setPropertyValue(u"FrameName"_ustr, uno::Any( aName ) );
if ( eScroll == ScrollingMode::Auto )
xSet->setPropertyValue(u"FrameIsAutoScroll"_ustr,
uno::Any( true ) );
else
xSet->setPropertyValue(u"FrameIsScrollingMode"_ustr,
uno::Any( eScroll == ScrollingMode::Yes ) );
xSet->setPropertyValue(u"FrameIsBorder"_ustr,
uno::Any( bHasBorder ) );
xSet->setPropertyValue(u"FrameMarginWidth"_ustr,
uno::Any( sal_Int32( aMargin.Width() ) ) );
xSet->setPropertyValue(u"FrameMarginHeight"_ustr,
uno::Any( sal_Int32( aMargin.Height() ) ) );
}
}
}
catch ( uno::Exception& )
{
}
SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
SvxCSS1PropertyInfo aPropInfo;
if( HasStyleOptions( aStyle, aId, aClass ) )
(void)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(u"PluginURL"_ustr);
if( (aAny >>= aStr) && !aStr.isEmpty() )
{
aURL = rWrt.normalizeURL(aStr, false);
}
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(u"PluginMimeType"_ustr);
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(u"AppletCodeBase"_ustr);
if( (aAny >>= aCd) && !aCd.isEmpty() )
{
OUString sCodeBase(rWrt.normalizeURL(aCd, false));
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(u"AppletCode"_ustr);
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(u"AppletName"_ustr);
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(u"AppletIsScript"_ustr);
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(u"AppletCommands"_ustr);
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(u"PluginCommands"_ustr);
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, true);
OutHTML_ImageEnd(aHtml, rWrt);
}
static void OutHTMLStartObject(SwHTMLWriter& rWrt, const OUString& rFileName, const OUString& rFileType)
{
// OutHTMLStartObject is only for own objects
OUString aFileName = rWrt.normalizeURL(rFileName, true);
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(u"com.sun.star.sheet.SpreadsheetDocument"_ustr))
aFilter = "HTML (StarCalc)";
else if (xServiceInfo->supportsService(u"com.sun.star.text.TextDocument"_ustr))
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[u"FilterName"_ustr] <<= aFilter;
aMediaDescriptor[u"FilterOptions"_ustr] <<= u"SkipHeaderFooter"_ustr;
aMediaDescriptor[u"OutputStream"_ustr] <<= xOutputStream;
xStorable->storeToURL(u"private:stream"_ustr, 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;
// Missing fallback graphic must not give up exporting the document, and also must produce
// valid output (see OutHTMLGraphic)
const Graphic* pFallbackGraphic = pOLENd->GetGraphic();
Graphic aGraphic(pFallbackGraphic ? *pFallbackGraphic : Graphic());
SwDocShell* pDocSh = rWrt.m_pDoc->GetDocShell();
bool bObjectOpened = false;
OUString aRTFType = u"text/rtf"_ustr;
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;
rtl::Reference<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(u"MediaType"_ustr) >>= 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: */
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.