Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : :
20 : :
21 : : #include <canvas/debug.hxx>
22 : : #include <tools/diagnose_ex.h>
23 : : #include <basegfx/range/b1drange.hxx>
24 : : #include <basegfx/matrix/b2dhommatrix.hxx>
25 : :
26 : : #include <comphelper/anytostring.hxx>
27 : : #include <cppuhelper/exc_hlp.hxx>
28 : :
29 : : #include <boost/bind.hpp>
30 : : #include <algorithm>
31 : :
32 : : #include <o3tl/compat_functional.hxx>
33 : :
34 : : #include "layermanager.hxx"
35 : :
36 : : using namespace ::com::sun::star;
37 : :
38 : : namespace boost
39 : : {
40 : : // add operator!= for weak_ptr
41 : 0 : inline bool operator!=( slideshow::internal::LayerWeakPtr const& rLHS,
42 : : slideshow::internal::LayerWeakPtr const& rRHS )
43 : : {
44 : 0 : return (rLHS<rRHS) || (rRHS<rLHS);
45 : : }
46 : : }
47 : :
48 : : namespace slideshow
49 : : {
50 : : namespace internal
51 : : {
52 : : template<typename LayerFunc,
53 : 0 : typename ShapeFunc> void LayerManager::manageViews(
54 : : LayerFunc layerFunc,
55 : : ShapeFunc shapeFunc )
56 : : {
57 : 0 : LayerSharedPtr pCurrLayer;
58 : 0 : ViewLayerSharedPtr pCurrViewLayer;
59 : 0 : LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
60 : 0 : const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
61 : 0 : while( aIter != aEnd )
62 : : {
63 : 0 : LayerSharedPtr pLayer = aIter->second.lock();
64 : 0 : if( pLayer && pLayer != pCurrLayer )
65 : : {
66 : 0 : pCurrLayer = pLayer;
67 : 0 : pCurrViewLayer = layerFunc(pCurrLayer);
68 : : }
69 : :
70 : 0 : if( pCurrViewLayer )
71 : 0 : shapeFunc(aIter->first,pCurrViewLayer);
72 : :
73 : 0 : ++aIter;
74 : : }
75 : 0 : }
76 : :
77 : 0 : LayerManager::LayerManager( const UnoViewContainer& rViews,
78 : : const ::basegfx::B2DRange& rPageBounds,
79 : : bool bDisableAnimationZOrder ) :
80 : : mrViews(rViews),
81 : : maLayers(),
82 : : maXShapeHash( 101 ),
83 : : maAllShapes(),
84 : : maUpdateShapes(),
85 : : maPageBounds( rPageBounds ),
86 : : mnActiveSprites(0),
87 : : mbLayerAssociationDirty(false),
88 : : mbActive(false),
89 : 0 : mbDisableAnimationZOrder(bDisableAnimationZOrder)
90 : : {
91 : : // prevent frequent resizes (won't have more than 4 layers
92 : : // for 99.9% of the cases)
93 : 0 : maLayers.reserve(4);
94 : :
95 : : // create initial background layer
96 : : maLayers.push_back(
97 : : Layer::createBackgroundLayer(
98 : 0 : maPageBounds ));
99 : :
100 : : // init views
101 : : std::for_each( mrViews.begin(),
102 : : mrViews.end(),
103 : : ::boost::bind(&LayerManager::viewAdded,
104 : : this,
105 : 0 : _1) );
106 : 0 : }
107 : :
108 : 0 : void LayerManager::activate( bool bSlideBackgoundPainted )
109 : : {
110 : 0 : mbActive = true;
111 : 0 : maUpdateShapes.clear(); // update gets forced via area, or
112 : : // has happend outside already
113 : :
114 : 0 : if( !bSlideBackgoundPainted )
115 : : {
116 : : std::for_each(mrViews.begin(),
117 : : mrViews.end(),
118 : 0 : boost::mem_fn(&View::clearAll));
119 : :
120 : : // force update of whole slide area
121 : : std::for_each( maLayers.begin(),
122 : : maLayers.end(),
123 : : boost::bind( &Layer::addUpdateRange,
124 : : _1,
125 : 0 : boost::cref(maPageBounds) ));
126 : : }
127 : : else
128 : : {
129 : : // clear all possibly pending update areas - content
130 : : // is there, already
131 : : std::for_each( maLayers.begin(),
132 : : maLayers.end(),
133 : 0 : boost::mem_fn( &Layer::clearUpdateRanges ));
134 : : }
135 : :
136 : 0 : updateShapeLayers( bSlideBackgoundPainted );
137 : 0 : }
138 : :
139 : 0 : void LayerManager::deactivate()
140 : : {
141 : : // TODO(F3): This is mostly a hack. Problem is, there's
142 : : // currently no smart way of telling shapes "remove your
143 : : // sprites". Others, like MediaShapes, listen to
144 : : // start/stop animation events, which is too much overhead
145 : : // for all shapes, though.
146 : :
147 : 0 : const bool bMoreThanOneLayer(maLayers.size() > 1);
148 : 0 : if( mnActiveSprites || bMoreThanOneLayer )
149 : : {
150 : : // clear all viewlayers, dump everything but the
151 : : // background layer - this will also remove all shape
152 : : // sprites
153 : : std::for_each(maAllShapes.begin(),
154 : : maAllShapes.end(),
155 : : boost::bind( &Shape::clearAllViewLayers,
156 : : boost::bind( o3tl::select1st<LayerShapeMap::value_type>(),
157 : 0 : _1 )));
158 : :
159 : 0 : for (LayerShapeMap::iterator
160 : 0 : iShape (maAllShapes.begin()),
161 : 0 : iEnd (maAllShapes.end());
162 : : iShape!=iEnd;
163 : : ++iShape)
164 : : {
165 : 0 : iShape->second.reset();
166 : : }
167 : :
168 : 0 : if( bMoreThanOneLayer )
169 : 0 : maLayers.erase(maLayers.begin()+1,
170 : 0 : maLayers.end());
171 : :
172 : 0 : mbLayerAssociationDirty = true;
173 : : }
174 : :
175 : 0 : mbActive = false;
176 : :
177 : : // only background layer left
178 : : OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
179 : 0 : }
180 : :
181 : 0 : void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
182 : : {
183 : : // view must be member of mrViews container
184 : : OSL_ASSERT( std::find(mrViews.begin(),
185 : : mrViews.end(),
186 : : rView) != mrViews.end() );
187 : :
188 : : // init view content
189 : 0 : if( mbActive )
190 : 0 : rView->clearAll();
191 : :
192 : : // add View to all registered shapes
193 : : manageViews(
194 : : boost::bind(&Layer::addView,
195 : : _1,
196 : : boost::cref(rView)),
197 : : // repaint on view add
198 : : boost::bind(&Shape::addViewLayer,
199 : : _1,
200 : : _2,
201 : 0 : true) );
202 : :
203 : : // in case we haven't reached all layers from the
204 : : // maAllShapes, issue addView again for good measure
205 : : std::for_each( maLayers.begin(),
206 : : maLayers.end(),
207 : : boost::bind( &Layer::addView,
208 : : _1,
209 : 0 : boost::cref(rView) ));
210 : 0 : }
211 : :
212 : 0 : void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
213 : : {
214 : : // view must not be member of mrViews container anymore
215 : : OSL_ASSERT( std::find(mrViews.begin(),
216 : : mrViews.end(),
217 : : rView) == mrViews.end() );
218 : :
219 : : // remove View from all registered shapes
220 : : manageViews(
221 : : boost::bind(&Layer::removeView,
222 : : _1,
223 : : boost::cref(rView)),
224 : : boost::bind(&Shape::removeViewLayer,
225 : : _1,
226 : 0 : _2) );
227 : :
228 : : // in case we haven't reached all layers from the
229 : : // maAllShapes, issue removeView again for good measure
230 : : std::for_each( maLayers.begin(),
231 : : maLayers.end(),
232 : : boost::bind( &Layer::removeView,
233 : : _1,
234 : 0 : boost::cref(rView) ));
235 : 0 : }
236 : :
237 : 0 : void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
238 : : {
239 : : (void)rView;
240 : :
241 : : // view must be member of mrViews container
242 : : OSL_ASSERT( std::find(mrViews.begin(),
243 : : mrViews.end(),
244 : : rView) != mrViews.end() );
245 : :
246 : : // TODO(P2): selectively update only changed view
247 : 0 : viewsChanged();
248 : 0 : }
249 : :
250 : 0 : void LayerManager::viewsChanged()
251 : : {
252 : 0 : if( !mbActive )
253 : 0 : return;
254 : :
255 : : // clear view area
256 : : ::std::for_each( mrViews.begin(),
257 : : mrViews.end(),
258 : 0 : ::boost::mem_fn(&View::clearAll) );
259 : :
260 : : // TODO(F3): resize and repaint all layers
261 : :
262 : : // render all shapes
263 : : std::for_each( maAllShapes.begin(),
264 : : maAllShapes.end(),
265 : : boost::bind(&Shape::render,
266 : 0 : boost::bind( ::o3tl::select1st<LayerShapeMap::value_type>(), _1)) );
267 : : }
268 : :
269 : 0 : void LayerManager::addShape( const ShapeSharedPtr& rShape )
270 : : {
271 : : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
272 : 0 : ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
273 : :
274 : : // add shape to XShape hash map
275 : 0 : if( !maXShapeHash.insert(
276 : 0 : XShapeHash::value_type( rShape->getXShape(),
277 : 0 : rShape) ).second )
278 : : {
279 : : // entry already present, nothing to do
280 : 0 : return;
281 : : }
282 : :
283 : : // add shape to appropriate layer
284 : 0 : implAddShape( rShape );
285 : : }
286 : :
287 : 0 : void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
288 : : {
289 : 0 : LayerSharedPtr& rBgLayer( maLayers.front() );
290 : 0 : rBgLayer->setShapeViews(rShapeEntry.first);
291 : 0 : rShapeEntry.second = rBgLayer;
292 : 0 : }
293 : :
294 : 0 : void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
295 : : {
296 : : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
297 : 0 : ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
298 : :
299 : 0 : LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
300 : :
301 : : OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
302 : 0 : mbLayerAssociationDirty = true;
303 : :
304 : 0 : if( mbDisableAnimationZOrder )
305 : : putShape2BackgroundLayer(
306 : 0 : *maAllShapes.insert(aValue).first );
307 : : else
308 : 0 : maAllShapes.insert(aValue);
309 : :
310 : : // update shape, it's just added and not yet painted
311 : 0 : if( rShape->isVisible() )
312 : 0 : notifyShapeUpdate( rShape );
313 : 0 : }
314 : :
315 : 0 : void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
316 : : {
317 : : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
318 : 0 : ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
319 : :
320 : 0 : const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
321 : :
322 : 0 : if( aShapeEntry == maAllShapes.end() )
323 : 0 : return;
324 : :
325 : 0 : const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
326 : :
327 : : // Enter shape area to the update area, but only if shape
328 : : // is visible and not in sprite mode (otherwise, updating
329 : : // the area doesn't do actual harm, but costs time)
330 : : // Actually, also add it if it was listed in
331 : : // maUpdateShapes (might have just gone invisible).
332 : 0 : if( bShapeUpdateNotified ||
333 : 0 : (rShape->isVisible() &&
334 : 0 : !rShape->isBackgroundDetached()) )
335 : : {
336 : 0 : LayerSharedPtr pLayer = aShapeEntry->second.lock();
337 : 0 : if( pLayer )
338 : : {
339 : : // store area early, once the shape is removed from
340 : : // the layers, it no longer has any view references
341 : 0 : pLayer->addUpdateRange( rShape->getUpdateArea() );
342 : 0 : }
343 : : }
344 : :
345 : 0 : rShape->clearAllViewLayers();
346 : 0 : maAllShapes.erase( aShapeEntry );
347 : :
348 : 0 : mbLayerAssociationDirty = true;
349 : : }
350 : :
351 : 0 : ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
352 : : {
353 : 0 : ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
354 : :
355 : 0 : const XShapeHash::const_iterator aIter( maXShapeHash.find( xShape ));
356 : 0 : if( aIter == maXShapeHash.end() )
357 : 0 : return ShapeSharedPtr(); // not found
358 : :
359 : : // found, return data part of entry pair.
360 : 0 : return aIter->second;
361 : : }
362 : :
363 : 0 : AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
364 : : const DocTreeNode& rTreeNode )
365 : : {
366 : : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
367 : :
368 : 0 : AttributableShapeSharedPtr pSubset;
369 : :
370 : : // shape already added?
371 : 0 : if( rOrigShape->createSubset( pSubset,
372 : 0 : rTreeNode ) )
373 : : {
374 : : OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
375 : :
376 : : // don't add to shape hash, we're dupes to the
377 : : // original XShape anyway - all subset shapes return
378 : : // the same XShape as the original one.
379 : :
380 : : // add shape to corresponding layer
381 : 0 : implAddShape( pSubset );
382 : :
383 : : // update original shape, it now shows less content
384 : : // (the subset is removed from its displayed
385 : : // output). Subset shape is updated within
386 : : // implAddShape().
387 : 0 : if( rOrigShape->isVisible() )
388 : 0 : notifyShapeUpdate( rOrigShape );
389 : : }
390 : :
391 : 0 : return pSubset;
392 : : }
393 : :
394 : 0 : void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
395 : : const AttributableShapeSharedPtr& rSubsetShape )
396 : : {
397 : : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
398 : :
399 : 0 : if( rOrigShape->revokeSubset( rSubsetShape ) )
400 : : {
401 : : OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
402 : :
403 : 0 : implRemoveShape( rSubsetShape );
404 : :
405 : : // update original shape, it now shows more content
406 : : // (the subset is added back to its displayed output)
407 : 0 : if( rOrigShape->isVisible() )
408 : 0 : notifyShapeUpdate( rOrigShape );
409 : : }
410 : 0 : }
411 : :
412 : 0 : void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
413 : : {
414 : : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
415 : 0 : ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
416 : :
417 : 0 : const bool bPrevAnimState( rShape->isBackgroundDetached() );
418 : :
419 : 0 : rShape->enterAnimationMode();
420 : :
421 : : // if this call _really_ enabled the animation mode at
422 : : // rShape, insert it to our enter animation queue, to
423 : : // perform the necessary layer reorg lazily on
424 : : // LayerManager::update()/render().
425 : 0 : if( bPrevAnimState != rShape->isBackgroundDetached() )
426 : : {
427 : 0 : ++mnActiveSprites;
428 : 0 : mbLayerAssociationDirty = true;
429 : :
430 : : // area needs update (shape is removed from normal
431 : : // slide, and now rendered as an autonomous
432 : : // sprite). store in update set
433 : 0 : if( rShape->isVisible() )
434 : 0 : addUpdateArea( rShape );
435 : : }
436 : :
437 : : // TODO(P1): this can lead to potential wasted effort, if
438 : : // a shape gets toggled animated/unanimated a few times
439 : : // between two frames, returning to the original state.
440 : 0 : }
441 : :
442 : 0 : void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
443 : : {
444 : 0 : ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
445 : 0 : ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
446 : :
447 : 0 : const bool bPrevAnimState( rShape->isBackgroundDetached() );
448 : :
449 : 0 : rShape->leaveAnimationMode();
450 : :
451 : : // if this call _really_ ended the animation mode at
452 : : // rShape, insert it to our leave animation queue, to
453 : : // perform the necessary layer reorg lazily on
454 : : // LayerManager::update()/render().
455 : 0 : if( bPrevAnimState != rShape->isBackgroundDetached() )
456 : : {
457 : 0 : --mnActiveSprites;
458 : 0 : mbLayerAssociationDirty = true;
459 : :
460 : : // shape needs update, no previous rendering, fast
461 : : // update possible.
462 : 0 : if( rShape->isVisible() )
463 : 0 : notifyShapeUpdate( rShape );
464 : : }
465 : :
466 : : // TODO(P1): this can lead to potential wasted effort, if
467 : : // a shape gets toggled animated/unanimated a few times
468 : : // between two frames, returning to the original state.
469 : 0 : }
470 : :
471 : 0 : void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
472 : : {
473 : 0 : if( !mbActive || mrViews.empty() )
474 : 0 : return;
475 : :
476 : : // hidden sprite-shape needs render() call still, to hide sprite
477 : 0 : if( rShape->isVisible() || rShape->isBackgroundDetached() )
478 : 0 : maUpdateShapes.insert( rShape );
479 : : else
480 : 0 : addUpdateArea( rShape );
481 : : }
482 : :
483 : 0 : bool LayerManager::isUpdatePending() const
484 : : {
485 : 0 : if( !mbActive )
486 : 0 : return false;
487 : :
488 : 0 : if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
489 : 0 : return true;
490 : :
491 : 0 : const LayerVector::const_iterator aEnd( maLayers.end() );
492 : 0 : if( std::find_if( maLayers.begin(),
493 : : aEnd,
494 : 0 : boost::mem_fn(&Layer::isUpdatePending)) != aEnd )
495 : 0 : return true;
496 : :
497 : 0 : return false;
498 : : }
499 : :
500 : 0 : bool LayerManager::updateSprites()
501 : : {
502 : 0 : bool bRet(true);
503 : :
504 : : // send update() calls to every shape in the
505 : : // maUpdateShapes set, which is _animated_ (i.e. a
506 : : // sprite).
507 : 0 : const ShapeUpdateSet::const_iterator aEnd=maUpdateShapes.end();
508 : 0 : ShapeUpdateSet::const_iterator aCurrShape=maUpdateShapes.begin();
509 : 0 : while( aCurrShape != aEnd )
510 : : {
511 : 0 : if( (*aCurrShape)->isBackgroundDetached() )
512 : : {
513 : : // can update shape directly, without
514 : : // affecting layer content (shape is
515 : : // currently displayed in a sprite)
516 : 0 : if( !(*aCurrShape)->update() )
517 : 0 : bRet = false; // delay error exit
518 : : }
519 : : else
520 : : {
521 : : // TODO(P2): addUpdateArea() involves log(n)
522 : : // search for shape layer. Have a frequent
523 : : // shape/layer association cache, or ptr back to
524 : : // layer at the shape?
525 : :
526 : : // cannot update shape directly, it's not
527 : : // animated and update() calls will prolly
528 : : // overwrite other page content.
529 : 0 : addUpdateArea( *aCurrShape );
530 : : }
531 : :
532 : 0 : ++aCurrShape;
533 : : }
534 : :
535 : 0 : maUpdateShapes.clear();
536 : :
537 : 0 : return bRet;
538 : : }
539 : :
540 : 0 : bool LayerManager::update()
541 : : {
542 : 0 : bool bRet = true;
543 : :
544 : 0 : if( !mbActive )
545 : 0 : return bRet;
546 : :
547 : : // going to render - better flush any pending layer reorg
548 : : // now
549 : 0 : updateShapeLayers(false);
550 : :
551 : : // all sprites
552 : 0 : bRet = updateSprites();
553 : :
554 : : // any non-sprite update areas left?
555 : 0 : if( std::find_if( maLayers.begin(),
556 : : maLayers.end(),
557 : 0 : boost::mem_fn( &Layer::isUpdatePending )) == maLayers.end() )
558 : 0 : return bRet; // nope, done.
559 : :
560 : : // update each shape on each layer, that has
561 : : // isUpdatePending()
562 : 0 : bool bIsCurrLayerUpdating(false);
563 : 0 : Layer::EndUpdater aEndUpdater;
564 : 0 : LayerSharedPtr pCurrLayer;
565 : 0 : LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
566 : 0 : const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
567 : 0 : while( aIter != aEnd )
568 : : {
569 : 0 : LayerSharedPtr pLayer = aIter->second.lock();
570 : 0 : if( pLayer != pCurrLayer )
571 : : {
572 : 0 : pCurrLayer = pLayer;
573 : 0 : bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
574 : :
575 : 0 : if( bIsCurrLayerUpdating )
576 : 0 : aEndUpdater = pCurrLayer->beginUpdate();
577 : : }
578 : :
579 : 0 : if( bIsCurrLayerUpdating &&
580 : 0 : !aIter->first->isBackgroundDetached() &&
581 : 0 : pCurrLayer->isInsideUpdateArea(aIter->first) )
582 : : {
583 : 0 : if( !aIter->first->render() )
584 : 0 : bRet = false;
585 : : }
586 : :
587 : 0 : ++aIter;
588 : 0 : }
589 : :
590 : 0 : return bRet;
591 : : }
592 : :
593 : : namespace
594 : : {
595 : : /** Little wrapper around a Canvas, to render one-shot
596 : : into a canvas
597 : : */
598 : 0 : class DummyLayer : public ViewLayer
599 : : {
600 : : public:
601 : 0 : explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
602 : 0 : mpCanvas( rCanvas )
603 : : {
604 : 0 : }
605 : :
606 : 0 : virtual bool isOnView(boost::shared_ptr<View> const& /*rView*/) const
607 : : {
608 : 0 : return true; // visible on all views
609 : : }
610 : :
611 : 0 : virtual ::cppcanvas::CanvasSharedPtr getCanvas() const
612 : : {
613 : 0 : return mpCanvas;
614 : : }
615 : :
616 : 0 : virtual void clear() const
617 : : {
618 : : // NOOP
619 : 0 : }
620 : :
621 : 0 : virtual void clearAll() const
622 : : {
623 : : // NOOP
624 : 0 : }
625 : :
626 : 0 : virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
627 : : double /*nSpritePrio*/ ) const
628 : : {
629 : 0 : ENSURE_OR_THROW( false,
630 : : "DummyLayer::createSprite(): This method is not supposed to be called!" );
631 : : return ::cppcanvas::CustomSpriteSharedPtr();
632 : : }
633 : :
634 : 0 : virtual void setPriority( const basegfx::B1DRange& /*rRange*/ )
635 : : {
636 : : OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
637 : 0 : }
638 : :
639 : 0 : virtual ::basegfx::B2DHomMatrix getTransformation() const
640 : : {
641 : 0 : return mpCanvas->getTransformation();
642 : : }
643 : :
644 : 0 : virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const
645 : : {
646 : : OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
647 : 0 : return ::basegfx::B2DHomMatrix();
648 : : }
649 : :
650 : 0 : virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ )
651 : : {
652 : : OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
653 : 0 : }
654 : :
655 : 0 : virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ )
656 : : {
657 : : OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
658 : 0 : return false;
659 : : }
660 : :
661 : : private:
662 : : ::cppcanvas::CanvasSharedPtr mpCanvas;
663 : : };
664 : : }
665 : :
666 : 0 : bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
667 : : {
668 : 0 : bool bRet( true );
669 : 0 : ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
670 : :
671 : 0 : LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
672 : 0 : const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
673 : 0 : while( aIter != aEnd )
674 : : {
675 : : try
676 : : {
677 : : // forward to all shape's addViewLayer method (which
678 : : // we request to render the Shape on the new
679 : : // ViewLayer. Since we add the shapes in the
680 : : // maShapeSet order (which is also the render order),
681 : : // this is equivalent to a subsequent render() call)
682 : 0 : aIter->first->addViewLayer( pTmpLayer,
683 : 0 : true );
684 : :
685 : : // and remove again, this is only temporary
686 : 0 : aIter->first->removeViewLayer( pTmpLayer );
687 : : }
688 : 0 : catch( uno::Exception& )
689 : : {
690 : : // TODO(E1): Might be superfluous. Nowadays,
691 : : // addViewLayer swallows all errors, anyway.
692 : : OSL_FAIL( rtl::OUStringToOString(
693 : : comphelper::anyToString( cppu::getCaughtException() ),
694 : : RTL_TEXTENCODING_UTF8 ).getStr() );
695 : :
696 : : // at least one shape could not be rendered
697 : 0 : bRet = false;
698 : : }
699 : :
700 : 0 : ++aIter;
701 : : }
702 : :
703 : 0 : return bRet;
704 : : }
705 : :
706 : 0 : void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
707 : : {
708 : : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
709 : 0 : ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
710 : :
711 : 0 : const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
712 : :
713 : 0 : if( aShapeEntry == maAllShapes.end() )
714 : 0 : return;
715 : :
716 : 0 : LayerSharedPtr pLayer = aShapeEntry->second.lock();
717 : 0 : if( pLayer )
718 : 0 : pLayer->addUpdateRange( rShape->getUpdateArea() );
719 : : }
720 : :
721 : 0 : void LayerManager::commitLayerChanges( std::size_t nCurrLayerIndex,
722 : : LayerShapeMap::const_iterator aFirstLayerShape,
723 : : LayerShapeMap::const_iterator aEndLayerShapes )
724 : : {
725 : 0 : const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
726 : 0 : if( bLayerExists )
727 : : {
728 : 0 : const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
729 : 0 : const bool bLayerResized( rLayer->commitBounds() );
730 : : rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
731 : 0 : nCurrLayerIndex+1) );
732 : :
733 : 0 : if( bLayerResized )
734 : : {
735 : : // need to re-render whole layer - start from
736 : : // clean state
737 : 0 : rLayer->clearContent();
738 : :
739 : : // render and remove from update set
740 : 0 : while( aFirstLayerShape != aEndLayerShapes )
741 : : {
742 : 0 : maUpdateShapes.erase(aFirstLayerShape->first);
743 : 0 : aFirstLayerShape->first->render();
744 : 0 : ++aFirstLayerShape;
745 : : }
746 : : }
747 : : }
748 : 0 : }
749 : :
750 : 0 : LayerSharedPtr LayerManager::createForegroundLayer() const
751 : : {
752 : : OSL_ASSERT( mbActive );
753 : :
754 : : LayerSharedPtr pLayer( Layer::createLayer(
755 : 0 : maPageBounds ));
756 : :
757 : : // create ViewLayers for all registered views, and add to
758 : : // newly created layer.
759 : : ::std::for_each( mrViews.begin(),
760 : : mrViews.end(),
761 : : boost::bind( &Layer::addView,
762 : : boost::cref(pLayer),
763 : 0 : _1 ));
764 : :
765 : 0 : return pLayer;
766 : : }
767 : :
768 : 0 : void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
769 : : {
770 : : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
771 : : OSL_ASSERT( mbActive );
772 : :
773 : : // do we need to process shapes?
774 : 0 : if( !mbLayerAssociationDirty )
775 : : return;
776 : :
777 : 0 : if( mbDisableAnimationZOrder )
778 : : {
779 : : // layer setup happened elsewhere, is only bg layer
780 : : // anyway.
781 : 0 : mbLayerAssociationDirty = false;
782 : : return;
783 : : }
784 : :
785 : : // scan through maAllShapes, and determine shape animation
786 : : // discontinuities: when a shape that has
787 : : // isBackgroundDetached() return false follows a shape
788 : : // with isBackgroundDetached() true, the former and all
789 : : // following ones must be moved into an own layer.
790 : :
791 : : // to avoid tons of temporaries, create weak_ptr to Layers
792 : : // beforehand
793 : 0 : std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
794 : 0 : std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
795 : :
796 : 0 : std::size_t nCurrLayerIndex(0);
797 : 0 : bool bIsBackgroundLayer(true);
798 : 0 : bool bLastWasBackgroundDetached(false); // last shape sprite state
799 : 0 : LayerShapeMap::iterator aCurrShapeEntry( maAllShapes.begin() );
800 : 0 : LayerShapeMap::iterator aCurrLayerFirstShapeEntry( maAllShapes.begin() );
801 : 0 : const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
802 : 0 : ShapeUpdateSet aUpdatedShapes; // shapes that need update
803 : 0 : while( aCurrShapeEntry != aEndShapeEntry )
804 : : {
805 : 0 : const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
806 : : const bool bThisIsBackgroundDetached(
807 : 0 : pCurrShape->isBackgroundDetached() );
808 : :
809 : 0 : if( bLastWasBackgroundDetached == true &&
810 : : bThisIsBackgroundDetached == false )
811 : : {
812 : : // discontinuity found - current shape needs to
813 : : // get into a new layer
814 : : // --------------------------------------------
815 : :
816 : : // commit changes to previous layer
817 : : commitLayerChanges(nCurrLayerIndex,
818 : : aCurrLayerFirstShapeEntry,
819 : 0 : aCurrShapeEntry);
820 : 0 : aCurrLayerFirstShapeEntry=aCurrShapeEntry;
821 : 0 : ++nCurrLayerIndex;
822 : 0 : bIsBackgroundLayer = false;
823 : :
824 : 0 : if( aWeakLayers.size() <= nCurrLayerIndex ||
825 : 0 : aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
826 : : {
827 : : // no more layers left, or shape was not
828 : : // member of this layer - create a new one
829 : 0 : maLayers.insert( maLayers.begin()+nCurrLayerIndex,
830 : 0 : createForegroundLayer() );
831 : : aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
832 : 0 : maLayers[nCurrLayerIndex] );
833 : : }
834 : : }
835 : :
836 : : OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
837 : :
838 : : // note: using indices here, since vector::insert
839 : : // above invalidates iterators
840 : 0 : LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
841 : 0 : LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
842 : 0 : if( rCurrWeakLayer != aCurrShapeEntry->second )
843 : : {
844 : : // mismatch: shape is not contained in current
845 : : // layer - move shape to that layer, then.
846 : 0 : maLayers.at(nCurrLayerIndex)->setShapeViews(
847 : 0 : pCurrShape );
848 : :
849 : : // layer got new shape(s), need full repaint, if
850 : : // non-sprite shape
851 : 0 : if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
852 : : {
853 : 0 : LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
854 : 0 : if( pOldLayer )
855 : : {
856 : : // old layer still valid? then we need to
857 : : // repaint former shape area
858 : : pOldLayer->addUpdateRange(
859 : 0 : pCurrShape->getUpdateArea() );
860 : : }
861 : :
862 : : // render on new layer (only if not
863 : : // explicitly disabled)
864 : 0 : if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
865 : 0 : maUpdateShapes.insert( pCurrShape );
866 : : }
867 : :
868 : 0 : aCurrShapeEntry->second = rCurrWeakLayer;
869 : : }
870 : :
871 : : // update layerbounds regardless of the fact that the
872 : : // shape might be contained in said layer
873 : : // already. updateBounds() is dumb and needs to
874 : : // collect all shape bounds.
875 : : // of course, no need to expand layer bounds for
876 : : // shapes that reside in sprites themselves.
877 : 0 : if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
878 : 0 : rCurrLayer->updateBounds( pCurrShape );
879 : :
880 : 0 : bLastWasBackgroundDetached = bThisIsBackgroundDetached;
881 : 0 : ++aCurrShapeEntry;
882 : 0 : }
883 : :
884 : : // commit very last layer data
885 : : commitLayerChanges(nCurrLayerIndex,
886 : : aCurrLayerFirstShapeEntry,
887 : 0 : aCurrShapeEntry);
888 : :
889 : : // any layers left? Bin them!
890 : 0 : if( maLayers.size() > nCurrLayerIndex+1 )
891 : 0 : maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
892 : 0 : maLayers.end());
893 : :
894 : 0 : mbLayerAssociationDirty = false;
895 : : }
896 : : }
897 : 0 : }
898 : :
899 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|