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 0 : }
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 happened 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 SAL_OVERRIDE
607 : {
608 0 : return true; // visible on all views
609 : }
610 :
611 0 : virtual ::cppcanvas::CanvasSharedPtr getCanvas() const SAL_OVERRIDE
612 : {
613 0 : return mpCanvas;
614 : }
615 :
616 0 : virtual void clear() const SAL_OVERRIDE
617 : {
618 : // NOOP
619 0 : }
620 :
621 0 : virtual void clearAll() const SAL_OVERRIDE
622 : {
623 : // NOOP
624 0 : }
625 :
626 0 : virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
627 : double /*nSpritePrio*/ ) const SAL_OVERRIDE
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*/ ) SAL_OVERRIDE
635 : {
636 : OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
637 0 : }
638 :
639 0 : virtual ::com::sun::star::geometry::IntegerSize2D getTranslationOffset() const SAL_OVERRIDE
640 : {
641 0 : return geometry::IntegerSize2D(0,0);
642 : }
643 :
644 0 : virtual ::basegfx::B2DHomMatrix getTransformation() const SAL_OVERRIDE
645 : {
646 0 : return mpCanvas->getTransformation();
647 : }
648 :
649 0 : virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const SAL_OVERRIDE
650 : {
651 : OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
652 0 : return ::basegfx::B2DHomMatrix();
653 : }
654 :
655 0 : virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ ) SAL_OVERRIDE
656 : {
657 : OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
658 0 : }
659 :
660 0 : virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ ) SAL_OVERRIDE
661 : {
662 : OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
663 0 : return false;
664 : }
665 :
666 : private:
667 : ::cppcanvas::CanvasSharedPtr mpCanvas;
668 : };
669 : }
670 :
671 0 : bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
672 : {
673 0 : bool bRet( true );
674 0 : ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
675 :
676 0 : LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
677 0 : const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
678 0 : while( aIter != aEnd )
679 : {
680 : try
681 : {
682 : // forward to all shape's addViewLayer method (which
683 : // we request to render the Shape on the new
684 : // ViewLayer. Since we add the shapes in the
685 : // maShapeSet order (which is also the render order),
686 : // this is equivalent to a subsequent render() call)
687 0 : aIter->first->addViewLayer( pTmpLayer,
688 0 : true );
689 :
690 : // and remove again, this is only temporary
691 0 : aIter->first->removeViewLayer( pTmpLayer );
692 : }
693 0 : catch( uno::Exception& )
694 : {
695 : // TODO(E1): Might be superfluous. Nowadays,
696 : // addViewLayer swallows all errors, anyway.
697 : OSL_FAIL( OUStringToOString(
698 : comphelper::anyToString( cppu::getCaughtException() ),
699 : RTL_TEXTENCODING_UTF8 ).getStr() );
700 :
701 : // at least one shape could not be rendered
702 0 : bRet = false;
703 : }
704 :
705 0 : ++aIter;
706 : }
707 :
708 0 : return bRet;
709 : }
710 :
711 0 : void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
712 : {
713 : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
714 0 : ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
715 :
716 0 : const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
717 :
718 0 : if( aShapeEntry == maAllShapes.end() )
719 0 : return;
720 :
721 0 : LayerSharedPtr pLayer = aShapeEntry->second.lock();
722 0 : if( pLayer )
723 0 : pLayer->addUpdateRange( rShape->getUpdateArea() );
724 : }
725 :
726 0 : void LayerManager::commitLayerChanges( std::size_t nCurrLayerIndex,
727 : LayerShapeMap::const_iterator aFirstLayerShape,
728 : LayerShapeMap::const_iterator aEndLayerShapes )
729 : {
730 0 : const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
731 0 : if( bLayerExists )
732 : {
733 0 : const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
734 0 : const bool bLayerResized( rLayer->commitBounds() );
735 : rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
736 0 : nCurrLayerIndex+1) );
737 :
738 0 : if( bLayerResized )
739 : {
740 : // need to re-render whole layer - start from
741 : // clean state
742 0 : rLayer->clearContent();
743 :
744 : // render and remove from update set
745 0 : while( aFirstLayerShape != aEndLayerShapes )
746 : {
747 0 : maUpdateShapes.erase(aFirstLayerShape->first);
748 0 : aFirstLayerShape->first->render();
749 0 : ++aFirstLayerShape;
750 : }
751 : }
752 : }
753 0 : }
754 :
755 0 : LayerSharedPtr LayerManager::createForegroundLayer() const
756 : {
757 : OSL_ASSERT( mbActive );
758 :
759 : LayerSharedPtr pLayer( Layer::createLayer(
760 0 : maPageBounds ));
761 :
762 : // create ViewLayers for all registered views, and add to
763 : // newly created layer.
764 : ::std::for_each( mrViews.begin(),
765 : mrViews.end(),
766 : boost::bind( &Layer::addView,
767 : boost::cref(pLayer),
768 0 : _1 ));
769 :
770 0 : return pLayer;
771 : }
772 :
773 0 : void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
774 : {
775 : OSL_ASSERT( !maLayers.empty() ); // always at least background layer
776 : OSL_ASSERT( mbActive );
777 :
778 : // do we need to process shapes?
779 0 : if( !mbLayerAssociationDirty )
780 0 : return;
781 :
782 0 : if( mbDisableAnimationZOrder )
783 : {
784 : // layer setup happened elsewhere, is only bg layer
785 : // anyway.
786 0 : mbLayerAssociationDirty = false;
787 0 : return;
788 : }
789 :
790 : // scan through maAllShapes, and determine shape animation
791 : // discontinuities: when a shape that has
792 : // isBackgroundDetached() return false follows a shape
793 : // with isBackgroundDetached() true, the former and all
794 : // following ones must be moved into an own layer.
795 :
796 : // to avoid tons of temporaries, create weak_ptr to Layers
797 : // beforehand
798 0 : std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
799 0 : std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
800 :
801 0 : std::size_t nCurrLayerIndex(0);
802 0 : bool bIsBackgroundLayer(true);
803 0 : bool bLastWasBackgroundDetached(false); // last shape sprite state
804 0 : LayerShapeMap::iterator aCurrShapeEntry( maAllShapes.begin() );
805 0 : LayerShapeMap::iterator aCurrLayerFirstShapeEntry( maAllShapes.begin() );
806 0 : const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
807 0 : ShapeUpdateSet aUpdatedShapes; // shapes that need update
808 0 : while( aCurrShapeEntry != aEndShapeEntry )
809 : {
810 0 : const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
811 : const bool bThisIsBackgroundDetached(
812 0 : pCurrShape->isBackgroundDetached() );
813 :
814 0 : if( bLastWasBackgroundDetached == true &&
815 0 : bThisIsBackgroundDetached == false )
816 : {
817 : // discontinuity found - current shape needs to
818 : // get into a new layer
819 :
820 :
821 : // commit changes to previous layer
822 : commitLayerChanges(nCurrLayerIndex,
823 : aCurrLayerFirstShapeEntry,
824 0 : aCurrShapeEntry);
825 0 : aCurrLayerFirstShapeEntry=aCurrShapeEntry;
826 0 : ++nCurrLayerIndex;
827 0 : bIsBackgroundLayer = false;
828 :
829 0 : if( aWeakLayers.size() <= nCurrLayerIndex ||
830 0 : aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
831 : {
832 : // no more layers left, or shape was not
833 : // member of this layer - create a new one
834 0 : maLayers.insert( maLayers.begin()+nCurrLayerIndex,
835 0 : createForegroundLayer() );
836 0 : aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
837 0 : maLayers[nCurrLayerIndex] );
838 : }
839 : }
840 :
841 : OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
842 :
843 : // note: using indices here, since vector::insert
844 : // above invalidates iterators
845 0 : LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
846 0 : LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
847 0 : if( rCurrWeakLayer != aCurrShapeEntry->second )
848 : {
849 : // mismatch: shape is not contained in current
850 : // layer - move shape to that layer, then.
851 0 : maLayers.at(nCurrLayerIndex)->setShapeViews(
852 0 : pCurrShape );
853 :
854 : // layer got new shape(s), need full repaint, if
855 : // non-sprite shape
856 0 : if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
857 : {
858 0 : LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
859 0 : if( pOldLayer )
860 : {
861 : // old layer still valid? then we need to
862 : // repaint former shape area
863 : pOldLayer->addUpdateRange(
864 0 : pCurrShape->getUpdateArea() );
865 : }
866 :
867 : // render on new layer (only if not
868 : // explicitly disabled)
869 0 : if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
870 0 : maUpdateShapes.insert( pCurrShape );
871 : }
872 :
873 0 : aCurrShapeEntry->second = rCurrWeakLayer;
874 : }
875 :
876 : // update layerbounds regardless of the fact that the
877 : // shape might be contained in said layer
878 : // already. updateBounds() is dumb and needs to
879 : // collect all shape bounds.
880 : // of course, no need to expand layer bounds for
881 : // shapes that reside in sprites themselves.
882 0 : if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
883 0 : rCurrLayer->updateBounds( pCurrShape );
884 :
885 0 : bLastWasBackgroundDetached = bThisIsBackgroundDetached;
886 0 : ++aCurrShapeEntry;
887 0 : }
888 :
889 : // commit very last layer data
890 : commitLayerChanges(nCurrLayerIndex,
891 : aCurrLayerFirstShapeEntry,
892 0 : aCurrShapeEntry);
893 :
894 : // any layers left? Bin them!
895 0 : if( maLayers.size() > nCurrLayerIndex+1 )
896 0 : maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
897 0 : maLayers.end());
898 :
899 0 : mbLayerAssociationDirty = false;
900 : }
901 : }
902 6 : }
903 :
904 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|