bump product version to 4.1.6.2
[LibreOffice.git] / slideshow / source / engine / slideview.cxx
blob250de4e9efd3550159ea9dd4df790673666cf273
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <canvas/debug.hxx>
21 #include <tools/diagnose_ex.h>
22 #include <canvas/canvastools.hxx>
24 #include "eventqueue.hxx"
25 #include "eventmultiplexer.hxx"
26 #include "slideview.hxx"
27 #include "delayevent.hxx"
28 #include "unoview.hxx"
30 #include <rtl/instance.hxx>
31 #include <cppuhelper/basemutex.hxx>
32 #include <cppuhelper/compbase2.hxx>
33 #include <cppuhelper/implementationentry.hxx>
34 #include <cppuhelper/interfacecontainer.h>
35 #include <comphelper/make_shared_from_uno.hxx>
37 #include <cppcanvas/spritecanvas.hxx>
38 #include <cppcanvas/customsprite.hxx>
39 #include <cppcanvas/vclfactory.hxx>
40 #include <cppcanvas/basegfxfactory.hxx>
42 #include <tools/debug.hxx>
44 #include <basegfx/range/b1drange.hxx>
45 #include <basegfx/range/b2drange.hxx>
46 #include <basegfx/range/b2irange.hxx>
47 #include <basegfx/point/b2dpoint.hxx>
48 #include <basegfx/polygon/b2dpolygon.hxx>
49 #include <basegfx/matrix/b2dhommatrix.hxx>
50 #include <basegfx/polygon/b2dpolygontools.hxx>
51 #include <basegfx/polygon/b2dpolypolygontools.hxx>
52 #include <basegfx/tools/canvastools.hxx>
53 #include <basegfx/polygon/b2dpolygonclipper.hxx>
54 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
56 #include <com/sun/star/presentation/XSlideShow.hpp>
58 #include <boost/noncopyable.hpp>
59 #include <boost/bind.hpp>
60 #include <boost/weak_ptr.hpp>
62 #include <vector>
63 #include <iterator>
64 #include <algorithm>
66 using namespace com::sun::star;
68 namespace slideshow {
69 namespace internal {
71 namespace {
73 struct StaticUnitRectPoly : public rtl::StaticWithInit<basegfx::B2DPolygon, StaticUnitRectPoly>
75 basegfx::B2DPolygon operator()()
77 return basegfx::tools::createUnitPolygon();
81 /** Sprite entry, to store sprite plus priority
83 The operator<() defines a strict weak ordering of sprites, sort
84 key is the sprite priority.
86 struct SpriteEntry
88 SpriteEntry( const cppcanvas::CustomSpriteSharedPtr& rSprite,
89 double nPrio ) :
90 mpSprite( rSprite ),
91 mnPriority( nPrio )
95 bool operator<(const SpriteEntry& rRHS) const
97 return mnPriority < rRHS.mnPriority;
100 boost::weak_ptr< cppcanvas::CustomSprite > mpSprite;
101 double mnPriority;
104 typedef std::vector< SpriteEntry > SpriteVector;
107 /** Create a clip polygon for slide views
109 @param rClip
110 Clip to set (can be empty)
112 @param rCanvas
113 Canvas to create the clip polygon for
115 @param rUserSize
116 The size of the view. Note that the returned clip will
117 <em>always</em> clip to at least the rect defined herein.
119 @return the view clip polygon, in view coordinates, which is
120 guaranteed to at least clip to the view size.
122 basegfx::B2DPolyPolygon createClipPolygon( const basegfx::B2DPolyPolygon& rClip,
123 const cppcanvas::CanvasSharedPtr& /*rCanvas*/,
124 const basegfx::B2DSize& rUserSize )
126 // setup canvas clipping
127 // =====================
129 // AW: Simplified
130 const basegfx::B2DRange aClipRange(0, 0, rUserSize.getX(), rUserSize.getY());
132 if(rClip.count())
134 return basegfx::tools::clipPolyPolygonOnRange(rClip, aClipRange, true, false);
136 else
138 return basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aClipRange));
142 /** Prepare given clip polygon to be stored as the current clip
144 Note that this is separate from createClipPolygon(), to allow
145 SlideView implementations to store this intermediate result
146 (createClipPolygon() has to be called every time the view size
147 changes)
149 basegfx::B2DPolyPolygon prepareClip( const basegfx::B2DPolyPolygon& rClip )
151 basegfx::B2DPolyPolygon aClip( rClip );
153 // TODO(P2): unnecessary, once XCanvas is correctly handling this
154 // AW: Should be no longer necessary; tools are now bezier-safe
155 if( aClip.areControlPointsUsed() )
156 aClip = basegfx::tools::adaptiveSubdivideByAngle( aClip );
158 // normalize polygon, preparation for clipping
159 // in updateCanvas()
160 aClip = basegfx::tools::correctOrientations(aClip);
161 aClip = basegfx::tools::solveCrossovers(aClip);
162 aClip = basegfx::tools::stripNeutralPolygons(aClip);
163 aClip = basegfx::tools::stripDispensablePolygons(aClip, false);
165 return aClip;
169 void clearRect( ::cppcanvas::CanvasSharedPtr const& pCanvas,
170 basegfx::B2IRange const& rArea )
172 // convert clip polygon to device coordinate system
173 ::basegfx::B2DPolyPolygon const* pClipPoly( pCanvas->getClip() );
174 if( pClipPoly )
176 ::basegfx::B2DPolyPolygon aClipPoly( *pClipPoly );
177 aClipPoly.transform( pCanvas->getTransformation() );
178 pCanvas->setClip( aClipPoly );
181 // set transformation to identitiy (->device pixel)
182 pCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
184 // #i42440# Fill the _full_ background in
185 // black. Since we had to extend the bitmap by one
186 // pixel, and the bitmap is initialized white,
187 // depending on the slide content a one pixel wide
188 // line will show to the bottom and the right.
189 const ::basegfx::B2DPolygon aPoly(
190 ::basegfx::tools::createPolygonFromRect(
191 basegfx::B2DRange(rArea)));
193 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
194 ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( pCanvas,
195 aPoly ) );
197 if( pPolyPoly )
199 pPolyPoly->setCompositeOp( cppcanvas::CanvasGraphic::SOURCE );
200 pPolyPoly->setRGBAFillColor( 0xFFFFFF00U );
201 pPolyPoly->draw();
204 #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
205 ::cppcanvas::CanvasSharedPtr pCliplessCanvas( pCanvas->clone() );
206 pCliplessCanvas->setClip();
208 if( pCanvas->getClip() )
210 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly2(
211 ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( pCliplessCanvas,
212 aPoly ));
213 if( pPolyPoly2 )
215 pPolyPoly2->setRGBALineColor( 0x008000FFU );
216 pPolyPoly2->draw();
219 #endif
222 /** Get bounds in pixel
224 @param rLayerBounds
225 Bound rect, in user space coordinates
227 @param rTransformation
228 User space to device pixel transformation
230 @return the layer bounds in pixel, extended by one pixel to the
231 right and bottom
233 basegfx::B2IRange getLayerBoundsPixel( basegfx::B2DRange const& rLayerBounds,
234 basegfx::B2DHomMatrix const& rTransformation )
236 ::basegfx::B2DRange aTmpRect;
237 ::canvas::tools::calcTransformedRectBounds( aTmpRect,
238 rLayerBounds,
239 rTransformation );
241 if( aTmpRect.isEmpty() )
242 return ::basegfx::B2IRange();
244 // #i42440# Returned layer size is one pixel too small, as
245 // rendering happens one pixel to the right and below the
246 // actual bound rect.
247 return ::basegfx::B2IRange( ::basegfx::fround(aTmpRect.getMinX()),
248 ::basegfx::fround(aTmpRect.getMinY()),
249 ::basegfx::fround(aTmpRect.getMaxX()) + 1,
250 ::basegfx::fround(aTmpRect.getMaxY()) + 1 );
254 // ----------------------------------------------------------------
256 /** Container class for sprites issued by a ViewLayer
258 This class handles the sprite prioritization issues, that are
259 needed for layer sprites (e.g. the need to re-prioritize sprites
260 when the layer changes prio).
262 class LayerSpriteContainer
264 /** Max fill level of maSprites, before we try to prune it from
265 deceased sprites
267 enum{ SPRITE_ULLAGE=256 };
269 /** All sprites that have been issued by this container (pruned
270 from time to time, for invalid references). This vector is
271 kept sorted with increasing sprite priority.
273 SpriteVector maSprites;
275 /// Priority of this layer, relative to other view layers
276 basegfx::B1DRange maLayerPrioRange;
278 double getSpritePriority( std::size_t nSpriteNum ) const
280 // divide the available layer range equally between all
281 // sprites, assign upper bound of individual sprite range as
282 // sprite prio (the layer itself gets assigned the lower bound
283 // of sprite 0's individual range):
285 // | layer 0 | layer 1 | ...
286 // | sprite 0 | sprite 1 | sprite 0 | sprite 1 | ...
287 return maLayerPrioRange.getMinimum() + maLayerPrioRange.getRange()*(nSpriteNum+1)/(maSprites.size()+1);
290 /** Rescan sprite vector, and remove deceased sprites (and reset
291 sprite prio)
293 @param aBegin
294 Iterator to the first entry to rescan
296 void updateSprites()
298 SpriteVector aValidSprites;
300 // check all sprites for validity and set new priority
301 SpriteVector::iterator aCurrSprite( maSprites.begin() );
302 const SpriteVector::iterator aEnd( maSprites.end() );
303 while( aCurrSprite != aEnd )
305 cppcanvas::CustomSpriteSharedPtr pCurrSprite( aCurrSprite->mpSprite.lock() );
307 if( pCurrSprite )
309 // only copy still valid sprites over to the refreshed
310 // sprite vector.
311 aValidSprites.push_back( *aCurrSprite );
313 pCurrSprite->setPriority(
314 getSpritePriority( aValidSprites.size()-1 ));
317 ++aCurrSprite;
320 // replace sprite list with pruned one
321 maSprites.swap( aValidSprites );
324 public:
325 LayerSpriteContainer() :
326 maSprites(),
327 maLayerPrioRange()
331 basegfx::B1DRange getLayerPriority() const
333 return maLayerPrioRange;
336 void setLayerPriority( const basegfx::B1DRange& rRange )
338 if( rRange != maLayerPrioRange )
340 maLayerPrioRange = rRange;
342 // prune and recalc sprite prios
343 updateSprites();
347 void addSprite( const cppcanvas::CustomSpriteSharedPtr& pSprite,
348 double nPriority )
350 if( !pSprite )
351 return;
353 SpriteEntry aEntry( pSprite,nPriority );
355 // insert new sprite, such that vector stays sorted
356 SpriteVector::iterator aInsertPos(
357 maSprites.insert(
358 std::lower_bound( maSprites.begin(),
359 maSprites.end(),
360 aEntry ),
361 aEntry ));
363 const std::size_t nNumSprites( maSprites.size() );
364 if( nNumSprites > SPRITE_ULLAGE ||
365 maSprites.end() - aInsertPos > 1 )
367 // updateSprites() also updates all sprite prios
368 updateSprites();
370 else
372 // added sprite to the end, and not too many sprites in
373 // vector - perform optimized update (only need to set
374 // prio). This basically caters for the common case of
375 // iterated character animations, which generate lots of
376 // sprites, all added to the end.
377 pSprite->setPriority(
378 getSpritePriority( nNumSprites-1 ));
382 void clear()
384 maSprites.clear();
389 // ----------------------------------------------------------------
392 /** This class provides layers for a slide view
394 Layers are used to render animations with the correct z order -
395 because sprites are always in front of the static canvas
396 background, shapes that must appear <em<before</em> an animation
397 must also be displayed as a sprite.
399 Each layer has a priority assigned to it (valid range [0,1]), which
400 also affects all sprites created for this specific layer - i.e. if
401 the layer priority changes, the sprites change z order together
402 with their parent.
404 class SlideViewLayer : public ViewLayer,
405 private boost::noncopyable
407 /// Smart container for all sprites issued by this layer
408 mutable LayerSpriteContainer maSpriteContainer;
410 /// Bounds of this layer in user space coordinates
411 basegfx::B2DRange maLayerBounds;
413 /// Bounds of this layer in device pixel
414 mutable basegfx::B2IRange maLayerBoundsPixel;
416 /// Current clip polygon in user coordinates
417 basegfx::B2DPolyPolygon maClip;
419 /// Current size of the view in user coordinates
420 basegfx::B2DSize maUserSize;
422 /// Current overall view transformation
423 basegfx::B2DHomMatrix maTransformation;
425 /// 'parent' canvas, this viewlayer is associated with
426 const cppcanvas::SpriteCanvasSharedPtr mpSpriteCanvas;
428 /** output surface (necessarily a sprite, won't otherwise be able
429 to display anything <em>before</em> other sprites)
431 mutable cppcanvas::CustomSpriteSharedPtr mpSprite;
433 /// actual output canvas retrieved from a sprite
434 mutable cppcanvas::CanvasSharedPtr mpOutputCanvas;
436 /// ptr back to owning view. needed for isOnView() method
437 View const* const mpParentView;
439 public:
440 /** Create a new layer
442 @param pCanvas
443 Sprite canvas to create the layer on
445 @param rTransform
446 Initial overall canvas transformation
448 @param rLayerBounds
449 Initial layer bounds, in view coordinate system
451 SlideViewLayer( const cppcanvas::SpriteCanvasSharedPtr& pCanvas,
452 const basegfx::B2DHomMatrix& rTransform,
453 const basegfx::B2DRange& rLayerBounds,
454 const basegfx::B2DSize& rUserSize,
455 View const* const pParentView) :
456 maSpriteContainer(),
457 maLayerBounds(rLayerBounds),
458 maLayerBoundsPixel(),
459 maClip(),
460 maUserSize(rUserSize),
461 maTransformation(rTransform),
462 mpSpriteCanvas(pCanvas),
463 mpSprite(),
464 mpOutputCanvas(),
465 mpParentView(pParentView)
469 void updateView( const basegfx::B2DHomMatrix& rMatrix,
470 const basegfx::B2DSize& rUserSize )
472 maTransformation = rMatrix;
473 maUserSize = rUserSize;
475 // limit layer bounds to visible screen
476 maLayerBounds.intersect( basegfx::B2DRange(0.0,
477 0.0,
478 maUserSize.getX(),
479 maUserSize.getY()) );
481 basegfx::B2IRange const& rNewLayerPixel(
482 getLayerBoundsPixel(maLayerBounds,
483 maTransformation) );
484 if( rNewLayerPixel != maLayerBoundsPixel )
486 // re-gen sprite with new size
487 mpOutputCanvas.reset();
488 mpSprite.reset();
492 private:
493 // ViewLayer interface
494 // ----------------------------------------------
496 virtual cppcanvas::CustomSpriteSharedPtr createSprite(
497 const ::basegfx::B2DSize& rSpriteSizePixel,
498 double nPriority ) const
500 cppcanvas::CustomSpriteSharedPtr pSprite(
501 mpSpriteCanvas->createCustomSprite( rSpriteSizePixel ) );
503 maSpriteContainer.addSprite( pSprite,
504 nPriority );
506 return pSprite;
509 virtual void setPriority( const basegfx::B1DRange& rRange )
511 OSL_ENSURE( !rRange.isEmpty() &&
512 rRange.getMinimum() >= 1.0,
513 "SlideViewLayer::setPriority(): prio MUST be larger than 1.0 (because "
514 "the background layer already lies there)" );
516 maSpriteContainer.setLayerPriority( rRange );
518 if( mpSprite )
519 mpSprite->setPriority( rRange.getMinimum() );
522 virtual basegfx::B2DHomMatrix getTransformation() const
524 // Offset given transformation by left, top border of given
525 // range (after transformation through given transformation)
526 basegfx::B2DRectangle aTmpRect;
527 canvas::tools::calcTransformedRectBounds( aTmpRect,
528 maLayerBounds,
529 maTransformation );
531 basegfx::B2DHomMatrix aMatrix( maTransformation );
533 // Add translation according to the origin of aTmpRect. Ignore the
534 // translation when aTmpRect was not properly initialized.
535 if ( ! aTmpRect.isEmpty())
537 aMatrix.translate( -basegfx::fround(aTmpRect.getMinX()),
538 -basegfx::fround(aTmpRect.getMinY()) );
541 return aMatrix;
544 virtual basegfx::B2DHomMatrix getSpriteTransformation() const
546 return maTransformation;
549 virtual void clear() const
551 // grab canvas - that also lazy-initializes maLayerBoundsPixel
552 cppcanvas::CanvasSharedPtr pCanvas=getCanvas()->clone();
554 // clear whole canvas
555 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
556 clearRect(pCanvas,
557 basegfx::B2IRange(0,0,rSpriteSize.getX(),rSpriteSize.getY()));
560 virtual void clearAll() const
562 // grab canvas - that also lazy-initializes maLayerBoundsPixel
563 ::cppcanvas::CanvasSharedPtr pCanvas( getCanvas()->clone() );
565 // clear layer clip, to clear whole area
566 pCanvas->setClip();
568 // clear whole canvas
569 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
570 clearRect(pCanvas,
571 basegfx::B2IRange(0,0,rSpriteSize.getX(),rSpriteSize.getY()));
574 virtual bool isOnView(boost::shared_ptr<View> const& rView) const
576 return rView.get() == mpParentView;
579 virtual cppcanvas::CanvasSharedPtr getCanvas() const
581 if( !mpOutputCanvas )
583 if( !mpSprite )
585 maLayerBoundsPixel = getLayerBoundsPixel(maLayerBounds,
586 maTransformation);
588 // HACK: ensure at least 1x1 pixel size. clients might
589 // need an actual canvas (e.g. for bound rect
590 // calculations) without rendering anything. Better
591 // solution: introduce something like a reference
592 // canvas for ViewLayers, which is always available.
593 if( maLayerBoundsPixel.isEmpty() )
594 maLayerBoundsPixel = basegfx::B2IRange(0,0,1,1);
596 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
597 mpSprite = mpSpriteCanvas->createCustomSprite(
598 basegfx::B2DVector(sal::static_int_cast<sal_Int32>(rSpriteSize.getX()),
599 sal::static_int_cast<sal_Int32>(rSpriteSize.getY())) );
601 mpSprite->setPriority(
602 maSpriteContainer.getLayerPriority().getMinimum() );
604 #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
605 mpSprite->movePixel(
606 basegfx::B2DPoint(maLayerBoundsPixel.getMinimum()) +
607 basegfx::B2DPoint(10,10) );
609 mpSprite->setAlpha(0.5);
610 #else
611 mpSprite->movePixel(
612 basegfx::B2DPoint(maLayerBoundsPixel.getMinimum()) );
614 mpSprite->setAlpha(1.0);
615 #endif
616 mpSprite->show();
619 ENSURE_OR_THROW( mpSprite,
620 "SlideViewLayer::getCanvas(): no layer sprite" );
622 mpOutputCanvas = mpSprite->getContentCanvas();
624 ENSURE_OR_THROW( mpOutputCanvas,
625 "SlideViewLayer::getCanvas(): sprite doesn't yield a canvas" );
627 // new canvas retrieved - setup transformation and clip
628 mpOutputCanvas->setTransformation( getTransformation() );
629 mpOutputCanvas->setClip(
630 createClipPolygon( maClip,
631 mpOutputCanvas,
632 maUserSize ));
635 return mpOutputCanvas;
638 virtual void setClip( const basegfx::B2DPolyPolygon& rClip )
640 basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
642 if( aNewClip != maClip )
644 maClip = aNewClip;
646 if(mpOutputCanvas )
647 mpOutputCanvas->setClip(
648 createClipPolygon( maClip,
649 mpOutputCanvas,
650 maUserSize ));
654 virtual bool resize( const ::basegfx::B2DRange& rArea )
656 const bool bRet( maLayerBounds != rArea );
657 maLayerBounds = rArea;
658 updateView( maTransformation,
659 maUserSize );
661 return bRet;
666 // ---------------------------------------------------------
668 typedef cppu::WeakComponentImplHelper2<
669 ::com::sun::star::util::XModifyListener,
670 ::com::sun::star::awt::XPaintListener> SlideViewBase;
672 /** SlideView class
674 This class implements the View interface, encapsulating
675 <em>one</em> view a slideshow is displayed on.
677 class SlideView : private cppu::BaseMutex,
678 public SlideViewBase,
679 public UnoView
681 public:
682 SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
683 EventQueue& rEventQueue,
684 EventMultiplexer& rEventMultiplexer );
685 void updateCanvas();
687 private:
688 // View:
689 virtual ViewLayerSharedPtr createViewLayer( const basegfx::B2DRange& rLayerBounds ) const;
690 virtual bool updateScreen() const;
691 virtual bool paintScreen() const;
692 virtual void setViewSize( const ::basegfx::B2DSize& );
693 virtual void setCursorShape( sal_Int16 nPointerShape );
695 // ViewLayer interface
696 virtual bool isOnView(boost::shared_ptr<View> const& rView) const;
697 virtual void clear() const;
698 virtual void clearAll() const;
699 virtual cppcanvas::CanvasSharedPtr getCanvas() const;
700 virtual cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& rSpriteSizePixel,
701 double nPriority ) const;
702 virtual void setPriority( const basegfx::B1DRange& rRange );
703 virtual ::basegfx::B2DHomMatrix getTransformation() const;
704 virtual basegfx::B2DHomMatrix getSpriteTransformation() const;
705 virtual void setClip( const ::basegfx::B2DPolyPolygon& rClip );
706 virtual bool resize( const ::basegfx::B2DRange& rArea );
708 // UnoView:
709 virtual void _dispose();
710 virtual uno::Reference<presentation::XSlideShowView> getUnoView()const;
711 virtual void setIsSoundEnabled (const bool bValue);
712 virtual bool isSoundEnabled (void) const;
714 // XEventListener:
715 virtual void SAL_CALL disposing( lang::EventObject const& evt )
716 throw (uno::RuntimeException);
717 // XModifyListener:
718 virtual void SAL_CALL modified( const lang::EventObject& aEvent )
719 throw (uno::RuntimeException);
720 // XPaintListener:
721 virtual void SAL_CALL windowPaint( const awt::PaintEvent& e )
722 throw (uno::RuntimeException);
724 // WeakComponentImplHelperBase:
725 virtual void SAL_CALL disposing();
727 void updateClip();
729 private:
730 typedef std::vector< boost::weak_ptr<SlideViewLayer> > ViewLayerVector;
732 /// Prune viewlayers from deceased ones, optionally update them
733 void pruneLayers( bool bWithViewLayerUpdate=false ) const;
735 /** Max fill level of maViewLayers, before we try to prune it from
736 deceased layers
738 enum{ LAYER_ULLAGE=8 };
740 uno::Reference<presentation::XSlideShowView> mxView;
741 cppcanvas::SpriteCanvasSharedPtr mpCanvas;
743 EventMultiplexer& mrEventMultiplexer;
744 EventQueue& mrEventQueue;
746 mutable LayerSpriteContainer maSprites;
747 mutable ViewLayerVector maViewLayers;
749 basegfx::B2DPolyPolygon maClip;
751 basegfx::B2DHomMatrix maViewTransform;
752 basegfx::B2DSize maUserSize;
753 bool mbIsSoundEnabled;
757 SlideView::SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
758 EventQueue& rEventQueue,
759 EventMultiplexer& rEventMultiplexer ) :
760 SlideViewBase( m_aMutex ),
761 mxView( xView ),
762 mpCanvas(),
763 mrEventMultiplexer( rEventMultiplexer ),
764 mrEventQueue( rEventQueue ),
765 maSprites(),
766 maViewLayers(),
767 maClip(),
768 maViewTransform(),
769 maUserSize( 1.0, 1.0 ), // default size: one-by-one rectangle
770 mbIsSoundEnabled(true)
772 // take care not constructing any UNO references to this _inside_
773 // ctor, shift that code to createSlideView()!
774 ENSURE_OR_THROW( mxView.is(),
775 "SlideView::SlideView(): Invalid view" );
777 mpCanvas = cppcanvas::VCLFactory::getInstance().createSpriteCanvas(
778 xView->getCanvas() );
779 ENSURE_OR_THROW( mpCanvas,
780 "Could not create cppcanvas" );
782 geometry::AffineMatrix2D aViewTransform(
783 xView->getTransformation() );
785 if( basegfx::fTools::equalZero(
786 basegfx::B2DVector(aViewTransform.m00,
787 aViewTransform.m10).getLength()) ||
788 basegfx::fTools::equalZero(
789 basegfx::B2DVector(aViewTransform.m01,
790 aViewTransform.m11).getLength()) )
792 OSL_FAIL( "SlideView::SlideView(): Singular matrix!" );
794 canvas::tools::setIdentityAffineMatrix2D(aViewTransform);
797 basegfx::unotools::homMatrixFromAffineMatrix(
798 maViewTransform, aViewTransform );
800 // once and forever: set fixed prio to this 'layer' (we're always
801 // the background layer)
802 maSprites.setLayerPriority( basegfx::B1DRange(0.0,1.0) );
805 void SlideView::disposing()
807 osl::MutexGuard aGuard( m_aMutex );
809 maViewLayers.clear();
810 maSprites.clear();
811 mpCanvas.reset();
813 // additionally, also de-register from XSlideShowView
814 if (mxView.is())
816 mxView->removeTransformationChangedListener( this );
817 mxView->removePaintListener( this );
818 mxView.clear();
822 ViewLayerSharedPtr SlideView::createViewLayer( const basegfx::B2DRange& rLayerBounds ) const
824 osl::MutexGuard aGuard( m_aMutex );
826 ENSURE_OR_THROW( mpCanvas,
827 "SlideView::createViewLayer(): Disposed" );
829 const std::size_t nNumLayers( maViewLayers.size() );
831 // avoid filling up layer vector with lots of deceased layer weak
832 // ptrs
833 if( nNumLayers > LAYER_ULLAGE )
834 pruneLayers();
836 boost::shared_ptr<SlideViewLayer> pViewLayer( new SlideViewLayer(mpCanvas,
837 getTransformation(),
838 rLayerBounds,
839 maUserSize,
840 this) );
841 maViewLayers.push_back( pViewLayer );
843 return pViewLayer;
846 bool SlideView::updateScreen() const
848 osl::MutexGuard aGuard( m_aMutex );
850 ENSURE_OR_RETURN_FALSE( mpCanvas.get(),
851 "SlideView::updateScreen(): Disposed" );
853 return mpCanvas->updateScreen( false );
856 bool SlideView::paintScreen() const
858 osl::MutexGuard aGuard( m_aMutex );
860 ENSURE_OR_RETURN_FALSE( mpCanvas.get(),
861 "SlideView::paintScreen(): Disposed" );
863 return mpCanvas->updateScreen( true );
866 void SlideView::clear() const
868 osl::MutexGuard aGuard( m_aMutex );
870 OSL_ENSURE( mxView.is() && mpCanvas,
871 "SlideView::clear(): Disposed" );
872 if( !mxView.is() || !mpCanvas )
873 return;
875 // keep layer clip
876 clearRect(getCanvas()->clone(),
877 getLayerBoundsPixel(
878 basegfx::B2DRange(0,0,
879 maUserSize.getX(),
880 maUserSize.getY()),
881 getTransformation()));
884 void SlideView::clearAll() const
886 osl::MutexGuard aGuard( m_aMutex );
888 OSL_ENSURE( mxView.is() && mpCanvas,
889 "SlideView::clear(): Disposed" );
890 if( !mxView.is() || !mpCanvas )
891 return;
893 // clear whole view
894 mxView->clear();
897 void SlideView::setViewSize( const basegfx::B2DSize& rSize )
899 osl::MutexGuard aGuard( m_aMutex );
901 maUserSize = rSize;
902 updateCanvas();
905 void SlideView::setCursorShape( sal_Int16 nPointerShape )
907 osl::MutexGuard const guard( m_aMutex );
909 if (mxView.is())
910 mxView->setMouseCursor( nPointerShape );
913 bool SlideView::isOnView(boost::shared_ptr<View> const& rView) const
915 return rView.get() == this;
918 cppcanvas::CanvasSharedPtr SlideView::getCanvas() const
920 osl::MutexGuard aGuard( m_aMutex );
922 ENSURE_OR_THROW( mpCanvas,
923 "SlideView::getCanvas(): Disposed" );
925 return mpCanvas;
928 cppcanvas::CustomSpriteSharedPtr SlideView::createSprite(
929 const basegfx::B2DSize& rSpriteSizePixel,
930 double nPriority ) const
932 osl::MutexGuard aGuard( m_aMutex );
934 ENSURE_OR_THROW( mpCanvas, "SlideView::createSprite(): Disposed" );
936 cppcanvas::CustomSpriteSharedPtr pSprite(
937 mpCanvas->createCustomSprite( rSpriteSizePixel ) );
939 maSprites.addSprite( pSprite,
940 nPriority );
942 return pSprite;
945 void SlideView::setPriority( const basegfx::B1DRange& /*rRange*/ )
947 osl::MutexGuard aGuard( m_aMutex );
949 OSL_FAIL( "SlideView::setPriority() is a NOOP for slide view - "
950 "content will always be shown in the background" );
953 basegfx::B2DHomMatrix SlideView::getTransformation() const
955 osl::MutexGuard aGuard( m_aMutex );
957 basegfx::B2DHomMatrix aMatrix;
958 aMatrix.scale( 1.0/maUserSize.getX(), 1.0/maUserSize.getY() );
960 return maViewTransform * aMatrix;
963 basegfx::B2DHomMatrix SlideView::getSpriteTransformation() const
965 return getTransformation();
968 void SlideView::setClip( const basegfx::B2DPolyPolygon& rClip )
970 osl::MutexGuard aGuard( m_aMutex );
972 basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
974 if( aNewClip != maClip )
976 maClip = aNewClip;
978 updateClip();
982 bool SlideView::resize( const ::basegfx::B2DRange& /*rArea*/ )
984 osl::MutexGuard aGuard( m_aMutex );
986 OSL_FAIL( "SlideView::resize(): ignored for the View, can't change size "
987 "effectively, anyway" );
989 return false;
992 uno::Reference<presentation::XSlideShowView> SlideView::getUnoView() const
994 osl::MutexGuard aGuard( m_aMutex );
995 return mxView;
998 void SlideView::setIsSoundEnabled (const bool bValue)
1000 mbIsSoundEnabled = bValue;
1003 bool SlideView::isSoundEnabled (void) const
1005 return mbIsSoundEnabled;
1008 void SlideView::_dispose()
1010 dispose();
1013 // XEventListener
1014 void SlideView::disposing( lang::EventObject const& evt )
1015 throw (uno::RuntimeException)
1017 (void)evt;
1019 // no deregistration necessary anymore, XView has left:
1020 osl::MutexGuard const guard( m_aMutex );
1022 if (mxView.is())
1024 OSL_ASSERT( evt.Source == mxView );
1025 mxView.clear();
1028 dispose();
1031 // XModifyListener
1032 void SlideView::modified( const lang::EventObject& /*aEvent*/ )
1033 throw (uno::RuntimeException)
1035 osl::MutexGuard const guard( m_aMutex );
1037 OSL_ENSURE( mxView.is(), "SlideView::modified(): "
1038 "Disposed, but event received from XSlideShowView?!");
1040 if( !mxView.is() )
1041 return;
1043 geometry::AffineMatrix2D aViewTransform(
1044 mxView->getTransformation() );
1046 if( basegfx::fTools::equalZero(
1047 basegfx::B2DVector(aViewTransform.m00,
1048 aViewTransform.m10).getLength()) ||
1049 basegfx::fTools::equalZero(
1050 basegfx::B2DVector(aViewTransform.m01,
1051 aViewTransform.m11).getLength()) )
1053 OSL_FAIL( "SlideView::modified(): Singular matrix!" );
1055 canvas::tools::setIdentityAffineMatrix2D(aViewTransform);
1058 // view transformation really changed?
1059 basegfx::B2DHomMatrix aNewTransform;
1060 basegfx::unotools::homMatrixFromAffineMatrix(
1061 aNewTransform,
1062 aViewTransform );
1064 if( aNewTransform == maViewTransform )
1065 return; // No change, nothing to do
1067 maViewTransform = aNewTransform;
1069 updateCanvas();
1071 // notify view change. Don't call EventMultiplexer directly, this
1072 // might not be the main thread!
1073 mrEventQueue.addEvent(
1074 makeEvent( boost::bind( (bool (EventMultiplexer::*)(
1075 const uno::Reference<presentation::XSlideShowView>&))
1076 &EventMultiplexer::notifyViewChanged,
1077 boost::ref(mrEventMultiplexer), mxView ),
1078 "EventMultiplexer::notifyViewChanged"));
1081 // XPaintListener
1082 void SlideView::windowPaint( const awt::PaintEvent& /*e*/ )
1083 throw (uno::RuntimeException)
1085 osl::MutexGuard aGuard( m_aMutex );
1087 OSL_ENSURE( mxView.is() && mpCanvas, "Disposed, but event received?!" );
1089 // notify view clobbering. Don't call EventMultiplexer directly,
1090 // this might not be the main thread!
1091 mrEventQueue.addEvent(
1092 makeEvent( boost::bind( &EventMultiplexer::notifyViewClobbered,
1093 boost::ref(mrEventMultiplexer), mxView ),
1094 "EventMultiplexer::notifyViewClobbered") );
1097 void SlideView::updateCanvas()
1099 OSL_ENSURE( mpCanvas,
1100 "SlideView::updateCanvasTransform(): Disposed" );
1102 if( !mpCanvas || !mxView.is())
1103 return;
1105 mpCanvas->clear(); // this is unnecessary, strictly speaking. but
1106 // it makes the SlideView behave exactly like a
1107 // sprite-based SlideViewLayer, because those
1108 // are created from scratch after a resize
1109 clearAll();
1110 mpCanvas->setTransformation( getTransformation() );
1111 mpCanvas->setClip(
1112 createClipPolygon( maClip,
1113 mpCanvas,
1114 maUserSize ));
1116 // forward update to viewlayers
1117 pruneLayers( true );
1120 void SlideView::updateClip()
1122 OSL_ENSURE( mpCanvas,
1123 "SlideView::updateClip(): Disposed" );
1125 if( !mpCanvas )
1126 return;
1128 mpCanvas->setClip(
1129 createClipPolygon( maClip,
1130 mpCanvas,
1131 maUserSize ));
1133 pruneLayers( false );
1136 void SlideView::pruneLayers( bool bWithViewLayerUpdate ) const
1138 ViewLayerVector aValidLayers;
1140 const basegfx::B2DHomMatrix& rCurrTransform(
1141 getTransformation() );
1143 // check all layers for validity, and retain only the live ones
1144 ViewLayerVector::const_iterator aCurr( maViewLayers.begin() );
1145 const ViewLayerVector::const_iterator aEnd( maViewLayers.end() );
1146 while( aCurr != aEnd )
1148 boost::shared_ptr< SlideViewLayer > pCurrLayer( aCurr->lock() );
1150 if( pCurrLayer )
1152 aValidLayers.push_back( pCurrLayer );
1154 if( bWithViewLayerUpdate )
1155 pCurrLayer->updateView( rCurrTransform,
1156 maUserSize );
1159 ++aCurr;
1162 // replace layer list with pruned one
1163 maViewLayers.swap( aValidLayers );
1166 } // anonymous namespace
1168 UnoViewSharedPtr createSlideView( uno::Reference< presentation::XSlideShowView> const& xView,
1169 EventQueue& rEventQueue,
1170 EventMultiplexer& rEventMultiplexer )
1172 boost::shared_ptr<SlideView> const that(
1173 comphelper::make_shared_from_UNO(
1174 new SlideView(xView,
1175 rEventQueue,
1176 rEventMultiplexer)));
1178 // register listeners with XSlideShowView
1179 xView->addTransformationChangedListener( that.get() );
1180 xView->addPaintListener( that.get() );
1182 // set new transformation
1183 that->updateCanvas();
1185 return that;
1188 } // namespace internal
1189 } // namespace slideshow
1191 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */