summaryrefslogtreecommitdiffstats
path: root/slideshow/source/engine/slide/layer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'slideshow/source/engine/slide/layer.cxx')
-rw-r--r--slideshow/source/engine/slide/layer.cxx272
1 files changed, 272 insertions, 0 deletions
diff --git a/slideshow/source/engine/slide/layer.cxx b/slideshow/source/engine/slide/layer.cxx
new file mode 100644
index 000000000..01ce4efa4
--- /dev/null
+++ b/slideshow/source/engine/slide/layer.cxx
@@ -0,0 +1,272 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b1drange.hxx>
+#include <basegfx/range/b2dpolyrange.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <osl/diagnose.h>
+
+#include "layer.hxx"
+
+using namespace ::com::sun::star;
+
+namespace slideshow::internal
+{
+ Layer::Layer( Dummy ) :
+ maViewEntries(),
+ maBounds(),
+ maNewBounds(),
+ mbBoundsDirty(false),
+ mbBackgroundLayer(true),
+ mbClipSet(false)
+ {
+ }
+
+ Layer::Layer() :
+ maViewEntries(),
+ maBounds(),
+ maNewBounds(),
+ mbBoundsDirty(false),
+ mbBackgroundLayer(false),
+ mbClipSet(false)
+ {
+ }
+
+ ViewLayerSharedPtr Layer::addView( const ViewSharedPtr& rNewView )
+ {
+ OSL_ASSERT( rNewView );
+
+ ViewEntryVector::iterator aIter;
+ const ViewEntryVector::iterator aEnd( maViewEntries.end() );
+ if( (aIter=std::find_if( maViewEntries.begin(),
+ aEnd,
+ [&rNewView]( const ViewEntry& rViewEntry )
+ { return rViewEntry.getView() == rNewView; } ) ) != aEnd )
+ {
+ // already added - just return existing layer
+ return aIter->mpViewLayer;
+
+ }
+
+ // not yet added - create new view layer
+ ViewLayerSharedPtr pNewLayer;
+ if( mbBackgroundLayer )
+ pNewLayer = rNewView;
+ else
+ pNewLayer = rNewView->createViewLayer(maBounds);
+
+ // add to local list
+ maViewEntries.emplace_back( rNewView,
+ pNewLayer );
+
+ return maViewEntries.back().mpViewLayer;
+ }
+
+ ViewLayerSharedPtr Layer::removeView( const ViewSharedPtr& rView )
+ {
+ OSL_ASSERT( rView );
+
+ ViewEntryVector::iterator aIter;
+ const ViewEntryVector::iterator aEnd( maViewEntries.end() );
+ if( (aIter=std::find_if( maViewEntries.begin(),
+ aEnd,
+ [&rView]( const ViewEntry& rViewEntry )
+ { return rViewEntry.getView() == rView; } ) ) == aEnd )
+ {
+ // View was not added/is already removed
+ return ViewLayerSharedPtr();
+ }
+
+ OSL_ENSURE( std::count_if( maViewEntries.begin(),
+ aEnd,
+ [&rView]( const ViewEntry& rViewEntry )
+ { return rViewEntry.getView() == rView; } ) == 1,
+ "Layer::removeView(): view added multiple times" );
+
+ ViewLayerSharedPtr pRet( aIter->mpViewLayer );
+ maViewEntries.erase(aIter);
+
+ return pRet;
+ }
+
+ void Layer::setShapeViews( ShapeSharedPtr const& rShape ) const
+ {
+ rShape->clearAllViewLayers();
+
+ for( const auto& rViewEntry : maViewEntries )
+ rShape->addViewLayer( rViewEntry.getViewLayer(), false );
+ }
+
+ void Layer::setPriority( const ::basegfx::B1DRange& rPrioRange )
+ {
+ if( !mbBackgroundLayer )
+ {
+ for( const auto& rViewEntry : maViewEntries )
+ rViewEntry.getViewLayer()->setPriority( rPrioRange );
+ }
+ }
+
+ void Layer::addUpdateRange( ::basegfx::B2DRange const& rUpdateRange )
+ {
+ // TODO(Q1): move this to B2DMultiRange
+ if( !rUpdateRange.isEmpty() )
+ maUpdateAreas.appendElement( rUpdateRange,
+ basegfx::B2VectorOrientation::Positive );
+ }
+
+ void Layer::updateBounds( ShapeSharedPtr const& rShape )
+ {
+ if( !mbBackgroundLayer )
+ {
+ if( !mbBoundsDirty )
+ maNewBounds.reset();
+
+ maNewBounds.expand( rShape->getUpdateArea() );
+ }
+
+ mbBoundsDirty = true;
+ }
+
+ bool Layer::commitBounds()
+ {
+ mbBoundsDirty = false;
+
+ if( mbBackgroundLayer )
+ return false;
+
+ if( maNewBounds == maBounds )
+ return false;
+
+ maBounds = maNewBounds;
+ if( std::count_if( maViewEntries.begin(),
+ maViewEntries.end(),
+ [this]( const ViewEntry& rViewEntry )
+ { return rViewEntry.getViewLayer()->resize( this->maBounds ); }
+ ) == 0 )
+ {
+ return false;
+ }
+
+ // layer content invalid, update areas have wrong
+ // coordinates/not sensible anymore.
+ clearUpdateRanges();
+
+ return true;
+ }
+
+ void Layer::clearUpdateRanges()
+ {
+ maUpdateAreas.clear();
+ }
+
+ void Layer::clearContent()
+ {
+ // clear content on all view layers
+ for( const auto& rViewEntry : maViewEntries )
+ rViewEntry.getViewLayer()->clearAll();
+
+ // layer content cleared, update areas are not sensible
+ // anymore.
+ clearUpdateRanges();
+ }
+
+ class LayerEndUpdate
+ {
+ public:
+ LayerEndUpdate( const LayerEndUpdate& ) = delete;
+ LayerEndUpdate& operator=( const LayerEndUpdate& ) = delete;
+ explicit LayerEndUpdate( LayerSharedPtr const& rLayer ) :
+ mpLayer( rLayer )
+ {}
+
+ ~LayerEndUpdate() { if(mpLayer) mpLayer->endUpdate(); }
+
+ private:
+ LayerSharedPtr mpLayer;
+ };
+
+ Layer::EndUpdater Layer::beginUpdate()
+ {
+ if( maUpdateAreas.count() )
+ {
+ // perform proper layer update. That means, setup proper
+ // clipping, and render each shape that intersects with
+ // the calculated update area
+ ::basegfx::B2DPolyPolygon aClip( maUpdateAreas.solveCrossovers() );
+ aClip = ::basegfx::utils::stripNeutralPolygons(aClip);
+ aClip = ::basegfx::utils::stripDispensablePolygons(aClip);
+
+ // actually, if there happen to be shapes with zero
+ // update area in the maUpdateAreas vector, the
+ // resulting clip polygon will be empty.
+ if( aClip.count() )
+ {
+ for( const auto& rViewEntry : maViewEntries )
+ {
+ const ViewLayerSharedPtr& pViewLayer = rViewEntry.getViewLayer();
+
+ // set clip to all view layers and
+ pViewLayer->setClip( aClip );
+
+ // clear update area on all view layers
+ pViewLayer->clear();
+ }
+
+ mbClipSet = true;
+ }
+ }
+
+ return std::make_shared<LayerEndUpdate>(shared_from_this());
+ }
+
+ void Layer::endUpdate()
+ {
+ if( mbClipSet )
+ {
+ mbClipSet = false;
+
+ basegfx::B2DPolyPolygon aEmptyClip;
+ for( const auto& rViewEntry : maViewEntries )
+ rViewEntry.getViewLayer()->setClip( aEmptyClip );
+ }
+
+ clearUpdateRanges();
+ }
+
+ bool Layer::isInsideUpdateArea( ShapeSharedPtr const& rShape ) const
+ {
+ return maUpdateAreas.overlaps( rShape->getUpdateArea() );
+ }
+
+ LayerSharedPtr Layer::createBackgroundLayer()
+ {
+ return LayerSharedPtr(new Layer( BackgroundLayer ));
+ }
+
+ LayerSharedPtr Layer::createLayer( )
+ {
+ return LayerSharedPtr( new Layer );
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */