1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_slideshow.hxx" 30 31 // must be first 32 #include <canvas/debug.hxx> 33 34 #include <basegfx/range/b2drange.hxx> 35 #include <basegfx/range/b1drange.hxx> 36 #include <basegfx/range/b2dpolyrange.hxx> 37 #include <basegfx/matrix/b2dhommatrix.hxx> 38 #include <basegfx/polygon/b2dpolypolygon.hxx> 39 #include <basegfx/polygon/b2dpolypolygontools.hxx> 40 #include <basegfx/polygon/b2dpolypolygoncutter.hxx> 41 42 #include "layer.hxx" 43 44 #include <boost/bind.hpp> 45 46 47 using namespace ::com::sun::star; 48 49 namespace slideshow 50 { 51 namespace internal 52 { 53 Layer::Layer( const basegfx::B2DRange& rMaxLayerBounds, 54 Dummy ) : 55 maViewEntries(), 56 maBounds(), 57 maNewBounds(), 58 maMaxBounds( rMaxLayerBounds ), 59 mbBoundsDirty(false), 60 mbBackgroundLayer(true), 61 mbClipSet(false) 62 { 63 } 64 65 Layer::Layer( const basegfx::B2DRange& rMaxLayerBounds ) : 66 maViewEntries(), 67 maBounds(), 68 maNewBounds(), 69 maMaxBounds( rMaxLayerBounds ), 70 mbBoundsDirty(false), 71 mbBackgroundLayer(false), 72 mbClipSet(false) 73 { 74 } 75 76 ViewLayerSharedPtr Layer::addView( const ViewSharedPtr& rNewView ) 77 { 78 OSL_ASSERT( rNewView ); 79 80 ViewEntryVector::iterator aIter; 81 const ViewEntryVector::iterator aEnd( maViewEntries.end() ); 82 if( (aIter=std::find_if( maViewEntries.begin(), 83 aEnd, 84 boost::bind<bool>( 85 std::equal_to< ViewSharedPtr >(), 86 boost::bind( &ViewEntry::getView, _1 ), 87 boost::cref( rNewView )))) != aEnd ) 88 { 89 // already added - just return existing layer 90 return aIter->mpViewLayer; 91 92 } 93 94 // not yet added - create new view layer 95 ViewLayerSharedPtr pNewLayer; 96 if( mbBackgroundLayer ) 97 pNewLayer = rNewView; 98 else 99 pNewLayer = rNewView->createViewLayer(maBounds); 100 101 // add to local list 102 maViewEntries.push_back( 103 ViewEntry( rNewView, 104 pNewLayer )); 105 106 return maViewEntries.back().mpViewLayer; 107 } 108 109 ViewLayerSharedPtr Layer::removeView( const ViewSharedPtr& rView ) 110 { 111 OSL_ASSERT( rView ); 112 113 ViewEntryVector::iterator aIter; 114 const ViewEntryVector::iterator aEnd( maViewEntries.end() ); 115 if( (aIter=std::find_if( maViewEntries.begin(), 116 aEnd, 117 boost::bind<bool>( 118 std::equal_to< ViewSharedPtr >(), 119 boost::bind( &ViewEntry::getView, _1 ), 120 boost::cref( rView )))) == aEnd ) 121 { 122 // View was not added/is already removed 123 return ViewLayerSharedPtr(); 124 } 125 126 OSL_ENSURE( std::count_if( maViewEntries.begin(), 127 aEnd, 128 boost::bind<bool>( 129 std::equal_to< ViewSharedPtr >(), 130 boost::bind( &ViewEntry::getView, _1 ), 131 boost::cref( rView ))) == 1, 132 "Layer::removeView(): view added multiple times" ); 133 134 ViewLayerSharedPtr pRet( aIter->mpViewLayer ); 135 maViewEntries.erase(aIter); 136 137 return pRet; 138 } 139 140 void Layer::viewChanged( const ViewSharedPtr& rChangedView ) 141 { 142 ViewEntryVector::iterator aIter; 143 const ViewEntryVector::iterator aEnd( maViewEntries.end() ); 144 if( (aIter=std::find_if( maViewEntries.begin(), 145 aEnd, 146 boost::bind<bool>( 147 std::equal_to< ViewSharedPtr >(), 148 boost::bind( &ViewEntry::getView, _1 ), 149 boost::cref( rChangedView )))) != 150 aEnd ) 151 { 152 // adapt size of given ViewLayer - background layer 153 // resizes with view. 154 if( !mbBackgroundLayer ) 155 aIter->mpViewLayer->resize(maBounds); 156 } 157 } 158 159 void Layer::viewsChanged() 160 { 161 // adapt size of given ViewLayer - background layer 162 // resizes with view. 163 if( !mbBackgroundLayer ) 164 { 165 std::for_each( maViewEntries.begin(), 166 maViewEntries.end(), 167 boost::bind( &ViewLayer::resize, 168 boost::bind( &ViewEntry::getViewLayer, 169 _1 ), 170 boost::cref(maBounds))); 171 } 172 } 173 174 void Layer::setShapeViews( ShapeSharedPtr const& rShape ) const 175 { 176 rShape->clearAllViewLayers(); 177 178 std::for_each( maViewEntries.begin(), 179 maViewEntries.end(), 180 boost::bind(&Shape::addViewLayer, 181 boost::cref(rShape), 182 boost::bind(&ViewEntry::getViewLayer, 183 _1), 184 false )); 185 } 186 187 void Layer::setPriority( const ::basegfx::B1DRange& rPrioRange ) 188 { 189 if( !mbBackgroundLayer ) 190 { 191 std::for_each( maViewEntries.begin(), 192 maViewEntries.end(), 193 boost::bind( &ViewLayer::setPriority, 194 boost::bind( &ViewEntry::getViewLayer, 195 _1 ), 196 boost::cref(rPrioRange))); 197 } 198 } 199 200 void Layer::addUpdateRange( ::basegfx::B2DRange const& rUpdateRange ) 201 { 202 // TODO(Q1): move this to B2DMultiRange 203 if( !rUpdateRange.isEmpty() ) 204 maUpdateAreas.appendElement( rUpdateRange, 205 basegfx::ORIENTATION_POSITIVE ); 206 } 207 208 void Layer::updateBounds( ShapeSharedPtr const& rShape ) 209 { 210 if( !mbBackgroundLayer ) 211 { 212 if( !mbBoundsDirty ) 213 maNewBounds.reset(); 214 215 maNewBounds.expand( rShape->getUpdateArea() ); 216 } 217 218 mbBoundsDirty = true; 219 } 220 221 bool Layer::commitBounds() 222 { 223 mbBoundsDirty = false; 224 225 if( mbBackgroundLayer ) 226 return false; 227 228 if( maNewBounds == maBounds ) 229 return false; 230 231 maBounds = maNewBounds; 232 if( std::count_if( maViewEntries.begin(), 233 maViewEntries.end(), 234 boost::bind( &ViewLayer::resize, 235 boost::bind( &ViewEntry::getViewLayer, 236 _1 ), 237 boost::cref(maBounds)) ) == 0 ) 238 { 239 return false; 240 } 241 242 // layer content invalid, update areas have wrong 243 // coordinates/not sensible anymore. 244 clearUpdateRanges(); 245 246 return true; 247 } 248 249 void Layer::clearUpdateRanges() 250 { 251 maUpdateAreas.clear(); 252 } 253 254 void Layer::clearContent() 255 { 256 // clear content on all view layers 257 std::for_each( maViewEntries.begin(), 258 maViewEntries.end(), 259 boost::bind( 260 &ViewLayer::clear, 261 boost::bind( 262 &ViewEntry::getViewLayer, 263 _1))); 264 265 // layer content cleared, update areas are not sensible 266 // anymore. 267 clearUpdateRanges(); 268 } 269 270 class LayerEndUpdate : private boost::noncopyable 271 { 272 public: 273 LayerEndUpdate( LayerSharedPtr const& rLayer ) : 274 mpLayer( rLayer ) 275 {} 276 277 ~LayerEndUpdate() { if(mpLayer) mpLayer->endUpdate(); } 278 279 void dismiss() { mpLayer.reset(); } 280 281 private: 282 LayerSharedPtr mpLayer; 283 }; 284 285 Layer::EndUpdater Layer::beginUpdate() 286 { 287 if( maUpdateAreas.count() ) 288 { 289 // perform proper layer update. That means, setup proper 290 // clipping, and render each shape that intersects with 291 // the calculated update area 292 ::basegfx::B2DPolyPolygon aClip( maUpdateAreas.solveCrossovers() ); 293 aClip = ::basegfx::tools::stripNeutralPolygons(aClip); 294 aClip = ::basegfx::tools::stripDispensablePolygons(aClip, false); 295 296 // actually, if there happen to be shapes with zero 297 // update area in the maUpdateAreas vector, the 298 // resulting clip polygon will be empty. 299 if( aClip.count() ) 300 { 301 // set clip to all view layers 302 std::for_each( maViewEntries.begin(), 303 maViewEntries.end(), 304 boost::bind( 305 &ViewLayer::setClip, 306 boost::bind( 307 &ViewEntry::getViewLayer, 308 _1), 309 boost::cref(aClip))); 310 311 // clear update area on all view layers 312 std::for_each( maViewEntries.begin(), 313 maViewEntries.end(), 314 boost::bind( 315 &ViewLayer::clear, 316 boost::bind( 317 &ViewEntry::getViewLayer, 318 _1))); 319 320 mbClipSet = true; 321 } 322 } 323 324 return EndUpdater(new LayerEndUpdate(shared_from_this())); 325 } 326 327 void Layer::endUpdate() 328 { 329 if( mbClipSet ) 330 { 331 mbClipSet = false; 332 333 basegfx::B2DPolyPolygon aEmptyClip; 334 std::for_each( maViewEntries.begin(), 335 maViewEntries.end(), 336 boost::bind( 337 &ViewLayer::setClip, 338 boost::bind( 339 &ViewEntry::getViewLayer, 340 _1), 341 boost::cref(aEmptyClip))); 342 } 343 344 clearUpdateRanges(); 345 } 346 347 bool Layer::isInsideUpdateArea( ShapeSharedPtr const& rShape ) const 348 { 349 return maUpdateAreas.overlaps( rShape->getUpdateArea() ); 350 } 351 352 LayerSharedPtr Layer::createBackgroundLayer( const basegfx::B2DRange& rMaxLayerBounds ) 353 { 354 return LayerSharedPtr(new Layer( rMaxLayerBounds, 355 BackgroundLayer )); 356 } 357 358 LayerSharedPtr Layer::createLayer( const basegfx::B2DRange& rMaxLayerBounds ) 359 { 360 return LayerSharedPtr( new Layer( rMaxLayerBounds ) ); 361 } 362 363 } 364 } 365