summaryrefslogtreecommitdiff
path: root/slideshow/source/engine/shapes
diff options
context:
space:
mode:
Diffstat (limited to 'slideshow/source/engine/shapes')
-rw-r--r--slideshow/source/engine/shapes/appletshape.cxx333
-rw-r--r--slideshow/source/engine/shapes/appletshape.hxx63
-rw-r--r--slideshow/source/engine/shapes/backgroundshape.cxx339
-rw-r--r--slideshow/source/engine/shapes/backgroundshape.hxx65
-rw-r--r--slideshow/source/engine/shapes/drawinglayeranimation.cxx984
-rw-r--r--slideshow/source/engine/shapes/drawinglayeranimation.hxx50
-rw-r--r--slideshow/source/engine/shapes/drawshape.cxx1481
-rw-r--r--slideshow/source/engine/shapes/drawshape.hxx385
-rw-r--r--slideshow/source/engine/shapes/drawshapesubsetting.cxx868
-rw-r--r--slideshow/source/engine/shapes/drawshapesubsetting.hxx291
-rw-r--r--slideshow/source/engine/shapes/externalshapebase.cxx249
-rw-r--r--slideshow/source/engine/shapes/externalshapebase.hxx148
-rw-r--r--slideshow/source/engine/shapes/gdimtftools.cxx551
-rw-r--r--slideshow/source/engine/shapes/gdimtftools.hxx158
-rw-r--r--slideshow/source/engine/shapes/intrinsicanimationactivity.cxx293
-rw-r--r--slideshow/source/engine/shapes/intrinsicanimationactivity.hxx79
-rw-r--r--slideshow/source/engine/shapes/makefile.mk60
-rw-r--r--slideshow/source/engine/shapes/mediashape.cxx300
-rw-r--r--slideshow/source/engine/shapes/mediashape.hxx58
-rw-r--r--slideshow/source/engine/shapes/shapeimporter.cxx672
-rw-r--r--slideshow/source/engine/shapes/viewappletshape.cxx303
-rw-r--r--slideshow/source/engine/shapes/viewappletshape.hxx172
-rw-r--r--slideshow/source/engine/shapes/viewbackgroundshape.cxx215
-rw-r--r--slideshow/source/engine/shapes/viewbackgroundshape.hxx107
-rw-r--r--slideshow/source/engine/shapes/viewmediashape.cxx575
-rw-r--r--slideshow/source/engine/shapes/viewmediashape.hxx182
-rw-r--r--slideshow/source/engine/shapes/viewshape.cxx901
-rw-r--r--slideshow/source/engine/shapes/viewshape.hxx343
28 files changed, 10225 insertions, 0 deletions
diff --git a/slideshow/source/engine/shapes/appletshape.cxx b/slideshow/source/engine/shapes/appletshape.cxx
new file mode 100644
index 000000000000..4b1cb5398fee
--- /dev/null
+++ b/slideshow/source/engine/shapes/appletshape.cxx
@@ -0,0 +1,333 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <boost/shared_ptr.hpp>
+
+#include "appletshape.hxx"
+#include "externalshapebase.hxx"
+#include "vieweventhandler.hxx"
+#include "viewappletshape.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Represents an applet shape.
+
+ This implementation offers support for applet shapes (both
+ Java applets, and Netscape plugins). Such shapes need
+ special treatment.
+ */
+ class AppletShape : public ExternalShapeBase
+ {
+ public:
+ /** Create a shape for the given XShape for a applet object
+
+ @param xShape
+ The XShape to represent.
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param rServiceName
+ Service name to use, when creating the actual viewer
+ component
+
+ @param pPropCopyTable
+ Table of plain ASCII property names, to copy from
+ xShape to applet.
+
+ @param nNumPropEntries
+ Number of property table entries (in pPropCopyTable)
+ */
+ AppletShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ private:
+
+ // View layer methods
+ //------------------------------------------------------------------
+
+ virtual void addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( const ViewLayerSharedPtr& rNewLayer );
+ virtual bool clearAllViewLayers();
+
+
+ // ExternalShapeBase methods
+ //------------------------------------------------------------------
+
+ virtual bool implRender( const ::basegfx::B2DRange& rCurrBounds ) const;
+ virtual void implViewChanged( const UnoViewSharedPtr& rView );
+ virtual void implViewsChanged();
+ virtual bool implStartIntrinsicAnimation();
+ virtual bool implEndIntrinsicAnimation();
+ virtual bool implPauseIntrinsicAnimation();
+ virtual bool implIsIntrinsicAnimationPlaying() const;
+ virtual void implSetIntrinsicAnimationTime(double);
+
+ const ::rtl::OUString maServiceName;
+ const char** mpPropCopyTable;
+ const sal_Size mnNumPropEntries;
+
+ /// the list of active view shapes (one for each registered view layer)
+ typedef ::std::vector< ViewAppletShapeSharedPtr > ViewAppletShapeVector;
+ ViewAppletShapeVector maViewAppletShapes;
+ bool mbIsPlaying;
+ };
+
+ AppletShape::AppletShape( const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const SlideShowContext& rContext ) :
+ ExternalShapeBase( xShape, nPrio, rContext ),
+ maServiceName( rServiceName ),
+ mpPropCopyTable( pPropCopyTable ),
+ mnNumPropEntries( nNumPropEntries ),
+ maViewAppletShapes(),
+ mbIsPlaying(false)
+ {
+ }
+
+ // ---------------------------------------------------------------------
+
+ void AppletShape::implViewChanged( const UnoViewSharedPtr& rView )
+ {
+ // determine ViewAppletShape that needs update
+ ViewAppletShapeVector::const_iterator aIter(maViewAppletShapes.begin());
+ ViewAppletShapeVector::const_iterator const aEnd (maViewAppletShapes.end());
+ while( aIter != aEnd )
+ {
+ if( (*aIter)->getViewLayer()->isOnView(rView) )
+ (*aIter)->resize(getBounds());
+
+ ++aIter;
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ void AppletShape::implViewsChanged()
+ {
+ // resize all ViewShapes
+ ::std::for_each( maViewAppletShapes.begin(),
+ maViewAppletShapes.end(),
+ ::boost::bind(
+ &ViewAppletShape::resize,
+ _1,
+ ::boost::cref( AppletShape::getBounds())) );
+ }
+
+ // ---------------------------------------------------------------------
+
+ void AppletShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer )
+ {
+ try
+ {
+ maViewAppletShapes.push_back(
+ ViewAppletShapeSharedPtr( new ViewAppletShape( rNewLayer,
+ getXShape(),
+ maServiceName,
+ mpPropCopyTable,
+ mnNumPropEntries,
+ mxComponentContext )));
+
+ // push new size to view shape
+ maViewAppletShapes.back()->resize( getBounds() );
+
+ // render the Shape on the newly added ViewLayer
+ if( bRedrawLayer )
+ maViewAppletShapes.back()->render( getBounds() );
+ }
+ catch(uno::Exception&)
+ {
+ // ignore failed shapes - slideshow should run with
+ // the remaining content
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
+ {
+ const ViewAppletShapeVector::iterator aEnd( maViewAppletShapes.end() );
+
+ OSL_ENSURE( ::std::count_if(maViewAppletShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewAppletShape::getViewLayer, _1 ),
+ ::boost::cref( rLayer ) ) ) < 2,
+ "AppletShape::removeViewLayer(): Duplicate ViewLayer entries!" );
+
+ ViewAppletShapeVector::iterator aIter;
+
+ if( (aIter=::std::remove_if( maViewAppletShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewAppletShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) )) == aEnd )
+ {
+ // view layer seemingly was not added, failed
+ return false;
+ }
+
+ // actually erase from container
+ maViewAppletShapes.erase( aIter, aEnd );
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::clearAllViewLayers()
+ {
+ maViewAppletShapes.clear();
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implRender( const ::basegfx::B2DRange& rCurrBounds ) const
+ {
+ // redraw all view shapes, by calling their update() method
+ if( ::std::count_if( maViewAppletShapes.begin(),
+ maViewAppletShapes.end(),
+ ::boost::bind<bool>(
+ ::boost::mem_fn( &ViewAppletShape::render ),
+ _1,
+ ::boost::cref( rCurrBounds ) ) )
+ != static_cast<ViewAppletShapeVector::difference_type>(maViewAppletShapes.size()) )
+ {
+ // at least one of the ViewShape::update() calls did return
+ // false - update failed on at least one ViewLayer
+ return false;
+ }
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implStartIntrinsicAnimation()
+ {
+ ::std::for_each( maViewAppletShapes.begin(),
+ maViewAppletShapes.end(),
+ ::boost::bind( &ViewAppletShape::startApplet,
+ _1,
+ ::boost::cref( getBounds() )));
+ mbIsPlaying = true;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implEndIntrinsicAnimation()
+ {
+ ::std::for_each( maViewAppletShapes.begin(),
+ maViewAppletShapes.end(),
+ ::boost::mem_fn( &ViewAppletShape::endApplet ) );
+
+ mbIsPlaying = false;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implPauseIntrinsicAnimation()
+ {
+ // TODO(F1): any way of temporarily disabling/deactivating
+ // applets?
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool AppletShape::implIsIntrinsicAnimationPlaying() const
+ {
+ return mbIsPlaying;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void AppletShape::implSetIntrinsicAnimationTime(double)
+ {
+ // No way of doing this, or?
+ }
+
+ boost::shared_ptr<Shape> createAppletShape(
+ const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const SlideShowContext& rContext )
+ {
+ boost::shared_ptr< AppletShape > pAppletShape(
+ new AppletShape(xShape,
+ nPrio,
+ rServiceName,
+ pPropCopyTable,
+ nNumPropEntries,
+ rContext) );
+
+ return pAppletShape;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/appletshape.hxx b/slideshow/source/engine/shapes/appletshape.hxx
new file mode 100644
index 000000000000..e967b9b381fb
--- /dev/null
+++ b/slideshow/source/engine/shapes/appletshape.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_APPLETSHAPE_HXX
+#define INCLUDED_SLIDESHOW_APPLETSHAPE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <boost/shared_ptr.hpp>
+
+namespace com { namespace sun { namespace star { namespace drawing
+{
+ class XShape;
+} } } }
+namespace rtl {
+ class OUString;
+}
+
+namespace slideshow
+{
+ namespace internal
+ {
+ struct SlideShowContext;
+ class Shape;
+
+ boost::shared_ptr<Shape> createAppletShape(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const SlideShowContext& rContext );
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_APPLETSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/backgroundshape.cxx b/slideshow/source/engine/shapes/backgroundshape.cxx
new file mode 100644
index 000000000000..7d13d9247455
--- /dev/null
+++ b/slideshow/source/engine/shapes/backgroundshape.cxx
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <rtl/logfile.hxx>
+
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+
+#include <basegfx/numeric/ftools.hxx>
+
+#include <boost/bind.hpp>
+
+#include <cmath> // for trigonometry and fabs
+#include <algorithm>
+#include <functional>
+#include <limits>
+
+#include "backgroundshape.hxx"
+#include "slideshowexceptions.hxx"
+#include "slideshowcontext.hxx"
+#include "gdimtftools.hxx"
+#include "shape.hxx"
+#include "viewbackgroundshape.hxx"
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Representation of a draw document's background shape.
+
+ This class implements the Shape interface for the
+ background shape. Since the background shape is neither
+ animatable nor attributable, those more specialized
+ derivations of the Shape interface are not implemented
+ here.
+
+ @attention this class is to be treated 'final', i.e. one
+ should not derive from it.
+ */
+ class BackgroundShape : public Shape
+ {
+ public:
+ /** Create the background shape.
+
+ This method creates a shape that handles the
+ peculiarities of the draw API regarding background
+ content.
+ */
+ BackgroundShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xDrawPage,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xMasterPage,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > getXShape() const;
+
+ // View layer methods
+ //------------------------------------------------------------------
+
+ virtual void addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( const ViewLayerSharedPtr& rNewLayer );
+ virtual bool clearAllViewLayers();
+
+
+ // attribute methods
+ //------------------------------------------------------------------
+
+ 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;
+
+
+ // render methods
+ //------------------------------------------------------------------
+
+ virtual bool update() const;
+ virtual bool render() const;
+ virtual bool isContentChanged() const;
+
+ private:
+ /// The metafile actually representing the Shape
+ GDIMetaFileSharedPtr mpMtf;
+
+ // The attributes of this Shape
+ ::basegfx::B2DRectangle maBounds; // always needed for rendering
+
+ /// the list of active view shapes (one for each registered view layer)
+ typedef ::std::vector< ViewBackgroundShapeSharedPtr > ViewBackgroundShapeVector;
+ ViewBackgroundShapeVector maViewShapes;
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ BackgroundShape::BackgroundShape( const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const uno::Reference< drawing::XDrawPage >& xMasterPage,
+ const SlideShowContext& rContext ) :
+ mpMtf(),
+ maBounds(),
+ maViewShapes()
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
+ uno::UNO_QUERY_THROW );
+ GDIMetaFileSharedPtr pMtf( new GDIMetaFile() );
+
+ // first try the page background (overrides
+ // masterpage background), then try masterpage
+ if( !getMetaFile( uno::Reference<lang::XComponent>(xDrawPage, uno::UNO_QUERY),
+ xDrawPage, *pMtf, MTF_LOAD_BACKGROUND_ONLY,
+ rContext.mxComponentContext ) &&
+ !getMetaFile( uno::Reference<lang::XComponent>(xMasterPage, uno::UNO_QUERY),
+ xDrawPage, *pMtf, MTF_LOAD_BACKGROUND_ONLY,
+ rContext.mxComponentContext ))
+ {
+ throw ShapeLoadFailedException();
+ }
+
+ // there is a special background shape, add it
+ // as the first one
+ // ---------------------------------------------------
+
+ sal_Int32 nDocWidth=0;
+ sal_Int32 nDocHeight=0;
+ xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Width") ) ) >>= nDocWidth;
+ xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Height") ) ) >>= nDocHeight;
+
+ mpMtf = pMtf;
+ maBounds = ::basegfx::B2DRectangle( 0,0,nDocWidth, nDocHeight );
+ }
+
+ uno::Reference< drawing::XShape > BackgroundShape::getXShape() const
+ {
+ // no real XShape representative
+ return uno::Reference< drawing::XShape >();
+ }
+
+ void BackgroundShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer )
+ {
+ ViewBackgroundShapeVector::iterator aEnd( maViewShapes.end() );
+
+ // already added?
+ if( ::std::find_if( maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewBackgroundShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rNewLayer ) ) ) != aEnd )
+ {
+ // yes, nothing to do
+ return;
+ }
+
+ maViewShapes.push_back(
+ ViewBackgroundShapeSharedPtr(
+ new ViewBackgroundShape( rNewLayer,
+ maBounds ) ) );
+
+ // render the Shape on the newly added ViewLayer
+ if( bRedrawLayer )
+ maViewShapes.back()->render( mpMtf );
+ }
+
+ bool BackgroundShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
+ {
+ const ViewBackgroundShapeVector::iterator aEnd( maViewShapes.end() );
+
+ OSL_ENSURE( ::std::count_if(maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewBackgroundShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) ) < 2,
+ "BackgroundShape::removeViewLayer(): Duplicate ViewLayer entries!" );
+
+ ViewBackgroundShapeVector::iterator aIter;
+
+ if( (aIter=::std::remove_if( maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewBackgroundShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) )) == aEnd )
+ {
+ // view layer seemingly was not added, failed
+ return false;
+ }
+
+ // actually erase from container
+ maViewShapes.erase( aIter, aEnd );
+
+ return true;
+ }
+
+ bool BackgroundShape::clearAllViewLayers()
+ {
+ maViewShapes.clear();
+ return true;
+ }
+
+ ::basegfx::B2DRectangle BackgroundShape::getBounds() const
+ {
+ return maBounds;
+ }
+
+ ::basegfx::B2DRectangle BackgroundShape::getDomBounds() const
+ {
+ return maBounds;
+ }
+
+ ::basegfx::B2DRectangle BackgroundShape::getUpdateArea() const
+ {
+ // TODO(F1): Need to expand background, too, when
+ // antialiasing?
+
+ // no transformation etc. possible for background shape
+ return maBounds;
+ }
+
+ bool BackgroundShape::isVisible() const
+ {
+ return true;
+ }
+
+ double BackgroundShape::getPriority() const
+ {
+ return 0.0; // lowest prio, we're the background
+ }
+
+ bool BackgroundShape::update() const
+ {
+ return render();
+ }
+
+ bool BackgroundShape::render() const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::BackgroundShape::render()" );
+ RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::presentation::internal::BackgroundShape: 0x%X", this );
+
+ // gcc again...
+ const ::basegfx::B2DRectangle& rCurrBounds( BackgroundShape::getBounds() );
+
+ if( rCurrBounds.getRange().equalZero() )
+ {
+ // zero-sized shapes are effectively invisible,
+ // thus, we save us the rendering...
+ return true;
+ }
+
+ // redraw all view shapes, by calling their render() method
+ if( ::std::count_if( maViewShapes.begin(),
+ maViewShapes.end(),
+ ::boost::bind( &ViewBackgroundShape::render,
+ _1,
+ ::boost::cref( mpMtf ) ) )
+ != static_cast<ViewBackgroundShapeVector::difference_type>(maViewShapes.size()) )
+ {
+ // at least one of the ViewBackgroundShape::render() calls did return
+ // false - update failed on at least one ViewLayer
+ return false;
+ }
+
+ return true;
+ }
+
+ bool BackgroundShape::isContentChanged() const
+ {
+ return false;
+ }
+
+ bool BackgroundShape::isBackgroundDetached() const
+ {
+ return false; // we're not animatable
+ }
+
+ //////////////////////////////////////////////////////////
+
+ ShapeSharedPtr createBackgroundShape(
+ const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const uno::Reference< drawing::XDrawPage >& xMasterPage,
+ const SlideShowContext& rContext )
+ {
+ return ShapeSharedPtr(
+ new BackgroundShape(
+ xDrawPage,
+ xMasterPage,
+ rContext ));
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/backgroundshape.hxx b/slideshow/source/engine/shapes/backgroundshape.hxx
new file mode 100644
index 000000000000..eb495b9b1aec
--- /dev/null
+++ b/slideshow/source/engine/shapes/backgroundshape.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_BACKGROUNDSHAPE_HXX
+#define INCLUDED_SLIDESHOW_BACKGROUNDSHAPE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <boost/shared_ptr.hpp>
+
+namespace com { namespace sun { namespace star { namespace drawing
+{
+ class XDrawPage;
+} } } }
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class Shape;
+ struct SlideShowContext;
+
+ /** Representation of a draw document's background shape.
+
+ This function generates the Shape for the background
+ shape. Since the background shape is neither animatable
+ nor attributable, those more specialized derivations of
+ the Shape interface are not implemented here.
+ */
+ boost::shared_ptr<Shape> createBackgroundShape(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xDrawPage,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xMasterPage,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_BACKGROUNDSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawinglayeranimation.cxx b/slideshow/source/engine/shapes/drawinglayeranimation.cxx
new file mode 100644
index 000000000000..a7cb526834bf
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawinglayeranimation.cxx
@@ -0,0 +1,984 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/elapsedtime.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <rtl/math.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/metaact.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/TextAnimationKind.hpp>
+#include <com/sun/star/drawing/TextAnimationDirection.hpp>
+#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/drawing/HomogenMatrix3.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+#include "activity.hxx"
+#include "wakeupevent.hxx"
+#include "eventqueue.hxx"
+#include "drawshapesubsetting.hxx"
+#include "drawshape.hxx"
+#include "shapesubset.hxx"
+#include "shapeattributelayerholder.hxx"
+#include "slideshowcontext.hxx"
+#include "tools.hxx"
+#include "gdimtftools.hxx"
+#include "eventmultiplexer.hxx"
+#include "intrinsicanimationactivity.hxx"
+#include "intrinsicanimationeventhandler.hxx"
+
+#include <boost/weak_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/noncopyable.hpp>
+#include <vector>
+
+using namespace com::sun::star;
+using namespace ::slideshow::internal;
+
+namespace {
+
+class ScrollTextAnimNode
+{
+ sal_uInt32 mnDuration; // single duration
+ sal_uInt32 mnRepeat; // 0 -> endless
+ double mfStart;
+ double mfStop;
+ sal_uInt32 mnFrequency; // in ms
+ // forth and back change at mnRepeat%2:
+ bool mbAlternate;
+
+public:
+ ScrollTextAnimNode(
+ sal_uInt32 nDuration, sal_uInt32 nRepeat, double fStart, double fStop,
+ sal_uInt32 nFrequency, bool bAlternate)
+ : mnDuration(nDuration),
+ mnRepeat(nRepeat),
+ mfStart(fStart),
+ mfStop(fStop),
+ mnFrequency(nFrequency),
+ mbAlternate(bAlternate)
+ {}
+
+ sal_uInt32 GetDuration() const { return mnDuration; }
+ sal_uInt32 GetRepeat() const { return mnRepeat; }
+ sal_uInt32 GetFullTime() const { return mnDuration * mnRepeat; }
+ double GetStart() const { return mfStart; }
+ double GetStop() const { return mfStop; }
+ sal_uInt32 GetFrequency() const { return mnFrequency; }
+ bool DoAlternate() const { return mbAlternate; }
+
+ double GetStateAtRelativeTime(sal_uInt32 nRelativeTime) const;
+};
+
+double ScrollTextAnimNode::GetStateAtRelativeTime(
+ sal_uInt32 nRelativeTime) const
+{
+ // #151174# Avoid division by zero.
+ if( mnDuration == 0 )
+ return mfStop;
+
+ if(mnRepeat)
+ {
+ // ending
+ const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
+ sal_uInt32 nFrameTime(nRelativeTime - (nRepeatCount * mnDuration));
+
+ if(DoAlternate() && (nRepeatCount + 1L) % 2L)
+ nFrameTime = mnDuration - nFrameTime;
+
+ return mfStart + ((mfStop - mfStart) *
+ (double(nFrameTime) / mnDuration));
+ }
+ else
+ {
+ // endless
+ sal_uInt32 nFrameTime(nRelativeTime % mnDuration);
+
+ if(DoAlternate())
+ {
+ const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
+
+ if((nRepeatCount + 1L) % 2L)
+ nFrameTime = mnDuration - nFrameTime;
+ }
+
+ return mfStart + ((mfStop - mfStart) * (double(nFrameTime) / mnDuration));
+ }
+}
+
+class ActivityImpl : public Activity,
+ public boost::enable_shared_from_this<ActivityImpl>,
+ private boost::noncopyable
+{
+public:
+ virtual ~ActivityImpl();
+
+ ActivityImpl(
+ SlideShowContext const& rContext,
+ boost::shared_ptr<WakeupEvent> const& pWakeupEvent,
+ boost::shared_ptr<DrawShape> const& pDrawShape );
+
+ bool enableAnimations();
+
+ // Disposable:
+ virtual void dispose();
+ // Activity:
+ virtual double calcTimeLag() const;
+ virtual bool perform();
+ virtual bool isActive() const;
+ virtual void dequeued();
+ virtual void end();
+
+private:
+ void updateShapeAttributes( double fTime,
+ basegfx::B2DRectangle const& parentBounds );
+
+ // Access to VisibleWhenSTarted flags
+ sal_Bool IsVisibleWhenStarted() const { return mbVisibleWhenStarted; }
+ sal_Bool IsVisibleWhenStopped() const { return mbVisibleWhenStopped; }
+
+ // scroll horizontal? if sal_False, scroll is vertical.
+ bool ScrollHorizontal() const {
+ return (drawing::TextAnimationDirection_LEFT == meDirection ||
+ drawing::TextAnimationDirection_RIGHT == meDirection);
+ }
+
+ // Access to StepWidth in logical units
+ sal_uInt32 GetStepWidthLogic() const;
+
+ // is the animation direction opposite?
+ bool DoScrollForward() const {
+ return (drawing::TextAnimationDirection_RIGHT == meDirection ||
+ drawing::TextAnimationDirection_DOWN == meDirection);
+ }
+
+ // do alternate text directions?
+ bool DoAlternate() const { return mbAlternate; }
+
+ // do scroll in?
+ bool DoScrollIn() const { return mbScrollIn; }
+
+ // Scroll helper methods
+ void ImpForceScrollTextAnimNodes();
+ ScrollTextAnimNode* ImpGetScrollTextAnimNode(
+ sal_uInt32 nTime, sal_uInt32& rRelativeTime );
+ sal_uInt32 ImpRegisterAgainScrollTextMixerState(
+ sal_uInt32 nTime);
+
+ // calculate the MixerState value for given time
+ double GetMixerState(sal_uInt32 nTime);
+
+ ////////////////////////////////////////////////////////////////////
+
+ SlideShowContext maContext;
+ boost::shared_ptr<WakeupEvent> mpWakeupEvent;
+ boost::weak_ptr<DrawShape> mpParentDrawShape;
+ DrawShapeSharedPtr mpDrawShape;
+ ShapeAttributeLayerHolder maShapeAttrLayer;
+ GDIMetaFileSharedPtr mpMetaFile;
+ IntrinsicAnimationEventHandlerSharedPtr mpListener;
+ canvas::tools::ElapsedTime maTimer;
+ double mfRotationAngle;
+ bool mbIsShapeAnimated;
+ bool mbIsDisposed;
+ bool mbIsActive;
+ drawing::TextAnimationKind meAnimKind;
+
+ // The blink frequency in ms
+ sal_uInt32 mnFrequency;
+
+ // The repeat count, init to 0L which means endless
+ sal_uInt32 mnRepeat;
+
+ // Flag to decide if text will be shown when animation has ended
+ bool mbVisibleWhenStopped;
+ bool mbVisibleWhenStarted;
+
+ // Flag decides if TextScroll alternates. Default is sal_False.
+ bool mbAlternate;
+
+ // Flag to remember if this is a simple scrollin text
+ bool mbScrollIn;
+
+ // start time for this animation
+ sal_uInt32 mnStartTime;
+
+ // The AnimationDirection
+ drawing::TextAnimationDirection meDirection;
+
+ // Get width per Step. Negative means pixel, positive logical units
+ sal_Int32 mnStepWidth;
+
+ // The single anim steps
+ std::vector< ScrollTextAnimNode > maVector;
+
+ // the scroll rectangle
+ Rectangle maScrollRectangleLogic;
+
+ // the paint rectangle
+ Rectangle maPaintRectangleLogic;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler,
+ private boost::noncopyable
+{
+public:
+ explicit IntrinsicAnimationListener( ActivityImpl& rActivity ) :
+ mrActivity( rActivity )
+ {}
+
+private:
+
+ virtual bool enableAnimations() { return mrActivity.enableAnimations(); }
+ virtual bool disableAnimations() { mrActivity.end(); return true; }
+
+ ActivityImpl& mrActivity;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+double ActivityImpl::GetMixerState( sal_uInt32 nTime )
+{
+ if( meAnimKind == drawing::TextAnimationKind_BLINK )
+ {
+ // from AInfoBlinkText:
+ double fRetval(0.0);
+ sal_Bool bDone(sal_False);
+ const sal_uInt32 nLoopTime(2 * mnFrequency);
+
+ if(mnRepeat)
+ {
+ const sal_uInt32 nEndTime(mnRepeat * nLoopTime);
+
+ if(nTime >= nEndTime)
+ {
+ if(mbVisibleWhenStopped)
+ fRetval = 0.0;
+ else
+ fRetval = 1.0;
+
+ bDone = sal_True;
+ }
+ }
+
+ if(!bDone)
+ {
+ sal_uInt32 nTimeInLoop(nTime % nLoopTime);
+ fRetval = double(nTimeInLoop) / nLoopTime;
+ }
+
+ return fRetval;
+ }
+ else
+ {
+ // from AInfoScrollText:
+ double fRetval(0.0);
+ ImpForceScrollTextAnimNodes();
+
+ if(!maVector.empty())
+ {
+ sal_uInt32 nRelativeTime;
+ ScrollTextAnimNode* pNode =
+ ImpGetScrollTextAnimNode(nTime, nRelativeTime);
+
+ if(pNode)
+ {
+ // use node
+ fRetval = pNode->GetStateAtRelativeTime(nRelativeTime);
+ }
+ else
+ {
+ // end of animation, take last entry's end
+ fRetval = maVector[maVector.size() - 1L].GetStop();
+ }
+ }
+
+ return fRetval;
+ }
+}
+
+// Access to StepWidth in logical units
+sal_uInt32 ActivityImpl::GetStepWidthLogic() const
+{
+ // #i69847# Assuming higher DPI
+ sal_uInt32 const PIXEL_TO_LOGIC = 30;
+
+ sal_uInt32 nRetval(0L);
+
+ if(mnStepWidth < 0L)
+ {
+ // is in pixels, convert to logical units
+ nRetval = (-mnStepWidth * PIXEL_TO_LOGIC);
+ }
+ else if(mnStepWidth > 0L)
+ {
+ // is in logical units
+ nRetval = mnStepWidth;
+ }
+
+ if(0L == nRetval)
+ {
+ // step 1 pixel, canned value
+
+ // #128389# with very high DPIs like in PDF export, this can
+ // still get zero. for that cases, set a default, too (taken
+ // from ainfoscrolltext.cxx)
+ nRetval = 100L;
+ }
+
+ return nRetval;
+}
+
+void ActivityImpl::ImpForceScrollTextAnimNodes()
+{
+ if(maVector.empty())
+ {
+ // prepare values
+ sal_uInt32 nLoopTime;
+ double fZeroLogic, fOneLogic, fInitLogic, fDistanceLogic;
+ double fZeroLogicAlternate = 0.0, fOneLogicAlternate = 0.0;
+ double fZeroRelative, fOneRelative, fInitRelative;
+
+ if(ScrollHorizontal())
+ {
+ if(DoAlternate())
+ {
+ if(maPaintRectangleLogic.GetWidth() >
+ maScrollRectangleLogic.GetWidth())
+ {
+ fZeroLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
+ fOneLogicAlternate = maScrollRectangleLogic.Left();
+ }
+ else
+ {
+ fZeroLogicAlternate = maScrollRectangleLogic.Left();
+ fOneLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
+ }
+ }
+
+ fZeroLogic = maScrollRectangleLogic.Left() - maPaintRectangleLogic.GetWidth();
+ fOneLogic = maScrollRectangleLogic.Right();
+ fInitLogic = maPaintRectangleLogic.Left();
+ }
+ else
+ {
+ if(DoAlternate())
+ {
+ if(maPaintRectangleLogic.GetHeight() > maScrollRectangleLogic.GetHeight())
+ {
+ fZeroLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
+ fOneLogicAlternate = maScrollRectangleLogic.Top();
+ }
+ else
+ {
+ fZeroLogicAlternate = maScrollRectangleLogic.Top();
+ fOneLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
+ }
+ }
+
+ fZeroLogic = maScrollRectangleLogic.Top() - maPaintRectangleLogic.GetHeight();
+ fOneLogic = maScrollRectangleLogic.Bottom();
+ fInitLogic = maPaintRectangleLogic.Top();
+ }
+
+ fDistanceLogic = fOneLogic - fZeroLogic;
+ fInitRelative = (fInitLogic - fZeroLogic) / fDistanceLogic;
+
+ if(DoAlternate())
+ {
+ fZeroRelative =
+ (fZeroLogicAlternate - fZeroLogic) / fDistanceLogic;
+ fOneRelative =
+ (fOneLogicAlternate - fZeroLogic) / fDistanceLogic;
+ }
+ else
+ {
+ fZeroRelative = 0.0;
+ fOneRelative = 1.0;
+ }
+
+ if(mnStartTime)
+ {
+ // Start time loop
+ ScrollTextAnimNode aStartNode(
+ mnStartTime, 1L, 0.0, 0.0, mnStartTime, false);
+ maVector.push_back(aStartNode);
+ }
+
+ if(IsVisibleWhenStarted())
+ {
+ double fRelativeStartValue, fRelativeEndValue,fRelativeDistance;
+
+ if(DoScrollForward())
+ {
+ fRelativeStartValue = fInitRelative;
+ fRelativeEndValue = fOneRelative;
+ fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
+ }
+ else
+ {
+ fRelativeStartValue = fInitRelative;
+ fRelativeEndValue = fZeroRelative;
+ fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
+ }
+
+ const double fNumberSteps =
+ (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
+ nLoopTime = FRound(fNumberSteps * mnFrequency);
+
+ // init loop
+ ScrollTextAnimNode aInitNode(
+ nLoopTime, 1L,
+ fRelativeStartValue, fRelativeEndValue,
+ mnFrequency, false);
+ maVector.push_back(aInitNode);
+ }
+
+ // prepare main loop values
+ {
+ double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
+
+ if(DoScrollForward())
+ {
+ fRelativeStartValue = fZeroRelative;
+ fRelativeEndValue = fOneRelative;
+ fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
+ }
+ else
+ {
+ fRelativeStartValue = fOneRelative;
+ fRelativeEndValue = fZeroRelative;
+ fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
+ }
+
+ const double fNumberSteps =
+ (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
+ nLoopTime = FRound(fNumberSteps * mnFrequency);
+
+ if(0L == mnRepeat)
+ {
+ if(!DoScrollIn())
+ {
+ // endless main loop
+ ScrollTextAnimNode aMainNode(
+ nLoopTime, 0L,
+ fRelativeStartValue, fRelativeEndValue,
+ mnFrequency, DoAlternate());
+ maVector.push_back(aMainNode);
+ }
+ }
+ else
+ {
+ sal_uInt32 nNumRepeat(mnRepeat);
+
+ if(DoAlternate() && (nNumRepeat + 1L) % 2L)
+ nNumRepeat += 1L;
+
+ // ending main loop
+ ScrollTextAnimNode aMainNode(
+ nLoopTime, nNumRepeat,
+ fRelativeStartValue, fRelativeEndValue,
+ mnFrequency, DoAlternate());
+ maVector.push_back(aMainNode);
+ }
+ }
+
+ if(IsVisibleWhenStopped())
+ {
+ double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
+
+ if(DoScrollForward())
+ {
+ fRelativeStartValue = fZeroRelative;
+ fRelativeEndValue = fInitRelative;
+ fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
+ }
+ else
+ {
+ fRelativeStartValue = fOneRelative;
+ fRelativeEndValue = fInitRelative;
+ fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
+ }
+
+ const double fNumberSteps =
+ (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
+ nLoopTime = FRound(fNumberSteps * mnFrequency);
+
+ // exit loop
+ ScrollTextAnimNode aExitNode(
+ nLoopTime, 1L,
+ fRelativeStartValue, fRelativeEndValue, mnFrequency, false);
+ maVector.push_back(aExitNode);
+ }
+ }
+}
+
+ScrollTextAnimNode* ActivityImpl::ImpGetScrollTextAnimNode(
+ sal_uInt32 nTime, sal_uInt32& rRelativeTime )
+{
+ ScrollTextAnimNode* pRetval = 0L;
+ ImpForceScrollTextAnimNodes();
+
+ if(!maVector.empty())
+ {
+ rRelativeTime = nTime;
+
+ for(sal_uInt32 a(0L); !pRetval && a < maVector.size(); a++)
+ {
+ ScrollTextAnimNode & rNode = maVector[a];
+ if(!rNode.GetRepeat())
+ {
+ // endless loop, use it
+ pRetval = &rNode;
+ }
+ else if(rNode.GetFullTime() > rRelativeTime)
+ {
+ // ending node
+ pRetval = &rNode;
+ }
+ else
+ {
+ // look at next
+ rRelativeTime -= rNode.GetFullTime();
+ }
+ }
+ }
+
+ return pRetval;
+}
+
+sal_uInt32 ActivityImpl::ImpRegisterAgainScrollTextMixerState(sal_uInt32 nTime)
+{
+ sal_uInt32 nRetval(0L);
+ ImpForceScrollTextAnimNodes();
+
+ if(maVector.size())
+ {
+ sal_uInt32 nRelativeTime;
+ ScrollTextAnimNode* pNode = ImpGetScrollTextAnimNode(nTime, nRelativeTime);
+
+ if(pNode)
+ {
+ // take register time
+ nRetval = pNode->GetFrequency();
+ }
+ }
+ else
+ {
+ // #i38135# not initialized, return default
+ nRetval = mnFrequency;
+ }
+
+ return nRetval;
+}
+
+void ActivityImpl::updateShapeAttributes(
+ double fTime, basegfx::B2DRectangle const& parentBounds )
+{
+ OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
+ if( meAnimKind == drawing::TextAnimationKind_NONE )
+ return;
+
+ double const fMixerState = GetMixerState(
+ static_cast<sal_uInt32>(fTime * 1000.0) );
+
+ if( meAnimKind == drawing::TextAnimationKind_BLINK )
+ {
+ // show/hide text:
+ maShapeAttrLayer.get()->setVisibility( fMixerState < 0.5 );
+ }
+ else if(mpMetaFile) // scroll mode:
+ {
+ //
+ // keep care: the below code is highly sensible to changes...
+ //
+
+ // rectangle of the pure text:
+ double const fPaintWidth = maPaintRectangleLogic.GetWidth();
+ double const fPaintHeight = maPaintRectangleLogic.GetHeight();
+ // rectangle where the scrolling takes place (-> clipping):
+ double const fScrollWidth = maScrollRectangleLogic.GetWidth();
+ double const fScrollHeight = maScrollRectangleLogic.GetHeight();
+
+ basegfx::B2DPoint pos, clipPos;
+
+ if(ScrollHorizontal())
+ {
+ double const fOneEquiv( fScrollWidth );
+ double const fZeroEquiv( -fPaintWidth );
+
+ pos.setX( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
+
+ clipPos.setX( -pos.getX() );
+ clipPos.setY( -pos.getY() );
+
+ // #i69844# Compensation for text-wider-than-shape case
+ if( fPaintWidth > fScrollWidth )
+ pos.setX( pos.getX() + (fPaintWidth-fScrollWidth) / 2.0 );
+ }
+ else
+ {
+ // scroll vertical:
+ double const fOneEquiv( fScrollHeight );
+ double const fZeroEquiv( -fPaintHeight );
+
+ pos.setY( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
+
+ clipPos.setX( -pos.getX() );
+ clipPos.setY( -pos.getY() );
+
+ // #i69844# Compensation for text-higher-than-shape case
+ if( fPaintHeight > fScrollHeight )
+ pos.setY( pos.getY() + (fPaintHeight-fScrollHeight) / 2.0 );
+ }
+
+ basegfx::B2DPolygon clipPoly(
+ basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRectangle( clipPos.getX(),
+ clipPos.getY(),
+ clipPos.getX() + fScrollWidth,
+ clipPos.getY() + fScrollHeight ) ) );
+
+ if( !::basegfx::fTools::equalZero( mfRotationAngle ))
+ {
+ maShapeAttrLayer.get()->setRotationAngle( mfRotationAngle );
+ double const fRotate = (mfRotationAngle * M_PI / 180.0);
+ basegfx::B2DHomMatrix aTransform;
+ // position:
+ aTransform.rotate( fRotate );
+ pos *= aTransform;
+ }
+
+ pos += parentBounds.getCenter();
+ maShapeAttrLayer.get()->setPosition( pos );
+ maShapeAttrLayer.get()->setClip( basegfx::B2DPolyPolygon(clipPoly) );
+ }
+}
+
+bool ActivityImpl::perform()
+{
+ if( !isActive() )
+ return false;
+
+ ENSURE_OR_RETURN_FALSE(
+ mpDrawShape,
+ "ActivityImpl::perform(): still active, but NULL draw shape" );
+
+ DrawShapeSharedPtr const pParentDrawShape( mpParentDrawShape );
+ if( !pParentDrawShape )
+ return false; // parent has vanished
+
+ if( pParentDrawShape->isVisible() )
+ {
+ if( !mbIsShapeAnimated )
+ {
+ mpDrawShape->setVisibility(true); // shape may be initially hidden
+ maContext.mpSubsettableShapeManager->enterAnimationMode( mpDrawShape );
+ maTimer.reset();
+ mbIsShapeAnimated = true;
+ }
+ // update attributes related to current time:
+ basegfx::B2DRectangle const parentBounds(
+ pParentDrawShape->getBounds() );
+
+ const double nCurrTime( maTimer.getElapsedTime() );
+ updateShapeAttributes( nCurrTime, parentBounds );
+
+ const sal_uInt32 nFrequency(
+ ImpRegisterAgainScrollTextMixerState(
+ static_cast<sal_uInt32>(nCurrTime * 1000.0)) );
+
+ if(nFrequency)
+ {
+ mpWakeupEvent->start();
+ mpWakeupEvent->setNextTimeout(
+ std::max(0.1,nFrequency/1000.0) );
+ maContext.mrEventQueue.addEvent( mpWakeupEvent );
+
+ if( mpDrawShape->isContentChanged() )
+ maContext.mpSubsettableShapeManager->notifyShapeUpdate( mpDrawShape );
+ }
+ // else: finished, not need to wake up again.
+ }
+ else
+ {
+ // busy-wait, until parent shape gets visible
+ mpWakeupEvent->start();
+ mpWakeupEvent->setNextTimeout( 2.0 );
+ }
+
+ // don't reinsert, WakeupEvent will perform that after the given timeout:
+ return false;
+}
+
+ActivityImpl::ActivityImpl(
+ SlideShowContext const& rContext,
+ boost::shared_ptr<WakeupEvent> const& pWakeupEvent,
+ boost::shared_ptr<DrawShape> const& pParentDrawShape )
+ : maContext(rContext),
+ mpWakeupEvent(pWakeupEvent),
+ mpParentDrawShape(pParentDrawShape),
+ mpListener( new IntrinsicAnimationListener(*this) ),
+ maTimer(rContext.mrEventQueue.getTimer()),
+ mbIsShapeAnimated(false),
+ mbIsDisposed(false),
+ mbIsActive(true),
+ meAnimKind(drawing::TextAnimationKind_NONE),
+ mnStartTime(0L)
+{
+ // get doctreenode:
+ sal_Int32 const nNodes = pParentDrawShape->getNumberOfTreeNodes(
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH );
+
+ DocTreeNode scrollTextNode(
+ pParentDrawShape->getTreeNode(
+ 0, DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ));
+ // xxx todo: remove this hack
+ if( nNodes > 1 )
+ scrollTextNode.setEndIndex(
+ pParentDrawShape->getTreeNode(
+ nNodes - 1,
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ).getEndIndex());
+
+ // TODO(Q3): Doing this manually, instead of using
+ // ShapeSubset. This is because of lifetime issues (ShapeSubset
+ // generates circular references to parent shape)
+ mpDrawShape = boost::dynamic_pointer_cast<DrawShape>(
+ maContext.mpSubsettableShapeManager->getSubsetShape(
+ pParentDrawShape,
+ scrollTextNode ));
+
+ mpMetaFile = mpDrawShape->forceScrollTextMetaFile();
+
+ // make scroll text invisible for slide transition bitmaps
+ mpDrawShape->setVisibility(false);
+
+ basegfx::B2DRectangle aScrollRect, aPaintRect;
+ ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
+ aPaintRect,
+ mpMetaFile ),
+ "ActivityImpl::ActivityImpl(): Could not extract "
+ "scroll anim rectangles from mtf" );
+
+ maScrollRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
+ aScrollRect );
+ maPaintRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
+ aPaintRect );
+
+ maShapeAttrLayer.createAttributeLayer(mpDrawShape);
+
+ uno::Reference<drawing::XShape> const xShape( mpDrawShape->getXShape() );
+ uno::Reference<beans::XPropertySet> const xProps( xShape, uno::UNO_QUERY_THROW );
+
+ getPropertyValue( meAnimKind, xProps, OUSTR("TextAnimationKind") );
+ OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
+ mbAlternate = (meAnimKind == drawing::TextAnimationKind_ALTERNATE);
+ mbScrollIn = (meAnimKind == drawing::TextAnimationKind_SLIDE);
+
+ // adopted from in AInfoBlinkText::ImplInit():
+ sal_Int16 nRepeat(0);
+ getPropertyValue( nRepeat, xProps, OUSTR("TextAnimationCount") );
+ mnRepeat = nRepeat;
+
+ if(mbAlternate)
+ {
+ // force visible when started for scroll-forth-and-back, because
+ // slide has been coming in with visible text in the middle:
+ mbVisibleWhenStarted = true;
+ }
+ else
+ {
+ getPropertyValue( mbVisibleWhenStarted, xProps,
+ OUSTR("TextAnimationStartInside") );
+ }
+
+ // set visible when stopped
+ getPropertyValue( mbVisibleWhenStopped, xProps,
+ OUSTR("TextAnimatiogonStopInside") );
+ // rotation:
+ getPropertyValue( mfRotationAngle, xProps,
+ OUSTR("RotateAngle") );
+ mfRotationAngle /= -100.0; // (switching direction)
+
+ // set frequency
+ sal_Int16 nDelay(0);
+ getPropertyValue( nDelay, xProps, OUSTR("TextAnimationDelay") );
+ // set delay if not automatic
+ mnFrequency = (nDelay ? nDelay :
+ // default:
+ meAnimKind == drawing::TextAnimationKind_BLINK
+ ? 250L : 50L );
+
+ // adopted from in AInfoScrollText::ImplInit():
+
+ // If it is a simple m_bScrollIn, reset some parameters
+ if( DoScrollIn() )
+ {
+ // most parameters are set correctly from the dialog logic, but
+ // eg VisisbleWhenStopped is grayed out and needs to be corrected here.
+ mbVisibleWhenStopped = true;
+ mbVisibleWhenStarted = false;
+ mnRepeat = 0L;
+ }
+
+ // Get animation direction
+ getPropertyValue( meDirection, xProps, OUSTR("TextAnimationDirection") );
+
+ // Get step width. Negative means pixel, positive logical units
+ getPropertyValue( mnStepWidth, xProps, OUSTR("TextAnimationAmount") );
+
+ maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler(
+ mpListener );
+}
+
+bool ActivityImpl::enableAnimations()
+{
+ mbIsActive = true;
+ return maContext.mrActivitiesQueue.addActivity(
+ shared_from_this() );
+}
+
+ActivityImpl::~ActivityImpl()
+{
+}
+
+void ActivityImpl::dispose()
+{
+ if( !mbIsDisposed )
+ {
+ end();
+
+ // only remove subset here, since end() is called on slide end
+ // (and we must not spoil the slide preview bitmap with scroll
+ // text)
+ maShapeAttrLayer.reset();
+ if( mpDrawShape )
+ {
+ // TODO(Q3): Doing this manually, instead of using
+ // ShapeSubset. This is because of lifetime issues
+ // (ShapeSubset generates circular references to parent
+ // shape)
+ DrawShapeSharedPtr pParent( mpParentDrawShape.lock() );
+ if( pParent )
+ maContext.mpSubsettableShapeManager->revokeSubset(
+ pParent,
+ mpDrawShape );
+ }
+
+ mpMetaFile.reset();
+ mpDrawShape.reset();
+ mpParentDrawShape.reset();
+ mpWakeupEvent.reset();
+ maContext.dispose();
+ mbIsDisposed = true;
+
+ maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler(
+ mpListener );
+ }
+}
+
+double ActivityImpl::calcTimeLag() const
+{
+ return 0.0;
+}
+
+bool ActivityImpl::isActive() const
+{
+ return mbIsActive;
+}
+
+void ActivityImpl::dequeued()
+{
+ // not used here
+}
+
+void ActivityImpl::end()
+{
+ // not used here
+ mbIsActive = false;
+
+ if( mbIsShapeAnimated )
+ {
+ maContext.mpSubsettableShapeManager->leaveAnimationMode( mpDrawShape );
+ mbIsShapeAnimated = false;
+ }
+}
+
+} // anon namespace
+
+namespace slideshow {
+namespace internal {
+
+boost::shared_ptr<Activity> createDrawingLayerAnimActivity(
+ SlideShowContext const& rContext,
+ boost::shared_ptr<DrawShape> const& pDrawShape )
+{
+ boost::shared_ptr<Activity> pActivity;
+
+ try
+ {
+ boost::shared_ptr<WakeupEvent> const pWakeupEvent(
+ new WakeupEvent( rContext.mrEventQueue.getTimer(),
+ rContext.mrActivitiesQueue ) );
+ pActivity.reset( new ActivityImpl( rContext, pWakeupEvent, pDrawShape ) );
+ pWakeupEvent->setActivity( pActivity );
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ // translate any error into empty factory product.
+ OSL_ENSURE( false,
+ rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+
+ return pActivity;
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawinglayeranimation.hxx b/slideshow/source/engine/shapes/drawinglayeranimation.hxx
new file mode 100644
index 000000000000..45d9afe91f03
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawinglayeranimation.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef INCLUDED_DRAWINGLAYERANIMATION_HXX
+#define INCLUDED_DRAWINGLAYERANIMATION_HXX
+
+#include <sal/config.h>
+#include <boost/shared_ptr.hpp>
+
+namespace slideshow {
+namespace internal {
+
+class Activity;
+struct SlideShowContext;
+class DrawShape;
+
+boost::shared_ptr<Activity> createDrawingLayerAnimActivity(
+ SlideShowContext const& rContext,
+ boost::shared_ptr<DrawShape> const& pDrawShape );
+
+} // namespace internal
+} // namespace presentation
+
+#endif // ! defined INCLUDED_DRAWINGLAYERANIMATION_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawshape.cxx b/slideshow/source/engine/shapes/drawshape.cxx
new file mode 100644
index 000000000000..e018c8015b0a
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawshape.cxx
@@ -0,0 +1,1481 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <rtl/logfile.hxx>
+#include <osl/diagnose.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/wrkwin.hxx>
+
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/range/rangeexpander.hxx>
+
+#include <rtl/math.hxx>
+
+#include <com/sun/star/drawing/TextAnimationKind.hpp>
+
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <tools/stream.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+
+#include <comphelper/scopeguard.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <cmath> // for trigonometry and fabs
+#include <algorithm>
+#include <functional>
+#include <limits>
+
+#include "drawshapesubsetting.hxx"
+#include "drawshape.hxx"
+#include "eventqueue.hxx"
+#include "wakeupevent.hxx"
+#include "subsettableshapemanager.hxx"
+#include "intrinsicanimationactivity.hxx"
+#include "slideshowexceptions.hxx"
+#include "tools.hxx"
+#include "gdimtftools.hxx"
+#include "drawinglayeranimation.hxx"
+
+#include <boost/bind.hpp>
+#include <math.h>
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
+ //metafiles are resolution dependent when bitmaps are contained with is the case for 3D scenes for example
+ //in addition a chart has resolution dependent content as it might skip points that are not visible for a given resolution (this is done for performance reasons)
+ bool local_getMetafileForChart( const uno::Reference< lang::XComponent >& xSource,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ GDIMetaFile& rMtf )
+ {
+ //get the chart model
+ uno::Reference< beans::XPropertySet > xPropSet( xSource, uno::UNO_QUERY );
+ uno::Reference< frame::XModel > xChartModel;
+ getPropertyValue( xChartModel, xPropSet, OUSTR("Model"));
+ uno::Reference< lang::XMultiServiceFactory > xFact( xChartModel, uno::UNO_QUERY );
+ OSL_ENSURE( xFact.is(), "Chart cannot be painted pretty!\n" );
+ if(!xFact.is())
+ return false;
+
+ //get the chart view
+ uno::Reference< datatransfer::XTransferable > xChartViewTransferable(
+ xFact->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.ChartView" ) ) ), uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySet > xChartViewProp( xChartViewTransferable, uno::UNO_QUERY );
+ OSL_ENSURE( xChartViewProp.is(), "Chart cannot be painted pretty!\n" );
+ if( !xChartViewProp.is() )
+ return false;
+
+ //estimate zoom and resolution (this is only a workaround, correct would be to know and use the exact zoom and resoltion during slideshow display)
+ sal_Int32 nScaleXNumerator = 100;//zoom factor -> exact values are important for the quality of the created bitmap especially for 3D charts
+ sal_Int32 nScaleYNumerator = 100;
+ sal_Int32 nScaleXDenominator = 100;
+ sal_Int32 nScaleYDenominator = 100;
+ awt::Size aPixelPerChart( 1000, 1000 );//when data points happen to be on the same pixel as their predecessor no shape is created to safe performance
+
+ Window* pActiveTopWindow( Application::GetActiveTopWindow() );
+ WorkWindow* pWorkWindow( dynamic_cast<WorkWindow*>(pActiveTopWindow));
+ if( pWorkWindow && pWorkWindow->IsPresentationMode() )
+ {
+ Size aPixScreenSize( pActiveTopWindow->GetOutputSizePixel() );
+ aPixelPerChart = awt::Size( aPixScreenSize.getWidth(), aPixScreenSize.getHeight() );//this is still to much (but costs only seldom performance), correct would be pixel per chart object
+
+ uno::Reference< beans::XPropertySet > xPageProp( xContainingPage, uno::UNO_QUERY );
+ sal_Int32 nLogicPageWidth=1;
+ sal_Int32 nLogicPageHeight=1;
+ if( getPropertyValue( nLogicPageWidth, xPageProp, OUSTR("Width")) &&
+ getPropertyValue( nLogicPageHeight, xPageProp, OUSTR("Height")) )
+ {
+ Size aLogicScreenSize( pActiveTopWindow->PixelToLogic( aPixScreenSize, MAP_100TH_MM ) );
+ nScaleXNumerator = aLogicScreenSize.getWidth();
+ nScaleYNumerator = aLogicScreenSize.getHeight();
+ nScaleXDenominator = nLogicPageWidth;
+ nScaleYDenominator = nLogicPageHeight;
+ }
+ }
+ else
+ {
+ long nMaxPixWidth = 0;
+ long nMaxPixHeight = 0;
+ unsigned int nScreenCount( Application::GetScreenCount() );
+ for( unsigned int nScreen=0; nScreen<nScreenCount; nScreen++ )
+ {
+ Rectangle aCurScreenRect( Application::GetScreenPosSizePixel( nScreen ) );
+ if( aCurScreenRect.GetWidth() > nMaxPixWidth )
+ nMaxPixWidth = aCurScreenRect.GetWidth();
+ if( aCurScreenRect.GetHeight() > nMaxPixHeight )
+ nMaxPixHeight = aCurScreenRect.GetHeight();
+ }
+ if(nMaxPixWidth>1 && nMaxPixHeight>1)
+ aPixelPerChart = awt::Size( nMaxPixWidth, nMaxPixHeight );//this is still to much (but costs only seldom performance), correct would be pixel per chart object
+ }
+
+ try
+ {
+ uno::Sequence< beans::PropertyValue > aZoomFactors(4);
+ aZoomFactors[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXNumerator") );
+ aZoomFactors[0].Value = uno::makeAny( nScaleXNumerator );
+ aZoomFactors[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXDenominator") );
+ aZoomFactors[1].Value = uno::makeAny( nScaleXDenominator );
+ aZoomFactors[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYNumerator") );
+ aZoomFactors[2].Value = uno::makeAny( nScaleYNumerator );
+ aZoomFactors[3].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYDenominator") );
+ aZoomFactors[3].Value = uno::makeAny( nScaleYDenominator );
+
+ xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZoomFactors") ), uno::makeAny( aZoomFactors ));
+ xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Resolution") ), uno::makeAny( aPixelPerChart ));
+ }
+ catch (uno::Exception &)
+ {
+ OSL_ENSURE( false, rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+
+ //get a metafile from the prepared chart view
+ datatransfer::DataFlavor aDataFlavor(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"") ),
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GDIMetaFile" ) ),
+ ::getCppuType( (const uno::Sequence< sal_Int8 >*) 0 ) );
+ uno::Any aData( xChartViewTransferable->getTransferData( aDataFlavor ) );
+ uno::Sequence< sal_Int8 > aSeq;
+ if( aData >>= aSeq )
+ {
+ ::std::auto_ptr< SvMemoryStream > pSrcStm( new SvMemoryStream( (char*) aSeq.getConstArray(), aSeq.getLength(), STREAM_WRITE | STREAM_TRUNC ) );
+ *(pSrcStm.get() ) >> rMtf;
+ return true;
+ }
+ return false;
+ }
+
+ //same as getMetafile with an exception for charts
+ //for charts a metafile with a higher resolution is created, because charts have resolution dependent content
+ bool local_getMetaFile_WithSpecialChartHandling( const uno::Reference< lang::XComponent >& xSource,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ GDIMetaFile& rMtf,
+ int mtfLoadFlags,
+ const uno::Reference< uno::XComponentContext >& rxContext )
+ {
+ uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
+ rtl::OUString sCLSID;
+ getPropertyValue( sCLSID, xProp, OUSTR("CLSID"));
+ if( sCLSID.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("12DCAE26-281F-416F-a234-c3086127382e")) && local_getMetafileForChart( xSource, xContainingPage, rMtf ) )
+ return true;
+ return getMetaFile( xSource, xContainingPage, rMtf, mtfLoadFlags, rxContext );
+ }
+
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Private methods
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ GDIMetaFileSharedPtr DrawShape::forceScrollTextMetaFile()
+ {
+ if ((mnCurrMtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != MTF_LOAD_SCROLL_TEXT_MTF)
+ {
+ // reload with added flags:
+ mpCurrMtf.reset( new GDIMetaFile );
+ mnCurrMtfLoadFlags |= MTF_LOAD_SCROLL_TEXT_MTF;
+ local_getMetaFile_WithSpecialChartHandling(
+ uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY),
+ mxPage, *mpCurrMtf, mnCurrMtfLoadFlags,
+ mxComponentContext );
+
+ // TODO(F1): Currently, the scroll metafile will
+ // never contain any verbose text comments. Thus,
+ // can only display the full mtf content, no
+ // subsets.
+ maSubsetting.reset( mpCurrMtf );
+
+ // adapt maBounds. the requested scroll text metafile
+ // will typically have dimension different from the
+ // actual shape
+ ::basegfx::B2DRectangle aScrollRect, aPaintRect;
+ ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
+ aPaintRect,
+ mpCurrMtf ),
+ "DrawShape::forceScrollTextMetaFile(): Could "
+ "not extract scroll anim rectangles from mtf" );
+
+ // take the larger one of the two rectangles (that
+ // should be the bound rect of the retrieved
+ // metafile)
+ if( aScrollRect.isInside( aPaintRect ) )
+ maBounds = aScrollRect;
+ else
+ maBounds = aPaintRect;
+ }
+ return mpCurrMtf;
+ }
+
+ void DrawShape::updateStateIds() const
+ {
+ // Update the states, we've just redrawn or created a new
+ // attribute layer.
+ if( mpAttributeLayer )
+ {
+ mnAttributeTransformationState = mpAttributeLayer->getTransformationState();
+ mnAttributeClipState = mpAttributeLayer->getClipState();
+ mnAttributeAlphaState = mpAttributeLayer->getAlphaState();
+ mnAttributePositionState = mpAttributeLayer->getPositionState();
+ mnAttributeContentState = mpAttributeLayer->getContentState();
+ mnAttributeVisibilityState = mpAttributeLayer->getVisibilityState();
+ }
+ }
+
+ void DrawShape::ensureVerboseMtfComments() const
+ {
+ // TODO(F1): Text effects don't currently work for drawing
+ // layer animations.
+
+ // only touch mpCurrMtf, if we're not a DrawingLayer
+ // animation.
+ if( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) == 0 &&
+ maAnimationFrames.empty() )
+ {
+ ENSURE_OR_THROW( !maSubsetting.hasSubsetShapes(),
+ "DrawShape::ensureVerboseMtfComments(): reloading the metafile "
+ "with active child subsets will wreak havoc on the view!" );
+ ENSURE_OR_THROW( maSubsetting.getSubsetNode().isEmpty(),
+ "DrawShape::ensureVerboseMtfComments(): reloading the metafile "
+ "for an ALREADY SUBSETTED shape is not possible!" );
+
+ // re-fetch metafile with comments
+ // note that, in case of shapes without text, the new
+ // metafile might still not provide any useful
+ // subsetting information!
+ mpCurrMtf.reset( new GDIMetaFile );
+ mnCurrMtfLoadFlags |= MTF_LOAD_VERBOSE_COMMENTS;
+ local_getMetaFile_WithSpecialChartHandling(
+ uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY),
+ mxPage, *mpCurrMtf, mnCurrMtfLoadFlags,
+ mxComponentContext );
+
+ maSubsetting.reset( maSubsetting.getSubsetNode(),
+ mpCurrMtf );
+ }
+ }
+
+ ViewShape::RenderArgs DrawShape::getViewRenderArgs() const
+ {
+ return ViewShape::RenderArgs(
+ maBounds,
+ getUpdateArea(),
+ getBounds(),
+ getActualUnitShapeBounds(),
+ mpAttributeLayer,
+ maSubsetting.getActiveSubsets(),
+ mnPriority);
+ }
+
+ bool DrawShape::implRender( int nUpdateFlags ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShape::implRender()" );
+ RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::presentation::internal::DrawShape: 0x%X", this );
+
+ // will perform the update now, clear update-enforcing
+ // flags
+ mbForceUpdate = false;
+ mbAttributeLayerRevoked = false;
+
+ ENSURE_OR_RETURN_FALSE( !maViewShapes.empty(),
+ "DrawShape::implRender(): render called on DrawShape without views" );
+
+ if( maBounds.isEmpty() )
+ {
+ // zero-sized shapes are effectively invisible,
+ // thus, we save us the rendering...
+ return true;
+ }
+
+ // redraw all view shapes, by calling their update() method
+ if( ::std::count_if( maViewShapes.begin(),
+ maViewShapes.end(),
+ ::boost::bind<bool>(
+ ::boost::mem_fn( &ViewShape::update ), // though _theoretically_,
+ // bind should eat this even
+ // with _1 being a shared_ptr,
+ // it does _not_ for MSVC without
+ // the extra mem_fn. WTF.
+ _1,
+ ::boost::cref( mpCurrMtf ),
+ ::boost::cref(
+ getViewRenderArgs() ),
+ nUpdateFlags,
+ isVisible() ) )
+ != static_cast<ViewShapeVector::difference_type>(maViewShapes.size()) )
+ {
+ // at least one of the ViewShape::update() calls did return
+ // false - update failed on at least one ViewLayer
+ return false;
+ }
+
+ // successfully redrawn - update state IDs to detect next changes
+ updateStateIds();
+
+ return true;
+ }
+
+ int DrawShape::getUpdateFlags() const
+ {
+ // default: update nothing, unless ShapeAttributeStack
+ // tells us below, or if the attribute layer was revoked
+ int nUpdateFlags(ViewShape::NONE);
+
+ // possibly the whole shape content changed
+ if( mbAttributeLayerRevoked )
+ nUpdateFlags = ViewShape::CONTENT;
+
+
+ // determine what has to be updated
+ // --------------------------------
+
+ // do we have an attribute layer?
+ if( mpAttributeLayer )
+ {
+ // Prevent nUpdateFlags to be modified when the shape is not
+ // visible, except when it just was hidden.
+ if (mpAttributeLayer->getVisibility()
+ || mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState )
+ {
+ if (mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState )
+ {
+ // Change of the visibility state is mapped to
+ // content change because when the visibility
+ // changes then usually a sprite is shown or hidden
+ // and the background under has to be painted once.
+ nUpdateFlags |= ViewShape::CONTENT;
+ }
+
+ // TODO(P1): This can be done without conditional branching.
+ // See HAKMEM.
+ if( mpAttributeLayer->getPositionState() != mnAttributePositionState )
+ {
+ nUpdateFlags |= ViewShape::POSITION;
+ }
+ if( mpAttributeLayer->getAlphaState() != mnAttributeAlphaState )
+ {
+ nUpdateFlags |= ViewShape::ALPHA;
+ }
+ if( mpAttributeLayer->getClipState() != mnAttributeClipState )
+ {
+ nUpdateFlags |= ViewShape::CLIP;
+ }
+ if( mpAttributeLayer->getTransformationState() != mnAttributeTransformationState )
+ {
+ nUpdateFlags |= ViewShape::TRANSFORMATION;
+ }
+ if( mpAttributeLayer->getContentState() != mnAttributeContentState )
+ {
+ nUpdateFlags |= ViewShape::CONTENT;
+ }
+ }
+ }
+
+ return nUpdateFlags;
+ }
+
+ ::basegfx::B2DRectangle DrawShape::getActualUnitShapeBounds() const
+ {
+ ENSURE_OR_THROW( !maViewShapes.empty(),
+ "DrawShape::getActualUnitShapeBounds(): called on DrawShape without views" );
+
+ const VectorOfDocTreeNodes& rSubsets(
+ maSubsetting.getActiveSubsets() );
+
+ const ::basegfx::B2DRectangle aDefaultBounds( 0.0,0.0,1.0,1.0 );
+
+ // perform the cheapest check first
+ if( rSubsets.empty() )
+ {
+ // if subset contains the whole shape, no need to call
+ // the somewhat expensive bound calculation, since as
+ // long as the subset is empty, this branch will be
+ // taken.
+ return aDefaultBounds;
+ }
+ else
+ {
+ OSL_ENSURE( rSubsets.size() != 1 ||
+ !rSubsets.front().isEmpty(),
+ "DrawShape::getActualUnitShapeBounds() expects a "
+ "_non-empty_ subset vector for a subsetted shape!" );
+
+ // are the cached bounds still valid?
+ if( !maCurrentShapeUnitBounds )
+ {
+ // no, (re)generate them
+ // =====================
+
+ // setup cached values to defaults (might fail to
+ // retrieve true bounds below)
+ maCurrentShapeUnitBounds.reset( aDefaultBounds );
+
+ // TODO(P2): the subset of the master shape (that from
+ // which the subsets are subtracted) changes
+ // relatively often (every time a subset shape is
+ // added or removed). Maybe we should exclude it here,
+ // always assuming full bounds?
+
+ ::cppcanvas::CanvasSharedPtr pDestinationCanvas(
+ maViewShapes.front()->getViewLayer()->getCanvas() );
+
+ // TODO(Q2): Although this _is_ currently
+ // view-agnostic, it might not stay like
+ // that. Maybe this method should again be moved
+ // to the ViewShape
+ ::cppcanvas::RendererSharedPtr pRenderer(
+ maViewShapes.front()->getRenderer(
+ pDestinationCanvas, mpCurrMtf, mpAttributeLayer ) );
+
+ // If we cannot not prefetch, be defensive and assume
+ // full shape size
+ if( pRenderer )
+ {
+ // temporarily, switch total transformation to identity
+ // (need the bounds in the [0,1]x[0,1] unit coordinate
+ // system.
+ ::basegfx::B2DHomMatrix aEmptyTransformation;
+
+ ::basegfx::B2DHomMatrix aOldTransform( pDestinationCanvas->getTransformation() );
+ pDestinationCanvas->setTransformation( aEmptyTransformation );
+ pRenderer->setTransformation( aEmptyTransformation );
+
+ // restore old transformation when leaving the scope
+ const ::comphelper::ScopeGuard aGuard(
+ boost::bind( &::cppcanvas::Canvas::setTransformation,
+ pDestinationCanvas, aOldTransform ) );
+
+
+ // retrieve bounds for subset of whole metafile
+ // --------------------------------------------
+
+ ::basegfx::B2DRange aTotalBounds;
+
+ // cannot use ::boost::bind, ::basegfx::B2DRange::expand()
+ // is overloaded.
+ VectorOfDocTreeNodes::const_iterator aCurr( rSubsets.begin() );
+ const VectorOfDocTreeNodes::const_iterator aEnd( rSubsets.end() );
+ while( aCurr != aEnd )
+ {
+ aTotalBounds.expand( pRenderer->getSubsetArea(
+ aCurr->getStartIndex(),
+ aCurr->getEndIndex() ) );
+ ++aCurr;
+ }
+
+ OSL_ENSURE( aTotalBounds.getMinX() >= -0.1 &&
+ aTotalBounds.getMinY() >= -0.1 &&
+ aTotalBounds.getMaxX() <= 1.1 &&
+ aTotalBounds.getMaxY() <= 1.1,
+ "DrawShape::getActualUnitShapeBounds(): bounds noticeably larger than original shape - clipping!" );
+
+ // really make sure no shape appears larger than its
+ // original bounds (there _are_ some pathologic cases,
+ // especially when imported from PPT, that have
+ // e.g. obscenely large polygon bounds)
+ aTotalBounds.intersect(
+ ::basegfx::B2DRange( 0.0, 0.0,
+ 1.0, 1.0 ));
+
+ maCurrentShapeUnitBounds.reset( aTotalBounds );
+ }
+ }
+
+ return *maCurrentShapeUnitBounds;
+ }
+ }
+
+ DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ bool bForeignSource,
+ const SlideShowContext& rContext ) :
+ mxShape( xShape ),
+ mxPage( xContainingPage ),
+ maAnimationFrames(), // empty, we don't have no intrinsic animation
+ mnCurrFrame(0),
+ mpCurrMtf(),
+ mnCurrMtfLoadFlags( bForeignSource
+ ? MTF_LOAD_FOREIGN_SOURCE : MTF_LOAD_NONE ),
+ maCurrentShapeUnitBounds(),
+ mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
+ maBounds( getAPIShapeBounds( xShape ) ),
+ mpAttributeLayer(),
+ mpIntrinsicAnimationActivity(),
+ mnAttributeTransformationState(0),
+ mnAttributeClipState(0),
+ mnAttributeAlphaState(0),
+ mnAttributePositionState(0),
+ mnAttributeContentState(0),
+ mnAttributeVisibilityState(0),
+ maViewShapes(),
+ mxComponentContext( rContext.mxComponentContext ),
+ maHyperlinkIndices(),
+ maHyperlinkRegions(),
+ maSubsetting(),
+ mnIsAnimatedCount(0),
+ mnAnimationLoopCount(0),
+ meCycleMode(CYCLE_LOOP),
+ mbIsVisible( true ),
+ mbForceUpdate( false ),
+ mbAttributeLayerRevoked( false ),
+ mbDrawingLayerAnim( false )
+ {
+ ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
+ ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" );
+
+ // check for drawing layer animations:
+ drawing::TextAnimationKind eKind = drawing::TextAnimationKind_NONE;
+ uno::Reference<beans::XPropertySet> xPropSet( mxShape,
+ uno::UNO_QUERY );
+ if( xPropSet.is() )
+ getPropertyValue( eKind, xPropSet,
+ OUSTR("TextAnimationKind") );
+ mbDrawingLayerAnim = (eKind != drawing::TextAnimationKind_NONE);
+
+ // must NOT be called from within initializer list, uses
+ // state from mnCurrMtfLoadFlags!
+ mpCurrMtf.reset( new GDIMetaFile );
+ local_getMetaFile_WithSpecialChartHandling(
+ uno::Reference<lang::XComponent>(xShape, uno::UNO_QUERY),
+ xContainingPage, *mpCurrMtf, mnCurrMtfLoadFlags,
+ mxComponentContext );
+ ENSURE_OR_THROW( mpCurrMtf,
+ "DrawShape::DrawShape(): Invalid metafile" );
+ maSubsetting.reset( mpCurrMtf );
+
+ prepareHyperlinkIndices();
+ }
+
+ DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ const Graphic& rGraphic,
+ const SlideShowContext& rContext ) :
+ mxShape( xShape ),
+ mxPage( xContainingPage ),
+ maAnimationFrames(),
+ mnCurrFrame(0),
+ mpCurrMtf(),
+ mnCurrMtfLoadFlags( MTF_LOAD_NONE ),
+ maCurrentShapeUnitBounds(),
+ mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
+ maBounds( getAPIShapeBounds( xShape ) ),
+ mpAttributeLayer(),
+ mpIntrinsicAnimationActivity(),
+ mnAttributeTransformationState(0),
+ mnAttributeClipState(0),
+ mnAttributeAlphaState(0),
+ mnAttributePositionState(0),
+ mnAttributeContentState(0),
+ mnAttributeVisibilityState(0),
+ maViewShapes(),
+ mxComponentContext( rContext.mxComponentContext ),
+ maHyperlinkIndices(),
+ maHyperlinkRegions(),
+ maSubsetting(),
+ mnIsAnimatedCount(0),
+ mnAnimationLoopCount(0),
+ meCycleMode(CYCLE_LOOP),
+ mbIsVisible( true ),
+ mbForceUpdate( false ),
+ mbAttributeLayerRevoked( false ),
+ mbDrawingLayerAnim( false )
+ {
+ ENSURE_OR_THROW( rGraphic.IsAnimated(),
+ "DrawShape::DrawShape(): Graphic is no animation" );
+
+ getAnimationFromGraphic( maAnimationFrames,
+ mnAnimationLoopCount,
+ meCycleMode,
+ rGraphic );
+
+ ENSURE_OR_THROW( !maAnimationFrames.empty() &&
+ maAnimationFrames.front().mpMtf,
+ "DrawShape::DrawShape(): " );
+ mpCurrMtf = maAnimationFrames.front().mpMtf;
+
+ ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
+ ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" );
+ ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" );
+ }
+
+ DrawShape::DrawShape( const DrawShape& rSrc,
+ const DocTreeNode& rTreeNode,
+ double nPrio ) :
+ mxShape( rSrc.mxShape ),
+ mxPage( rSrc.mxPage ),
+ maAnimationFrames(), // don't copy animations for subsets,
+ // only the current frame!
+ mnCurrFrame(0),
+ mpCurrMtf( rSrc.mpCurrMtf ),
+ mnCurrMtfLoadFlags( rSrc.mnCurrMtfLoadFlags ),
+ maCurrentShapeUnitBounds(),
+ mnPriority( nPrio ),
+ maBounds( rSrc.maBounds ),
+ mpAttributeLayer(),
+ mpIntrinsicAnimationActivity(),
+ mnAttributeTransformationState(0),
+ mnAttributeClipState(0),
+ mnAttributeAlphaState(0),
+ mnAttributePositionState(0),
+ mnAttributeContentState(0),
+ mnAttributeVisibilityState(0),
+ maViewShapes(),
+ mxComponentContext( rSrc.mxComponentContext ),
+ maHyperlinkIndices(),
+ maHyperlinkRegions(),
+ maSubsetting( rTreeNode, mpCurrMtf ),
+ mnIsAnimatedCount(0),
+ mnAnimationLoopCount(0),
+ meCycleMode(CYCLE_LOOP),
+ mbIsVisible( rSrc.mbIsVisible ),
+ mbForceUpdate( false ),
+ mbAttributeLayerRevoked( false ),
+ mbDrawingLayerAnim( false )
+ {
+ ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
+ ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" );
+
+ // xxx todo: currently not implemented for subsetted shapes;
+ // would mean modifying set of hyperlink regions when
+ // subsetting text portions. N.B.: there's already an
+ // issue for this #i72828#
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Public methods
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ DrawShapeSharedPtr DrawShape::create(
+ const uno::Reference< drawing::XShape >& xShape,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ bool bForeignSource,
+ const SlideShowContext& rContext )
+ {
+ DrawShapeSharedPtr pShape( new DrawShape(xShape,
+ xContainingPage,
+ nPrio,
+ bForeignSource,
+ rContext) );
+
+ if( pShape->hasIntrinsicAnimation() )
+ {
+ OSL_ASSERT( pShape->maAnimationFrames.empty() );
+ if( pShape->getNumberOfTreeNodes(
+ DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH) > 0 )
+ {
+ pShape->mpIntrinsicAnimationActivity =
+ createDrawingLayerAnimActivity(
+ rContext,
+ pShape);
+ }
+ }
+
+ if( pShape->hasHyperlinks() )
+ rContext.mpSubsettableShapeManager->addHyperlinkArea( pShape );
+
+ return pShape;
+ }
+
+ DrawShapeSharedPtr DrawShape::create(
+ const uno::Reference< drawing::XShape >& xShape,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ const Graphic& rGraphic,
+ const SlideShowContext& rContext )
+ {
+ DrawShapeSharedPtr pShape( new DrawShape(xShape,
+ xContainingPage,
+ nPrio,
+ rGraphic,
+ rContext) );
+
+ if( pShape->hasIntrinsicAnimation() )
+ {
+ OSL_ASSERT( !pShape->maAnimationFrames.empty() );
+
+ std::vector<double> aTimeout;
+ std::transform(
+ pShape->maAnimationFrames.begin(),
+ pShape->maAnimationFrames.end(),
+ std::back_insert_iterator< std::vector<double> >( aTimeout ),
+ boost::mem_fn(&MtfAnimationFrame::getDuration) );
+
+ WakeupEventSharedPtr pWakeupEvent(
+ new WakeupEvent( rContext.mrEventQueue.getTimer(),
+ rContext.mrActivitiesQueue ) );
+
+ ActivitySharedPtr pActivity =
+ createIntrinsicAnimationActivity(
+ rContext,
+ pShape,
+ pWakeupEvent,
+ aTimeout,
+ pShape->mnAnimationLoopCount,
+ pShape->meCycleMode);
+
+ pWakeupEvent->setActivity( pActivity );
+ pShape->mpIntrinsicAnimationActivity = pActivity;
+ }
+
+ OSL_ENSURE( !pShape->hasHyperlinks(),
+ "DrawShape::create(): graphic-only shapes must not have hyperlinks!" );
+
+ return pShape;
+ }
+
+ DrawShape::~DrawShape()
+ {
+ try
+ {
+ // dispose intrinsic animation activity, else, it will
+ // linger forever
+ ActivitySharedPtr pActivity( mpIntrinsicAnimationActivity.lock() );
+ if( pActivity )
+ pActivity->dispose();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_ENSURE( false, rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ uno::Reference< drawing::XShape > DrawShape::getXShape() const
+ {
+ return mxShape;
+ }
+
+ void DrawShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer )
+ {
+ ViewShapeVector::iterator aEnd( maViewShapes.end() );
+
+ // already added?
+ if( ::std::find_if( maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rNewLayer ) ) ) != aEnd )
+ {
+ // yes, nothing to do
+ return;
+ }
+
+ ViewShapeSharedPtr pNewShape( new ViewShape( rNewLayer ) );
+
+ maViewShapes.push_back( pNewShape );
+
+ // pass on animation state
+ if( mnIsAnimatedCount )
+ {
+ for( int i=0; i<mnIsAnimatedCount; ++i )
+ pNewShape->enterAnimationMode();
+ }
+
+ // render the Shape on the newly added ViewLayer
+ if( bRedrawLayer )
+ {
+ pNewShape->update( mpCurrMtf,
+ getViewRenderArgs(),
+ ViewShape::FORCE,
+ isVisible() );
+ }
+ }
+
+ bool DrawShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
+ {
+ const ViewShapeVector::iterator aEnd( maViewShapes.end() );
+
+ OSL_ENSURE( ::std::count_if(maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) ) < 2,
+ "DrawShape::removeViewLayer(): Duplicate ViewLayer entries!" );
+
+ ViewShapeVector::iterator aIter;
+
+ if( (aIter=::std::remove_if( maViewShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) )) == aEnd )
+ {
+ // view layer seemingly was not added, failed
+ return false;
+ }
+
+ // actually erase from container
+ maViewShapes.erase( aIter, aEnd );
+
+ return true;
+ }
+
+ bool DrawShape::clearAllViewLayers()
+ {
+ maViewShapes.clear();
+ return true;
+ }
+
+ bool DrawShape::update() const
+ {
+ if( mbForceUpdate )
+ {
+ return render();
+ }
+ else
+ {
+ return implRender( getUpdateFlags() );
+ }
+ }
+
+ bool DrawShape::render() const
+ {
+ // force redraw. Have to also pass on the update flags,
+ // because e.g. content update (regeneration of the
+ // metafile renderer) is normally not performed. A simple
+ // ViewShape::FORCE would only paint the metafile in its
+ // old state.
+ return implRender( ViewShape::FORCE | getUpdateFlags() );
+ }
+
+ bool DrawShape::isContentChanged() const
+ {
+ return mbForceUpdate ?
+ true :
+ getUpdateFlags() != ViewShape::NONE;
+ }
+
+
+ ::basegfx::B2DRectangle DrawShape::getBounds() const
+ {
+ // little optimization: for non-modified shapes, we don't
+ // create an ShapeAttributeStack, and therefore also don't
+ // have to check it.
+ return getShapePosSize( maBounds,
+ mpAttributeLayer );
+ }
+
+ ::basegfx::B2DRectangle DrawShape::getDomBounds() const
+ {
+ return maBounds;
+ }
+
+ namespace
+ {
+ /** Functor expanding AA border for each passed ViewShape
+
+ Could not use ::boost::bind here, since
+ B2DRange::expand is overloaded (which yields one or
+ the other template type deduction ambiguous)
+ */
+ class Expander
+ {
+ public:
+ Expander( ::basegfx::B2DSize& rBounds ) :
+ mrBounds( rBounds )
+ {
+ }
+
+ void operator()( const ViewShapeSharedPtr& rShape ) const
+ {
+ const ::basegfx::B2DSize& rShapeBorder( rShape->getAntialiasingBorder() );
+
+ mrBounds.setX(
+ ::std::max(
+ rShapeBorder.getX(),
+ mrBounds.getX() ) );
+ mrBounds.setY(
+ ::std::max(
+ rShapeBorder.getY(),
+ mrBounds.getY() ) );
+ }
+
+ private:
+ ::basegfx::B2DSize& mrBounds;
+ };
+ }
+
+ ::basegfx::B2DRectangle DrawShape::getUpdateArea() const
+ {
+ ::basegfx::B2DRectangle aBounds;
+
+ // an already empty shape bound need no further
+ // treatment. In fact, any changes applied below would
+ // actually remove the special empty state, thus, don't
+ // change!
+ if( !maBounds.isEmpty() )
+ {
+ basegfx::B2DRectangle aUnitBounds(0.0,0.0,1.0,1.0);
+
+ if( !maViewShapes.empty() )
+ aUnitBounds = getActualUnitShapeBounds();
+
+ if( !aUnitBounds.isEmpty() )
+ {
+ if( mpAttributeLayer )
+ {
+ // calc actual shape area (in user coordinate
+ // space) from the transformation as given by the
+ // shape attribute layer
+ aBounds = getShapeUpdateArea( aUnitBounds,
+ getShapeTransformation( getBounds(),
+ mpAttributeLayer ),
+ mpAttributeLayer );
+ }
+ else
+ {
+ // no attribute layer, thus, the true shape bounds
+ // can be directly derived from the XShape bound
+ // attribute
+ aBounds = getShapeUpdateArea( aUnitBounds,
+ maBounds );
+ }
+
+ if( !maViewShapes.empty() )
+ {
+ // determine border needed for antialiasing the shape
+ ::basegfx::B2DSize aAABorder(0.0,0.0);
+
+ // for every view, get AA border and 'expand' aAABorder
+ // appropriately.
+ ::std::for_each( maViewShapes.begin(),
+ maViewShapes.end(),
+ Expander( aAABorder ) );
+
+ // add calculated AA border to aBounds
+ aBounds = ::basegfx::B2DRectangle( aBounds.getMinX() - aAABorder.getX(),
+ aBounds.getMinY() - aAABorder.getY(),
+ aBounds.getMaxX() + aAABorder.getX(),
+ aBounds.getMaxY() + aAABorder.getY() );
+ }
+ }
+ }
+
+ return aBounds;
+ }
+
+ bool DrawShape::isVisible() const
+ {
+ bool bIsVisible( mbIsVisible );
+
+ if( mpAttributeLayer )
+ {
+ // check whether visibility and alpha are not default
+ // (mpAttributeLayer->isVisibilityValid() returns true
+ // then): bVisible becomes true, if shape visibility
+ // is on and alpha is not 0.0 (fully transparent)
+ if( mpAttributeLayer->isVisibilityValid() )
+ bIsVisible = mpAttributeLayer->getVisibility();
+
+ // only touch bIsVisible, if the shape is still
+ // visible - if getVisibility already made us
+ // invisible, no alpha value will make us appear
+ // again.
+ if( bIsVisible && mpAttributeLayer->isAlphaValid() )
+ bIsVisible = !::basegfx::fTools::equalZero( mpAttributeLayer->getAlpha() );
+ }
+
+ return bIsVisible;
+ }
+
+ double DrawShape::getPriority() const
+ {
+ return mnPriority;
+ }
+
+ bool DrawShape::isBackgroundDetached() const
+ {
+ return mnIsAnimatedCount > 0;
+ }
+
+ bool DrawShape::hasIntrinsicAnimation() const
+ {
+ return (!maAnimationFrames.empty() || mbDrawingLayerAnim);
+ }
+
+ bool DrawShape::setIntrinsicAnimationFrame( ::std::size_t nCurrFrame )
+ {
+ ENSURE_OR_RETURN_FALSE( nCurrFrame < maAnimationFrames.size(),
+ "DrawShape::setIntrinsicAnimationFrame(): frame index out of bounds" );
+
+ if( mnCurrFrame != nCurrFrame )
+ {
+ mnCurrFrame = nCurrFrame;
+ mpCurrMtf = maAnimationFrames[ mnCurrFrame ].mpMtf;
+ mbForceUpdate = true;
+ }
+
+ return true;
+ }
+
+ // hyperlink support
+ void DrawShape::prepareHyperlinkIndices() const
+ {
+ if ( !maHyperlinkIndices.empty())
+ {
+ maHyperlinkIndices.clear();
+ maHyperlinkRegions.clear();
+ }
+
+ sal_Int32 nIndex = 0;
+ for ( MetaAction * pCurrAct = mpCurrMtf->FirstAction();
+ pCurrAct != 0; pCurrAct = mpCurrMtf->NextAction() )
+ {
+ if (pCurrAct->GetType() == META_COMMENT_ACTION) {
+ MetaCommentAction * pAct =
+ static_cast<MetaCommentAction *>(pCurrAct);
+ // skip comment if not a special XTEXT comment
+ if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN") ) ==
+ COMPARE_EQUAL &&
+ // e.g. date field doesn't have data!
+ // currently assuming that only url field, this is
+ // somehow fragile! xxx todo if possible
+ pAct->GetData() != 0 &&
+ pAct->GetDataSize() > 0)
+ {
+ if (!maHyperlinkIndices.empty() &&
+ maHyperlinkIndices.back().second == -1) {
+ OSL_ENSURE( false, "### pending FIELD_SEQ_END!" );
+ maHyperlinkIndices.pop_back();
+ maHyperlinkRegions.pop_back();
+ }
+ maHyperlinkIndices.push_back(
+ HyperlinkIndexPair( nIndex + 1,
+ -1 /* to be filled below */ ) );
+ maHyperlinkRegions.push_back(
+ HyperlinkRegion(
+ basegfx::B2DRectangle(),
+ rtl::OUString(
+ reinterpret_cast<sal_Unicode const*>(
+ pAct->GetData()),
+ pAct->GetDataSize() / sizeof(sal_Unicode) )
+ ) );
+ }
+ else if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_END")) ==
+ COMPARE_EQUAL &&
+ // pending end is expected:
+ !maHyperlinkIndices.empty() &&
+ maHyperlinkIndices.back().second == -1)
+ {
+ maHyperlinkIndices.back().second = nIndex;
+ }
+ ++nIndex;
+ }
+ else
+ nIndex += getNextActionOffset(pCurrAct);
+ }
+ if (!maHyperlinkIndices.empty() &&
+ maHyperlinkIndices.back().second == -1) {
+ OSL_ENSURE( false, "### pending FIELD_SEQ_END!" );
+ maHyperlinkIndices.pop_back();
+ maHyperlinkRegions.pop_back();
+ }
+ OSL_ASSERT( maHyperlinkIndices.size() == maHyperlinkRegions.size());
+ }
+
+ bool DrawShape::hasHyperlinks() const
+ {
+ return ! maHyperlinkRegions.empty();
+ }
+
+ HyperlinkArea::HyperlinkRegions DrawShape::getHyperlinkRegions() const
+ {
+ OSL_ASSERT( !maViewShapes.empty() );
+
+ if( !isVisible() )
+ return HyperlinkArea::HyperlinkRegions();
+
+ // late init, determine regions:
+ if( !maHyperlinkRegions.empty() &&
+ !maViewShapes.empty() &&
+ // region already inited?
+ maHyperlinkRegions.front().first.getWidth() == 0 &&
+ maHyperlinkRegions.front().first.getHeight() == 0 &&
+ maHyperlinkRegions.size() == maHyperlinkIndices.size() )
+ {
+ // TODO(Q2): Although this _is_ currently
+ // view-agnostic, it might not stay like that.
+ ViewShapeSharedPtr const& pViewShape = maViewShapes.front();
+ cppcanvas::CanvasSharedPtr const pCanvas(
+ pViewShape->getViewLayer()->getCanvas() );
+
+ // reuse Renderer of first view shape:
+ cppcanvas::RendererSharedPtr const pRenderer(
+ pViewShape->getRenderer(
+ pCanvas, mpCurrMtf, mpAttributeLayer ) );
+
+ OSL_ASSERT( pRenderer );
+
+ if (pRenderer)
+ {
+ basegfx::B2DHomMatrix const aOldTransform(
+ pCanvas->getTransformation() );
+ basegfx::B2DHomMatrix aTransform;
+ pCanvas->setTransformation( aTransform /* empty */ );
+
+ comphelper::ScopeGuard const resetOldTransformation(
+ boost::bind( &cppcanvas::Canvas::setTransformation,
+ pCanvas.get(),
+ boost::cref(aOldTransform) ));
+
+ aTransform.scale( maBounds.getWidth(),
+ maBounds.getHeight() );
+ pRenderer->setTransformation( aTransform );
+ pRenderer->setClip();
+
+ for( std::size_t pos = maHyperlinkRegions.size(); pos--; )
+ {
+ // get region:
+ HyperlinkIndexPair const& rIndices = maHyperlinkIndices[pos];
+ basegfx::B2DRectangle const region(
+ pRenderer->getSubsetArea( rIndices.first,
+ rIndices.second ));
+ maHyperlinkRegions[pos].first = region;
+ }
+ }
+ }
+
+ // shift shape-relative hyperlink regions to
+ // slide-absolute position
+
+ HyperlinkRegions aTranslatedRegions;
+ const basegfx::B2DPoint& rOffset(getBounds().getMinimum());
+ HyperlinkRegions::const_iterator aIter( maHyperlinkRegions.begin() );
+ HyperlinkRegions::const_iterator const aEnd ( maHyperlinkRegions.end() );
+ while( aIter != aEnd )
+ {
+ basegfx::B2DRange const& relRegion( aIter->first );
+ aTranslatedRegions.push_back(
+ std::make_pair(
+ basegfx::B2DRange(
+ relRegion.getMinimum() + rOffset,
+ relRegion.getMaximum() + rOffset),
+ aIter->second) );
+ ++aIter;
+ }
+
+ return aTranslatedRegions;
+ }
+
+ double DrawShape::getHyperlinkPriority() const
+ {
+ return getPriority();
+ }
+
+
+ // AnimatableShape methods
+ // ======================================================
+
+ void DrawShape::enterAnimationMode()
+ {
+ OSL_ENSURE( !maViewShapes.empty(),
+ "DrawShape::enterAnimationMode(): called on DrawShape without views" );
+
+ if( mnIsAnimatedCount == 0 )
+ {
+ // notify all ViewShapes, by calling their enterAnimationMode method.
+ // We're now entering animation mode
+ ::std::for_each( maViewShapes.begin(),
+ maViewShapes.end(),
+ ::boost::mem_fn( &ViewShape::enterAnimationMode ) );
+ }
+
+ ++mnIsAnimatedCount;
+ }
+
+ void DrawShape::leaveAnimationMode()
+ {
+ OSL_ENSURE( !maViewShapes.empty(),
+ "DrawShape::leaveAnimationMode(): called on DrawShape without views" );
+
+ --mnIsAnimatedCount;
+
+ if( mnIsAnimatedCount == 0 )
+ {
+ // notify all ViewShapes, by calling their leaveAnimationMode method.
+ // we're now leaving animation mode
+ ::std::for_each( maViewShapes.begin(),
+ maViewShapes.end(),
+ ::boost::mem_fn( &ViewShape::leaveAnimationMode ) );
+ }
+ }
+
+
+ // AttributableShape methods
+ // ======================================================
+
+ ShapeAttributeLayerSharedPtr DrawShape::createAttributeLayer()
+ {
+ // create new layer, with last as its new child
+ mpAttributeLayer.reset( new ShapeAttributeLayer( mpAttributeLayer ) );
+
+ // Update the local state ids to reflect those of the new layer.
+ updateStateIds();
+
+ return mpAttributeLayer;
+ }
+
+ bool DrawShape::revokeAttributeLayer( const ShapeAttributeLayerSharedPtr& rLayer )
+ {
+ if( !mpAttributeLayer )
+ return false; // no layers
+
+ if( mpAttributeLayer == rLayer )
+ {
+ // it's the toplevel layer
+ mpAttributeLayer = mpAttributeLayer->getChildLayer();
+
+ // force content redraw, all state variables have
+ // possibly changed
+ mbAttributeLayerRevoked = true;
+
+ return true;
+ }
+ else
+ {
+ // pass on to the layer, to try its children
+ return mpAttributeLayer->revokeChildLayer( rLayer );
+ }
+ }
+
+ ShapeAttributeLayerSharedPtr DrawShape::getTopmostAttributeLayer() const
+ {
+ return mpAttributeLayer;
+ }
+
+ void DrawShape::setVisibility( bool bVisible )
+ {
+ if( mbIsVisible != bVisible )
+ {
+ mbIsVisible = bVisible;
+ mbForceUpdate = true;
+ }
+ }
+
+ const DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier() const
+ {
+ return *this;
+ }
+
+ DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier()
+ {
+ return *this;
+ }
+
+ DocTreeNode DrawShape::getSubsetNode() const
+ {
+ ensureVerboseMtfComments();
+
+ // forward to delegate
+ return maSubsetting.getSubsetNode();
+ }
+
+ AttributableShapeSharedPtr DrawShape::getSubset( const DocTreeNode& rTreeNode ) const
+ {
+ ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
+ "DrawShape::getSubset(): subset query on shape with apparently no subsets" );
+
+ // forward to delegate
+ return maSubsetting.getSubsetShape( rTreeNode );
+ }
+
+ bool DrawShape::createSubset( AttributableShapeSharedPtr& o_rSubset,
+ const DocTreeNode& rTreeNode )
+ {
+ ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
+ "DrawShape::createSubset(): subset query on shape with apparently no subsets" );
+
+ // subset shape already created for this DocTreeNode?
+ AttributableShapeSharedPtr pSubset( maSubsetting.getSubsetShape( rTreeNode ) );
+
+ // when true, this method has created a new subset
+ // DrawShape
+ bool bNewlyCreated( false );
+
+ if( pSubset )
+ {
+ o_rSubset = pSubset;
+
+ // reusing existing subset
+ }
+ else
+ {
+ // not yet created, init entry
+ o_rSubset.reset( new DrawShape( *this,
+ rTreeNode,
+ // TODO(Q3): That's a
+ // hack. We assume
+ // that start and end
+ // index will always
+ // be less than 65535
+ mnPriority +
+ rTreeNode.getStartIndex()/double(SAL_MAX_INT16) ));
+
+ bNewlyCreated = true; // subset newly created
+ }
+
+ // always register shape at DrawShapeSubsetting, to keep
+ // refcount up-to-date
+ maSubsetting.addSubsetShape( o_rSubset );
+
+ // flush bounds cache
+ maCurrentShapeUnitBounds.reset();
+
+ return bNewlyCreated;
+ }
+
+ bool DrawShape::revokeSubset( const AttributableShapeSharedPtr& rShape )
+ {
+ ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
+ "DrawShape::createSubset(): subset query on shape with apparently no subsets" );
+
+ // flush bounds cache
+ maCurrentShapeUnitBounds.reset();
+
+ // forward to delegate
+ if( maSubsetting.revokeSubsetShape( rShape ) )
+ {
+ // force redraw, our content has possibly changed (as
+ // one of the subsets now display within our shape
+ // again).
+ mbForceUpdate = true;
+
+ // #i47428# TEMP FIX: synchronize visibility of subset
+ // with parent.
+
+ // TODO(F3): Remove here, and implement
+ // TEXT_ONLY/BACKGROUND_ONLY with the proverbial
+ // additional level of indirection: create a
+ // persistent subset, containing all text/only the
+ // background respectively. From _that_ object,
+ // generate the temporary character subset shapes.
+ const ShapeAttributeLayerSharedPtr& rAttrLayer(
+ rShape->getTopmostAttributeLayer() );
+ if( rAttrLayer &&
+ rAttrLayer->isVisibilityValid() &&
+ rAttrLayer->getVisibility() != isVisible() )
+ {
+ const bool bVisibility( rAttrLayer->getVisibility() );
+
+ // visibilities differ - adjust ours, then
+ if( mpAttributeLayer )
+ mpAttributeLayer->setVisibility( bVisibility );
+ else
+ mbIsVisible = bVisibility;
+ }
+
+ // END TEMP FIX
+
+ return true;
+ }
+
+ return false;
+ }
+
+ sal_Int32 DrawShape::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
+ {
+ ensureVerboseMtfComments();
+
+ return maSubsetting.getNumberOfTreeNodes( eNodeType );
+ }
+
+ DocTreeNode DrawShape::getTreeNode( sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
+ {
+ ensureVerboseMtfComments();
+
+ if ( hasHyperlinks())
+ {
+ prepareHyperlinkIndices();
+ }
+
+ return maSubsetting.getTreeNode( nNodeIndex, eNodeType );
+ }
+
+ sal_Int32 DrawShape::getNumberOfSubsetTreeNodes ( const DocTreeNode& rParentNode,
+ DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
+ {
+ ensureVerboseMtfComments();
+
+ return maSubsetting.getNumberOfSubsetTreeNodes( rParentNode, eNodeType );
+ }
+
+ DocTreeNode DrawShape::getSubsetTreeNode( const DocTreeNode& rParentNode,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
+ {
+ ensureVerboseMtfComments();
+
+ return maSubsetting.getSubsetTreeNode( rParentNode, nNodeIndex, eNodeType );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawshape.hxx b/slideshow/source/engine/shapes/drawshape.hxx
new file mode 100644
index 000000000000..a657d337064e
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawshape.hxx
@@ -0,0 +1,385 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_DRAWSHAPE_HXX
+#define INCLUDED_SLIDESHOW_DRAWSHAPE_HXX
+
+#include <osl/diagnose.hxx>
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include "attributableshape.hxx"
+#include "doctreenodesupplier.hxx"
+#include "gdimtftools.hxx"
+#include "viewshape.hxx"
+#include "hyperlinkarea.hxx"
+
+#include <boost/optional.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <set>
+#include <vector>
+
+class Graphic;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class Activity;
+ struct SlideShowContext;
+ class DrawShapeSubsetting;
+ class DrawShape;
+ typedef ::boost::shared_ptr< DrawShape > DrawShapeSharedPtr;
+
+ /** This class is the representation of a draw document's
+ XShape, and implements the Shape, AnimatableShape, and
+ AttributableShape interfaces.
+
+ @attention this class is to be treated 'final', i.e. one
+ should not derive from it.
+ */
+ class DrawShape : public AttributableShape,
+ public DocTreeNodeSupplier,
+ public HyperlinkArea,
+ protected ::osl::DebugBase<DrawShape>
+ {
+ public:
+ /** Create a shape for the given XShape
+
+ @param xShape
+ The XShape to represent.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param bForeignSource
+ When true, the source of the shape metafile might be a
+ foreign application. The metafile is checked against
+ unsupported content, and, if necessary, returned as a
+ pre-rendererd bitmap.
+ */
+ static DrawShapeSharedPtr create(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ bool bForeignSource,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ /** Create a shape for the given XShape and graphic content
+
+ @param xShape
+ The XShape to represent.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param rGraphic
+ Graphic to display in the shape's bound rect. If this
+ Graphic contains animatable content, the created
+ DrawShape will register itself for intrinsic animation
+ events.
+ */
+ static DrawShapeSharedPtr create(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ const Graphic& rGraphic,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > getXShape() const;
+
+ virtual ~DrawShape();
+
+
+ // View layer methods
+ //------------------------------------------------------------------
+
+ virtual void addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( const ViewLayerSharedPtr& rNewLayer );
+ virtual bool clearAllViewLayers();
+
+ // attribute methods
+ //------------------------------------------------------------------
+
+ virtual ShapeAttributeLayerSharedPtr createAttributeLayer();
+ virtual bool revokeAttributeLayer( const ShapeAttributeLayerSharedPtr& rLayer );
+ virtual ShapeAttributeLayerSharedPtr getTopmostAttributeLayer() const;
+ virtual void setVisibility( bool bVisible );
+ virtual ::basegfx::B2DRectangle getBounds() const;
+ virtual ::basegfx::B2DRectangle getDomBounds() const;
+ virtual ::basegfx::B2DRectangle getUpdateArea() const;
+ virtual bool isVisible() const;
+ virtual double getPriority() const;
+
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ virtual void enterAnimationMode();
+ virtual void leaveAnimationMode();
+ virtual bool isBackgroundDetached() const;
+
+ // render methods
+ //------------------------------------------------------------------
+
+ virtual bool update() const;
+ virtual bool render() const;
+ virtual bool isContentChanged() const;
+
+ // Sub item specialities
+ //------------------------------------------------------------------
+
+ virtual const DocTreeNodeSupplier& getTreeNodeSupplier() const;
+ virtual DocTreeNodeSupplier& getTreeNodeSupplier();
+
+ virtual DocTreeNode getSubsetNode() const;
+ virtual AttributableShapeSharedPtr getSubset( const DocTreeNode& rTreeNode ) const;
+ virtual bool createSubset( AttributableShapeSharedPtr& o_rSubset,
+ const DocTreeNode& rTreeNode );
+ virtual bool revokeSubset( const AttributableShapeSharedPtr& rShape );
+
+
+ // DocTreeNodeSupplier methods
+ //------------------------------------------------------------------
+
+ virtual sal_Int32 getNumberOfTreeNodes ( DocTreeNode::NodeType eNodeType ) const; // throw ShapeLoadFailedException;
+ virtual DocTreeNode getTreeNode ( sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const; // throw ShapeLoadFailedException;
+ virtual sal_Int32 getNumberOfSubsetTreeNodes ( const DocTreeNode& rParentNode,
+ DocTreeNode::NodeType eNodeType ) const; // throw ShapeLoadFailedException;
+ virtual DocTreeNode getSubsetTreeNode ( const DocTreeNode& rParentNode,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const; // throw ShapeLoadFailedException;
+
+ // HyperlinkArea methods
+ //------------------------------------------------------------------
+
+ virtual HyperlinkRegions getHyperlinkRegions() const;
+ virtual double getHyperlinkPriority() const;
+
+
+ // intrinsic animation methods
+ //------------------------------------------------------------------
+
+ /** Display next frame of an intrinsic animation.
+
+ Used by IntrinsicAnimationActivity, to show the next
+ animation frame.
+ */
+ bool setIntrinsicAnimationFrame( ::std::size_t nCurrFrame );
+
+ /** forces the drawshape to load and return a specially
+ crafted metafile, usable to display drawing layer text
+ animations.
+ */
+ GDIMetaFileSharedPtr forceScrollTextMetaFile();
+
+ private:
+ /** Create a shape for the given XShape
+
+ @param xShape
+ The XShape to represent.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param bForeignSource
+ When true, the source of the shape metafile might be a
+ foreign application. The metafile is checked against
+ unsupported content, and, if necessary, returned as a
+ pre-rendererd bitmap.
+ */
+ DrawShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ bool bForeignSource,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ /** Create a shape for the given XShape and graphic content
+
+ @param xShape
+ The XShape to represent.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+
+ @param rGraphic
+ Graphic to display in the shape's bound rect. If this
+ Graphic contains animatable content, the created
+ DrawShape will register itself for intrinsic animation
+ events.
+ */
+ DrawShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ double nPrio,
+ const Graphic& rGraphic,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ /** Private copy constructor
+
+ Used to create subsetted shapes
+ */
+ DrawShape( const DrawShape&, const DocTreeNode& rTreeNode, double nPrio );
+
+ int getUpdateFlags() const;
+ bool implRender( int nUpdateFlags ) const;
+ void updateStateIds() const;
+
+ ViewShape::RenderArgs getViewRenderArgs() const;
+ ::basegfx::B2DRectangle getActualUnitShapeBounds() const;
+
+ void ensureVerboseMtfComments() const;
+ bool hasIntrinsicAnimation() const;
+ bool hasHyperlinks() const;
+ void prepareHyperlinkIndices() const;
+
+ /// The associated XShape
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > mxShape;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XDrawPage > mxPage;
+
+ /** A vector of metafiles actually representing the Shape.
+
+ If this shape is not animated, only a single entry is
+ available.
+ */
+ mutable VectorOfMtfAnimationFrames maAnimationFrames;
+ ::std::size_t mnCurrFrame;
+
+ /// Metafile of currently active frame (static for shapes w/o intrinsic animation)
+ mutable GDIMetaFileSharedPtr mpCurrMtf;
+
+ /// loadflags of current meta file
+ mutable int mnCurrMtfLoadFlags;
+
+ /// Contains the current shape bounds, in unit rect space
+ mutable ::boost::optional<basegfx::B2DRectangle> maCurrentShapeUnitBounds;
+
+ // The attributes of this Shape
+ const double mnPriority;
+ ::basegfx::B2DRectangle maBounds; // always needed for rendering.
+ // for subset shapes, this member
+ // might change when views are
+ // added, as minimal bounds are
+ // calculated
+
+ // Pointer to modifiable shape attributes
+ ShapeAttributeLayerSharedPtr mpAttributeLayer; // only created lazily
+
+ // held here, to signal our destruction
+ boost::weak_ptr<Activity> mpIntrinsicAnimationActivity;
+
+ // The attribute states, to detect attribute changes,
+ // without buffering and querying each single attribute
+ mutable State::StateId mnAttributeTransformationState;
+ mutable State::StateId mnAttributeClipState;
+ mutable State::StateId mnAttributeAlphaState;
+ mutable State::StateId mnAttributePositionState;
+ mutable State::StateId mnAttributeContentState;
+ mutable State::StateId mnAttributeVisibilityState;
+
+ /// the list of active view shapes (one for each registered view layer)
+ typedef ::std::vector< ViewShapeSharedPtr > ViewShapeVector;
+ ViewShapeVector maViewShapes;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext> mxComponentContext;
+
+ /// hyperlink support
+ typedef ::std::pair<sal_Int32 /* mtf start */,
+ sal_Int32 /* mtf end */> HyperlinkIndexPair;
+ typedef ::std::vector<HyperlinkIndexPair> HyperlinkIndexPairVector;
+ mutable HyperlinkIndexPairVector maHyperlinkIndices;
+ mutable HyperlinkRegions maHyperlinkRegions;
+
+ /// Delegated subset handling
+ mutable DrawShapeSubsetting maSubsetting;
+
+ /// Whether this shape is currently in animation mode (value != 0)
+ int mnIsAnimatedCount;
+
+ /// Number of times the bitmap animation shall loop
+ ::std::size_t mnAnimationLoopCount;
+
+ /// Cycle mode for bitmap animation
+ CycleMode meCycleMode;
+
+ /// Whether shape is visible (without attribute layers)
+ bool mbIsVisible;
+
+ /// Whether redraw is necessary, regardless of state ids
+ mutable bool mbForceUpdate;
+
+ /// Whether attribute layer was revoked (making a redraw necessary)
+ mutable bool mbAttributeLayerRevoked;
+
+ /// whether a drawing layer animation has to be performed
+ bool mbDrawingLayerAnim;
+
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_DRAWSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawshapesubsetting.cxx b/slideshow/source/engine/shapes/drawshapesubsetting.cxx
new file mode 100644
index 000000000000..62dc22ea3dc0
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawshapesubsetting.cxx
@@ -0,0 +1,868 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <rtl/math.hxx>
+#include <rtl/logfile.hxx>
+
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+#include <basegfx/numeric/ftools.hxx>
+
+#include "drawshapesubsetting.hxx"
+#include "drawshape.hxx"
+
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <limits>
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Private methods
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ void DrawShapeSubsetting::ensureInitializedNodeTree() const
+ {
+ ENSURE_OR_THROW( mpMtf,
+ "DrawShapeSubsetting::ensureInitializedNodeTree(): Invalid mtf" );
+
+ if( mbNodeTreeInitialized )
+ return; // done, already initialized.
+
+ // init doctree vector
+ maActionClassVector.clear();
+ maActionClassVector.reserve( mpMtf->GetActionCount() );
+
+ // search metafile for text output
+ MetaAction* pCurrAct;
+
+ sal_Int32 nActionIndex(0);
+ sal_Int32 nLastTextActionIndex(0);
+ for( pCurrAct = mpMtf->FirstAction(); pCurrAct; pCurrAct = mpMtf->NextAction() )
+ {
+ // check for one of our special text doctree comments
+ switch( pCurrAct->GetType() )
+ {
+ case META_COMMENT_ACTION:
+ {
+ MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
+
+ // skip comment if not a special XTEXT comment
+ if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT", 5 ) == COMPARE_EQUAL )
+ {
+ // fill classification vector with NOOPs,
+ // then insert corresponding classes at
+ // the given index
+ maActionClassVector.resize( nActionIndex+1, CLASS_NOOP );
+
+ if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOC" ) == COMPARE_EQUAL )
+ {
+ // special, because can happen
+ // in-between of portions - set
+ // character-end classificator at
+ // given index (relative to last text
+ // action).
+ const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
+
+ ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
+ "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
+
+ maActionClassVector[ nIndex ] = CLASS_CHARACTER_CELL_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOW" ) == COMPARE_EQUAL )
+ {
+ // special, because can happen
+ // in-between of portions - set
+ // word-end classificator at given
+ // index (relative to last text
+ // action).
+ const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
+
+ ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
+ "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
+
+ maActionClassVector[ nIndex ] = CLASS_WORD_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOS" ) == COMPARE_EQUAL )
+ {
+ // special, because can happen
+ // in-between of portions - set
+ // sentence-end classificator at given
+ // index (relative to last text
+ // action).
+ const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
+
+ ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
+ "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
+
+ maActionClassVector[ nIndex ] = CLASS_SENTENCE_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOL" ) == COMPARE_EQUAL )
+ {
+ maActionClassVector[ nActionIndex ] = CLASS_LINE_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOP" ) == COMPARE_EQUAL )
+ {
+ maActionClassVector[ nActionIndex ] = CLASS_PARAGRAPH_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_PAINTSHAPE_END" ) == COMPARE_EQUAL )
+ {
+ maActionClassVector[ nActionIndex ] = CLASS_SHAPE_END;
+ }
+ else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_PAINTSHAPE_BEGIN" ) == COMPARE_EQUAL )
+ {
+ maActionClassVector[ nActionIndex ] = CLASS_SHAPE_START;
+ }
+ }
+ ++nActionIndex;
+ break;
+ }
+ case META_TEXT_ACTION:
+ case META_TEXTARRAY_ACTION:
+ case META_STRETCHTEXT_ACTION:
+ nLastTextActionIndex = nActionIndex;
+ // fallthrough intended
+ default:
+ // comment action and all actions not
+ // explicitely handled here:
+ nActionIndex += getNextActionOffset(pCurrAct);
+ break;
+ }
+ }
+
+ mbNodeTreeInitialized = true;
+ }
+
+ void DrawShapeSubsetting::updateSubsetBounds( const SubsetEntry& rSubsetEntry )
+ {
+ // TODO(F1): This removes too much from non-contiguous subsets
+ mnMinSubsetActionIndex = ::std::min(
+ mnMinSubsetActionIndex,
+ rSubsetEntry.mnStartActionIndex );
+ mnMaxSubsetActionIndex = ::std::max(
+ mnMaxSubsetActionIndex,
+ rSubsetEntry.mnEndActionIndex );
+ }
+
+ void DrawShapeSubsetting::updateSubsets()
+ {
+ maCurrentSubsets.clear();
+
+ if( !maSubsetShapes.empty() )
+ {
+ if( maSubset.isEmpty() )
+ {
+ // non-subsetted node, with some child subsets
+ // that subtract from it
+ maCurrentSubsets.push_back( DocTreeNode( 0,
+ mnMinSubsetActionIndex,
+ DocTreeNode::NODETYPE_INVALID ) );
+ maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
+ maActionClassVector.size(),
+ DocTreeNode::NODETYPE_INVALID ) );
+ }
+ else
+ {
+ // subsetted node, from which some further child
+ // subsets subtract content
+ maCurrentSubsets.push_back( DocTreeNode( maSubset.getStartIndex(),
+ mnMinSubsetActionIndex,
+ DocTreeNode::NODETYPE_INVALID ) );
+ maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
+ maSubset.getEndIndex(),
+ DocTreeNode::NODETYPE_INVALID ) );
+ }
+ }
+ else
+ {
+ // no further child subsets, simply add our subset (if any)
+ if( !maSubset.isEmpty() )
+ {
+ // subsetted node, without any subset children
+ maCurrentSubsets.push_back( maSubset );
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Public methods
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ DrawShapeSubsetting::DrawShapeSubsetting() :
+ maActionClassVector(),
+ mpMtf(),
+ maSubset(),
+ maSubsetShapes(),
+ mnMinSubsetActionIndex( SAL_MAX_INT32 ),
+ mnMaxSubsetActionIndex(0),
+ maCurrentSubsets(),
+ mbNodeTreeInitialized( false )
+ {
+ }
+
+ DrawShapeSubsetting::DrawShapeSubsetting( const GDIMetaFileSharedPtr& rMtf ) :
+ maActionClassVector(),
+ mpMtf( rMtf ),
+ maSubset(),
+ maSubsetShapes(),
+ mnMinSubsetActionIndex( SAL_MAX_INT32 ),
+ mnMaxSubsetActionIndex(0),
+ maCurrentSubsets(),
+ mbNodeTreeInitialized( false )
+ {
+ ENSURE_OR_THROW( mpMtf,
+ "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
+
+ initCurrentSubsets();
+ }
+
+ DrawShapeSubsetting::DrawShapeSubsetting( const DocTreeNode& rShapeSubset,
+ const GDIMetaFileSharedPtr& rMtf ) :
+ maActionClassVector(),
+ mpMtf( rMtf ),
+ maSubset( rShapeSubset ),
+ maSubsetShapes(),
+ mnMinSubsetActionIndex( SAL_MAX_INT32 ),
+ mnMaxSubsetActionIndex(0),
+ maCurrentSubsets(),
+ mbNodeTreeInitialized( false )
+ {
+ ENSURE_OR_THROW( mpMtf,
+ "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
+
+ initCurrentSubsets();
+ }
+
+ void DrawShapeSubsetting::reset()
+ {
+ maActionClassVector.clear();
+ mpMtf.reset();
+ maSubset.reset();
+ maSubsetShapes.clear();
+ mnMinSubsetActionIndex = SAL_MAX_INT32;
+ mnMaxSubsetActionIndex = 0;
+ maCurrentSubsets.clear();
+ mbNodeTreeInitialized = false;
+ }
+
+ void DrawShapeSubsetting::reset( const ::boost::shared_ptr< GDIMetaFile >& rMtf )
+ {
+ reset();
+ mpMtf = rMtf;
+
+ initCurrentSubsets();
+ }
+
+ void DrawShapeSubsetting::reset( const DocTreeNode& rShapeSubset,
+ const ::boost::shared_ptr< GDIMetaFile >& rMtf )
+ {
+ reset();
+ mpMtf = rMtf;
+ maSubset = rShapeSubset;
+
+ initCurrentSubsets();
+ }
+
+ void DrawShapeSubsetting::initCurrentSubsets()
+ {
+ // only add subset to vector, if it's not empty - that's
+ // because the vector's content is later literally used
+ // for e.g. painting.
+ if( !maSubset.isEmpty() )
+ maCurrentSubsets.push_back( maSubset );
+ }
+
+ DocTreeNode DrawShapeSubsetting::getSubsetNode() const
+ {
+ return maSubset;
+ }
+
+ bool DrawShapeSubsetting::hasSubsetShapes() const
+ {
+ return !maSubsetShapes.empty();
+ }
+
+ AttributableShapeSharedPtr DrawShapeSubsetting::getSubsetShape( const DocTreeNode& rTreeNode ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
+
+ // subset shape already created for this DocTreeNode?
+ SubsetEntry aEntry;
+
+ aEntry.mnStartActionIndex = rTreeNode.getStartIndex();
+ aEntry.mnEndActionIndex = rTreeNode.getEndIndex();
+
+ ShapeSet::const_iterator aIter;
+ if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
+ {
+ // already created, return found entry
+ return aIter->mpShape;
+ }
+
+ return AttributableShapeSharedPtr();
+ }
+
+ void DrawShapeSubsetting::addSubsetShape( const AttributableShapeSharedPtr& rShape )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::addSubsetShape()" );
+
+ // subset shape already created for this DocTreeNode?
+ SubsetEntry aEntry;
+ const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
+
+ aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
+ aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
+
+ ShapeSet::const_iterator aIter;
+ if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
+ {
+ // already created, increment use count and return
+
+ // safe cast, since set order does not depend on
+ // mnSubsetQueriedCount
+ const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount++;
+ }
+ else
+ {
+ // not yet created, init entry
+ aEntry.mnSubsetQueriedCount = 1;
+ aEntry.mpShape = rShape;
+
+ maSubsetShapes.insert( aEntry );
+
+ // update cached subset borders
+ updateSubsetBounds( aEntry );
+ updateSubsets();
+ }
+ }
+
+ bool DrawShapeSubsetting::revokeSubsetShape( const AttributableShapeSharedPtr& rShape )
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::revokeSubsetShape()" );
+
+ // lookup subset shape
+ SubsetEntry aEntry;
+ const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
+
+ aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
+ aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
+
+ ShapeSet::iterator aIter;
+ if( (aIter=maSubsetShapes.find( aEntry )) == maSubsetShapes.end() )
+ return false; // not found, subset was never queried
+
+ // last client of the subset revoking?
+ if( aIter->mnSubsetQueriedCount > 1 )
+ {
+ // no, still clients out there. Just decrement use count
+ // safe cast, since order does not depend on mnSubsetQueriedCount
+ const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount--;
+
+ VERBOSE_TRACE( "Subset summary: shape 0x%X, %d open subsets, revoked subset has refcount %d",
+ this,
+ maSubsetShapes.size(),
+ aIter->mnSubsetQueriedCount );
+
+ return false; // not the last client
+ }
+
+ VERBOSE_TRACE( "Subset summary: shape 0x%X, %d open subsets, cleared subset has range [%d,%d]",
+ this,
+ maSubsetShapes.size(),
+ aEntry.mnStartActionIndex,
+ aEntry.mnEndActionIndex );
+
+ // yes, remove from set
+ maSubsetShapes.erase( aIter );
+
+
+ // update currently active subset for _our_ shape (the
+ // part of this shape that is visible, i.e. not displayed
+ // in subset shapes)
+ // ======================================================
+
+ // init bounds
+ mnMinSubsetActionIndex = SAL_MAX_INT32;
+ mnMaxSubsetActionIndex = 0;
+
+ // TODO(P2): This is quite expensive, when
+ // after every subset effect end, we have to scan
+ // the whole shape set
+
+ // determine new subset range
+ ::std::for_each( maSubsetShapes.begin(),
+ maSubsetShapes.end(),
+ ::boost::bind(&DrawShapeSubsetting::updateSubsetBounds,
+ this,
+ _1 ) );
+
+ updateSubsets();
+
+ return true;
+ }
+
+ namespace
+ {
+ /** Iterate over all action classification entries in the
+ given range, pass each element range found to the
+ given functor.
+
+ This method extracts, for each of the different action
+ classifications, the count and the ranges for each of
+ them, and calls the provided functor with that
+ information.
+
+ @tpl FunctorT
+ This is the functor's operator() calling signature,
+ with eCurrElemClassification denoting the current
+ classification type the functor is called for,
+ nCurrElemCount the running total of elements visited
+ for the given class (starting from 0), and
+ rCurrElemBegin/rCurrElemEnd the range of the current
+ element (i.e. the iterators from the start to the end
+ of this element).
+ <pre>
+ bool operator()( IndexClassificator eCurrElemClassification
+ sal_Int32 nCurrElemCount,
+ const IndexClassificatorVector::const_iterator& rCurrElemBegin,
+ const IndexClassificatorVector::const_iterator& rCurrElemEnd );
+ </pre>
+ If the functor returns false, iteration over the
+ shapes is immediately stopped.
+
+ @param io_pFunctor
+ This functor is called for every shape found.
+
+ @param rBegin
+ Start of range to iterate over
+
+ @param rEnd
+ End of range to iterate over
+
+ @return the number of shapes found in the metafile
+ */
+ template< typename FunctorT > void iterateActionClassifications(
+ FunctorT& io_rFunctor,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd )
+ {
+ sal_Int32 nCurrShapeCount( 0 );
+ sal_Int32 nCurrParaCount( 0 );
+ sal_Int32 nCurrLineCount( 0 );
+ sal_Int32 nCurrSentenceCount( 0 );
+ sal_Int32 nCurrWordCount( 0 );
+ sal_Int32 nCurrCharCount( 0 );
+
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastShapeStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastParaStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastLineStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastSentenceStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastWordStart(rBegin);
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastCharStart(rBegin);
+
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aNext;
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator aCurr( rBegin );
+ while( aCurr != rEnd )
+ {
+ // aNext will hold an iterator to the next element
+ // (or the past-the-end iterator, if aCurr
+ // references the last element). Used to pass a
+ // valid half-open range to the functors.
+ aNext = aCurr;
+ ++aNext;
+
+ switch( *aCurr )
+ {
+ default:
+ ENSURE_OR_THROW( false,
+ "Unexpected type in iterateDocShapes()" );
+ case DrawShapeSubsetting::CLASS_NOOP:
+ // ignore NOOP actions
+ break;
+
+ case DrawShapeSubsetting::CLASS_SHAPE_START:
+ // regardless of ending action
+ // classifications before: a new shape
+ // always also starts contained elements
+ // anew
+ aLastShapeStart =
+ aLastParaStart =
+ aLastLineStart =
+ aLastSentenceStart =
+ aLastWordStart =
+ aLastCharStart = aCurr;
+ break;
+
+ case DrawShapeSubsetting::CLASS_SHAPE_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END,
+ nCurrShapeCount,
+ aLastShapeStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrShapeCount;
+ // FALLTHROUGH intended: shape end also
+ // ends lines
+ case DrawShapeSubsetting::CLASS_PARAGRAPH_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_PARAGRAPH_END,
+ nCurrParaCount,
+ aLastParaStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrParaCount;
+ aLastParaStart = aNext;
+ // FALLTHROUGH intended: para end also
+ // ends line
+ case DrawShapeSubsetting::CLASS_LINE_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END,
+ nCurrLineCount,
+ aLastLineStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrLineCount;
+ aLastLineStart = aNext;
+
+ if( *aCurr == DrawShapeSubsetting::CLASS_LINE_END )
+ {
+ // DON'T fall through here, as a line
+ // does NOT end neither a sentence,
+ // nor a word. OTOH, all parent
+ // structures (paragraph and shape),
+ // which itself fall through to this
+ // code, DO end word, sentence and
+ // character cell.
+
+ // TODO(F1): Maybe a line should end a
+ // character cell, OTOH?
+ break;
+ }
+ // FALLTHROUGH intended
+ case DrawShapeSubsetting::CLASS_SENTENCE_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_SENTENCE_END,
+ nCurrSentenceCount,
+ aLastSentenceStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrSentenceCount;
+ aLastSentenceStart = aNext;
+ // FALLTHROUGH intended
+ case DrawShapeSubsetting::CLASS_WORD_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END,
+ nCurrWordCount,
+ aLastWordStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrWordCount;
+ aLastWordStart = aNext;
+ // FALLTHROUGH intended
+ case DrawShapeSubsetting::CLASS_CHARACTER_CELL_END:
+ if( !io_rFunctor( DrawShapeSubsetting::CLASS_CHARACTER_CELL_END,
+ nCurrCharCount,
+ aLastCharStart,
+ aNext ) )
+ {
+ return;
+ }
+
+ ++nCurrCharCount;
+ aLastCharStart = aNext;
+ break;
+ }
+
+ aCurr = aNext;
+ }
+ }
+
+ DrawShapeSubsetting::IndexClassificator mapDocTreeNode( DocTreeNode::NodeType eNodeType )
+ {
+ switch( eNodeType )
+ {
+ case DocTreeNode::NODETYPE_INVALID:
+ // FALLTHROUGH intended
+ default:
+ OSL_ENSURE(false,
+ "DrawShapeSubsetting::mapDocTreeNode(): unexpected node type");
+ return DrawShapeSubsetting::CLASS_NOOP;
+
+ case DocTreeNode::NODETYPE_LOGICAL_SHAPE:
+ // FALLTHROUGH intended
+ case DocTreeNode::NODETYPE_FORMATTING_SHAPE:
+ return DrawShapeSubsetting::CLASS_SHAPE_END;
+
+ case DocTreeNode::NODETYPE_FORMATTING_LINE:
+ return DrawShapeSubsetting::CLASS_LINE_END;
+
+ case DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH:
+ return DrawShapeSubsetting::CLASS_PARAGRAPH_END;
+
+ case DocTreeNode::NODETYPE_LOGICAL_SENTENCE:
+ return DrawShapeSubsetting::CLASS_SENTENCE_END;
+
+ case DocTreeNode::NODETYPE_LOGICAL_WORD:
+ return DrawShapeSubsetting::CLASS_WORD_END;
+
+ case DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL:
+ return DrawShapeSubsetting::CLASS_CHARACTER_CELL_END;
+ };
+ }
+
+ /// Counts number of class occurences
+ class CountClassFunctor
+ {
+ public:
+ CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass ) :
+ meClass( eClass ),
+ mnCurrCount(0)
+ {
+ }
+
+ bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
+ sal_Int32 /*nCurrElemCount*/,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemBegin*/,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemEnd*/ )
+ {
+ if( eCurrElemClassification == meClass )
+ ++mnCurrCount;
+
+ return true; // never stop, count all occurences
+ }
+
+ sal_Int32 getCount() const
+ {
+ return mnCurrCount;
+ }
+
+ private:
+ DrawShapeSubsetting::IndexClassificator meClass;
+ sal_Int32 mnCurrCount;
+ };
+ }
+
+ sal_Int32 DrawShapeSubsetting::implGetNumberOfTreeNodes( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ const IndexClassificator eRequestedClass(
+ mapDocTreeNode( eNodeType ) );
+
+ // create a counting functor for the requested class of
+ // actions
+ CountClassFunctor aFunctor( eRequestedClass );
+
+ // count all occurences in the given range
+ iterateActionClassifications( aFunctor, rBegin, rEnd );
+
+ return aFunctor.getCount();
+ }
+
+ sal_Int32 DrawShapeSubsetting::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const
+ {
+ ensureInitializedNodeTree();
+
+ return implGetNumberOfTreeNodes( maActionClassVector.begin(),
+ maActionClassVector.end(),
+ eNodeType );
+ }
+
+ namespace
+ {
+ /** This functor finds the nth occurrence of a given
+ action class.
+
+ The operator() compares the given index value with the
+ requested index, as given on the functor's
+ constructor. Then, the operator() returns false,
+ denoting that the requested action is found.
+ */
+ class FindNthElementFunctor
+ {
+ public:
+ FindNthElementFunctor( sal_Int32 nNodeIndex,
+ DrawShapeSubsetting::IndexClassificator eClass ) :
+ mnNodeIndex( nNodeIndex ),
+ meClass( eClass )
+ {
+ }
+
+ bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
+ sal_Int32 nCurrElemCount,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemBegin,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemEnd )
+ {
+ if( eCurrElemClassification == meClass &&
+ nCurrElemCount == mnNodeIndex )
+ {
+ maLastBegin = rCurrElemBegin;
+ maLastEnd = rCurrElemEnd;
+
+ return false; // abort iteration, we've
+ // already found what we've been
+ // looking for
+ }
+
+ return true; // keep on truckin'
+ }
+
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator getBeginElement() const
+ {
+ return maLastBegin;
+ }
+
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator getEndElement() const
+ {
+ return maLastEnd;
+ }
+
+ private:
+ sal_Int32 mnNodeIndex;
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator maLastBegin;
+ DrawShapeSubsetting::IndexClassificatorVector::const_iterator maLastEnd;
+ DrawShapeSubsetting::IndexClassificator meClass;
+ };
+
+ DocTreeNode makeTreeNode( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rStart,
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
+ DocTreeNode::NodeType eNodeType )
+ {
+ return DocTreeNode( ::std::distance(rBegin,
+ rStart),
+ ::std::distance(rBegin,
+ rEnd),
+ eNodeType );
+ }
+ }
+
+ DocTreeNode DrawShapeSubsetting::implGetTreeNode( const IndexClassificatorVector::const_iterator& rBegin,
+ const IndexClassificatorVector::const_iterator& rEnd,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ const IndexClassificator eRequestedClass(
+ mapDocTreeNode( eNodeType ) );
+
+ // create a nth element functor for the requested class of
+ // actions, and nNodeIndex as the target index
+ FindNthElementFunctor aFunctor( nNodeIndex,
+ eRequestedClass );
+
+ // find given index in the given range
+ iterateActionClassifications( aFunctor, rBegin, rEnd );
+
+ return makeTreeNode( maActionClassVector.begin(),
+ aFunctor.getBeginElement(),
+ aFunctor.getEndElement(),
+ eNodeType );
+ }
+
+ DocTreeNode DrawShapeSubsetting::getTreeNode( sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ ensureInitializedNodeTree();
+
+ return implGetTreeNode( maActionClassVector.begin(),
+ maActionClassVector.end(),
+ nNodeIndex,
+ eNodeType );
+ }
+
+ sal_Int32 DrawShapeSubsetting::getNumberOfSubsetTreeNodes( const DocTreeNode& rParentNode,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ ensureInitializedNodeTree();
+
+ // convert from vector indices to vector iterators
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
+
+ return implGetNumberOfTreeNodes( aParentBegin,
+ aParentEnd,
+ eNodeType );
+ }
+
+ DocTreeNode DrawShapeSubsetting::getSubsetTreeNode( const DocTreeNode& rParentNode,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const
+ {
+ ensureInitializedNodeTree();
+
+ // convert from vector indices to vector iterators
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
+ const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
+
+ return implGetTreeNode( aParentBegin,
+ aParentEnd,
+ nNodeIndex,
+ eNodeType );
+ }
+
+ const VectorOfDocTreeNodes& DrawShapeSubsetting::getActiveSubsets() const
+ {
+ return maCurrentSubsets;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/drawshapesubsetting.hxx b/slideshow/source/engine/shapes/drawshapesubsetting.hxx
new file mode 100644
index 000000000000..1dc560a9b97c
--- /dev/null
+++ b/slideshow/source/engine/shapes/drawshapesubsetting.hxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_DRAWSHAPESUBSETTING_HXX
+#define INCLUDED_SLIDESHOW_DRAWSHAPESUBSETTING_HXX
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "doctreenode.hxx"
+#include "attributableshape.hxx"
+
+
+class GDIMetaFile;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class encapsulates the subsetting aspects of a
+ DrawShape.
+ */
+ class DrawShapeSubsetting : private boost::noncopyable
+ {
+ public:
+ /** Create empty shape subset handling.
+
+ This method creates a subset handler which contains no
+ subset information. All methods will return default
+ values.
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ DrawShapeSubsetting();
+
+ /** Create new shape subset handling.
+
+ This method creates a subset handler which initially
+ displays the whole shape.
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ explicit DrawShapeSubsetting( const ::boost::shared_ptr< GDIMetaFile >& rMtf );
+
+ /** Create new shape subset handling.
+
+ @param rShapeSubset
+ The subset this object represents (can be empty, then
+ denoting 'represents a whole shape')
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ DrawShapeSubsetting( const DocTreeNode& rShapeSubset,
+ const ::boost::shared_ptr< GDIMetaFile >& rMtf );
+
+ /** Reset metafile.
+
+ Use this method to completely reset the
+ ShapeSubsetting, with a new metafile. Note that any
+ information previously set will be lost, including
+ added subset shapes!
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ void reset( const ::boost::shared_ptr< GDIMetaFile >& rMtf );
+
+ /** Reset metafile and subset.
+
+ Use this method to completely reset the
+ ShapeSubsetting, with a new metafile and subset
+ range. Note that any information previously set will
+ be lost, including added subset shapes!
+
+ @param rShapeSubset
+ The subset this object represents (can be empty, then
+ denoting 'represents a whole shape')
+
+ @param rMtf
+ Metafile to retrieve subset info from (must have been
+ generated with verbose text comments switched on).
+ */
+ void reset( const DocTreeNode& rShapeSubset,
+ const ::boost::shared_ptr< GDIMetaFile >& rMtf );
+
+
+ // Shape subsetting methods
+ // ========================================================
+
+ /// Return subset node for this shape
+ DocTreeNode getSubsetNode () const;
+
+ /// Return true, if any child subset shapes exist
+ bool hasSubsetShapes () const;
+
+ /// Get subset shape for given node, if any
+ AttributableShapeSharedPtr getSubsetShape ( const DocTreeNode& rTreeNode ) const;
+
+ /// Add child subset shape (or increase use count, if already existent)
+ void addSubsetShape ( const AttributableShapeSharedPtr& rShape );
+
+ /** Revoke subset shape
+
+ This method revokes a subset shape, decrementing the
+ use count for this subset by one. If the use count
+ reaches zero (i.e. when the number of addSubsetShape()
+ matches the number of revokeSubsetShape() calls for
+ the same subset), the subset entry is removed from the
+ internal list, and subsequent getSubsetShape() calls
+ will return the empty pointer for this subset.
+
+ @return true, if the subset shape was physically
+ removed from the list (false is returned, when nothing
+ was removed, either because only the use count was
+ decremented, or there was no such subset found, in the
+ first place).
+ */
+ bool revokeSubsetShape ( const AttributableShapeSharedPtr& rShape );
+
+
+ // Doc tree methods
+ // ========================================================
+
+ /// Return overall number of nodes for given type
+ sal_Int32 getNumberOfTreeNodes ( DocTreeNode::NodeType eNodeType ) const;
+
+ /// Return tree node of given index and given type
+ DocTreeNode getTreeNode ( sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const;
+
+ /// Return number of nodes of given type, below parent node
+ sal_Int32 getNumberOfSubsetTreeNodes ( const DocTreeNode& rParentNode,
+ DocTreeNode::NodeType eNodeType ) const;
+
+ /// Return tree node of given index and given type, relative to parent node
+ DocTreeNode getSubsetTreeNode ( const DocTreeNode& rParentNode,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const;
+
+ // Helper
+ // ========================================================
+
+ /** Return a vector of currently active subsets.
+
+ Needed when rendering a shape, this method provides a
+ vector of subsets currently visible (the range as
+ returned by getEffectiveSubset(), minus the parts that
+ are currently hidden, because displayed by child
+ shapes).
+ */
+ const VectorOfDocTreeNodes& getActiveSubsets() const;
+
+ /** This enum classifies each action index in the
+ metafile.
+
+ Of interest are, of course, the places where
+ structural shape and/or text elements end. The
+ remainder of the action gets classified as 'noop'
+ */
+ enum IndexClassificator
+ {
+ CLASS_NOOP,
+ CLASS_SHAPE_START,
+ CLASS_SHAPE_END,
+
+ CLASS_LINE_END,
+ CLASS_PARAGRAPH_END,
+ CLASS_SENTENCE_END,
+ CLASS_WORD_END,
+ CLASS_CHARACTER_CELL_END
+ };
+
+ typedef ::std::vector< IndexClassificator > IndexClassificatorVector;
+
+ private:
+ /** Entry for subset shape
+
+ This struct contains data for every subset shape
+ generated. Note that for a given start/end action
+ index combination, only one subset instance is
+ generated (and reused for subsequent queries).
+ */
+ struct SubsetEntry
+ {
+ AttributableShapeSharedPtr mpShape;
+ sal_Int32 mnStartActionIndex;
+ sal_Int32 mnEndActionIndex;
+
+ /// Number of times this subset was queried, and not yet revoked
+ int mnSubsetQueriedCount;
+
+ sal_Int32 getHashValue() const
+ {
+ // TODO(Q3): That's a hack. We assume that start
+ // index will always be less than 65535 (if this
+ // assumption is violated, hash map performance
+ // will degrade severely)
+ return mnStartActionIndex*SAL_MAX_INT16 + mnEndActionIndex;
+ }
+
+ /// The shape set is ordered according to this method
+ bool operator<(const SubsetEntry& rOther) const
+ {
+ return getHashValue() < rOther.getHashValue();
+ }
+
+ };
+
+ typedef ::std::set< SubsetEntry > ShapeSet;
+
+ void ensureInitializedNodeTree() const;
+ void updateSubsetBounds( const SubsetEntry& rSubsetEntry );
+ void updateSubsets();
+ void initCurrentSubsets();
+ void reset();
+
+ sal_Int32 implGetNumberOfTreeNodes( const IndexClassificatorVector::const_iterator& rBegin,
+ const IndexClassificatorVector::const_iterator& rEnd,
+ DocTreeNode::NodeType eNodeType ) const;
+ DocTreeNode implGetTreeNode( const IndexClassificatorVector::const_iterator& rBegin,
+ const IndexClassificatorVector::const_iterator& rEnd,
+ sal_Int32 nNodeIndex,
+ DocTreeNode::NodeType eNodeType ) const;
+
+ mutable IndexClassificatorVector maActionClassVector;
+
+ /// Metafile to retrieve subset info from
+ ::boost::shared_ptr< GDIMetaFile > mpMtf;
+
+ /// Subset of the metafile represented by this object
+ DocTreeNode maSubset;
+
+ /// the list of subset shapes spawned from this one.
+ ShapeSet maSubsetShapes;
+
+ /// caches minimal subset index from maSubsetShapes
+ sal_Int32 mnMinSubsetActionIndex;
+
+ /// caches maximal subset index from maSubsetShapes
+ sal_Int32 mnMaxSubsetActionIndex;
+
+ /** Current number of subsets to render (calculated from
+ maSubset and mnMin/MaxSubsetActionIndex).
+
+ Note that this is generally _not_ equivalent to
+ maSubset, as it excludes all active subset children!
+ */
+ mutable VectorOfDocTreeNodes maCurrentSubsets;
+
+ /// Whether the shape's doc tree has been initialized successfully, or not
+ mutable bool mbNodeTreeInitialized;
+ };
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_DRAWSHAPESUBSETTING_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/externalshapebase.cxx b/slideshow/source/engine/shapes/externalshapebase.cxx
new file mode 100644
index 000000000000..7874143ca916
--- /dev/null
+++ b/slideshow/source/engine/shapes/externalshapebase.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include "externalshapebase.hxx"
+#include "eventmultiplexer.hxx"
+#include "vieweventhandler.hxx"
+#include "intrinsicanimationeventhandler.hxx"
+#include "tools.hxx"
+
+#include <boost/noncopyable.hpp>
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ class ExternalShapeBase::ExternalShapeBaseListener : public ViewEventHandler,
+ public IntrinsicAnimationEventHandler,
+ private boost::noncopyable
+ {
+ public:
+ explicit ExternalShapeBaseListener( ExternalShapeBase& rBase ) :
+ mrBase( rBase )
+ {}
+
+
+ private:
+ // ViewEventHandler
+ // -------------------------------------------------
+
+ virtual void viewAdded( const UnoViewSharedPtr& ) {}
+ virtual void viewRemoved( const UnoViewSharedPtr& ) {}
+ virtual void viewChanged( const UnoViewSharedPtr& rView )
+ {
+ mrBase.implViewChanged(rView);
+ }
+ virtual void viewsChanged()
+ {
+ mrBase.implViewsChanged();
+ }
+
+
+ // IntrinsicAnimationEventHandler
+ // -------------------------------------------------
+
+ virtual bool enableAnimations()
+ {
+ return mrBase.implStartIntrinsicAnimation();
+ }
+ virtual bool disableAnimations()
+ {
+ return mrBase.implEndIntrinsicAnimation();
+ }
+
+ ExternalShapeBase& mrBase;
+ };
+
+
+ ExternalShapeBase::ExternalShapeBase( const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext ) :
+ mxComponentContext( rContext.mxComponentContext ),
+ mxShape( xShape ),
+ mpListener( new ExternalShapeBaseListener(*this) ),
+ mpShapeManager( rContext.mpSubsettableShapeManager ),
+ mrEventMultiplexer( rContext.mrEventMultiplexer ),
+ mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
+ maBounds( getAPIShapeBounds( xShape ) )
+ {
+ ENSURE_OR_THROW( mxShape.is(), "ExternalShapeBase::ExternalShapeBase(): Invalid XShape" );
+
+ mpShapeManager->addIntrinsicAnimationHandler( mpListener );
+ mrEventMultiplexer.addViewHandler( mpListener );
+ }
+
+ // ---------------------------------------------------------------------
+
+ ExternalShapeBase::~ExternalShapeBase()
+ {
+ try
+ {
+ mrEventMultiplexer.removeViewHandler( mpListener );
+ mpShapeManager->removeIntrinsicAnimationHandler( mpListener );
+ }
+ catch (uno::Exception &)
+ {
+ OSL_ENSURE( false, rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ uno::Reference< drawing::XShape > ExternalShapeBase::getXShape() const
+ {
+ return mxShape;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ExternalShapeBase::play()
+ {
+ implStartIntrinsicAnimation();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ExternalShapeBase::stop()
+ {
+ implEndIntrinsicAnimation();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ExternalShapeBase::pause()
+ {
+ implPauseIntrinsicAnimation();
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::isPlaying() const
+ {
+ return implIsIntrinsicAnimationPlaying();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ExternalShapeBase::setMediaTime(double fTime)
+ {
+ implSetIntrinsicAnimationTime(fTime);
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::update() const
+ {
+ return render();
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::render() const
+ {
+ if( maBounds.getRange().equalZero() )
+ {
+ // zero-sized shapes are effectively invisible,
+ // thus, we save us the rendering...
+ return true;
+ }
+
+ return implRender( maBounds );
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::isContentChanged() const
+ {
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ ::basegfx::B2DRectangle ExternalShapeBase::getBounds() const
+ {
+ return maBounds;
+ }
+
+ // ---------------------------------------------------------------------
+
+ ::basegfx::B2DRectangle ExternalShapeBase::getDomBounds() const
+ {
+ return maBounds;
+ }
+
+ // ---------------------------------------------------------------------
+
+ ::basegfx::B2DRectangle ExternalShapeBase::getUpdateArea() const
+ {
+ return maBounds;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::isVisible() const
+ {
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ double ExternalShapeBase::getPriority() const
+ {
+ return mnPriority;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ExternalShapeBase::isBackgroundDetached() const
+ {
+ // external shapes always have their own window/surface
+ return true;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/externalshapebase.hxx b/slideshow/source/engine/shapes/externalshapebase.hxx
new file mode 100644
index 000000000000..ecde71bc7b54
--- /dev/null
+++ b/slideshow/source/engine/shapes/externalshapebase.hxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_EXTERNALSHAPEBASE_HXX
+#define INCLUDED_SLIDESHOW_EXTERNALSHAPEBASE_HXX
+
+#include <vector>
+
+#include "externalmediashape.hxx"
+#include "unoview.hxx"
+#include "subsettableshapemanager.hxx"
+#include "slideshowexceptions.hxx"
+#include "slideshowcontext.hxx"
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Base class for shapes rendered by external engines.
+
+ Used as the common base for e.g. MediaShape or
+ AppletShape, all of which are rendered by external
+ components (and all employ distinct windows).
+
+ Please note that this base class indeed assumes the shape
+ does not interfere with the internal shapes in any way
+ (including mutual overdraw). It therefore reports yes for
+ the isBackgroundDetached() question.
+ */
+ class ExternalShapeBase : public ExternalMediaShape
+ {
+ public:
+ /** Create a shape for the given XShape for an external shape
+
+ @param xShape
+ The XShape to represent.
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+ */
+ ExternalShapeBase( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+ virtual ~ExternalShapeBase();
+
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape > getXShape() const;
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ virtual void play();
+ virtual void stop();
+ virtual void pause();
+ virtual bool isPlaying() const;
+ virtual void setMediaTime(double);
+
+ // render methods
+ //------------------------------------------------------------------
+
+ virtual bool update() const;
+ virtual bool render() const;
+ virtual bool isContentChanged() const;
+
+
+ // Shape attributes
+ //------------------------------------------------------------------
+
+ 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;
+
+ protected:
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext> mxComponentContext;
+
+ private:
+ class ExternalShapeBaseListener; friend class ExternalShapeBaseListener;
+
+ /// override in derived class to render preview
+ virtual bool implRender( const ::basegfx::B2DRange& rCurrBounds ) const = 0;
+
+ /// override in derived class to resize
+ virtual void implViewChanged( const UnoViewSharedPtr& rView ) = 0;
+ /// override in derived class to resize
+ virtual void implViewsChanged() = 0;
+
+ /// override in derived class to start external viewer
+ virtual bool implStartIntrinsicAnimation() = 0;
+ /// override in derived class to stop external viewer
+ virtual bool implEndIntrinsicAnimation() = 0;
+ /// override in derived class to pause external viewer
+ virtual bool implPauseIntrinsicAnimation() = 0;
+ /// override in derived class to return status of animation
+ virtual bool implIsIntrinsicAnimationPlaying() const = 0;
+ /// override in derived class to set media time
+ virtual void implSetIntrinsicAnimationTime(double) = 0;
+
+
+ /// The associated XShape
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > mxShape;
+
+ boost::shared_ptr<ExternalShapeBaseListener> mpListener;
+
+ SubsettableShapeManagerSharedPtr mpShapeManager;
+ EventMultiplexer& mrEventMultiplexer;
+
+ // The attributes of this Shape
+ const double mnPriority;
+ ::basegfx::B2DRectangle maBounds;
+ };
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_EXTERNALSHAPEBASE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/gdimtftools.cxx b/slideshow/source/engine/shapes/gdimtftools.cxx
new file mode 100644
index 000000000000..9f3252453e30
--- /dev/null
+++ b/slideshow/source/engine/shapes/gdimtftools.cxx
@@ -0,0 +1,551 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <gdimtftools.hxx>
+
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/XGraphicRenderer.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase1.hxx>
+
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+#include <tools/stream.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/animate.hxx>
+#include <vcl/graph.hxx>
+
+#include <unotools/streamwrap.hxx>
+
+#include "tools.hxx"
+
+using namespace ::com::sun::star;
+
+
+// free support functions
+// ======================
+
+namespace slideshow
+{
+namespace internal
+{
+// TODO(E2): Detect the case when svx/drawing layer is not
+// in-process, or even not on the same machine, and
+// fallback to metafile streaming!
+
+// For fixing #i48102#, have to be a _lot_ more selective
+// on which metafiles to convert to bitmaps. The problem
+// here is that we _always_ get the shape content as a
+// metafile, even if we have a bitmap graphic shape. Thus,
+// calling GetBitmapEx on such a Graphic (see below) will
+// result in one poorly scaled bitmap into another,
+// somewhat arbitrarily sized bitmap.
+bool hasUnsupportedActions( const GDIMetaFile& rMtf )
+{
+ // search metafile for RasterOp action
+ MetaAction* pCurrAct;
+
+ // TODO(Q3): avoid const-cast
+ for( pCurrAct = const_cast<GDIMetaFile&>(rMtf).FirstAction();
+ pCurrAct;
+ pCurrAct = const_cast<GDIMetaFile&>(rMtf).NextAction() )
+ {
+ switch( pCurrAct->GetType() )
+ {
+ case META_RASTEROP_ACTION:
+ // overpaint is okay - that's the default, anyway
+ if( ROP_OVERPAINT ==
+ static_cast<MetaRasterOpAction*>(pCurrAct)->GetRasterOp() )
+ {
+ break;
+ }
+ // FALLTHROUGH intended
+ case META_MOVECLIPREGION_ACTION:
+ // FALLTHROUGH intended
+ case META_REFPOINT_ACTION:
+ // FALLTHROUGH intended
+ case META_WALLPAPER_ACTION:
+ return true; // at least one unsupported
+ // action encountered
+ }
+ }
+
+ return false; // no unsupported action found
+}
+
+namespace {
+
+typedef ::cppu::WeakComponentImplHelper1< graphic::XGraphicRenderer > DummyRenderer_Base;
+
+class DummyRenderer :
+ public DummyRenderer_Base,
+ public cppu::BaseMutex
+{
+public:
+ DummyRenderer() :
+ DummyRenderer_Base( m_aMutex ),
+ mxGraphic()
+ {
+ }
+
+ //--- XGraphicRenderer -----------------------------------
+ virtual void SAL_CALL render( const uno::Reference< graphic::XGraphic >& rGraphic ) throw (uno::RuntimeException)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ mxGraphic = rGraphic;
+ }
+
+ /** Retrieve GDIMetaFile from renderer
+
+ @param bForeignSource
+ When true, the source of the metafile might be a
+ foreign application. The metafile is checked
+ against unsupported content, and, if necessary,
+ returned as a pre-rendererd bitmap.
+ */
+ GDIMetaFile getMtf( bool bForeignSource ) const
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Graphic aGraphic( mxGraphic );
+
+ if( aGraphic.GetType() == GRAPHIC_BITMAP ||
+ (bForeignSource &&
+ hasUnsupportedActions(aGraphic.GetGDIMetaFile()) ) )
+ {
+ // wrap bitmap into GDIMetafile
+ GDIMetaFile aMtf;
+ ::Point aEmptyPoint;
+
+ ::BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
+
+ aMtf.AddAction( new MetaBmpExAction( aEmptyPoint,
+ aBmpEx ) );
+ aMtf.SetPrefSize( aBmpEx.GetPrefSize() );
+ aMtf.SetPrefMapMode( aBmpEx.GetPrefMapMode() );
+
+ return aMtf;
+ }
+ else
+ {
+ return aGraphic.GetGDIMetaFile();
+ }
+ }
+
+private:
+ uno::Reference< graphic::XGraphic > mxGraphic;
+};
+
+} // anon namespace
+
+// Quick'n'dirty way: tunnel Graphic (only works for
+// in-process slideshow, of course)
+bool getMetaFile( const uno::Reference< lang::XComponent >& xSource,
+ const uno::Reference< drawing::XDrawPage >& xContainingPage,
+ GDIMetaFile& rMtf,
+ int mtfLoadFlags,
+ const uno::Reference< uno::XComponentContext >& rxContext )
+{
+ ENSURE_OR_RETURN_FALSE( rxContext.is(),
+ "getMetaFile(): Invalid context" );
+
+ // create dummy XGraphicRenderer, which receives the
+ // generated XGraphic from the GraphicExporter
+
+ // TODO(P3): Move creation of DummyRenderer out of the
+ // loop! Either by making it static, or transforming
+ // the whole thing here into a class.
+ DummyRenderer* pRenderer( new DummyRenderer() );
+ uno::Reference< graphic::XGraphicRenderer > xRenderer( pRenderer );
+
+ // -> stuff that into UnoGraphicExporter.
+ uno::Reference<lang::XMultiComponentFactory> xFactory(
+ rxContext->getServiceManager() );
+
+ OSL_ENSURE( xFactory.is(), "### no UNO?!" );
+ if( !xFactory.is() )
+ return false;
+
+ // creating the graphic exporter
+ uno::Reference< document::XExporter > xExporter(
+ xFactory->createInstanceWithContext(
+ OUSTR("com.sun.star.drawing.GraphicExportFilter"),
+ rxContext),
+ uno::UNO_QUERY );
+ uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY );
+
+ OSL_ENSURE( xExporter.is() && xFilter.is(), "### no graphic exporter?!" );
+ if( !xExporter.is() || !xFilter.is() )
+ return false;
+
+ uno::Sequence< beans::PropertyValue > aProps(3);
+ aProps[0].Name = OUSTR("FilterName");
+ aProps[0].Value <<= OUSTR("SVM");
+
+ aProps[1].Name = OUSTR("GraphicRenderer");
+ aProps[1].Value <<= xRenderer;
+
+ uno::Sequence< beans::PropertyValue > aFilterData(5);
+ aFilterData[0].Name = OUSTR("VerboseComments");
+ aFilterData[0].Value <<= ((mtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0);
+
+ aFilterData[1].Name = OUSTR("ScrollText");
+ aFilterData[1].Value <<= ((mtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != 0);
+
+ aFilterData[2].Name = OUSTR("ExportOnlyBackground");
+ aFilterData[2].Value <<= ((mtfLoadFlags & MTF_LOAD_BACKGROUND_ONLY) != 0);
+
+ aFilterData[3].Name = OUSTR("Version");
+ aFilterData[3].Value <<= static_cast<sal_Int32>( SOFFICE_FILEFORMAT_50 );
+
+ aFilterData[4].Name = OUSTR("CurrentPage");
+ aFilterData[4].Value <<= uno::Reference< uno::XInterface >( xContainingPage,
+ uno::UNO_QUERY_THROW );
+
+ aProps[2].Name = OUSTR("FilterData");
+ aProps[2].Value <<= aFilterData;
+
+ xExporter->setSourceDocument( xSource );
+ if( !xFilter->filter( aProps ) )
+ return false;
+
+ rMtf = pRenderer->getMtf( (mtfLoadFlags & MTF_LOAD_FOREIGN_SOURCE) != 0 );
+
+ // pRenderer is automatically destroyed when xRenderer
+ // goes out of scope
+
+ // TODO(E3): Error handling. Exporter might have
+ // generated nothing, a bitmap, threw an exception,
+ // whatever.
+ return true;
+}
+
+void removeTextActions( GDIMetaFile& rMtf )
+{
+ // search metafile for text output
+ MetaAction* pCurrAct;
+
+ int nActionIndex(0);
+ pCurrAct = rMtf.FirstAction();
+ while( pCurrAct )
+ {
+ switch( pCurrAct->GetType() )
+ {
+ case META_TEXTCOLOR_ACTION:
+ case META_TEXTFILLCOLOR_ACTION:
+ case META_TEXTLINECOLOR_ACTION:
+ case META_TEXTALIGN_ACTION:
+ case META_FONT_ACTION:
+ case META_LAYOUTMODE_ACTION:
+ case META_TEXT_ACTION:
+ case META_TEXTARRAY_ACTION:
+ case META_TEXTRECT_ACTION:
+ case META_STRETCHTEXT_ACTION:
+ case META_TEXTLINE_ACTION:
+ {
+ // remove every text-related actions
+ pCurrAct = rMtf.NextAction();
+
+ rMtf.RemoveAction( nActionIndex );
+ break;
+ }
+
+ default:
+ pCurrAct = rMtf.NextAction();
+ ++nActionIndex;
+ break;
+ }
+ }
+}
+
+sal_Int32 getNextActionOffset( MetaAction * pCurrAct )
+{
+ // Special handling for actions that represent
+ // more than one indexable action
+ // ===========================================
+
+ switch (pCurrAct->GetType()) {
+ case META_TEXT_ACTION: {
+ MetaTextAction * pAct = static_cast<MetaTextAction *>(pCurrAct);
+ return (pAct->GetLen() == (USHORT)STRING_LEN
+ ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
+ }
+ case META_TEXTARRAY_ACTION: {
+ MetaTextArrayAction * pAct =
+ static_cast<MetaTextArrayAction *>(pCurrAct);
+ return (pAct->GetLen() == (USHORT)STRING_LEN
+ ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
+ }
+ case META_STRETCHTEXT_ACTION: {
+ MetaStretchTextAction * pAct =
+ static_cast<MetaStretchTextAction *>(pCurrAct);
+ return (pAct->GetLen() == (USHORT)STRING_LEN
+ ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen());
+ }
+ case META_FLOATTRANSPARENT_ACTION: {
+ MetaFloatTransparentAction * pAct =
+ static_cast<MetaFloatTransparentAction*>(pCurrAct);
+ // TODO(F2): Recurse into action metafile
+ // (though this is currently not used from the
+ // DrawingLayer - shape transparency gradients
+ // don't affect shape text)
+ return pAct->GetGDIMetaFile().GetActionCount();
+ }
+ default:
+ return 1;
+ }
+}
+
+bool getAnimationFromGraphic( VectorOfMtfAnimationFrames& o_rFrames,
+ ::std::size_t& o_rLoopCount,
+ CycleMode& o_eCycleMode,
+ const Graphic& rGraphic )
+{
+ o_rFrames.clear();
+
+ if( !rGraphic.IsAnimated() )
+ return false;
+
+ // some loop invariants
+ Animation aAnimation( rGraphic.GetAnimation() );
+ const Point aEmptyPoint;
+ const Size aAnimSize( aAnimation.GetDisplaySizePixel() );
+
+ // setup VDev, into which all bitmaps are painted (want to
+ // normalize animations to n bitmaps of same size. An Animation,
+ // though, can contain bitmaps of varying sizes and different
+ // update modes)
+ VirtualDevice aVDev;
+ aVDev.SetOutputSizePixel( aAnimSize );
+ aVDev.EnableMapMode( FALSE );
+
+ // setup mask VDev (alpha VDev is currently rather slow)
+ VirtualDevice aVDevMask;
+ aVDevMask.SetOutputSizePixel( aAnimSize );
+ aVDevMask.EnableMapMode( FALSE );
+
+ switch( aAnimation.GetCycleMode() )
+ {
+ case CYCLE_NOT:
+ o_rLoopCount = 1;
+ o_eCycleMode = CYCLE_LOOP;
+ break;
+
+ case CYCLE_FALLBACK:
+ // FALLTHROUGH intended
+ case CYCLE_NORMAL:
+ o_rLoopCount = aAnimation.GetLoopCount();
+ o_eCycleMode = CYCLE_LOOP;
+ break;
+
+ case CYCLE_REVERS:
+ // FALLTHROUGH intended
+ case CYCLE_REVERS_FALLBACK:
+ o_rLoopCount = aAnimation.GetLoopCount();
+ o_eCycleMode = CYCLE_PINGPONGLOOP;
+ break;
+
+ default:
+ ENSURE_OR_RETURN_FALSE(false,
+ "getAnimationFromGraphic(): Unexpected case" );
+ break;
+ }
+
+ for( USHORT i=0, nCount=aAnimation.Count(); i<nCount; ++i )
+ {
+ const AnimationBitmap& rAnimBmp( aAnimation.Get(i) );
+ switch(rAnimBmp.eDisposal)
+ {
+ case DISPOSE_NOT:
+ {
+ aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
+ rAnimBmp.aBmpEx);
+ Bitmap aMask = rAnimBmp.aBmpEx.GetMask();
+
+ if( aMask.IsEmpty() )
+ {
+ const Point aEmpty;
+ const Rectangle aRect(aEmptyPoint,
+ aVDevMask.GetOutputSizePixel());
+ const Wallpaper aWallpaper(COL_BLACK);
+ aVDevMask.DrawWallpaper(aRect,
+ aWallpaper);
+ }
+ else
+ {
+ BitmapEx aTmpMask = BitmapEx(aMask,
+ aMask);
+ aVDevMask.DrawBitmapEx(rAnimBmp.aPosPix,
+ aTmpMask );
+ }
+ break;
+ }
+
+ case DISPOSE_BACK:
+ {
+ // #i70772# react on no mask
+ const Bitmap aMask(rAnimBmp.aBmpEx.GetMask());
+ const Bitmap aContent(rAnimBmp.aBmpEx.GetBitmap());
+
+ aVDevMask.Erase();
+ aVDev.DrawBitmap(rAnimBmp.aPosPix, aContent);
+
+ if(aMask.IsEmpty())
+ {
+ const Rectangle aRect(rAnimBmp.aPosPix, aContent.GetSizePixel());
+ aVDevMask.SetFillColor(COL_BLACK);
+ aVDevMask.SetLineColor();
+ aVDevMask.DrawRect(aRect);
+ }
+ else
+ {
+ aVDevMask.DrawBitmap(rAnimBmp.aPosPix, aMask);
+ }
+ break;
+ }
+
+ case DISPOSE_FULL:
+ {
+ aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
+ rAnimBmp.aBmpEx);
+ break;
+ }
+
+ case DISPOSE_PREVIOUS :
+ {
+ aVDev.DrawBitmapEx(rAnimBmp.aPosPix,
+ rAnimBmp.aBmpEx);
+ aVDevMask.DrawBitmap(rAnimBmp.aPosPix,
+ rAnimBmp.aBmpEx.GetMask());
+ break;
+ }
+ }
+
+ // extract current aVDev content into a new animation
+ // frame
+ GDIMetaFileSharedPtr pMtf( new GDIMetaFile() );
+ pMtf->AddAction(
+ new MetaBmpExAction( aEmptyPoint,
+ BitmapEx(
+ aVDev.GetBitmap(
+ aEmptyPoint,
+ aAnimSize ),
+ aVDevMask.GetBitmap(
+ aEmptyPoint,
+ aAnimSize ))));
+
+ // setup mtf dimensions and pref map mode (for
+ // simplicity, keep it all in pixel. the metafile
+ // renderer scales it down to (1, 1) box anyway)
+ pMtf->SetPrefMapMode( MapMode() );
+ pMtf->SetPrefSize( aAnimSize );
+
+ // #115934#
+ // Take care of special value for MultiPage TIFFs. ATM these shall just
+ // show their first page for _quite_ some time.
+ sal_Int32 nWaitTime100thSeconds( rAnimBmp.nWait );
+ if( ANIMATION_TIMEOUT_ON_CLICK == nWaitTime100thSeconds )
+ {
+ // ATM the huge value would block the timer, so use a long
+ // time to show first page (whole day)
+ nWaitTime100thSeconds = 100 * 60 * 60 * 24;
+ }
+
+ // There are animated GIFs with no WaitTime set. Take 1 sec, then.
+ if( nWaitTime100thSeconds == 0 )
+ nWaitTime100thSeconds = 100;
+
+ o_rFrames.push_back( MtfAnimationFrame( pMtf,
+ nWaitTime100thSeconds / 100.0 ) );
+ }
+
+ return !o_rFrames.empty();
+}
+
+bool getRectanglesFromScrollMtf( ::basegfx::B2DRectangle& o_rScrollRect,
+ ::basegfx::B2DRectangle& o_rPaintRect,
+ const GDIMetaFileSharedPtr& rMtf )
+{
+ // extract bounds: scroll rect, paint rect
+ bool bScrollRectSet(false);
+ bool bPaintRectSet(false);
+
+ for ( MetaAction * pCurrAct = rMtf->FirstAction();
+ pCurrAct != 0; pCurrAct = rMtf->NextAction() )
+ {
+ if (pCurrAct->GetType() == META_COMMENT_ACTION)
+ {
+ MetaCommentAction * pAct =
+ static_cast<MetaCommentAction *>(pCurrAct);
+ // skip comment if not a special XTEXT comment
+ if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ RTL_CONSTASCII_STRINGPARAM("XTEXT") ) == COMPARE_EQUAL)
+ {
+ if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ "XTEXT_SCROLLRECT" ) == COMPARE_EQUAL) {
+ o_rScrollRect = ::vcl::unotools::b2DRectangleFromRectangle(
+ *reinterpret_cast<Rectangle const *>(
+ pAct->GetData() ) );
+
+ bScrollRectSet = true;
+ }
+ else if (pAct->GetComment().CompareIgnoreCaseToAscii(
+ "XTEXT_PAINTRECT" ) == COMPARE_EQUAL) {
+ o_rPaintRect = ::vcl::unotools::b2DRectangleFromRectangle(
+ *reinterpret_cast<Rectangle const *>(
+ pAct->GetData() ) );
+
+ bPaintRectSet = true;
+ }
+ }
+ }
+ }
+
+ return bScrollRectSet && bPaintRectSet;
+}
+
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/gdimtftools.hxx b/slideshow/source/engine/shapes/gdimtftools.hxx
new file mode 100644
index 000000000000..072880739e14
--- /dev/null
+++ b/slideshow/source/engine/shapes/gdimtftools.hxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_GDIMTFTOOLS_HXX
+#define INCLUDED_SLIDESHOW_GDIMTFTOOLS_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <boost/shared_ptr.hpp>
+
+#include "tools.hxx"
+
+#include <vector>
+
+class MetaAction;
+class GDIMetaFile;
+class Graphic;
+
+// -----------------------------------------------------------------------------
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /// meta file loading specialities:
+ enum mtf_load_flags {
+ /// no flags
+ MTF_LOAD_NONE = 0,
+ /// annotate text actions with verbose comments,
+ /// denoting logical and physical text entities.
+ MTF_LOAD_VERBOSE_COMMENTS = 1,
+ /// the source of the metafile might be a foreign
+ /// application. The metafile is checked against unsupported
+ /// content, and, if necessary, returned as a pre-rendererd
+ /// bitmap.
+ MTF_LOAD_FOREIGN_SOURCE = 2,
+ /// retrieve a meta file for the page background only
+ MTF_LOAD_BACKGROUND_ONLY = 4,
+ /// retrieve the drawing layer scroll text metafile
+ MTF_LOAD_SCROLL_TEXT_MTF = 8
+ };
+
+ // Animation info
+ // ==============
+
+ struct MtfAnimationFrame
+ {
+ MtfAnimationFrame( const GDIMetaFileSharedPtr& rMtf,
+ double nDuration ) :
+ mpMtf( rMtf ),
+ mnDuration( nDuration )
+ {
+ }
+
+ /// Enables STL algos to be used for duration extraction
+ double getDuration() const
+ {
+ return mnDuration;
+ }
+
+ GDIMetaFileSharedPtr mpMtf;
+ double mnDuration;
+ };
+
+ typedef ::std::vector< MtfAnimationFrame > VectorOfMtfAnimationFrames;
+
+
+ /** Retrieve a meta file for the given shape
+
+ @param xShape
+ XShape to retrieve a metafile for.
+
+ @param xContainingPage
+ The page that contains this shape. Needed for proper
+ import (currently, the UnoGraphicExporter needs this
+ information).
+
+ @param o_rMtf
+ Metafile to extract shape content into
+ */
+ bool getMetaFile( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xSource,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& xContainingPage,
+ GDIMetaFile& o_rMtf,
+ int mtfLoadFlags,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext >& rxContext );
+
+ /** Remove all text actions from the given metafile.
+ */
+ void removeTextActions( GDIMetaFile& io_rMtf );
+
+ /** Gets the next action offset for iterating meta actions which is most
+ often returns 1.
+ */
+ sal_Int32 getNextActionOffset( MetaAction * pCurrAct );
+
+ /** Extract a vector of animation frames from given Graphic.
+
+ @param o_rFrames
+ Resulting vector of animated metafiles
+
+ @param o_rLoopCount
+ Number of times the bitmap animation shall be repeated
+
+ @param o_eCycleMode
+ Repeat mode (normal, or ping-pong mode)
+
+ @param rGraphic
+ Input graphic object, to extract animations from
+ */
+ bool getAnimationFromGraphic( VectorOfMtfAnimationFrames& o_rFrames,
+ ::std::size_t& o_rLoopCount,
+ CycleMode& o_eCycleMode,
+ const Graphic& rGraphic );
+
+ /** Retrieve scroll text animation rectangles from given metafile
+
+ @return true, if both rectangles have been found, false
+ otherwise.
+ */
+ bool getRectanglesFromScrollMtf( ::basegfx::B2DRectangle& o_rScrollRect,
+ ::basegfx::B2DRectangle& o_rPaintRect,
+ const GDIMetaFileSharedPtr& rMtf );
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_GDIMTFTOOLS_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/intrinsicanimationactivity.cxx b/slideshow/source/engine/shapes/intrinsicanimationactivity.cxx
new file mode 100644
index 000000000000..fb5179545821
--- /dev/null
+++ b/slideshow/source/engine/shapes/intrinsicanimationactivity.cxx
@@ -0,0 +1,293 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include "drawshapesubsetting.hxx"
+#include "subsettableshapemanager.hxx"
+#include "eventqueue.hxx"
+#include "eventmultiplexer.hxx"
+#include "intrinsicanimationactivity.hxx"
+#include "intrinsicanimationeventhandler.hxx"
+
+#include <boost/noncopyable.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/weak_ptr.hpp>
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Activity for intrinsic shape animations
+
+ This is an Activity interface implementation for intrinsic
+ shape animations. Intrinsic shape animations are
+ animations directly within a shape, e.g. drawing layer
+ animations, or GIF animations.
+ */
+ class IntrinsicAnimationActivity : public Activity,
+ public boost::enable_shared_from_this<IntrinsicAnimationActivity>,
+ private boost::noncopyable
+ {
+ public:
+ /** Create an IntrinsicAnimationActivity.
+
+ @param rContext
+ Common slideshow objects
+
+ @param rDrawShape
+ Shape to control the intrinsic animation for
+
+ @param rWakeupEvent
+ Externally generated wakeup event, to set this
+ activity to sleep during inter-frame intervals. Must
+ come frome the outside, since wakeup event and this
+ object have mutual references to each other.
+
+ @param rTimeouts
+ Vector of timeout values, to wait before the next
+ frame is shown.
+ */
+ IntrinsicAnimationActivity( const SlideShowContext& rContext,
+ const DrawShapeSharedPtr& rDrawShape,
+ const WakeupEventSharedPtr& rWakeupEvent,
+ const ::std::vector<double>& rTimeouts,
+ ::std::size_t nNumLoops,
+ CycleMode eCycleMode );
+
+ virtual void dispose();
+ virtual double calcTimeLag() const;
+ virtual bool perform();
+ virtual bool isActive() const;
+ virtual void dequeued();
+ virtual void end();
+
+ bool enableAnimations();
+
+ private:
+ SlideShowContext maContext;
+ boost::weak_ptr<DrawShape> mpDrawShape;
+ WakeupEventSharedPtr mpWakeupEvent;
+ IntrinsicAnimationEventHandlerSharedPtr mpListener;
+ ::std::vector<double> maTimeouts;
+ CycleMode meCycleMode;
+ ::std::size_t mnCurrIndex;
+ ::std::size_t mnNumLoops;
+ ::std::size_t mnLoopCount;
+ bool mbIsActive;
+ };
+
+ //////////////////////////////////////////////////////////////////////
+
+ class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler,
+ private boost::noncopyable
+ {
+ public:
+ explicit IntrinsicAnimationListener( IntrinsicAnimationActivity& rActivity ) :
+ mrActivity( rActivity )
+ {}
+
+ private:
+
+ virtual bool enableAnimations() { return mrActivity.enableAnimations(); }
+ virtual bool disableAnimations() { mrActivity.end(); return true; }
+
+ IntrinsicAnimationActivity& mrActivity;
+ };
+
+ //////////////////////////////////////////////////////////////////////
+
+ IntrinsicAnimationActivity::IntrinsicAnimationActivity( const SlideShowContext& rContext,
+ const DrawShapeSharedPtr& rDrawShape,
+ const WakeupEventSharedPtr& rWakeupEvent,
+ const ::std::vector<double>& rTimeouts,
+ ::std::size_t nNumLoops,
+ CycleMode eCycleMode ) :
+ maContext( rContext ),
+ mpDrawShape( rDrawShape ),
+ mpWakeupEvent( rWakeupEvent ),
+ mpListener( new IntrinsicAnimationListener(*this) ),
+ maTimeouts( rTimeouts ),
+ meCycleMode( eCycleMode ),
+ mnCurrIndex(0),
+ mnNumLoops(nNumLoops),
+ mnLoopCount(0),
+ mbIsActive(false)
+ {
+ ENSURE_OR_THROW( rContext.mpSubsettableShapeManager,
+ "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid shape manager" );
+ ENSURE_OR_THROW( rDrawShape,
+ "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid draw shape" );
+ ENSURE_OR_THROW( rWakeupEvent,
+ "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid wakeup event" );
+ ENSURE_OR_THROW( !rTimeouts.empty(),
+ "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Empty timeout vector" );
+
+ maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler(
+ mpListener );
+ }
+
+ void IntrinsicAnimationActivity::dispose()
+ {
+ end();
+
+ if( mpWakeupEvent )
+ mpWakeupEvent->dispose();
+
+ maContext.dispose();
+ mpDrawShape.reset();
+ mpWakeupEvent.reset();
+ maTimeouts.clear();
+ mnCurrIndex = 0;
+
+ maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler(
+ mpListener );
+ }
+
+ double IntrinsicAnimationActivity::calcTimeLag() const
+ {
+ return 0.0;
+ }
+
+ bool IntrinsicAnimationActivity::perform()
+ {
+ if( !isActive() )
+ return false;
+
+ DrawShapeSharedPtr pDrawShape( mpDrawShape.lock() );
+ if( !pDrawShape || !mpWakeupEvent )
+ {
+ // event or draw shape vanished, no sense living on ->
+ // commit suicide.
+ dispose();
+ return false;
+ }
+
+ // mnNumLoops == 0 means infinite looping
+ if( mnNumLoops != 0 &&
+ mnLoopCount >= mnNumLoops )
+ {
+ // #i55294# After finishing the loops, display the first frame
+ pDrawShape->setIntrinsicAnimationFrame( 0 );
+ maContext.mpSubsettableShapeManager->notifyShapeUpdate( pDrawShape );
+
+ end();
+
+ return false;
+ }
+
+ ::std::size_t nNewIndex = 0;
+ const ::std::size_t nNumFrames(maTimeouts.size());
+ switch( meCycleMode )
+ {
+ case CYCLE_LOOP:
+ {
+ pDrawShape->setIntrinsicAnimationFrame( mnCurrIndex );
+
+ mpWakeupEvent->start();
+ mpWakeupEvent->setNextTimeout( maTimeouts[mnCurrIndex] );
+
+ mnLoopCount += (mnCurrIndex + 1) / nNumFrames;
+ nNewIndex = (mnCurrIndex + 1) % nNumFrames;
+ break;
+ }
+
+ case CYCLE_PINGPONGLOOP:
+ {
+ ::std::size_t nTrueIndex( mnCurrIndex < nNumFrames ?
+ mnCurrIndex :
+ 2*nNumFrames - mnCurrIndex - 1 );
+ pDrawShape->setIntrinsicAnimationFrame( nTrueIndex );
+
+ mpWakeupEvent->start();
+ mpWakeupEvent->setNextTimeout( maTimeouts[nTrueIndex] );
+
+ mnLoopCount += (mnCurrIndex + 1) / (2*nNumFrames);
+ nNewIndex = (mnCurrIndex + 1) % 2*nNumFrames;
+ break;
+ }
+ }
+
+ maContext.mrEventQueue.addEvent( mpWakeupEvent );
+ maContext.mpSubsettableShapeManager->notifyShapeUpdate( pDrawShape );
+ mnCurrIndex = nNewIndex;
+
+ return false; // don't reinsert, WakeupEvent will perform
+ // that after the given timeout
+ }
+
+ bool IntrinsicAnimationActivity::isActive() const
+ {
+ return mbIsActive;
+ }
+
+ void IntrinsicAnimationActivity::dequeued()
+ {
+ // not used here
+ }
+
+ void IntrinsicAnimationActivity::end()
+ {
+ // there is no dedicated end state, just become inactive:
+ mbIsActive = false;
+ }
+
+ bool IntrinsicAnimationActivity::enableAnimations()
+ {
+ mbIsActive = true;
+ return maContext.mrActivitiesQueue.addActivity(
+ shared_from_this() );
+ }
+
+ //////////////////////////////////////////////////////////////////////
+
+ ActivitySharedPtr createIntrinsicAnimationActivity(
+ const SlideShowContext& rContext,
+ const DrawShapeSharedPtr& rDrawShape,
+ const WakeupEventSharedPtr& rWakeupEvent,
+ const ::std::vector<double>& rTimeouts,
+ ::std::size_t nNumLoops,
+ CycleMode eCycleMode )
+ {
+ return ActivitySharedPtr(
+ new IntrinsicAnimationActivity(rContext,
+ rDrawShape,
+ rWakeupEvent,
+ rTimeouts,
+ nNumLoops,
+ eCycleMode) );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/intrinsicanimationactivity.hxx b/slideshow/source/engine/shapes/intrinsicanimationactivity.hxx
new file mode 100644
index 000000000000..a48ae8f1117e
--- /dev/null
+++ b/slideshow/source/engine/shapes/intrinsicanimationactivity.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_INTRINSICANIMATIONACTIVITY_HXX
+#define INCLUDED_SLIDESHOW_INTRINSICANIMATIONACTIVITY_HXX
+
+#include "wakeupevent.hxx"
+#include "activity.hxx"
+#include "slideshowcontext.hxx"
+#include "drawshape.hxx"
+#include "tools.hxx"
+
+/* Definition of IntrinsicAnimationActivity class */
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Create an IntrinsicAnimationActivity.
+
+ This is an Activity interface implementation for intrinsic
+ shape animations. Intrinsic shape animations are
+ animations directly within a shape, e.g. drawing layer
+ animations, or GIF animations.
+
+ @param rContext
+ Common slideshow objects
+
+ @param rDrawShape
+ Shape to control the intrinsic animation for
+
+ @param rWakeupEvent
+ Externally generated wakeup event, to set this
+ activity to sleep during inter-frame intervals. Must
+ come frome the outside, since wakeup event and this
+ object have mutual references to each other.
+
+ @param rTimeouts
+ Vector of timeout values, to wait before the next
+ frame is shown.
+ */
+ ActivitySharedPtr createIntrinsicAnimationActivity(
+ const SlideShowContext& rContext,
+ const DrawShapeSharedPtr& rDrawShape,
+ const WakeupEventSharedPtr& rWakeupEvent,
+ const ::std::vector<double>& rTimeouts,
+ ::std::size_t nNumLoops,
+ CycleMode eCycleMode );
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_INTRINSICANIMATIONACTIVITY_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/makefile.mk b/slideshow/source/engine/shapes/makefile.mk
new file mode 100644
index 000000000000..1d40c165707c
--- /dev/null
+++ b/slideshow/source/engine/shapes/makefile.mk
@@ -0,0 +1,60 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=slideshow
+TARGET=shapes
+ENABLE_EXCEPTIONS=TRUE
+PRJINC=..$/..
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Common ----------------------------------------------------------
+
+SLOFILES = $(SLO)$/appletshape.obj \
+ $(SLO)$/backgroundshape.obj \
+ $(SLO)$/drawinglayeranimation.obj \
+ $(SLO)$/drawshape.obj \
+ $(SLO)$/drawshapesubsetting.obj \
+ $(SLO)$/externalshapebase.obj \
+ $(SLO)$/gdimtftools.obj \
+ $(SLO)$/intrinsicanimationactivity.obj \
+ $(SLO)$/mediashape.obj \
+ $(SLO)$/shapeimporter.obj \
+ $(SLO)$/viewappletshape.obj \
+ $(SLO)$/viewbackgroundshape.obj \
+ $(SLO)$/viewmediashape.obj \
+ $(SLO)$/viewshape.obj
+
+
+# ==========================================================================
+
+.INCLUDE : target.mk
diff --git a/slideshow/source/engine/shapes/mediashape.cxx b/slideshow/source/engine/shapes/mediashape.cxx
new file mode 100644
index 000000000000..9bcf66a030f6
--- /dev/null
+++ b/slideshow/source/engine/shapes/mediashape.cxx
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include "mediashape.hxx"
+#include "viewmediashape.hxx"
+#include "externalshapebase.hxx"
+#include "slideshowcontext.hxx"
+#include "shape.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** Represents a media shape.
+
+ This implementation offers support for media shapes.
+ Such shapes need special treatment.
+ */
+ class MediaShape : public ExternalShapeBase
+ {
+ public:
+ /** Create a shape for the given XShape for a media object
+
+ @param xShape
+ The XShape to represent.
+
+ @param nPrio
+ Externally-determined shape priority (used e.g. for
+ paint ordering). This number _must be_ unique!
+ */
+ MediaShape( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
+
+ private:
+
+ // View layer methods
+ //------------------------------------------------------------------
+
+ virtual void addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer );
+ virtual bool removeViewLayer( const ViewLayerSharedPtr& rNewLayer );
+ virtual bool clearAllViewLayers();
+
+
+ // ExternalShapeBase methods
+ //------------------------------------------------------------------
+
+ virtual bool implRender( const ::basegfx::B2DRange& rCurrBounds ) const;
+ virtual void implViewChanged( const UnoViewSharedPtr& rView );
+ virtual void implViewsChanged();
+ virtual bool implStartIntrinsicAnimation();
+ virtual bool implEndIntrinsicAnimation();
+ virtual bool implPauseIntrinsicAnimation();
+ virtual bool implIsIntrinsicAnimationPlaying() const;
+ virtual void implSetIntrinsicAnimationTime(double);
+
+ /// the list of active view shapes (one for each registered view layer)
+ typedef ::std::vector< ViewMediaShapeSharedPtr > ViewMediaShapeVector;
+ ViewMediaShapeVector maViewMediaShapes;
+ bool mbIsPlaying;
+ };
+
+
+ MediaShape::MediaShape( const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext ) :
+ ExternalShapeBase( xShape, nPrio, rContext ),
+ maViewMediaShapes(),
+ mbIsPlaying(false)
+ {
+ }
+
+ // ---------------------------------------------------------------------
+
+ void MediaShape::implViewChanged( const UnoViewSharedPtr& rView )
+ {
+ // determine ViewMediaShape that needs update
+ ViewMediaShapeVector::const_iterator aIter(maViewMediaShapes.begin());
+ ViewMediaShapeVector::const_iterator const aEnd (maViewMediaShapes.end());
+ while( aIter != aEnd )
+ {
+ if( (*aIter)->getViewLayer()->isOnView(rView) )
+ (*aIter)->resize(getBounds());
+
+ ++aIter;
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ void MediaShape::implViewsChanged()
+ {
+ // resize all ViewShapes
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::bind(
+ &ViewMediaShape::resize,
+ _1,
+ ::boost::cref( getBounds())) );
+ }
+
+ // ---------------------------------------------------------------------
+
+ void MediaShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
+ bool bRedrawLayer )
+ {
+ maViewMediaShapes.push_back(
+ ViewMediaShapeSharedPtr( new ViewMediaShape( rNewLayer,
+ getXShape(),
+ mxComponentContext )));
+
+ // push new size to view shape
+ maViewMediaShapes.back()->resize( getBounds() );
+
+ // render the Shape on the newly added ViewLayer
+ if( bRedrawLayer )
+ maViewMediaShapes.back()->render( getBounds() );
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
+ {
+ const ViewMediaShapeVector::iterator aEnd( maViewMediaShapes.end() );
+
+ OSL_ENSURE( ::std::count_if(maViewMediaShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewMediaShape::getViewLayer, _1 ),
+ ::boost::cref( rLayer ) ) ) < 2,
+ "MediaShape::removeViewLayer(): Duplicate ViewLayer entries!" );
+
+ ViewMediaShapeVector::iterator aIter;
+
+ if( (aIter=::std::remove_if( maViewMediaShapes.begin(),
+ aEnd,
+ ::boost::bind<bool>(
+ ::std::equal_to< ViewLayerSharedPtr >(),
+ ::boost::bind( &ViewMediaShape::getViewLayer,
+ _1 ),
+ ::boost::cref( rLayer ) ) )) == aEnd )
+ {
+ // view layer seemingly was not added, failed
+ return false;
+ }
+
+ // actually erase from container
+ maViewMediaShapes.erase( aIter, aEnd );
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::clearAllViewLayers()
+ {
+ maViewMediaShapes.clear();
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implRender( const ::basegfx::B2DRange& rCurrBounds ) const
+ {
+ // redraw all view shapes, by calling their update() method
+ if( ::std::count_if( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::bind<bool>(
+ ::boost::mem_fn( &ViewMediaShape::render ),
+ _1,
+ ::boost::cref( rCurrBounds ) ) )
+ != static_cast<ViewMediaShapeVector::difference_type>(maViewMediaShapes.size()) )
+ {
+ // at least one of the ViewShape::update() calls did return
+ // false - update failed on at least one ViewLayer
+ return false;
+ }
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implStartIntrinsicAnimation()
+ {
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::mem_fn( &ViewMediaShape::startMedia ) );
+
+ mbIsPlaying = true;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implEndIntrinsicAnimation()
+ {
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::mem_fn( &ViewMediaShape::endMedia ) );
+
+ mbIsPlaying = false;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implPauseIntrinsicAnimation()
+ {
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::mem_fn( &ViewMediaShape::pauseMedia ) );
+
+ mbIsPlaying = false;
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool MediaShape::implIsIntrinsicAnimationPlaying() const
+ {
+ return mbIsPlaying;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void MediaShape::implSetIntrinsicAnimationTime(double fTime)
+ {
+ ::std::for_each( maViewMediaShapes.begin(),
+ maViewMediaShapes.end(),
+ ::boost::bind( &ViewMediaShape::setMediaTime,
+ _1, boost::cref(fTime)) );
+ }
+
+ // ---------------------------------------------------------------------
+
+ ShapeSharedPtr createMediaShape(
+ const uno::Reference< drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext)
+ {
+ boost::shared_ptr< MediaShape > pMediaShape(
+ new MediaShape(xShape, nPrio, rContext));
+
+ return pMediaShape;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/mediashape.hxx b/slideshow/source/engine/shapes/mediashape.hxx
new file mode 100644
index 000000000000..babe30e8b122
--- /dev/null
+++ b/slideshow/source/engine/shapes/mediashape.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_MEDIASHAPE_HXX
+#define INCLUDED_SLIDESHOW_MEDIASHAPE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <boost/shared_ptr.hpp>
+
+
+namespace com { namespace sun { namespace star { namespace drawing
+{
+ class XShape;
+} } } }
+
+namespace slideshow
+{
+ namespace internal
+ {
+ struct SlideShowContext;
+ class Shape;
+
+ boost::shared_ptr<Shape> createMediaShape(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& xShape,
+ double nPrio,
+ const SlideShowContext& rContext);
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_MEDIASHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/shapeimporter.cxx b/slideshow/source/engine/shapes/shapeimporter.cxx
new file mode 100644
index 000000000000..0c8d6cbcf23e
--- /dev/null
+++ b/slideshow/source/engine/shapes/shapeimporter.cxx
@@ -0,0 +1,672 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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;
+using namespace ::comphelper;
+
+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") ))
+ {
+ // 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") ))
+ {
+ // #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") ))
+ {
+ 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<BYTE>(nTransparency) );
+ aGraphAttrs.SetRotation( static_cast<USHORT>(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(RTL_CONSTASCII_USTRINGPARAM("Name"))) );
+ bool const bRet = (a >>= layerName);
+ if(bRet)
+ {
+ if( layerName.equals(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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 ),
+#ifdef ENABLE_PRESENTER_EXTRA_UI
+ mxPagesSupplier( xPagesSupplier ),
+#else
+ mxPagesSupplier( NULL ),
+#endif
+ mrContext( rContext ),
+ maPolygons(),
+ maShapesStack(),
+ mnAscendingPrio( nOrdNumStart ),
+ mbConvertingMasterPage( bConvertingMasterPage )
+{
+#ifndef ENABLE_PRESENTER_EXTRA_UI
+ (void)xPagesSupplier;
+#endif
+ uno::Reference<drawing::XShapes> const xShapes(
+ xPage, uno::UNO_QUERY_THROW );
+ maShapesStack.push( XShapesEntry(xShapes) );
+}
+
+} // namespace internal
+} // namespace presentation
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewappletshape.cxx b/slideshow/source/engine/shapes/viewappletshape.cxx
new file mode 100644
index 000000000000..f22927ddd520
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewappletshape.cxx
@@ -0,0 +1,303 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/verbosetrace.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/debug.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basegfx/tools/canvastools.hxx>
+
+#include <cppcanvas/spritecanvas.hxx>
+#include <canvas/canvastools.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/awt/WindowDescriptor.hpp>
+#include <com/sun/star/awt/XToolkit.hpp>
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <com/sun/star/awt/WindowAttribute.hpp>
+#include <com/sun/star/awt/VclWindowPeerAttribute.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
+
+#include "viewappletshape.hxx"
+#include "tools.hxx"
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ViewAppletShape::ViewAppletShape( const ViewLayerSharedPtr& rViewLayer,
+ const uno::Reference< drawing::XShape >& rxShape,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const uno::Reference< uno::XComponentContext >& rxContext ) :
+ mpViewLayer( rViewLayer ),
+ mxViewer(),
+ mxFrame(),
+ mxComponentContext( rxContext )
+ {
+ ENSURE_OR_THROW( rxShape.is(), "ViewAppletShape::ViewAppletShape(): Invalid Shape" );
+ ENSURE_OR_THROW( mpViewLayer, "ViewAppletShape::ViewAppletShape(): Invalid View" );
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(), "ViewAppletShape::ViewAppletShape(): Invalid ViewLayer canvas" );
+ ENSURE_OR_THROW( mxComponentContext.is(), "ViewAppletShape::ViewAppletShape(): Invalid component context" );
+
+ uno::Reference<lang::XMultiComponentFactory> xFactory(
+ mxComponentContext->getServiceManager(),
+ uno::UNO_QUERY_THROW );
+
+ mxViewer.set( xFactory->createInstanceWithContext( rServiceName,
+ mxComponentContext),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< beans::XPropertySet > xShapePropSet( rxShape,
+ uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > mxViewerPropSet( mxViewer,
+ uno::UNO_QUERY_THROW );
+
+ // copy shape properties to applet viewer
+ ::rtl::OUString aPropName;
+ for( sal_Size i=0; i<nNumPropEntries; ++i )
+ {
+ aPropName = ::rtl::OUString::createFromAscii( pPropCopyTable[i] );
+ mxViewerPropSet->setPropertyValue( aPropName,
+ xShapePropSet->getPropertyValue(
+ aPropName ));
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ ViewAppletShape::~ViewAppletShape()
+ {
+ try
+ {
+ endApplet();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_ENSURE( false, rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ ViewLayerSharedPtr ViewAppletShape::getViewLayer() const
+ {
+ return mpViewLayer;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewAppletShape::startApplet( const ::basegfx::B2DRectangle& rBounds )
+ {
+ ENSURE_OR_RETURN_FALSE( mpViewLayer && mpViewLayer->getCanvas() && mpViewLayer->getCanvas()->getUNOCanvas().is(),
+ "ViewAppletShape::startApplet(): Invalid or disposed view" );
+ try
+ {
+ ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();
+
+ uno::Reference< beans::XPropertySet > xPropSet( pCanvas->getUNOCanvas()->getDevice(),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference< awt::XWindow2 > xParentWindow(
+ xPropSet->getPropertyValue(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Window" ))),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference<lang::XMultiComponentFactory> xFactory(
+ mxComponentContext->getServiceManager() );
+
+ if( xFactory.is() )
+ {
+ // create an awt window to contain the applet
+ // ==========================================
+
+ uno::Reference< awt::XToolkit > xToolkit(
+ xFactory->createInstanceWithContext(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.Toolkit" )),
+ mxComponentContext ),
+ uno::UNO_QUERY_THROW );
+
+ awt::WindowDescriptor aOwnWinDescriptor( awt::WindowClass_SIMPLE,
+ ::rtl::OUString(),
+ uno::Reference< awt::XWindowPeer >(xParentWindow,
+ uno::UNO_QUERY_THROW),
+ 0,
+ awt::Rectangle(),
+ awt::WindowAttribute::SHOW
+ | awt::VclWindowPeerAttribute::CLIPCHILDREN );
+
+ uno::Reference< awt::XWindowPeer > xNewWinPeer(
+ xToolkit->createWindow( aOwnWinDescriptor ));
+ uno::Reference< awt::XWindow > xOwnWindow( xNewWinPeer,
+ uno::UNO_QUERY_THROW );
+
+
+ // create a frame, and load the applet into it
+ // ===========================================
+
+ mxFrame.set(
+ xFactory->createInstanceWithContext(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Frame" )),
+ mxComponentContext ),
+ uno::UNO_QUERY_THROW );
+
+ mxFrame->initialize( xOwnWindow );
+
+ uno::Reference < frame::XSynchronousFrameLoader > xLoader( mxViewer,
+ uno::UNO_QUERY_THROW );
+ xLoader->load( uno::Sequence < beans::PropertyValue >(),
+ mxFrame );
+
+
+ // resize surrounding window and applet to current shape size
+ // ==========================================================
+
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rPixelBounds(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ uno::Reference< awt::XWindow > xSurroundingWindow( mxFrame->getContainerWindow() );
+ if( xSurroundingWindow.is() )
+ xSurroundingWindow->setPosSize( static_cast<sal_Int32>(rPixelBounds.getMinX()),
+ static_cast<sal_Int32>(rPixelBounds.getMinY()),
+ static_cast<sal_Int32>(rPixelBounds.getWidth()),
+ static_cast<sal_Int32>(rPixelBounds.getHeight()),
+ awt::PosSize::POSSIZE );
+
+ uno::Reference< awt::XWindow > xAppletWindow( mxFrame->getComponentWindow() );
+ if( xAppletWindow.is() )
+ xAppletWindow->setPosSize( 0, 0,
+ static_cast<sal_Int32>(rPixelBounds.getWidth()),
+ static_cast<sal_Int32>(rPixelBounds.getHeight()),
+ awt::PosSize::POSSIZE );
+ }
+ }
+ catch (uno::Exception &)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewAppletShape::endApplet()
+ {
+ uno::Reference<util::XCloseable> xCloseable(
+ mxFrame,
+ uno::UNO_QUERY );
+
+ if( xCloseable.is() )
+ {
+ xCloseable->close( sal_True );
+ mxFrame.clear();
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewAppletShape::render( const ::basegfx::B2DRectangle& rBounds ) const
+ {
+ ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();
+
+ if( !pCanvas )
+ return false;
+
+ if( !mxFrame.is() )
+ {
+ // fill the shape background with black
+ fillRect( pCanvas,
+ rBounds,
+ 0xFFFFFFFFU );
+ }
+
+ return true;
+ }
+
+ bool ViewAppletShape::resize( const ::basegfx::B2DRectangle& rBounds ) const
+ {
+ if( !mxFrame.is() )
+ return false;
+
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rPixelBounds(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ uno::Reference< awt::XWindow > xFrameWindow( mxFrame->getContainerWindow() );
+ if( xFrameWindow.is() )
+ xFrameWindow->setPosSize( static_cast<sal_Int32>(rPixelBounds.getMinX()),
+ static_cast<sal_Int32>(rPixelBounds.getMinY()),
+ static_cast<sal_Int32>(rPixelBounds.getWidth()),
+ static_cast<sal_Int32>(rPixelBounds.getHeight()),
+ awt::PosSize::POSSIZE );
+
+ uno::Reference< awt::XWindow > xAppletWindow( mxFrame->getComponentWindow() );
+ if( xAppletWindow.is() )
+ xAppletWindow->setPosSize( 0, 0,
+ static_cast<sal_Int32>(rPixelBounds.getWidth()),
+ static_cast<sal_Int32>(rPixelBounds.getHeight()),
+ awt::PosSize::POSSIZE );
+
+ return true;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewappletshape.hxx b/slideshow/source/engine/shapes/viewappletshape.hxx
new file mode 100644
index 000000000000..29e81c4e2bc5
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewappletshape.hxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_VIEWAPPLETSHAPE_HXX
+#define INCLUDED_SLIDESHOW_VIEWAPPLETSHAPE_HXX
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <com/sun/star/awt/Point.hpp>
+
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "viewlayer.hxx"
+
+namespace com { namespace sun { namespace star {
+namespace frame {
+ class XSynchronousFrameLoader;
+ class XFrame;
+}
+namespace uno {
+ class XComponentContext;
+}
+namespace drawing {
+ class XShape;
+}}}}
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class is the viewable representation of a draw
+ document's applet object, associated to a specific View
+
+ The class is able to render the associated applet on View
+ implementations.
+ */
+ class ViewAppletShape : private boost::noncopyable
+ {
+ public:
+ /** Create a ViewAppletShape for the given View
+
+ @param rViewLayer
+ The associated View object.
+
+ @param rxShape
+ The associated Shape
+
+ @param rServiceName
+ The service name to use, when actually creating the
+ viewer component
+
+ @param pPropCopyTable
+ Table of plain ASCII property names, to copy from
+ xShape to applet.
+
+ @param nNumPropEntries
+ Number of property table entries (in pPropCopyTable)
+ */
+ ViewAppletShape( const ViewLayerSharedPtr& rViewLayer,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& rxShape,
+ const ::rtl::OUString& rServiceName,
+ const char** pPropCopyTable,
+ sal_Size nNumPropEntries,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext >& rxContext );
+
+ /** destroy the object
+ */
+ virtual ~ViewAppletShape();
+
+ /** Query the associated view layer of this shape
+ */
+ ViewLayerSharedPtr getViewLayer() const;
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ /** Notify the ViewShape that an animation starts now
+
+ This method enters animation mode on the associate
+ target view. The shape can be animated in parallel on
+ different views.
+
+ @param rBounds
+ The current applet shape bounds
+
+ @return whether the mode change finished successfully.
+ */
+ bool startApplet( const ::basegfx::B2DRectangle& rBounds );
+
+ /** Notify the ViewShape that it is no longer animated
+
+ This methods ends animation mode on the associate
+ target view
+ */
+ void endApplet();
+
+ // render methods
+ //------------------------------------------------------------------
+
+ /** Render the ViewShape
+
+ This method renders the ViewAppletShape on the associated view.
+
+ @param rBounds
+ The current applet shape bounds
+
+ @return whether the rendering finished successfully.
+ */
+ bool render( const ::basegfx::B2DRectangle& rBounds ) const;
+
+ /** Resize the ViewShape
+
+ This method resizes the ViewAppletShape on the
+ associated view. It does not render.
+
+ @param rBounds
+ The current applet shape bounds
+
+ @return whether the resize finished successfully.
+ */
+ bool resize( const ::basegfx::B2DRectangle& rBounds ) const;
+
+ private:
+
+ ViewLayerSharedPtr mpViewLayer;
+
+ /// the actual viewer component for this applet
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::frame::XSynchronousFrameLoader> mxViewer;
+
+ /// the frame containing the applet
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::frame::XFrame> mxFrame;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext> mxComponentContext;
+ };
+
+ typedef ::boost::shared_ptr< ViewAppletShape > ViewAppletShapeSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_VIEWAPPLETSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewbackgroundshape.cxx b/slideshow/source/engine/shapes/viewbackgroundshape.cxx
new file mode 100644
index 000000000000..e8b0930e1940
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewbackgroundshape.cxx
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include "viewbackgroundshape.hxx"
+#include "tools.hxx"
+
+#include <rtl/logfile.hxx>
+#include <rtl/math.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <cppcanvas/renderer.hxx>
+#include <cppcanvas/bitmap.hxx>
+
+using namespace ::com::sun::star;
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+
+ bool ViewBackgroundShape::prefetch( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewBackgroundShape::prefetch()" );
+ ENSURE_OR_RETURN_FALSE( rMtf,
+ "ViewBackgroundShape::prefetch(): no valid metafile!" );
+
+ const ::basegfx::B2DHomMatrix& rCanvasTransform(
+ mpViewLayer->getTransformation() );
+
+ if( !mxBitmap.is() ||
+ rMtf != mpLastMtf ||
+ rCanvasTransform != maLastTransformation )
+ {
+ // buffered bitmap is invalid, re-create
+
+ // determine transformed page bounds
+ ::basegfx::B2DRectangle aTmpRect;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRect,
+ maBounds,
+ rCanvasTransform );
+
+ // determine pixel size of bitmap (choose it one pixel
+ // larger, as polygon rendering takes one pixel more
+ // to the right and to the bottom)
+ const ::basegfx::B2ISize aBmpSizePixel(
+ ::basegfx::fround( aTmpRect.getRange().getX() + 1),
+ ::basegfx::fround( aTmpRect.getRange().getY() + 1) );
+
+ // create a bitmap of appropriate size
+ ::cppcanvas::BitmapSharedPtr pBitmap(
+ ::cppcanvas::BaseGfxFactory::getInstance().createBitmap(
+ rDestinationCanvas,
+ aBmpSizePixel ) );
+
+ ENSURE_OR_THROW( pBitmap,
+ "ViewBackgroundShape::prefetch(): Cannot create background bitmap" );
+
+ ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas( pBitmap->getBitmapCanvas() );
+
+ ENSURE_OR_THROW( pBitmapCanvas,
+ "ViewBackgroundShape::prefetch(): Cannot create background bitmap canvas" );
+
+ // clear bitmap
+ initSlideBackground( pBitmapCanvas,
+ aBmpSizePixel );
+
+ // apply linear part of destination canvas transformation (linear means in this context:
+ // transformation without any translational components)
+ ::basegfx::B2DHomMatrix aLinearTransform( rCanvasTransform );
+ aLinearTransform.set( 0, 2, 0.0 );
+ aLinearTransform.set( 1, 2, 0.0 );
+ pBitmapCanvas->setTransformation( aLinearTransform );
+
+ const basegfx::B2DHomMatrix aShapeTransform(basegfx::tools::createScaleTranslateB2DHomMatrix(
+ maBounds.getWidth(), maBounds.getHeight(),
+ maBounds.getMinX(), maBounds.getMinY()));
+
+ ::cppcanvas::RendererSharedPtr pRenderer(
+ ::cppcanvas::VCLFactory::getInstance().createRenderer(
+ pBitmapCanvas,
+ *rMtf.get(),
+ ::cppcanvas::Renderer::Parameters() ) );
+
+ ENSURE_OR_RETURN_FALSE( pRenderer,
+ "ViewBackgroundShape::prefetch(): Could not create Renderer" );
+
+ pRenderer->setTransformation( aShapeTransform );
+ pRenderer->draw();
+
+ mxBitmap = pBitmap->getUNOBitmap();
+ }
+
+ mpLastMtf = rMtf;
+ maLastTransformation = rCanvasTransform;
+
+ return mxBitmap.is();
+ }
+
+ ViewBackgroundShape::ViewBackgroundShape( const ViewLayerSharedPtr& rViewLayer,
+ const ::basegfx::B2DRectangle& rShapeBounds ) :
+ mpViewLayer( rViewLayer ),
+ mxBitmap(),
+ mpLastMtf(),
+ maLastTransformation(),
+ maBounds( rShapeBounds )
+ {
+ ENSURE_OR_THROW( mpViewLayer, "ViewBackgroundShape::ViewBackgroundShape(): Invalid View" );
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(), "ViewBackgroundShape::ViewBackgroundShape(): Invalid ViewLayer canvas" );
+ }
+
+ ViewLayerSharedPtr ViewBackgroundShape::getViewLayer() const
+ {
+ return mpViewLayer;
+ }
+
+ bool ViewBackgroundShape::render( const GDIMetaFileSharedPtr& rMtf ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewBackgroundShape::draw()" );
+
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas( mpViewLayer->getCanvas() );
+
+ if( !prefetch( rDestinationCanvas, rMtf ) )
+ return false;
+
+ ENSURE_OR_RETURN_FALSE( mxBitmap.is(),
+ "ViewBackgroundShape::draw(): Invalid background bitmap" );
+
+ ::basegfx::B2DHomMatrix aTransform( mpViewLayer->getTransformation() );
+
+ // invert the linear part of the view transformation
+ // (i.e. the view transformation without translational
+ // components), to be able to leave the canvas
+ // transformation intact (would otherwise destroy possible
+ // clippings, as the clip polygon is relative to the view
+ // coordinate system).
+ aTransform.set(0,2, 0.0 );
+ aTransform.set(1,2, 0.0 );
+ aTransform.invert();
+
+ rendering::RenderState aRenderState;
+ ::canvas::tools::initRenderState( aRenderState );
+
+ ::canvas::tools::setRenderStateTransform( aRenderState, aTransform );
+
+ try
+ {
+ rDestinationCanvas->getUNOCanvas()->drawBitmap( mxBitmap,
+ rDestinationCanvas->getViewState(),
+ aRenderState );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_ENSURE( false,
+ rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewbackgroundshape.hxx b/slideshow/source/engine/shapes/viewbackgroundshape.hxx
new file mode 100644
index 000000000000..da7beb7b03be
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewbackgroundshape.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_VIEWBACKGROUNDSHAPE_HXX
+#define INCLUDED_SLIDESHOW_VIEWBACKGROUNDSHAPE_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/rendering/XBitmap.hpp>
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <cppcanvas/spritecanvas.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+#include "gdimtftools.hxx"
+#include "viewlayer.hxx"
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class is the viewable representation of a draw
+ document's background, associated to a specific View
+
+ The class is able to render the associated background on
+ View implementations.
+ */
+ class ViewBackgroundShape : private boost::noncopyable
+ {
+ public:
+ /** Create a ViewBackgroundShape for the given View
+
+ @param rView
+ The associated View object.
+
+ @param rShapeBounds
+ Bounds of the background shape, in document coordinate
+ system.
+ */
+ ViewBackgroundShape( const ViewLayerSharedPtr& rViewLayer,
+ const ::basegfx::B2DRectangle& rShapeBounds );
+
+ /** Query the associated view layer of this shape
+ */
+ ViewLayerSharedPtr getViewLayer() const;
+
+ bool render( const GDIMetaFileSharedPtr& rMtf ) const;
+
+ private:
+ /** Prefetch bitmap for given canvas
+ */
+ bool prefetch( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf ) const;
+
+ /** The view layer this object is part of.
+ */
+ ViewLayerSharedPtr mpViewLayer;
+
+ /// Generated content bitmap, already with correct output size
+ mutable ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XBitmap > mxBitmap;
+
+ /// The last metafile a render object was generated for
+ mutable GDIMetaFileSharedPtr mpLastMtf;
+
+ /// The canvas, mpRenderer is associated with
+ mutable ::basegfx::B2DHomMatrix maLastTransformation;
+
+ const ::basegfx::B2DRectangle maBounds;
+ };
+
+ typedef ::boost::shared_ptr< ViewBackgroundShape > ViewBackgroundShapeSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_VIEWBACKGROUNDSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewmediashape.cxx b/slideshow/source/engine/shapes/viewmediashape.cxx
new file mode 100644
index 000000000000..e861b789e561
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewmediashape.cxx
@@ -0,0 +1,575 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <canvas/verbosetrace.hxx>
+
+#include <math.h>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <vcl/window.hxx>
+#include <vcl/javachild.hxx>
+#include <vcl/salbtype.hxx>
+#ifdef GSTREAMER
+#include <vcl/sysdata.hxx>
+#endif
+
+#include <basegfx/tools/canvastools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <canvas/canvastools.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <avmedia/mediawindow.hxx>
+
+#include <com/sun/star/media/XManager.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <com/sun/star/media/XPlayerWindow.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/lang/XComponent.hdl>
+
+#include "viewmediashape.hxx"
+#include "mediashape.hxx"
+#include "tools.hxx"
+#include "unoview.hxx"
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+ ViewMediaShape::ViewMediaShape( const ViewLayerSharedPtr& rViewLayer,
+ const uno::Reference< drawing::XShape >& rxShape,
+ const uno::Reference< uno::XComponentContext >& rxContext ) :
+ mpViewLayer( rViewLayer ),
+ mpMediaWindow(),
+ maWindowOffset( 0, 0 ),
+ maBounds(),
+ mxShape( rxShape ),
+ mxPlayer(),
+ mxPlayerWindow(),
+ mxComponentContext( rxContext ),
+ mbIsSoundEnabled(true)
+ {
+ ENSURE_OR_THROW( mxShape.is(), "ViewMediaShape::ViewMediaShape(): Invalid Shape" );
+ ENSURE_OR_THROW( mpViewLayer, "ViewMediaShape::ViewMediaShape(): Invalid View" );
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(), "ViewMediaShape::ViewMediaShape(): Invalid ViewLayer canvas" );
+ ENSURE_OR_THROW( mxComponentContext.is(), "ViewMediaShape::ViewMediaShape(): Invalid component context" );
+
+ UnoViewSharedPtr pUnoView (::boost::dynamic_pointer_cast<UnoView>(rViewLayer));
+ if (pUnoView)
+ {
+ mbIsSoundEnabled = pUnoView->isSoundEnabled();
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ ViewMediaShape::~ViewMediaShape()
+ {
+ try
+ {
+ endMedia();
+ }
+ catch (uno::Exception &)
+ {
+ OSL_ENSURE( false, rtl::OUStringToOString(
+ comphelper::anyToString(
+ cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ ViewLayerSharedPtr ViewMediaShape::getViewLayer() const
+ {
+ return mpViewLayer;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::startMedia()
+ {
+ if( !mxPlayer.is() )
+ implInitialize( maBounds );
+
+ if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
+ mxPlayer->start();
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::endMedia()
+ {
+ // shutdown player window
+ if( mxPlayerWindow.is() )
+ {
+ uno::Reference< lang::XComponent > xComponent( mxPlayerWindow, uno::UNO_QUERY );
+
+ if( xComponent.is() )
+ xComponent->dispose();
+
+ mxPlayerWindow.clear();
+ }
+
+#ifdef GSTREAMER
+ mpMediaWindow = ::std::auto_ptr< SystemChildWindow >();
+#else
+ mpMediaWindow = ::std::auto_ptr< JavaChildWindow >();
+#endif
+
+ // shutdown player
+ if( mxPlayer.is() )
+ {
+ mxPlayer->stop();
+
+ uno::Reference< lang::XComponent > xComponent( mxPlayer, uno::UNO_QUERY );
+
+ if( xComponent.is() )
+ xComponent->dispose();
+
+ mxPlayer.clear();
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::pauseMedia()
+ {
+ if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
+ mxPlayer->stop();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::setMediaTime(double fTime)
+ {
+ if( mxPlayer.is() && ( mxPlayer->getDuration() > 0.0 ) )
+ mxPlayer->setMediaTime(fTime);
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::render( const ::basegfx::B2DRectangle& rBounds ) const
+ {
+ ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();;
+
+ if( !pCanvas )
+ return false;
+
+ if( !mpMediaWindow.get() && !mxPlayerWindow.is() )
+ {
+ // fill the shape background with black
+ fillRect( pCanvas,
+ rBounds,
+ 0x000000FFU );
+ }
+
+ return true;
+ }
+
+ bool ViewMediaShape::resize( const ::basegfx::B2DRectangle& rNewBounds ) const
+ {
+ maBounds = rNewBounds;
+
+ ::cppcanvas::CanvasSharedPtr pCanvas = mpViewLayer->getCanvas();;
+
+ if( !pCanvas )
+ return false;
+
+ if( !mxPlayerWindow.is() )
+ return true;
+
+ uno::Reference< beans::XPropertySet > xPropSet( pCanvas->getUNOCanvas()->getDevice(),
+ uno::UNO_QUERY );
+
+ uno::Reference< awt::XWindow > xParentWindow;
+ if( xPropSet.is() &&
+ getPropertyValue( xParentWindow,
+ xPropSet,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Window" ))) )
+ {
+ const awt::Rectangle aRect( xParentWindow->getPosSize() );
+
+ maWindowOffset.X = aRect.X;
+ maWindowOffset.Y = aRect.Y;
+ }
+
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rNewBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rRangePix(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ mxPlayerWindow->setEnable( !rRangePix.isEmpty() );
+
+ if( rRangePix.isEmpty() )
+ return true;
+
+ const Point aPosPixel( rRangePix.getMinX() + maWindowOffset.X,
+ rRangePix.getMinY() + maWindowOffset.Y );
+ const Size aSizePixel( rRangePix.getMaxX() - rRangePix.getMinX(),
+ rRangePix.getMaxY() - rRangePix.getMinY() );
+
+ if( mpMediaWindow.get() )
+ {
+ mpMediaWindow->SetPosSizePixel( aPosPixel, aSizePixel );
+ mxPlayerWindow->setPosSize( 0, 0,
+ aSizePixel.Width(), aSizePixel.Height(),
+ 0 );
+ }
+ else
+ {
+ mxPlayerWindow->setPosSize( aPosPixel.X(), aPosPixel.Y(),
+ aSizePixel.Width(), aSizePixel.Height(),
+ 0 );
+ }
+
+ return true;
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::implInitialize( const ::basegfx::B2DRectangle& rBounds )
+ {
+ if( !mxPlayer.is() && mxShape.is() )
+ {
+ ENSURE_OR_RETURN_FALSE( mpViewLayer->getCanvas(),
+ "ViewMediaShape::update(): Invalid layer canvas" );
+
+ uno::Reference< rendering::XCanvas > xCanvas( mpViewLayer->getCanvas()->getUNOCanvas() );
+
+ if( xCanvas.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet;
+ ::rtl::OUString aURL;
+
+ try
+ {
+ xPropSet.set( mxShape, uno::UNO_QUERY );
+
+ // create Player
+ if( xPropSet.is() &&
+ ( xPropSet->getPropertyValue(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaURL" ) ) ) >>=aURL ) )
+ {
+ implInitializeMediaPlayer( aURL );
+ }
+
+ // create visible object
+ uno::Sequence< uno::Any > aDeviceParams;
+
+ if( ::canvas::tools::getDeviceInfo( xCanvas, aDeviceParams ).getLength() > 1 )
+ {
+ ::rtl::OUString aImplName;
+
+ aDeviceParams[ 0 ] >>= aImplName;
+
+ if( aImplName.endsWithIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("VCL") ) || aImplName.endsWithIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("Cairo") ) )
+ {
+ implInitializeVCLBasedPlayerWindow( rBounds, aDeviceParams );
+ }
+ else if( aImplName.endsWithIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("DX")) ||
+ aImplName.endsWithIgnoreAsciiCaseAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("DX9")))
+ {
+ implInitializeDXBasedPlayerWindow( rBounds, aDeviceParams );
+ }
+ }
+
+ // set player properties
+ implSetMediaProperties( xPropSet );
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_ENSURE( false,
+ rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ }
+
+ return mxPlayer.is() || mxPlayerWindow.is();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::implSetMediaProperties( const uno::Reference< beans::XPropertySet >& rxProps )
+ {
+ if( mxPlayer.is() )
+ {
+ mxPlayer->setMediaTime( 0.0 );
+
+ if( rxProps.is() )
+ {
+ sal_Bool bLoop( false );
+ getPropertyValue( bLoop,
+ rxProps,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Loop" )));
+ mxPlayer->setPlaybackLoop( bLoop );
+
+ sal_Bool bMute( false );
+ getPropertyValue( bMute,
+ rxProps,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Mute" )));
+ mxPlayer->setMute( bMute || !mbIsSoundEnabled);
+
+ sal_Int16 nVolumeDB(0);
+ getPropertyValue( nVolumeDB,
+ rxProps,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VolumeDB" )));
+ mxPlayer->setVolumeDB( nVolumeDB );
+
+ if( mxPlayerWindow.is() )
+ {
+ media::ZoomLevel eZoom(media::ZoomLevel_FIT_TO_WINDOW);
+ getPropertyValue( eZoom,
+ rxProps,
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Zoom" )));
+ mxPlayerWindow->setZoomLevel( eZoom );
+ }
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ void ViewMediaShape::implInitializeMediaPlayer( const ::rtl::OUString& rMediaURL )
+ {
+ if( !mxPlayer.is() )
+ {
+ try
+ {
+ if( rMediaURL.getLength() )
+ {
+ mxPlayer.set( avmedia::MediaWindow::createPlayer( rMediaURL ),
+ uno::UNO_QUERY );
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( const uno::Exception& )
+ {
+ throw lang::NoSupportException(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "No video support for ") ) + rMediaURL,
+ uno::Reference<uno::XInterface>() );
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::implInitializeVCLBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
+ const uno::Sequence< uno::Any >& rVCLDeviceParams)
+ {
+ OSL_TRACE( "ViewMediaShape::implInitializeVCLBasedPlayerWindow" );
+ if( !mpMediaWindow.get() && !rBounds.isEmpty() )
+ {
+ try
+ {
+ sal_Int64 aVal=0;
+
+ rVCLDeviceParams[ 1 ] >>= aVal;
+
+ Window* pWindow = reinterpret_cast< Window* >( aVal );
+
+ if( pWindow )
+ {
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rRangePix(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ if( !rRangePix.isEmpty() )
+ {
+ uno::Sequence< uno::Any > aArgs( 3 );
+ awt::Rectangle aAWTRect( rRangePix.getMinX(),
+ rRangePix.getMinY(),
+ rRangePix.getMaxX() - rRangePix.getMinX(),
+ rRangePix.getMaxY() - rRangePix.getMinY() );
+
+#ifdef GSTREAMER
+ OSL_TRACE( "created sys child window for viewmediashape" );
+ mpMediaWindow = ::std::auto_ptr< SystemChildWindow >( new SystemChildWindow( pWindow, WB_CLIPCHILDREN ) );
+#else
+ mpMediaWindow = ::std::auto_ptr< JavaChildWindow >( new JavaChildWindow( pWindow, WB_CLIPCHILDREN ) );
+#endif
+ mpMediaWindow->SetBackground( Color( COL_BLACK ) );
+ mpMediaWindow->SetPosSizePixel( Point( aAWTRect.X,
+ aAWTRect.Y ),
+ Size( aAWTRect.Width,
+ aAWTRect.Height ));
+ mpMediaWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP );
+ mpMediaWindow->EnableEraseBackground( FALSE );
+ mpMediaWindow->EnablePaint( FALSE );
+ mpMediaWindow->SetForwardKey( TRUE );
+ mpMediaWindow->SetMouseTransparent( TRUE );
+ mpMediaWindow->Show();
+
+ if( mxPlayer.is() )
+ {
+#ifndef GSTREAMER
+ aArgs[ 0 ] = uno::makeAny(
+ sal::static_int_cast<sal_IntPtr>(
+ mpMediaWindow->getParentWindowHandleForJava()) );
+#else
+ aArgs[ 0 ] = uno::makeAny ( (sal_Int32) 0 );
+#endif
+ aAWTRect.X = aAWTRect.Y = 0;
+ aArgs[ 1 ] = uno::makeAny( aAWTRect );
+#ifdef GSTREAMER
+ const SystemEnvData *pSystemData = mpMediaWindow->GetSystemData();
+ OSL_TRACE( "xwindow id: %ld", pSystemData->aWindow );
+ aArgs[ 2 ] = uno::makeAny( pSystemData->aWindow );
+#endif
+
+ mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
+
+ if( mxPlayerWindow.is() )
+ {
+ mxPlayerWindow->setVisible( true );
+ mxPlayerWindow->setEnable( true );
+ }
+ }
+ }
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_ENSURE( false,
+ rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ return mxPlayerWindow.is();
+ }
+
+ // ---------------------------------------------------------------------
+
+ bool ViewMediaShape::implInitializeDXBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
+ const uno::Sequence< uno::Any >& rDXDeviceParams )
+ {
+ if( !mxPlayerWindow.is() )
+ {
+ try
+ {
+ if( rDXDeviceParams.getLength() == 2 )
+ {
+ sal_Int64 aWNDVal=0;
+
+ rDXDeviceParams[ 1 ] >>= aWNDVal;
+
+ if( aWNDVal )
+ {
+ ::basegfx::B2DRange aTmpRange;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRange,
+ rBounds,
+ mpViewLayer->getTransformation() );
+ const ::basegfx::B2IRange& rRangePix(
+ ::basegfx::unotools::b2ISurroundingRangeFromB2DRange( aTmpRange ));
+
+ if( !rRangePix.isEmpty() )
+ {
+ uno::Sequence< uno::Any > aArgs( 2 );
+ awt::Rectangle aAWTRect( rRangePix.getMinX() + maWindowOffset.X,
+ rRangePix.getMinY() + maWindowOffset.Y,
+ rRangePix.getMaxX() - rRangePix.getMinX(),
+ rRangePix.getMaxY() - rRangePix.getMinY() );
+
+ if( mxPlayer.is() )
+ {
+ aArgs[ 0 ] = uno::makeAny(
+ sal::static_int_cast<sal_Int32>(
+ aWNDVal) );
+ aArgs[ 1 ] = uno::makeAny( aAWTRect );
+
+ mxPlayerWindow.set( mxPlayer->createPlayerWindow( aArgs ) );
+ }
+ }
+ }
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ OSL_ENSURE( false,
+ rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ return mxPlayerWindow.is();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewmediashape.hxx b/slideshow/source/engine/shapes/viewmediashape.hxx
new file mode 100644
index 000000000000..4815f2dc9e6a
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewmediashape.hxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_VIEWMEDIASHAPE_HXX
+#define INCLUDED_SLIDESHOW_VIEWMEDIASHAPE_HXX
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <com/sun/star/awt/Point.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+#include "viewlayer.hxx"
+
+class JavaChildWindow;
+class SystemChildWindow;
+
+namespace com { namespace sun { namespace star { namespace drawing {
+ class XShape;
+}
+namespace media {
+ class XPlayer;
+ class XPlayerWindow;
+}
+namespace uno {
+ class XComponentContext;
+}
+namespace beans{
+ class XPropertySet;
+} } } }
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class is the viewable representation of a draw
+ document's media object, associated to a specific View
+
+ The class is able to render the associated media shape on
+ View implementations.
+ */
+ class ViewMediaShape : private boost::noncopyable
+ {
+ public:
+ /** Create a ViewMediaShape for the given View
+
+ @param rView
+ The associated View object.
+ */
+ ViewMediaShape( const ViewLayerSharedPtr& rViewLayer,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShape >& rxShape,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XComponentContext >& rxContext );
+
+ /** destroy the object
+ */
+ virtual ~ViewMediaShape();
+
+ /** Query the associated view layer of this shape
+ */
+ ViewLayerSharedPtr getViewLayer() const;
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ /** Notify the ViewShape that an animation starts now
+
+ This method enters animation mode on the associate
+ target view. The shape can be animated in parallel on
+ different views.
+
+ @return whether the mode change finished successfully.
+ */
+ bool startMedia();
+
+ /** Notify the ViewShape that it is no longer animated
+
+ This methods ends animation mode on the associate
+ target view
+ */
+ void endMedia();
+
+ /** Notify the ViewShape that it should pause playback
+
+ This methods pauses animation on the associate
+ target view. The content stays visible (for video)
+ */
+ void pauseMedia();
+
+ /** Set current time of media.
+
+ @param fTime
+ Local media time that should now be presented, in seconds.
+ */
+ void setMediaTime(double fTime);
+
+ // render methods
+ //------------------------------------------------------------------
+
+ /** Render the ViewShape
+
+ This method renders the ViewMediaShape on the associated view.
+
+ @param rBounds
+ The current media shape bounds
+
+ @return whether the rendering finished successfully.
+ */
+ bool render( const ::basegfx::B2DRectangle& rBounds ) const;
+
+ /** Resize the ViewShape
+
+ This method updates the ViewMediaShape size on the
+ associated view. It does not render.
+
+ @param rBounds
+ The current media shape bounds
+
+ @return whether the resize finished successfully.
+ */
+ bool resize( const ::basegfx::B2DRectangle& rNewBounds ) const;
+
+ private:
+
+ bool implInitialize( const ::basegfx::B2DRectangle& rBounds );
+ void implSetMediaProperties( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& rxProps );
+ void implInitializeMediaPlayer( const ::rtl::OUString& rMediaURL );
+ bool implInitializeVCLBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rVCLDeviceParams );
+ bool implInitializeDXBasedPlayerWindow( const ::basegfx::B2DRectangle& rBounds,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rDXDeviceParams );
+
+ ViewLayerSharedPtr mpViewLayer;
+#ifdef GSTREAMER
+ ::std::auto_ptr< SystemChildWindow > mpMediaWindow;
+#else
+ ::std::auto_ptr< JavaChildWindow > mpMediaWindow;
+#endif
+ mutable ::com::sun::star::awt::Point maWindowOffset;
+ mutable ::basegfx::B2DRectangle maBounds;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > mxShape;
+ ::com::sun::star::uno::Reference< ::com::sun::star::media::XPlayer > mxPlayer;
+ ::com::sun::star::uno::Reference< ::com::sun::star::media::XPlayerWindow > mxPlayerWindow;
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> mxComponentContext;
+ bool mbIsSoundEnabled;
+ };
+
+ typedef ::boost::shared_ptr< ViewMediaShape > ViewMediaShapeSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_VIEWMEDIASHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewshape.cxx b/slideshow/source/engine/shapes/viewshape.cxx
new file mode 100644
index 000000000000..20b85756f389
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewshape.cxx
@@ -0,0 +1,901 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+// must be first
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <math.h>
+
+#include <rtl/logfile.hxx>
+#include <rtl/math.hxx>
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/rendering/PanoseLetterForm.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/anytostring.hxx>
+
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include <canvas/verbosetrace.hxx>
+#include <canvas/canvastools.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include "viewshape.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+
+
+using namespace ::com::sun::star;
+
+namespace slideshow
+{
+ namespace internal
+ {
+
+ // TODO(F2): Provide sensible setup for mtf-related attributes (fill mode,
+ // char rotation etc.). Do that via mtf argument at this object
+
+ bool ViewShape::prefetch( RendererCacheEntry& io_rCacheEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::prefetch()" );
+ ENSURE_OR_RETURN_FALSE( rMtf,
+ "ViewShape::prefetch(): no valid metafile!" );
+
+ if( rMtf != io_rCacheEntry.mpMtf ||
+ rDestinationCanvas != io_rCacheEntry.getDestinationCanvas() )
+ {
+ // buffered renderer invalid, re-create
+ ::cppcanvas::Renderer::Parameters aParms;
+
+ // rendering attribute override parameter struct. For
+ // every valid attribute, the corresponding struct
+ // member is filled, which in the metafile renderer
+ // forces rendering with the given attribute.
+ if( rAttr )
+ {
+ if( rAttr->isFillColorValid() )
+ {
+ // convert RGBColor to RGBA32 integer. Note
+ // that getIntegerColor() also truncates
+ // out-of-range values appropriately
+ aParms.maFillColor =
+ rAttr->getFillColor().getIntegerColor();
+ }
+ if( rAttr->isLineColorValid() )
+ {
+ // convert RGBColor to RGBA32 integer. Note
+ // that getIntegerColor() also truncates
+ // out-of-range values appropriately
+ aParms.maLineColor =
+ rAttr->getLineColor().getIntegerColor();
+ }
+ if( rAttr->isCharColorValid() )
+ {
+ // convert RGBColor to RGBA32 integer. Note
+ // that getIntegerColor() also truncates
+ // out-of-range values appropriately
+ aParms.maTextColor =
+ rAttr->getCharColor().getIntegerColor();
+ }
+ if( rAttr->isDimColorValid() )
+ {
+ // convert RGBColor to RGBA32 integer. Note
+ // that getIntegerColor() also truncates
+ // out-of-range values appropriately
+
+ // dim color overrides all other colors
+ aParms.maFillColor =
+ aParms.maLineColor =
+ aParms.maTextColor =
+ rAttr->getDimColor().getIntegerColor();
+ }
+ if( rAttr->isFontFamilyValid() )
+ {
+ aParms.maFontName =
+ rAttr->getFontFamily();
+ }
+ if( rAttr->isCharScaleValid() )
+ {
+ ::basegfx::B2DHomMatrix aMatrix;
+
+ // enlarge text by given scale factor. Do that
+ // with the middle of the shape as the center
+ // of scaling.
+ aMatrix.translate( -0.5, -0.5 );
+ aMatrix.scale( rAttr->getCharScale(),
+ rAttr->getCharScale() );
+ aMatrix.translate( 0.5, 0.5 );
+
+ aParms.maTextTransformation = aMatrix;
+ }
+ if( rAttr->isCharWeightValid() )
+ {
+ aParms.maFontWeight =
+ static_cast< sal_Int8 >(
+ ::basegfx::fround(
+ ::std::max( 0.0,
+ ::std::min( 11.0,
+ rAttr->getCharWeight() / 20.0 ) ) ) );
+ }
+ if( rAttr->isCharPostureValid() )
+ {
+ aParms.maFontLetterForm =
+ rAttr->getCharPosture() == awt::FontSlant_NONE ?
+ rendering::PanoseLetterForm::ANYTHING :
+ rendering::PanoseLetterForm::OBLIQUE_CONTACT;
+ }
+ if( rAttr->isUnderlineModeValid() )
+ {
+ aParms.maFontUnderline =
+ rAttr->getUnderlineMode();
+ }
+ }
+
+ io_rCacheEntry.mpRenderer = ::cppcanvas::VCLFactory::getInstance().createRenderer( rDestinationCanvas,
+ *rMtf.get(),
+ aParms );
+
+ io_rCacheEntry.mpMtf = rMtf;
+ io_rCacheEntry.mpDestinationCanvas = rDestinationCanvas;
+
+ // also invalidate alpha compositing bitmap (created
+ // new renderer, which possibly generates different
+ // output). Do NOT invalidate, if we're incidentally
+ // rendering INTO it.
+ if( rDestinationCanvas != io_rCacheEntry.mpLastBitmapCanvas )
+ {
+ io_rCacheEntry.mpLastBitmapCanvas.reset();
+ io_rCacheEntry.mpLastBitmap.reset();
+ }
+ }
+
+ return io_rCacheEntry.mpRenderer;
+ }
+
+ bool ViewShape::draw( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ const ::basegfx::B2DPolyPolygon* pClip,
+ const VectorOfDocTreeNodes& rSubsets ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::draw()" );
+
+ ::cppcanvas::RendererSharedPtr pRenderer(
+ getRenderer( rDestinationCanvas, rMtf, rAttr ) );
+
+ ENSURE_OR_RETURN_FALSE( pRenderer, "ViewShape::draw(): Invalid renderer" );
+
+ pRenderer->setTransformation( rTransform );
+#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
+ rendering::RenderState aRenderState;
+ ::canvas::tools::initRenderState(aRenderState);
+ ::canvas::tools::setRenderStateTransform(aRenderState,
+ rTransform);
+ aRenderState.DeviceColor.realloc(4);
+ aRenderState.DeviceColor[0] = 1.0;
+ aRenderState.DeviceColor[1] = 0.0;
+ aRenderState.DeviceColor[2] = 0.0;
+ aRenderState.DeviceColor[3] = 1.0;
+
+ try
+ {
+ rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(0.0,0.0),
+ geometry::RealPoint2D(1.0,1.0),
+ rDestinationCanvas->getViewState(),
+ aRenderState );
+ rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(1.0,0.0),
+ geometry::RealPoint2D(0.0,1.0),
+ rDestinationCanvas->getViewState(),
+ aRenderState );
+ }
+ catch( uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+#endif
+ if( pClip )
+ pRenderer->setClip( *pClip );
+ else
+ pRenderer->setClip();
+
+ if( rSubsets.empty() )
+ {
+ return pRenderer->draw();
+ }
+ else
+ {
+ // render subsets of whole metafile
+ // --------------------------------
+
+ bool bRet(true);
+ VectorOfDocTreeNodes::const_iterator aIter( rSubsets.begin() );
+ const VectorOfDocTreeNodes::const_iterator aEnd ( rSubsets.end() );
+ while( aIter != aEnd )
+ {
+ if( !pRenderer->drawSubset( aIter->getStartIndex(),
+ aIter->getEndIndex() ) )
+ bRet = false;
+
+ ++aIter;
+ }
+
+ return bRet;
+ }
+ }
+
+ namespace
+ {
+ /// Convert untransformed shape update area to device pixel.
+ ::basegfx::B2DRectangle shapeArea2AreaPixel( const ::basegfx::B2DHomMatrix& rCanvasTransformation,
+ const ::basegfx::B2DRectangle& rUntransformedArea )
+ {
+ // convert area to pixel, and add anti-aliasing border
+
+ // TODO(P1): Should the view transform some
+ // day contain rotation/shear, transforming
+ // the original bounds with the total
+ // transformation might result in smaller
+ // overall bounds.
+
+ ::basegfx::B2DRectangle aBoundsPixel;
+ ::canvas::tools::calcTransformedRectBounds( aBoundsPixel,
+ rUntransformedArea,
+ rCanvasTransformation );
+
+ // add antialiasing border around the shape (AA
+ // touches pixel _outside_ the nominal bound rect)
+ aBoundsPixel.grow( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE );
+
+ return aBoundsPixel;
+ }
+
+ /// Convert shape unit rect to device pixel.
+ ::basegfx::B2DRectangle calcUpdateAreaPixel( const ::basegfx::B2DRectangle& rUnitBounds,
+ const ::basegfx::B2DHomMatrix& rShapeTransformation,
+ const ::basegfx::B2DHomMatrix& rCanvasTransformation,
+ const ShapeAttributeLayerSharedPtr& pAttr )
+ {
+ // calc update area for whole shape (including
+ // character scaling)
+ return shapeArea2AreaPixel( rCanvasTransformation,
+ getShapeUpdateArea( rUnitBounds,
+ rShapeTransformation,
+ pAttr ) );
+ }
+ }
+
+ bool ViewShape::renderSprite( const ViewLayerSharedPtr& rViewLayer,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ::basegfx::B2DRectangle& rOrigBounds,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUnitBounds,
+ int nUpdateFlags,
+ const ShapeAttributeLayerSharedPtr& pAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ double nPrio,
+ bool bIsVisible ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::renderSprite()" );
+
+ // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
+ // in that all the common setup steps here are refactored to Shape (would then
+ // have to be performed only _once_ per Shape paint).
+
+ if( !bIsVisible ||
+ rUnitBounds.isEmpty() ||
+ rOrigBounds.isEmpty() ||
+ rBounds.isEmpty() )
+ {
+ // shape is invisible or has zero size, no need to
+ // update anything.
+ if( mpSprite )
+ mpSprite->hide();
+
+ return true;
+ }
+
+
+ // calc sprite position, size and content transformation
+ // =====================================================
+
+ // the shape transformation for a sprite is always a
+ // simple scale-up to the nominal shape size. Everything
+ // else is handled via the sprite transformation
+ ::basegfx::B2DHomMatrix aNonTranslationalShapeTransformation;
+ aNonTranslationalShapeTransformation.scale( rOrigBounds.getWidth(),
+ rOrigBounds.getHeight() );
+ ::basegfx::B2DHomMatrix aShapeTransformation( aNonTranslationalShapeTransformation );
+ aShapeTransformation.translate( rOrigBounds.getMinX(),
+ rOrigBounds.getMinY() );
+
+ const ::basegfx::B2DHomMatrix& rCanvasTransform(
+ rViewLayer->getSpriteTransformation() );
+
+ // area actually needed for the sprite
+ const ::basegfx::B2DRectangle& rSpriteBoundsPixel(
+ calcUpdateAreaPixel( rUnitBounds,
+ aShapeTransformation,
+ rCanvasTransform,
+ pAttr ) );
+
+ // actual area for the shape (without subsetting, but
+ // including char scaling)
+ const ::basegfx::B2DRectangle& rShapeBoundsPixel(
+ calcUpdateAreaPixel( ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
+ aShapeTransformation,
+ rCanvasTransform,
+ pAttr ) );
+
+ // nominal area for the shape (without subsetting, without
+ // char scaling). NOTE: to cancel the shape translation,
+ // contained in rSpriteBoundsPixel, this is _without_ any
+ // translational component (fixed along with #121921#).
+ ::basegfx::B2DRectangle aLogShapeBounds;
+ const ::basegfx::B2DRectangle& rNominalShapeBoundsPixel(
+ shapeArea2AreaPixel( rCanvasTransform,
+ ::canvas::tools::calcTransformedRectBounds(
+ aLogShapeBounds,
+ ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0),
+ aNonTranslationalShapeTransformation ) ) );
+
+ // create (or resize) sprite with sprite's pixel size, if
+ // not done already
+ const ::basegfx::B2DSize& rSpriteSizePixel(rSpriteBoundsPixel.getRange());
+ if( !mpSprite )
+ {
+ mpSprite.reset(
+ new AnimatedSprite( mpViewLayer,
+ rSpriteSizePixel,
+ nPrio ));
+ }
+ else
+ {
+ // TODO(F2): when the sprite _actually_ gets resized,
+ // content needs a repaint!
+ mpSprite->resize( rSpriteSizePixel );
+ }
+
+ ENSURE_OR_RETURN_FALSE( mpSprite, "ViewShape::renderSprite(): No sprite" );
+
+ VERBOSE_TRACE( "ViewShape::renderSprite(): Rendering sprite 0x%X",
+ mpSprite.get() );
+
+
+ // always show the sprite (might have been hidden before)
+ mpSprite->show();
+
+ // determine center of sprite output position in pixel
+ // (assumption here: all shape transformations have the
+ // shape center as the pivot point). From that, subtract
+ // distance of rSpriteBoundsPixel's left, top edge from
+ // rShapeBoundsPixel's center. This moves the sprite at
+ // the appropriate output position within the virtual
+ // rShapeBoundsPixel area.
+ ::basegfx::B2DPoint aSpritePosPixel( rBounds.getCenter() );
+ aSpritePosPixel *= rCanvasTransform;
+ aSpritePosPixel -= rShapeBoundsPixel.getCenter() - rSpriteBoundsPixel.getMinimum();
+
+ // the difference between rShapeBoundsPixel and
+ // rSpriteBoundsPixel upper, left corner is: the offset we
+ // have to move sprite output to the right, top (to make
+ // the desired subset content visible at all)
+ const ::basegfx::B2DSize& rSpriteCorrectionOffset(
+ rSpriteBoundsPixel.getMinimum() - rNominalShapeBoundsPixel.getMinimum() );
+
+ // offset added top, left for anti-aliasing (otherwise,
+ // shapes fully filling the sprite will have anti-aliased
+ // pixel cut off)
+ const ::basegfx::B2DSize aAAOffset(
+ ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE,
+ ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE );
+
+ // set pixel output offset to sprite: we always leave
+ // ANTIALIASING_EXTRA_SIZE room atop and to the left, and,
+ // what's more, for subsetted shapes, we _have_ to cancel
+ // the effect of the shape renderer outputting the subset
+ // at its absolute position inside the shape, instead of
+ // at the origin.
+ // NOTE: As for now, sprites are always positioned on
+ // integer pixel positions on screen, have to round to
+ // nearest integer here, too (fixed along with #121921#)
+ mpSprite->setPixelOffset(
+ aAAOffset - ::basegfx::B2DSize(
+ ::basegfx::fround( rSpriteCorrectionOffset.getX() ),
+ ::basegfx::fround( rSpriteCorrectionOffset.getY() ) ) );
+
+ // always set sprite position and transformation, since
+ // they do not relate directly to the update flags
+ // (e.g. sprite position changes when sprite size changes)
+ mpSprite->movePixel( aSpritePosPixel );
+ mpSprite->transform( getSpriteTransformation( rSpriteSizePixel,
+ rOrigBounds.getRange(),
+ pAttr ) );
+
+
+ // process flags
+ // =============
+
+ bool bRedrawRequired( mbForceUpdate || (nUpdateFlags & FORCE) );
+
+ if( mbForceUpdate || (nUpdateFlags & ALPHA) )
+ {
+ mpSprite->setAlpha( (pAttr && pAttr->isAlphaValid()) ?
+ ::basegfx::clamp(pAttr->getAlpha(),
+ 0.0,
+ 1.0) :
+ 1.0 );
+ }
+ if( mbForceUpdate || (nUpdateFlags & CLIP) )
+ {
+ if( pAttr && pAttr->isClipValid() )
+ {
+ ::basegfx::B2DPolyPolygon aClipPoly( pAttr->getClip() );
+
+ // extract linear part of canvas view transformation
+ // (linear means: without translational components)
+ ::basegfx::B2DHomMatrix aViewTransform(
+ mpViewLayer->getTransformation() );
+ aViewTransform.set( 0, 2, 0.0 );
+ aViewTransform.set( 1, 2, 0.0 );
+
+ // make the clip 2*ANTIALIASING_EXTRA_SIZE larger
+ // such that it's again centered over the sprite.
+ aViewTransform.scale(rSpriteSizePixel.getX()/
+ (rSpriteSizePixel.getX()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE),
+ rSpriteSizePixel.getY()/
+ (rSpriteSizePixel.getY()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE));
+
+ // transform clip polygon from view to device
+ // coordinate space
+ aClipPoly.transform( aViewTransform );
+
+ mpSprite->clip( aClipPoly );
+ }
+ else
+ mpSprite->clip();
+ }
+ if( mbForceUpdate || (nUpdateFlags & CONTENT) )
+ {
+ bRedrawRequired = true;
+
+ // TODO(P1): maybe provide some appearance change methods at
+ // the Renderer interface
+
+ // force the renderer to be regenerated below, for the
+ // different attributes to take effect
+ invalidateRenderer();
+ }
+
+ mbForceUpdate = false;
+
+ if( !bRedrawRequired )
+ return true;
+
+
+ // sprite needs repaint - output to sprite canvas
+ // ==============================================
+
+ ::cppcanvas::CanvasSharedPtr pContentCanvas( mpSprite->getContentCanvas() );
+
+ return draw( pContentCanvas,
+ rMtf,
+ pAttr,
+ aShapeTransformation,
+ NULL, // clipping is done via Sprite::clip()
+ rSubsets );
+ }
+
+ bool ViewShape::render( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUpdateBounds,
+ int nUpdateFlags,
+ const ShapeAttributeLayerSharedPtr& pAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ bool bIsVisible ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::render()" );
+
+ // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape,
+ // in that all the common setup steps here are refactored to Shape (would then
+ // have to be performed only _once_ per Shape paint).
+
+ if( !bIsVisible )
+ {
+ VERBOSE_TRACE( "ViewShape::render(): skipping shape %X", this );
+
+ // shape is invisible, no need to update anything.
+ return true;
+ }
+
+ // since we have no sprite here, _any_ update request
+ // translates into a required redraw.
+ bool bRedrawRequired( mbForceUpdate || nUpdateFlags != 0 );
+
+ if( (nUpdateFlags & CONTENT) )
+ {
+ // TODO(P1): maybe provide some appearance change methods at
+ // the Renderer interface
+
+ // force the renderer to be regenerated below, for the
+ // different attributes to take effect
+ invalidateRenderer();
+ }
+
+ mbForceUpdate = false;
+
+ if( !bRedrawRequired )
+ return true;
+
+ VERBOSE_TRACE( "ViewShape::render(): rendering shape %X at position (%f,%f)",
+ this,
+ rBounds.getMinX(),
+ rBounds.getMinY() );
+
+
+ // shape needs repaint - setup all that's needed
+ // ---------------------------------------------
+
+ boost::optional<basegfx::B2DPolyPolygon> aClip;
+
+ if( pAttr )
+ {
+ // setup clip poly
+ if( pAttr->isClipValid() )
+ aClip.reset( pAttr->getClip() );
+
+ // emulate global shape alpha by first rendering into
+ // a temp bitmap, and then to screen (this would have
+ // been much easier if we'd be currently a sprite -
+ // see above)
+ if( pAttr->isAlphaValid() )
+ {
+ const double nAlpha( pAttr->getAlpha() );
+
+ if( !::basegfx::fTools::equalZero( nAlpha ) &&
+ !::rtl::math::approxEqual(nAlpha, 1.0) )
+ {
+ // render with global alpha - have to prepare
+ // a bitmap, and render that with modulated
+ // alpha
+ // -------------------------------------------
+
+ const ::basegfx::B2DHomMatrix aTransform(
+ getShapeTransformation( rBounds,
+ pAttr ) );
+
+ // TODO(P1): Should the view transform some
+ // day contain rotation/shear, transforming
+ // the original bounds with the total
+ // transformation might result in smaller
+ // overall bounds.
+
+ // determine output rect of _shape update
+ // area_ in device pixel
+ const ::basegfx::B2DHomMatrix aCanvasTransform(
+ rDestinationCanvas->getTransformation() );
+ ::basegfx::B2DRectangle aTmpRect;
+ ::canvas::tools::calcTransformedRectBounds( aTmpRect,
+ rUpdateBounds,
+ aCanvasTransform );
+
+ // pixel size of cache bitmap: round up to
+ // nearest int
+ const ::basegfx::B2ISize aBmpSize( static_cast<sal_Int32>( aTmpRect.getWidth() )+1,
+ static_cast<sal_Int32>( aTmpRect.getHeight() )+1 );
+
+ // try to fetch temporary surface for alpha
+ // compositing (to achieve the global alpha
+ // blend effect, have to first render shape as
+ // a whole, then blit that surface with global
+ // alpha to the destination)
+ const RendererCacheVector::iterator aCompositingSurface(
+ getCacheEntry( rDestinationCanvas ) );
+
+ if( !aCompositingSurface->mpLastBitmapCanvas ||
+ aCompositingSurface->mpLastBitmapCanvas->getSize() != aBmpSize )
+ {
+ // create a bitmap of appropriate size
+ ::cppcanvas::BitmapSharedPtr pBitmap(
+ ::cppcanvas::BaseGfxFactory::getInstance().createAlphaBitmap(
+ rDestinationCanvas,
+ aBmpSize ) );
+
+ ENSURE_OR_THROW(pBitmap,
+ "ViewShape::render(): Could not create compositing surface");
+
+ aCompositingSurface->mpDestinationCanvas = rDestinationCanvas;
+ aCompositingSurface->mpLastBitmap = pBitmap;
+ aCompositingSurface->mpLastBitmapCanvas = pBitmap->getBitmapCanvas();
+ }
+
+ // buffer aCompositingSurface iterator content
+ // - said one might get invalidated during
+ // draw() below.
+ ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas(
+ aCompositingSurface->mpLastBitmapCanvas );
+
+ ::cppcanvas::BitmapSharedPtr pBitmap(
+ aCompositingSurface->mpLastBitmap);
+
+ // setup bitmap canvas transformation -
+ // which happens to be the destination
+ // canvas transformation without any
+ // translational components.
+ //
+ // But then, the render transformation as
+ // calculated by getShapeTransformation()
+ // above outputs the shape at its real
+ // destination position. Thus, we have to
+ // offset the output back to the origin,
+ // for which we simply plug in the
+ // negative position of the left, top edge
+ // of the shape's bound rect in device
+ // pixel into aLinearTransform below.
+ ::basegfx::B2DHomMatrix aAdjustedCanvasTransform( aCanvasTransform );
+ aAdjustedCanvasTransform.translate( -aTmpRect.getMinX(),
+ -aTmpRect.getMinY() );
+
+ pBitmapCanvas->setTransformation( aAdjustedCanvasTransform );
+
+ // TODO(P2): If no update flags, or only
+ // alpha_update is set, we can save us the
+ // rendering into the bitmap (uh, it's not
+ // _that_ easy - for a forced redraw,
+ // e.g. when ending an animation, we always
+ // get UPDATE_FORCE here).
+
+ // render into this bitmap
+ if( !draw( pBitmapCanvas,
+ rMtf,
+ pAttr,
+ aTransform,
+ !aClip ? NULL : &(*aClip),
+ rSubsets ) )
+ {
+ return false;
+ }
+
+ // render bitmap to screen, with given global
+ // alpha. Since the bitmap already contains
+ // pixel-equivalent output, we have to use the
+ // inverse view transformation, adjusted with
+ // the final shape output position (note:
+ // cannot simply change the view
+ // transformation here, as that would affect a
+ // possibly set clip!)
+ ::basegfx::B2DHomMatrix aBitmapTransform( aCanvasTransform );
+ OSL_ENSURE( aBitmapTransform.isInvertible(),
+ "ViewShape::render(): View transformation is singular!" );
+
+ aBitmapTransform.invert();
+
+ const basegfx::B2DHomMatrix aTranslation(basegfx::tools::createTranslateB2DHomMatrix(
+ aTmpRect.getMinX(), aTmpRect.getMinY()));
+
+ aBitmapTransform = aBitmapTransform * aTranslation;
+ pBitmap->setTransformation( aBitmapTransform );
+
+ // finally, render bitmap alpha-modulated
+ pBitmap->drawAlphaModulated( nAlpha );
+
+ return true;
+ }
+ }
+ }
+
+ // retrieve shape transformation, _with_ shape translation
+ // to actual page position.
+ const ::basegfx::B2DHomMatrix aTransform(
+ getShapeTransformation( rBounds,
+ pAttr ) );
+
+ return draw( rDestinationCanvas,
+ rMtf,
+ pAttr,
+ aTransform,
+ !aClip ? NULL : &(*aClip),
+ rSubsets );
+ }
+
+
+ // -------------------------------------------------------------------------------------
+
+ ViewShape::ViewShape( const ViewLayerSharedPtr& rViewLayer ) :
+ mpViewLayer( rViewLayer ),
+ maRenderers(),
+ mpSprite(),
+ mbAnimationMode( false ),
+ mbForceUpdate( true )
+ {
+ ENSURE_OR_THROW( mpViewLayer, "ViewShape::ViewShape(): Invalid View" );
+ }
+
+ ViewLayerSharedPtr ViewShape::getViewLayer() const
+ {
+ return mpViewLayer;
+ }
+
+ ViewShape::RendererCacheVector::iterator ViewShape::getCacheEntry( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas ) const
+ {
+ // lookup destination canvas - is there already a renderer
+ // created for that target?
+ RendererCacheVector::iterator aIter;
+ const RendererCacheVector::iterator aEnd( maRenderers.end() );
+
+ // already there?
+ if( (aIter=::std::find_if( maRenderers.begin(),
+ aEnd,
+ ::boost::bind(
+ ::std::equal_to< ::cppcanvas::CanvasSharedPtr >(),
+ ::boost::cref( rDestinationCanvas ),
+ ::boost::bind(
+ &RendererCacheEntry::getDestinationCanvas,
+ _1 ) ) ) ) == aEnd )
+ {
+ if( maRenderers.size() >= MAX_RENDER_CACHE_ENTRIES )
+ {
+ // cache size exceeded - prune entries. For now,
+ // simply remove the first one, which of course
+ // breaks for more complex access schemes. But in
+ // general, this leads to most recently used
+ // entries to reside at the end of the vector.
+ maRenderers.erase( maRenderers.begin() );
+
+ // ATTENTION: after this, both aIter and aEnd are
+ // invalid!
+ }
+
+ // not yet in cache - add default-constructed cache
+ // entry, to have something to return
+ maRenderers.push_back( RendererCacheEntry() );
+ aIter = maRenderers.end()-1;
+ }
+
+ return aIter;
+ }
+
+ ::cppcanvas::RendererSharedPtr ViewShape::getRenderer( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr ) const
+ {
+ // lookup destination canvas - is there already a renderer
+ // created for that target?
+ const RendererCacheVector::iterator aIter(
+ getCacheEntry( rDestinationCanvas ) );
+
+ // now we have a valid entry, either way. call prefetch()
+ // on it, nevertheless - maybe the metafile changed, and
+ // the renderer still needs an update (prefetch() will
+ // detect that)
+ if( prefetch( *aIter,
+ rDestinationCanvas,
+ rMtf,
+ rAttr ) )
+ {
+ return aIter->mpRenderer;
+ }
+ else
+ {
+ // prefetch failed - renderer is invalid
+ return ::cppcanvas::RendererSharedPtr();
+ }
+ }
+
+ void ViewShape::invalidateRenderer() const
+ {
+ // simply clear the cache. Subsequent getRenderer() calls
+ // will regenerate the Renderers.
+ maRenderers.clear();
+ }
+
+ ::basegfx::B2DSize ViewShape::getAntialiasingBorder() const
+ {
+ ENSURE_OR_THROW( mpViewLayer->getCanvas(),
+ "ViewShape::getAntialiasingBorder(): Invalid ViewLayer canvas" );
+
+ const ::basegfx::B2DHomMatrix& rViewTransform(
+ mpViewLayer->getTransformation() );
+
+ // TODO(F1): As a quick shortcut (did not want to invert
+ // whole matrix here), taking only scale components of
+ // view transformation matrix. This will be wrong when
+ // e.g. shearing is involved.
+ const double nXBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE / rViewTransform.get(0,0) );
+ const double nYBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE / rViewTransform.get(1,1) );
+
+ return ::basegfx::B2DSize( nXBorder,
+ nYBorder );
+ }
+
+ bool ViewShape::enterAnimationMode()
+ {
+ mbForceUpdate = true;
+ mbAnimationMode = true;
+
+ return true;
+ }
+
+ void ViewShape::leaveAnimationMode()
+ {
+ mpSprite.reset();
+ mbAnimationMode = false;
+ mbForceUpdate = true;
+ }
+
+ bool ViewShape::update( const GDIMetaFileSharedPtr& rMtf,
+ const RenderArgs& rArgs,
+ int nUpdateFlags,
+ bool bIsVisible ) const
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::update()" );
+ ENSURE_OR_RETURN_FALSE( mpViewLayer->getCanvas(), "ViewShape::update(): Invalid layer canvas" );
+
+ // Shall we render to a sprite, or to a plain canvas?
+ if( isBackgroundDetached() )
+ return renderSprite( mpViewLayer,
+ rMtf,
+ rArgs.maOrigBounds,
+ rArgs.maBounds,
+ rArgs.maUnitBounds,
+ nUpdateFlags,
+ rArgs.mrAttr,
+ rArgs.mrSubsets,
+ rArgs.mnShapePriority,
+ bIsVisible );
+ else
+ return render( mpViewLayer->getCanvas(),
+ rMtf,
+ rArgs.maBounds,
+ rArgs.maUpdateBounds,
+ nUpdateFlags,
+ rArgs.mrAttr,
+ rArgs.mrSubsets,
+ bIsVisible );
+ }
+
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/slideshow/source/engine/shapes/viewshape.hxx b/slideshow/source/engine/shapes/viewshape.hxx
new file mode 100644
index 000000000000..2ab97a27ca98
--- /dev/null
+++ b/slideshow/source/engine/shapes/viewshape.hxx
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SLIDESHOW_VIEWSHAPE_HXX
+#define INCLUDED_SLIDESHOW_VIEWSHAPE_HXX
+
+#include <cppcanvas/renderer.hxx>
+#include <cppcanvas/bitmap.hxx>
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+#include "tools.hxx"
+#include "shapeattributelayer.hxx"
+#include "animatedsprite.hxx"
+#include "viewlayer.hxx"
+#include "doctreenode.hxx"
+
+#include <vector>
+
+
+namespace slideshow
+{
+ namespace internal
+ {
+ /** This class is the viewable representation of a draw
+ document's XShape, associated to a specific View
+
+ The class is able to render the associated XShape on
+ View implementations.
+ */
+ class ViewShape : private boost::noncopyable
+ {
+ public:
+ /** Create a ViewShape for the given View
+
+ @param rView
+ The associated View object.
+ */
+ explicit ViewShape( const ViewLayerSharedPtr& rViewLayer );
+
+ /** Query the associated view layer of this shape
+ */
+ ViewLayerSharedPtr getViewLayer() const;
+
+ /** Query dimension of a safety border around the shape for AA
+
+ If the view performs antialiasing, this method
+ calculates a safety border around the shape, in the
+ shape coordinate system, which is guaranteed to
+ include every pixel touched when rendering the shape.
+ */
+ ::basegfx::B2DSize getAntialiasingBorder() const;
+
+
+ // animation methods
+ //------------------------------------------------------------------
+
+ /** Notify the ViewShape that an animation starts now
+
+ This method enters animation mode on the associate
+ target view. The shape can be animated in parallel on
+ different views.
+
+ @return whether the mode change finished successfully.
+ */
+ bool enterAnimationMode();
+
+ /** Notify the ViewShape that it is no longer animated
+
+ This methods ends animation mode on the associate
+ target view
+ */
+ void leaveAnimationMode();
+
+ /** Query whether the ViewShape is currently animated
+
+ This method checks whether the ViewShape is currently in
+ animation mode.
+ */
+ bool isBackgroundDetached() const { return mbAnimationMode; }
+
+
+ // render methods
+ //------------------------------------------------------------------
+
+ enum UpdateFlags
+ {
+ NONE= 0,
+ TRANSFORMATION= 1,
+ CLIP= 2,
+ ALPHA= 4,
+ POSITION= 8,
+ CONTENT= 16,
+ FORCE= 32
+ };
+
+ struct RenderArgs
+ {
+ /** Create render argument struct
+
+ @param rOrigBounds
+ The initial shape bounds
+
+ @param rUpdateBounds
+ The area covered by the shape
+
+ @param rBounds
+ The current shape bounds
+
+ @param rAttr
+ The current shape attribute set. Can be NULL, for
+ default attributes. Attention: stored as a reference,
+ thus, parameter object must stay valid!
+
+ @param rSubsets
+ Vector of subset rendering ranges. Attention:
+ stored as a reference, thus, parameter object must
+ stay valid!
+
+ @param nPrio
+ Shape priority
+ */
+ RenderArgs( const ::basegfx::B2DRectangle& rOrigBounds,
+ const ::basegfx::B2DRectangle& rUpdateBounds,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUnitBounds,
+ const ShapeAttributeLayerSharedPtr& rAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ double nPrio ) :
+ maOrigBounds( rOrigBounds ),
+ maUpdateBounds( rUpdateBounds ),
+ maBounds( rBounds ),
+ maUnitBounds( rUnitBounds ),
+ mrAttr( rAttr ),
+ mrSubsets( rSubsets ),
+ mnShapePriority( nPrio )
+ {
+ }
+
+ const ::basegfx::B2DRectangle maOrigBounds;
+ const ::basegfx::B2DRectangle maUpdateBounds;
+ const ::basegfx::B2DRectangle maBounds;
+ const ::basegfx::B2DRectangle maUnitBounds;
+ const ShapeAttributeLayerSharedPtr& mrAttr;
+ const VectorOfDocTreeNodes& mrSubsets;
+ const double mnShapePriority;
+ };
+
+ /** Update the ViewShape
+
+ This method updates the ViewShape on the associated
+ view. If the shape is currently animated, the render
+ target is the sprite, otherwise the view's
+ canvas. This method does not render anything, if the
+ update flags are 0.
+
+ @param rMtf
+ The metafile representation of the shape
+
+ @param rArgs
+ Parameter structure, containing all necessary arguments
+
+ @param nUpdateFlags
+ Bitmask of things to update. Use FORCE to force a repaint.
+
+ @param bIsVisible
+ When false, the shape is fully invisible (and possibly
+ don't need to be painted)
+
+ @return whether the rendering finished successfully.
+ */
+ bool update( const GDIMetaFileSharedPtr& rMtf,
+ const RenderArgs& rArgs,
+ int nUpdateFlags,
+ bool bIsVisible ) const;
+
+ /** Retrieve renderer for given canvas and metafile.
+
+ If necessary, the renderer is created or updated for
+ the metafile and attribute layer.
+
+ @return a renderer that renders to the given
+ destination canvas
+ */
+ ::cppcanvas::RendererSharedPtr getRenderer( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr ) const;
+
+
+ private:
+ struct RendererCacheEntry
+ {
+ RendererCacheEntry() :
+ mpDestinationCanvas(),
+ mpRenderer(),
+ mpMtf(),
+ mpLastBitmap(),
+ mpLastBitmapCanvas()
+ {
+ }
+
+ ::cppcanvas::CanvasSharedPtr getDestinationCanvas()
+ {
+ return mpDestinationCanvas;
+ }
+
+ ::cppcanvas::CanvasSharedPtr mpDestinationCanvas;
+ ::cppcanvas::RendererSharedPtr mpRenderer;
+ GDIMetaFileSharedPtr mpMtf;
+ ::cppcanvas::BitmapSharedPtr mpLastBitmap;
+ ::cppcanvas::BitmapCanvasSharedPtr mpLastBitmapCanvas;
+ };
+
+ typedef ::std::vector< RendererCacheEntry > RendererCacheVector;
+
+
+ /** Prefetch Renderer for given canvas
+ */
+ bool prefetch( RendererCacheEntry& io_rCacheEntry,
+ const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr ) const;
+
+ /** Draw with prefetched Renderer to stored canvas
+
+ This method draws prefetched Renderer to its
+ associated canvas (which happens to be mpLastCanvas).
+ */
+ bool draw( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ShapeAttributeLayerSharedPtr& rAttr,
+ const ::basegfx::B2DHomMatrix& rTransform,
+ const ::basegfx::B2DPolyPolygon* pClip,
+ const VectorOfDocTreeNodes& rSubsets ) const;
+
+ /** Render shape to an active sprite
+ */
+ bool renderSprite( const ViewLayerSharedPtr& rViewLayer,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ::basegfx::B2DRectangle& rOrigBounds,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUnitBounds,
+ int nUpdateFlags,
+ const ShapeAttributeLayerSharedPtr& pAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ double nPrio,
+ bool bIsVisible ) const;
+
+ /** Render shape to given canvas
+ */
+ bool render( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
+ const GDIMetaFileSharedPtr& rMtf,
+ const ::basegfx::B2DRectangle& rBounds,
+ const ::basegfx::B2DRectangle& rUpdateBounds,
+ int nUpdateFlags,
+ const ShapeAttributeLayerSharedPtr& pAttr,
+ const VectorOfDocTreeNodes& rSubsets,
+ bool bIsVisible ) const;
+
+ /** Calc sprite size in pixel
+
+ Converts user coordinate system to device pixel, and
+ adds antialiasing border.
+
+ @param rUserSize
+ Size of the sprite in user coordinate system (doc coordinates)
+ */
+ ::basegfx::B2DSize calcSpriteSizePixel( const ::basegfx::B2DSize& rUserSize ) const;
+
+ enum{ MAX_RENDER_CACHE_ENTRIES=2 };
+
+ /** Retrieve a valid iterator to renderer cache entry
+
+ This method ensures that an internal limit of
+ MAX_RENDER_CACHE_ENTRIES is not exceeded.
+
+ @param rDestinationCanvas
+ Destination canvas to retrieve cache entry for
+
+ @return a valid iterator to a renderer cache entry for
+ the given canvas. The entry might be
+ default-constructed (if newly added)
+ */
+ RendererCacheVector::iterator getCacheEntry( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas ) const;
+
+ void invalidateRenderer() const;
+
+ /** The view layer this object is part of.
+
+ Needed for sprite creation
+ */
+ ViewLayerSharedPtr mpViewLayer;
+
+ /// A set of cached mtf/canvas combinations
+ mutable RendererCacheVector maRenderers;
+
+ /// The sprite object
+ mutable AnimatedSpriteSharedPtr mpSprite;
+
+ /// If true, render() calls go to the sprite
+ mutable bool mbAnimationMode;
+
+ /// If true, shape needs full repaint (and the sprite a setup, if any)
+ mutable bool mbForceUpdate;
+ };
+
+ typedef ::boost::shared_ptr< ViewShape > ViewShapeSharedPtr;
+
+ }
+}
+
+#endif /* INCLUDED_SLIDESHOW_VIEWSHAPE_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */