blob: bf67a8341920abac2edd9d56c32bed0dbb3a2099 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_slideshow.hxx"
// must be first
#include <canvas/debug.hxx>
#include <vcl/cvtgrf.hxx>
#include <tools/urlobj.hxx>
#include <tools/stream.hxx>
#include <svtools/grfmgr.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <unotools/streamwrap.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/container/XNameContainer.hpp>
#include <com/sun/star/drawing/PointSequenceSequence.hpp>
#include <com/sun/star/drawing/PointSequence.hpp>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/drawing/XLayerSupplier.hpp>
#include <com/sun/star/drawing/XLayerManager.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include "drawshapesubsetting.hxx"
#include "drawshape.hxx"
#include "backgroundshape.hxx"
#include "mediashape.hxx"
#include "appletshape.hxx"
#include "shapeimporter.hxx"
#include "slideshowexceptions.hxx"
#include "gdimtftools.hxx"
#include "tools.hxx"
#include "slideshowcontext.hxx"
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
using namespace com::sun::star;
namespace slideshow {
namespace internal {
namespace {
bool importShapeGraphic(
GraphicObject & o_rGraphic,
uno::Reference<beans::XPropertySet> const& xPropSet )
{
rtl::OUString aURL;
if( !getPropertyValue( aURL, xPropSet, OUSTR("GraphicURL")) ||
aURL.getLength() == 0 )
{
// no or empty property - cannot import shape graphic
return false;
}
rtl::OUString const aVndUrl(
RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.GraphicObject:" ) );
sal_Int32 nIndex( aURL.indexOf( aVndUrl ) );
if(nIndex != -1)
{
// skip past the end of the "vnd..." prefix
nIndex += aVndUrl.getLength();
if(nIndex >= aURL.getLength())
{
OSL_ENSURE( false, "ShapeImporter::importShape(): "
"embedded graphic has no graphic ID" );
return false;
}
// unique ID string found in URL, extract
// to separate string
rtl::OUString const aUniqueId(
aURL.copy( nIndex, aURL.getLength() - nIndex ) );
// TODO(T2): Creating a GraphicObject is not
// thread safe (internally calls VCL, and has
// unguarded internal singleton mpGlobalMgr)
// fetch already loaded graphic from graphic manager.
ByteString const aOldString( static_cast<String>(aUniqueId),
RTL_TEXTENCODING_UTF8 );
o_rGraphic = GraphicObject( aOldString );
if( GRAPHIC_DEFAULT == o_rGraphic.GetType()
|| GRAPHIC_NONE == o_rGraphic.GetType() )
{
// even the GrfMgr does not seem to know this graphic
return false;
}
}
else
{
// no special string found, graphic must be
// external. Load via GraphicIm porter
INetURLObject aTmp( aURL );
boost::scoped_ptr<SvStream> pGraphicStream(
utl::UcbStreamHelper::CreateStream(
aTmp.GetMainURL( INetURLObject::NO_DECODE ),
STREAM_READ ) );
if( !pGraphicStream )
{
OSL_ENSURE( false, "ShapeImporter::importShape(): "
"cannot create input stream for graphic" );
return false;
}
Graphic aTmpGraphic;
if( GraphicConverter::Import(
*pGraphicStream, aTmpGraphic ) != ERRCODE_NONE )
{
OSL_ENSURE( false, "ShapeImporter::importShape(): "
"Failed to import shape graphic from given URL" );
return false;
}
o_rGraphic = GraphicObject( aTmpGraphic );
}
return true;
}
/** 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> const& xShape,
uno::Reference<beans::XPropertySet> const& xPropSet,
double nPrio );
// Shape:
virtual uno::Reference<drawing::XShape> getXShape() const;
virtual void addViewLayer( ViewLayerSharedPtr const& pNewLayer,
bool bRedrawLayer );
virtual bool removeViewLayer( ViewLayerSharedPtr const& pNewLayer );
virtual bool clearAllViewLayers();
virtual bool update() const;
virtual bool render() const;
virtual bool isContentChanged() const;
virtual basegfx::B2DRectangle getBounds() const;
virtual basegfx::B2DRectangle getDomBounds() const;
virtual basegfx::B2DRectangle getUpdateArea() const;
virtual bool isVisible() const;
virtual double getPriority() const;
virtual bool isBackgroundDetached() const;
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> const& xShape,
uno::Reference<beans::XPropertySet> const& xPropSet,
double nPrio ) :
mpGroupShape(pGroupShape),
mxShape(xShape),
mnPrio(nPrio)
{
// read bound rect
uno::Any const aTmpRect_( xPropSet->getPropertyValue( OUSTR("BoundRect") ));
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;
}
bool ShapeOfGroup::clearAllViewLayers()
{
return true;
}
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,
rtl::OUString const& shapeType ) const
{
if( shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.MediaShape") ) ||
shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.MediaShape") ) )
{
// Media shape (video etc.). This is a special object
return createMediaShape(xCurrShape,
mnAscendingPrio,
mrContext);
}
else if( shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.PluginShape") ))
{
// PropertyValues to copy from XShape to plugin
static const char* aPropertyValues[] =
{
"PluginURL",
"PluginMimeType",
"PluginCommands"
};
// (Netscape)Plugin shape. This is a special object
return createAppletShape( xCurrShape,
mnAscendingPrio,
::rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM(
"com.sun.star.comp.sfx2.PluginObject" )),
aPropertyValues,
sizeof(aPropertyValues)/sizeof(*aPropertyValues),
mrContext );
}
else if( shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("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,
::rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM(
"com.sun.star.comp.sfx2.AppletObject" )),
aPropertyValues,
sizeof(aPropertyValues)/sizeof(*aPropertyValues),
mrContext );
}
else if( shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.OLE2Shape") ) ||
shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("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,
mxPage,
mnAscendingPrio,
true,
mrContext );
}
else if( shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.drawing.GraphicObjectShape") ) ||
shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.presentation.GraphicObjectShape") ) )
{
GraphicObject aGraphicObject;
// 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)
if( !importShapeGraphic( aGraphicObject, xPropSet ) )
return ShapeSharedPtr(); // error loading graphic -
// #142147# no placeholders in
// slideshow
if( !aGraphicObject.IsAnimated() )
{
// no animation - simply utilize plain draw shape import
// import shape as bitmap - either its a bitmap
// anyway, or its a metafile, which currently the
// metafile renderer might not display correctly.
return DrawShape::create( xCurrShape,
mxPage,
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, OUSTR("GraphicColorMode") );
getPropertyValue( nLuminance, xPropSet, OUSTR("AdjustLuminance") );
getPropertyValue( nContrast, xPropSet, OUSTR("AdjustContrast") );
getPropertyValue( nRed, xPropSet, OUSTR("AdjustRed") );
getPropertyValue( nGreen, xPropSet, OUSTR("AdjustGreen") );
getPropertyValue( nBlue, xPropSet, OUSTR("AdjustBlue") );
getPropertyValue( nGamma, xPropSet, OUSTR("Gamma") );
getPropertyValue( nTransparency, xPropSet, OUSTR("Transparency") );
getPropertyValue( nRotation, xPropSet, OUSTR("RotateAngle") );
GraphicAttr aGraphAttrs;
aGraphAttrs.SetDrawMode( (GraphicDrawMode)eColorMode );
aGraphAttrs.SetLuminance( nLuminance );
aGraphAttrs.SetContrast( nContrast );
aGraphAttrs.SetChannelR( nRed );
aGraphAttrs.SetChannelG( nGreen );
aGraphAttrs.SetChannelB( nBlue );
aGraphAttrs.SetGamma( nGamma );
aGraphAttrs.SetTransparency( static_cast<sal_uInt8>(nTransparency) );
aGraphAttrs.SetRotation( static_cast<sal_uInt16>(nRotation*10) );
text::GraphicCrop aGraphCrop;
if( getPropertyValue( aGraphCrop, xPropSet, OUSTR("GraphicCrop") ))
{
aGraphAttrs.SetCrop( aGraphCrop.Left,
aGraphCrop.Top,
aGraphCrop.Right,
aGraphCrop.Bottom );
}
// fetch readily transformed and color-modified
// graphic
// ---------------------------------------------
Graphic aGraphic(
aGraphicObject.GetTransformedGraphic(
aGraphicObject.GetPrefSize(),
aGraphicObject.GetPrefMapMode(),
aGraphAttrs ) );
return DrawShape::create( xCurrShape,
mxPage,
mnAscendingPrio,
aGraphic,
mrContext );
}
else
{
return DrawShape::create( xCurrShape,
mxPage,
mnAscendingPrio,
false,
mrContext );
}
}
bool ShapeImporter::isSkip(
uno::Reference<beans::XPropertySet> const& xPropSet,
rtl::OUString const& shapeType,
uno::Reference< drawing::XLayer> const& xLayer )
{
// skip empty presentation objects:
bool bEmpty = false;
if( getPropertyValue( bEmpty,
xPropSet,
OUSTR("IsEmptyPresentationObject")) &&
bEmpty )
{
return true;
}
//skip shapes which corresponds to annotations
if(xLayer.is())
{
rtl::OUString layerName;
uno::Reference<beans::XPropertySet> xPropLayerSet(
xLayer, uno::UNO_QUERY );
const uno::Any& a(xPropLayerSet->getPropertyValue(rtl::OUString::createFromAscii("Name")) );
bool const bRet = (a >>= layerName);
if(bRet)
{
if( layerName.equals(rtl::OUString::createFromAscii("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.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation."
"TitleTextShape") ) ||
shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation."
"OutlinerShape") ))
{
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, OUSTR("PolyPolygon") );
getPropertyValue( nLineColor, xPropSet, OUSTR("LineColor") );
getPropertyValue( fLineWidth, xPropSet, OUSTR("LineWidth") );
drawing::PointSequence* pOuterSequence = aRetval.getArray();
awt::Point* pInnerSequence = pOuterSequence->getArray();
::basegfx::B2DPolygon aPoly;
basegfx::B2DPoint aPoint;
for( sal_Int32 nCurrPoly=0; nCurrPoly<pOuterSequence->getLength(); ++nCurrPoly, ++pInnerSequence )
{
aPoint.setX((*pInnerSequence).X);
aPoint.setY((*pInnerSequence).Y);
aPoly.append( aPoint );
}
UnoViewVector::const_iterator aIter=(mrContext.mrViewContainer).begin();
UnoViewVector::const_iterator aEnd=(mrContext.mrViewContainer).end();
while(aIter != aEnd)
{
::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( (*aIter)->getCanvas(),
aPoly ) );
if( pPolyPoly )
{
pPolyPoly->setRGBALineColor( unoColor2RGBColor( nLineColor ).getIntegerColor() );
pPolyPoly->setStrokeWidth(fLineWidth);
pPolyPoly->draw();
maPolygons.push_back(pPolyPoly);
}
aIter++;
}
}
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);
}
rtl::OUString const shapeType( xCurrShape->getShapeType());
// is this shape presentation-invisible?
if( !isSkip(xPropSet, shapeType, xDrawnInSlideshow) )
{
bIsGroupShape = shapeType.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"com.sun.star.drawing.GroupShape") );
if( rTop.mpGroupShape ) // in group particle mode?
{
pRet.reset( new 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();
}
PolyPolygonVector ShapeImporter::getPolygons()
{
return maPolygons;
}
ShapeImporter::ShapeImporter( uno::Reference<drawing::XDrawPage> const& xPage,
uno::Reference<drawing::XDrawPage> const& xActualPage,
uno::Reference<drawing::XDrawPagesSupplier> const& xPagesSupplier,
const SlideShowContext& rContext,
sal_Int32 nOrdNumStart,
bool bConvertingMasterPage ) :
mxPage( xActualPage ),
mxPagesSupplier( xPagesSupplier ),
mrContext( rContext ),
maPolygons(),
maShapesStack(),
mnAscendingPrio( nOrdNumStart ),
mbConvertingMasterPage( bConvertingMasterPage )
{
uno::Reference<drawing::XShapes> const xShapes(
xPage, uno::UNO_QUERY_THROW );
maShapesStack.push( XShapesEntry(xShapes) );
}
} // namespace internal
} // namespace presentation