1
0
Fork 0
libreoffice/slideshow/source/engine/shapes/shapeimporter.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

575 lines
20 KiB
C++

/* -*- 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 <utility>
#include <vcl/GraphicObject.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <cppcanvas/basegfxfactory.hxx>
#include <cppcanvas/polypolygon.hxx>
#include <com/sun/star/awt/Rectangle.hpp>
#include <com/sun/star/drawing/ColorMode.hpp>
#include <com/sun/star/text/GraphicCrop.hpp>
#include <com/sun/star/drawing/PointSequenceSequence.hpp>
#include <com/sun/star/drawing/PointSequence.hpp>
#include <com/sun/star/drawing/XLayerSupplier.hpp>
#include <com/sun/star/drawing/XLayerManager.hpp>
#include <com/sun/star/graphic/XGraphic.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include "drawshape.hxx"
#include "backgroundshape.hxx"
#include "mediashape.hxx"
#include "appletshape.hxx"
#include <shapeimporter.hxx>
#include <slideshowexceptions.hxx>
#include <tools.hxx>
#include <slideshowcontext.hxx>
#include <unoviewcontainer.hxx>
#include <memory>
using namespace com::sun::star;
namespace slideshow::internal {
namespace {
std::unique_ptr<GraphicObject> importShapeGraphic(uno::Reference<beans::XPropertySet> const& xPropSet)
{
std::unique_ptr<GraphicObject> xRet;
uno::Reference<graphic::XGraphic> xGraphic;
if (!getPropertyValue(xGraphic, xPropSet, u"Graphic"_ustr) || !xGraphic.is())
{
// no or empty property - cannot import shape graphic
return xRet;
}
Graphic aGraphic(xGraphic);
xRet.reset(new GraphicObject(std::move(aGraphic)));
if (GraphicType::Default == xRet->GetType() || GraphicType::NONE == xRet->GetType())
{
xRet.reset();
}
return xRet;
}
/** This shape implementation just acts as a dummy for the layermanager.
Its sole role is for hit test detection of group shapes.
*/
class ShapeOfGroup : public Shape
{
public:
ShapeOfGroup( ShapeSharedPtr const& pGroupShape,
uno::Reference<drawing::XShape> xShape,
uno::Reference<beans::XPropertySet> const& xPropSet,
double nPrio );
// Shape:
virtual uno::Reference<drawing::XShape> getXShape() const override;
virtual void addViewLayer( ViewLayerSharedPtr const& pNewLayer,
bool bRedrawLayer ) override;
virtual bool removeViewLayer( ViewLayerSharedPtr const& pNewLayer ) override;
virtual void clearAllViewLayers() override;
virtual bool update() const override;
virtual bool render() const override;
virtual bool isContentChanged() const override;
virtual basegfx::B2DRectangle getBounds() const override;
virtual basegfx::B2DRectangle getDomBounds() const override;
virtual basegfx::B2DRectangle getUpdateArea() const override;
virtual bool isVisible() const override;
virtual double getPriority() const override;
virtual bool isBackgroundDetached() const override;
private:
ShapeSharedPtr const mpGroupShape;
uno::Reference<drawing::XShape> const mxShape;
double const mnPrio;
basegfx::B2DPoint maPosOffset;
double mnWidth;
double mnHeight;
};
ShapeOfGroup::ShapeOfGroup( ShapeSharedPtr const& pGroupShape,
uno::Reference<drawing::XShape> xShape,
uno::Reference<beans::XPropertySet> const& xPropSet,
double nPrio ) :
mpGroupShape(pGroupShape),
mxShape(std::move(xShape)),
mnPrio(nPrio)
{
// read bound rect
uno::Any const aTmpRect_( xPropSet->getPropertyValue( u"BoundRect"_ustr ));
awt::Rectangle const aTmpRect( aTmpRect_.get<awt::Rectangle>() );
basegfx::B2DRectangle const groupPosSize( pGroupShape->getBounds() );
maPosOffset = basegfx::B2DPoint( aTmpRect.X - groupPosSize.getMinX(),
aTmpRect.Y - groupPosSize.getMinY() );
mnWidth = aTmpRect.Width;
mnHeight = aTmpRect.Height;
}
uno::Reference<drawing::XShape> ShapeOfGroup::getXShape() const
{
return mxShape;
}
void ShapeOfGroup::addViewLayer( ViewLayerSharedPtr const& /*pNewLayer*/,
bool /*bRedrawLayer*/ )
{
}
bool ShapeOfGroup::removeViewLayer( ViewLayerSharedPtr const& /*pNewLayer*/ )
{
return true;
}
void ShapeOfGroup::clearAllViewLayers()
{
}
bool ShapeOfGroup::update() const
{
return true;
}
bool ShapeOfGroup::render() const
{
return true;
}
bool ShapeOfGroup::isContentChanged() const
{
return false;
}
basegfx::B2DRectangle ShapeOfGroup::getBounds() const
{
basegfx::B2DRectangle const groupPosSize( mpGroupShape->getBounds() );
double const posX = groupPosSize.getMinX() + maPosOffset.getX();
double const posY = groupPosSize.getMinY() + maPosOffset.getY();
return basegfx::B2DRectangle( posX, posY, posX + mnWidth, posY + mnHeight );
}
basegfx::B2DRectangle ShapeOfGroup::getDomBounds() const
{
return getBounds();
}
basegfx::B2DRectangle ShapeOfGroup::getUpdateArea() const
{
return getBounds();
}
bool ShapeOfGroup::isVisible() const
{
return mpGroupShape->isVisible();
}
double ShapeOfGroup::getPriority() const
{
return mnPrio;
}
bool ShapeOfGroup::isBackgroundDetached() const
{
return false;
}
} // anon namespace
ShapeSharedPtr ShapeImporter::createShape(
uno::Reference<drawing::XShape> const& xCurrShape,
uno::Reference<beans::XPropertySet> const& xPropSet,
std::u16string_view shapeType ) const
{
css::uno::Reference<css::drawing::XDrawPage> xPage = mxPage;
if (mbConvertingMasterPage && mbMasterPageObjectsOnly)
{
const XShapesEntry& rTop = maShapesStack.top();
css::uno::Reference<css::drawing::XDrawPage> xMasterPage(rTop.mxShapes, uno::UNO_QUERY_THROW);
if (xMasterPage.is())
xPage = std::move(xMasterPage);
}
if( shapeType == u"com.sun.star.drawing.MediaShape" || shapeType == u"com.sun.star.presentation.MediaShape" )
{
// Media shape (video etc.). This is a special object
return createMediaShape(xCurrShape,
mnAscendingPrio,
mrContext);
}
else if( shapeType == u"com.sun.star.drawing.AppletShape" )
{
// PropertyValues to copy from XShape to applet
static const char* aPropertyValues[] =
{
"AppletCodeBase",
"AppletName",
"AppletCode",
"AppletCommands",
"AppletIsScript"
};
// (Java)Applet shape. This is a special object
return createAppletShape( xCurrShape,
mnAscendingPrio,
u"com.sun.star.comp.sfx2.AppletObject"_ustr,
aPropertyValues,
SAL_N_ELEMENTS(aPropertyValues),
mrContext );
}
else if( shapeType == u"com.sun.star.drawing.OLE2Shape" || shapeType == u"com.sun.star.presentation.OLE2Shape" )
{
// #i46224# Mark OLE shapes as foreign content - scan them for
// unsupported actions, and fallback to bitmap, if necessary
return DrawShape::create( xCurrShape,
xPage,
mnAscendingPrio,
true,
mrContext );
}
else if( shapeType == u"com.sun.star.drawing.GraphicObjectShape" || shapeType == u"com.sun.star.presentation.GraphicObjectShape" )
{
// to get hold of GIF animations, inspect Graphic
// objects more thoroughly (the plain-jane shape
// metafile of course would only contain the first
// animation frame)
std::unique_ptr<GraphicObject> xGraphicObject(importShapeGraphic(xPropSet));
if (!xGraphicObject)
return ShapeSharedPtr(); // error loading graphic -
// no placeholders in
// slideshow
if (!xGraphicObject->IsAnimated())
{
// no animation - simply utilize plain draw shape import
// import shape as bitmap - either it's a bitmap
// anyway, or it's a metafile, which currently the
// metafile renderer might not display correctly.
return DrawShape::create( xCurrShape,
xPage,
mnAscendingPrio,
true,
mrContext );
}
// now extract relevant shape attributes via API
drawing::ColorMode eColorMode( drawing::ColorMode_STANDARD );
sal_Int16 nLuminance(0);
sal_Int16 nContrast(0);
sal_Int16 nRed(0);
sal_Int16 nGreen(0);
sal_Int16 nBlue(0);
double nGamma(1.0);
sal_Int16 nTransparency(0);
sal_Int32 nRotation(0);
getPropertyValue( eColorMode, xPropSet, u"GraphicColorMode"_ustr );
getPropertyValue( nLuminance, xPropSet, u"AdjustLuminance"_ustr );
getPropertyValue( nContrast, xPropSet, u"AdjustContrast"_ustr );
getPropertyValue( nRed, xPropSet, u"AdjustRed"_ustr );
getPropertyValue( nGreen, xPropSet, u"AdjustGreen"_ustr );
getPropertyValue( nBlue, xPropSet, u"AdjustBlue"_ustr );
getPropertyValue( nGamma, xPropSet, u"Gamma"_ustr );
getPropertyValue( nTransparency, xPropSet, u"Transparency"_ustr );
getPropertyValue( nRotation, xPropSet, u"RotateAngle"_ustr );
GraphicAttr aGraphAttrs;
aGraphAttrs.SetDrawMode( static_cast<GraphicDrawMode>(eColorMode) );
aGraphAttrs.SetLuminance( nLuminance );
aGraphAttrs.SetContrast( nContrast );
aGraphAttrs.SetChannelR( nRed );
aGraphAttrs.SetChannelG( nGreen );
aGraphAttrs.SetChannelB( nBlue );
aGraphAttrs.SetGamma( nGamma );
aGraphAttrs.SetAlpha( 255 - static_cast<sal_uInt8>(nTransparency) );
aGraphAttrs.SetRotation( Degree10(static_cast<sal_Int16>(nRotation*10)) );
text::GraphicCrop aGraphCrop;
if( getPropertyValue( aGraphCrop, xPropSet, u"GraphicCrop"_ustr ))
{
aGraphAttrs.SetCrop( aGraphCrop.Left,
aGraphCrop.Top,
aGraphCrop.Right,
aGraphCrop.Bottom );
}
// fetch readily transformed and color-modified
// graphic
std::shared_ptr<Graphic> pGraphic
= ::std::make_shared<Graphic>(xGraphicObject->GetTransformedGraphic(
xGraphicObject->GetPrefSize(),
xGraphicObject->GetPrefMapMode(),
aGraphAttrs ) );
return DrawShape::create( xCurrShape,
xPage,
mnAscendingPrio,
std::move(pGraphic),
mrContext );
}
else
{
return DrawShape::create( xCurrShape,
xPage,
mnAscendingPrio,
false,
mrContext );
}
}
bool ShapeImporter::isSkip(
uno::Reference<beans::XPropertySet> const& xPropSet,
std::u16string_view shapeType,
uno::Reference< drawing::XLayer> const& xLayer )
{
// skip empty presentation objects:
bool bEmpty = false;
if( getPropertyValue( bEmpty,
xPropSet,
u"IsEmptyPresentationObject"_ustr) &&
bEmpty )
{
// check object have fill or linestyle, if have, it should be visible
drawing::FillStyle aFillStyle{ drawing::FillStyle_NONE };
if (getPropertyValue(aFillStyle,
xPropSet, u"FillStyle"_ustr) &&
aFillStyle != drawing::FillStyle_NONE)
{
bEmpty = false;
}
drawing::LineStyle aLineStyle{ drawing::LineStyle_NONE };
if (bEmpty && getPropertyValue(aLineStyle,
xPropSet, u"LineStyle"_ustr) &&
aLineStyle != drawing::LineStyle_NONE)
{
bEmpty = false;
}
if (bEmpty)
return true;
}
//skip shapes which corresponds to annotations
if(xLayer.is())
{
OUString layerName;
const uno::Any a(xLayer->getPropertyValue(u"Name"_ustr) );
bool const bRet = (a >>= layerName);
if(bRet)
{
if( layerName == "DrawnInSlideshow" )
{
//Transform shapes into PolyPolygons
importPolygons(xPropSet);
return true;
}
}
}
// don't export presentation placeholders on masterpage
// they can be non empty when user edits the default texts
if(mbConvertingMasterPage)
{
if( shapeType == u"com.sun.star.presentation.TitleTextShape" || shapeType == u"com.sun.star.presentation.OutlinerShape" )
{
return true;
}
if( mbTextFieldsOnly )
{
if( !( shapeType == u"com.sun.star.presentation.SlideNumberShape" ||
shapeType == u"com.sun.star.presentation.FooterShape" ||
shapeType == u"com.sun.star.presentation.DateTimeShape" ) )
{
return true;
}
}
}
return false;
}
void ShapeImporter::importPolygons(uno::Reference<beans::XPropertySet> const& xPropSet) {
drawing::PointSequenceSequence aRetval;
sal_Int32 nLineColor=0;
double fLineWidth;
getPropertyValue( aRetval, xPropSet, u"PolyPolygon"_ustr );
getPropertyValue( nLineColor, xPropSet, u"LineColor"_ustr );
getPropertyValue( fLineWidth, xPropSet, u"LineWidth"_ustr );
const drawing::PointSequence* pOuterSequence = aRetval.getArray();
::basegfx::B2DPolygon aPoly;
basegfx::B2DPoint aPoint;
for( const awt::Point& rPoint : *pOuterSequence )
{
aPoint.setX(rPoint.X);
aPoint.setY(rPoint.Y);
aPoly.append( aPoint );
}
for( const auto& pView : mrContext.mrViewContainer )
{
::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
::cppcanvas::BaseGfxFactory::createPolyPolygon( pView->getCanvas(),
aPoly ) );
if( pPolyPoly )
{
pPolyPoly->setRGBALineColor( unoColor2RGBColor( nLineColor ).getIntegerColor() );
pPolyPoly->setStrokeWidth(fLineWidth);
pPolyPoly->draw();
maPolygons.push_back(pPolyPoly);
}
}
}
ShapeSharedPtr ShapeImporter::importBackgroundShape() // throw (ShapeLoadFailedException)
{
if( maShapesStack.empty() )
throw ShapeLoadFailedException();
XShapesEntry& rTop = maShapesStack.top();
ShapeSharedPtr pBgShape(
createBackgroundShape(mxPage,
uno::Reference<drawing::XDrawPage>(
rTop.mxShapes,
uno::UNO_QUERY_THROW),
mrContext) );
mnAscendingPrio += 1.0;
return pBgShape;
}
ShapeSharedPtr ShapeImporter::importShape() // throw (ShapeLoadFailedException)
{
ShapeSharedPtr pRet;
bool bIsGroupShape = false;
while( !maShapesStack.empty() && !pRet )
{
XShapesEntry& rTop = maShapesStack.top();
if( rTop.mnPos < rTop.mnCount )
{
uno::Reference<drawing::XShape> const xCurrShape(
rTop.mxShapes->getByIndex( rTop.mnPos ), uno::UNO_QUERY );
++rTop.mnPos;
uno::Reference<beans::XPropertySet> xPropSet(
xCurrShape, uno::UNO_QUERY );
if( !xPropSet.is() )
{
// we definitely need the properties of
// the shape here. This will also fail,
// if getByIndex did not return a valid
// shape
throw ShapeLoadFailedException();
}
//Retrieve the layer for the current shape
uno::Reference< drawing::XLayer > xDrawnInSlideshow;
uno::Reference< drawing::XLayerSupplier > xLayerSupplier(mxPagesSupplier, uno::UNO_QUERY);
if(xLayerSupplier.is())
{
uno::Reference< container::XNameAccess > xNameAccess = xLayerSupplier->getLayerManager();
uno::Reference< drawing::XLayerManager > xLayerManager(xNameAccess, uno::UNO_QUERY);
xDrawnInSlideshow = xLayerManager->getLayerForShape(xCurrShape);
}
OUString const shapeType( xCurrShape->getShapeType());
// is this shape presentation-invisible?
if( !isSkip(xPropSet, shapeType, xDrawnInSlideshow) )
{
bIsGroupShape = shapeType == "com.sun.star.drawing.GroupShape";
if( rTop.mpGroupShape ) // in group particle mode?
{
pRet = std::make_shared<ShapeOfGroup>(
rTop.mpGroupShape /* container shape */,
xCurrShape, xPropSet,
mnAscendingPrio );
}
else
{
pRet = createShape( xCurrShape, xPropSet, shapeType );
}
mnAscendingPrio += 1.0;
}
}
if( rTop.mnPos >= rTop.mnCount )
{
// group or top-level shapes finished:
maShapesStack.pop();
}
if( bIsGroupShape && pRet )
{
// push new group on the stack: group traversal
maShapesStack.push( XShapesEntry( pRet ) );
}
}
return pRet;
}
bool ShapeImporter::isImportDone() const
{
return maShapesStack.empty();
}
const PolyPolygonVector& ShapeImporter::getPolygons() const
{
return maPolygons;
}
ShapeImporter::ShapeImporter( uno::Reference<drawing::XDrawPage> const& xPage,
uno::Reference<drawing::XDrawPage> xActualPage,
uno::Reference<drawing::XDrawPagesSupplier> xPagesSupplier,
const SlideShowContext& rContext,
sal_Int32 nOrdNumStart,
bool bConvertingMasterPage ) :
mxPage(std::move( xActualPage )),
mxPagesSupplier(std::move( xPagesSupplier )),
mrContext( rContext ),
maPolygons(),
maShapesStack(),
mnAscendingPrio( nOrdNumStart ),
mbConvertingMasterPage( bConvertingMasterPage ),
mbMasterPageObjectsOnly( false ),
mbTextFieldsOnly( false )
{
uno::Reference<drawing::XShapes> const xShapes(
xPage, uno::UNO_QUERY_THROW );
maShapesStack.push( XShapesEntry(xShapes) );
}
} // namespace presentation
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */