fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / slideshow / source / engine / slideview.cxx
blob04170a72cc1bbaa95f56ffd6cc717d29dac9e861
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 <cppuhelper/basemutex.hxx>
31 #include <cppuhelper/compbase2.hxx>
32 #include <cppuhelper/implementationentry.hxx>
33 #include <cppuhelper/interfacecontainer.h>
34 #include <comphelper/make_shared_from_uno.hxx>
36 #include <cppcanvas/spritecanvas.hxx>
37 #include <cppcanvas/customsprite.hxx>
38 #include <cppcanvas/vclfactory.hxx>
39 #include <cppcanvas/basegfxfactory.hxx>
41 #include <basegfx/range/b1drange.hxx>
42 #include <basegfx/range/b2drange.hxx>
43 #include <basegfx/range/b2irange.hxx>
44 #include <basegfx/point/b2dpoint.hxx>
45 #include <basegfx/polygon/b2dpolygon.hxx>
46 #include <basegfx/matrix/b2dhommatrix.hxx>
47 #include <basegfx/polygon/b2dpolygontools.hxx>
48 #include <basegfx/polygon/b2dpolypolygontools.hxx>
49 #include <basegfx/tools/canvastools.hxx>
50 #include <basegfx/polygon/b2dpolygonclipper.hxx>
51 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
53 #include <com/sun/star/presentation/XSlideShow.hpp>
55 #include <boost/noncopyable.hpp>
56 #include <boost/bind.hpp>
57 #include <boost/weak_ptr.hpp>
59 #include <vector>
60 #include <iterator>
61 #include <algorithm>
63 using namespace com::sun::star;
65 namespace slideshow {
66 namespace internal {
68 namespace {
70 /** Sprite entry, to store sprite plus priority
72 The operator<() defines a strict weak ordering of sprites, sort
73 key is the sprite priority.
75 struct SpriteEntry
77 SpriteEntry( const cppcanvas::CustomSpriteSharedPtr& rSprite,
78 double nPrio ) :
79 mpSprite( rSprite ),
80 mnPriority( nPrio )
84 bool operator<(const SpriteEntry& rRHS) const
86 return mnPriority < rRHS.mnPriority;
89 boost::weak_ptr< cppcanvas::CustomSprite > mpSprite;
90 double mnPriority;
93 typedef std::vector< SpriteEntry > SpriteVector;
96 /** Create a clip polygon for slide views
98 @param rClip
99 Clip to set (can be empty)
101 @param rCanvas
102 Canvas to create the clip polygon for
104 @param rUserSize
105 The size of the view. Note that the returned clip will
106 <em>always</em> clip to at least the rect defined herein.
108 @return the view clip polygon, in view coordinates, which is
109 guaranteed to at least clip to the view size.
111 basegfx::B2DPolyPolygon createClipPolygon( const basegfx::B2DPolyPolygon& rClip,
112 const cppcanvas::CanvasSharedPtr& /*rCanvas*/,
113 const basegfx::B2DSize& rUserSize )
115 // setup canvas clipping
116 // =====================
118 // AW: Simplified
119 const basegfx::B2DRange aClipRange(0, 0, rUserSize.getX(), rUserSize.getY());
121 if(rClip.count())
123 return basegfx::tools::clipPolyPolygonOnRange(rClip, aClipRange, true, false);
125 else
127 return basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aClipRange));
131 /** Prepare given clip polygon to be stored as the current clip
133 Note that this is separate from createClipPolygon(), to allow
134 SlideView implementations to store this intermediate result
135 (createClipPolygon() has to be called every time the view size
136 changes)
138 basegfx::B2DPolyPolygon prepareClip( const basegfx::B2DPolyPolygon& rClip )
140 basegfx::B2DPolyPolygon aClip( rClip );
142 // TODO(P2): unnecessary, once XCanvas is correctly handling this
143 // AW: Should be no longer necessary; tools are now bezier-safe
144 if( aClip.areControlPointsUsed() )
145 aClip = basegfx::tools::adaptiveSubdivideByAngle( aClip );
147 // normalize polygon, preparation for clipping
148 // in updateCanvas()
149 aClip = basegfx::tools::correctOrientations(aClip);
150 aClip = basegfx::tools::solveCrossovers(aClip);
151 aClip = basegfx::tools::stripNeutralPolygons(aClip);
152 aClip = basegfx::tools::stripDispensablePolygons(aClip, false);
154 return aClip;
158 void clearRect( ::cppcanvas::CanvasSharedPtr const& pCanvas,
159 basegfx::B2IRange const& rArea )
161 // convert clip polygon to device coordinate system
162 ::basegfx::B2DPolyPolygon const* pClipPoly( pCanvas->getClip() );
163 if( pClipPoly )
165 ::basegfx::B2DPolyPolygon aClipPoly( *pClipPoly );
166 aClipPoly.transform( pCanvas->getTransformation() );
167 pCanvas->setClip( aClipPoly );
170 // set transformation to identitiy (->device pixel)
171 pCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
173 // #i42440# Fill the _full_ background in
174 // black. Since we had to extend the bitmap by one
175 // pixel, and the bitmap is initialized white,
176 // depending on the slide content a one pixel wide
177 // line will show to the bottom and the right.
178 const ::basegfx::B2DPolygon aPoly(
179 ::basegfx::tools::createPolygonFromRect(
180 basegfx::B2DRange(rArea)));
182 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
183 ::cppcanvas::BaseGfxFactory::createPolyPolygon( pCanvas, aPoly ) );
185 if( pPolyPoly )
187 pPolyPoly->setCompositeOp( cppcanvas::CanvasGraphic::SOURCE );
188 pPolyPoly->setRGBAFillColor( 0xFFFFFF00U );
189 pPolyPoly->draw();
192 #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
193 ::cppcanvas::CanvasSharedPtr pCliplessCanvas( pCanvas->clone() );
194 pCliplessCanvas->setClip();
196 if( pCanvas->getClip() )
198 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly2(
199 ::cppcanvas::BaseGfxFactory::createPolyPolygon( pCliplessCanvas, aPoly ));
200 if( pPolyPoly2 )
202 pPolyPoly2->setRGBALineColor( 0x008000FFU );
203 pPolyPoly2->draw();
206 #endif
209 /** Get bounds in pixel
211 @param rLayerBounds
212 Bound rect, in user space coordinates
214 @param rTransformation
215 User space to device pixel transformation
217 @return the layer bounds in pixel, extended by one pixel to the
218 right and bottom
220 basegfx::B2IRange getLayerBoundsPixel( basegfx::B2DRange const& rLayerBounds,
221 basegfx::B2DHomMatrix const& rTransformation )
223 ::basegfx::B2DRange aTmpRect;
224 ::canvas::tools::calcTransformedRectBounds( aTmpRect,
225 rLayerBounds,
226 rTransformation );
228 if( aTmpRect.isEmpty() )
229 return ::basegfx::B2IRange();
231 // #i42440# Returned layer size is one pixel too small, as
232 // rendering happens one pixel to the right and below the
233 // actual bound rect.
234 return ::basegfx::B2IRange( ::basegfx::fround(aTmpRect.getMinX()),
235 ::basegfx::fround(aTmpRect.getMinY()),
236 ::basegfx::fround(aTmpRect.getMaxX()) + 1,
237 ::basegfx::fround(aTmpRect.getMaxY()) + 1 );
243 /** Container class for sprites issued by a ViewLayer
245 This class handles the sprite prioritization issues, that are
246 needed for layer sprites (e.g. the need to re-prioritize sprites
247 when the layer changes prio).
249 class LayerSpriteContainer
251 /** Max fill level of maSprites, before we try to prune it from
252 deceased sprites
254 enum{ SPRITE_ULLAGE=256 };
256 /** All sprites that have been issued by this container (pruned
257 from time to time, for invalid references). This vector is
258 kept sorted with increasing sprite priority.
260 SpriteVector maSprites;
262 /// Priority of this layer, relative to other view layers
263 basegfx::B1DRange maLayerPrioRange;
265 double getSpritePriority( std::size_t nSpriteNum ) const
267 // divide the available layer range equally between all
268 // sprites, assign upper bound of individual sprite range as
269 // sprite prio (the layer itself gets assigned the lower bound
270 // of sprite 0's individual range):
272 // | layer 0 | layer 1 | ...
273 // | sprite 0 | sprite 1 | sprite 0 | sprite 1 | ...
274 return maLayerPrioRange.getMinimum() + maLayerPrioRange.getRange()*(nSpriteNum+1)/(maSprites.size()+1);
277 /** Rescan sprite vector, and remove deceased sprites (and reset
278 sprite prio)
280 @param aBegin
281 Iterator to the first entry to rescan
283 void updateSprites()
285 SpriteVector aValidSprites;
287 // check all sprites for validity and set new priority
288 SpriteVector::iterator aCurrSprite( maSprites.begin() );
289 const SpriteVector::iterator aEnd( maSprites.end() );
290 while( aCurrSprite != aEnd )
292 cppcanvas::CustomSpriteSharedPtr pCurrSprite( aCurrSprite->mpSprite.lock() );
294 if( pCurrSprite )
296 // only copy still valid sprites over to the refreshed
297 // sprite vector.
298 aValidSprites.push_back( *aCurrSprite );
300 pCurrSprite->setPriority(
301 getSpritePriority( aValidSprites.size()-1 ));
304 ++aCurrSprite;
307 // replace sprite list with pruned one
308 maSprites.swap( aValidSprites );
311 public:
312 LayerSpriteContainer() :
313 maSprites(),
314 maLayerPrioRange()
318 basegfx::B1DRange getLayerPriority() const
320 return maLayerPrioRange;
323 void setLayerPriority( const basegfx::B1DRange& rRange )
325 if( rRange != maLayerPrioRange )
327 maLayerPrioRange = rRange;
329 // prune and recalc sprite prios
330 updateSprites();
334 void addSprite( const cppcanvas::CustomSpriteSharedPtr& pSprite,
335 double nPriority )
337 if( !pSprite )
338 return;
340 SpriteEntry aEntry( pSprite,nPriority );
342 // insert new sprite, such that vector stays sorted
343 SpriteVector::iterator aInsertPos(
344 maSprites.insert(
345 std::lower_bound( maSprites.begin(),
346 maSprites.end(),
347 aEntry ),
348 aEntry ));
350 const std::size_t nNumSprites( maSprites.size() );
351 if( nNumSprites > SPRITE_ULLAGE ||
352 maSprites.end() - aInsertPos > 1 )
354 // updateSprites() also updates all sprite prios
355 updateSprites();
357 else
359 // added sprite to the end, and not too many sprites in
360 // vector - perform optimized update (only need to set
361 // prio). This basically caters for the common case of
362 // iterated character animations, which generate lots of
363 // sprites, all added to the end.
364 pSprite->setPriority(
365 getSpritePriority( nNumSprites-1 ));
369 void clear()
371 maSprites.clear();
379 /** This class provides layers for a slide view
381 Layers are used to render animations with the correct z order -
382 because sprites are always in front of the static canvas
383 background, shapes that must appear <em<before</em> an animation
384 must also be displayed as a sprite.
386 Each layer has a priority assigned to it (valid range [0,1]), which
387 also affects all sprites created for this specific layer - i.e. if
388 the layer priority changes, the sprites change z order together
389 with their parent.
391 class SlideViewLayer : public ViewLayer,
392 private boost::noncopyable
394 /// Smart container for all sprites issued by this layer
395 mutable LayerSpriteContainer maSpriteContainer;
397 /// Bounds of this layer in user space coordinates
398 basegfx::B2DRange maLayerBounds;
400 /// Bounds of this layer in device pixel
401 mutable basegfx::B2IRange maLayerBoundsPixel;
403 /// Current clip polygon in user coordinates
404 basegfx::B2DPolyPolygon maClip;
406 /// Current size of the view in user coordinates
407 basegfx::B2DSize maUserSize;
409 /// Current overall view transformation
410 basegfx::B2DHomMatrix maTransformation;
412 /// 'parent' canvas, this viewlayer is associated with
413 const cppcanvas::SpriteCanvasSharedPtr mpSpriteCanvas;
415 /** output surface (necessarily a sprite, won't otherwise be able
416 to display anything <em>before</em> other sprites)
418 mutable cppcanvas::CustomSpriteSharedPtr mpSprite;
420 /// actual output canvas retrieved from a sprite
421 mutable cppcanvas::CanvasSharedPtr mpOutputCanvas;
423 /// ptr back to owning view. needed for isOnView() method
424 View const* const mpParentView;
426 public:
427 /** Create a new layer
429 @param pCanvas
430 Sprite canvas to create the layer on
432 @param rTransform
433 Initial overall canvas transformation
435 @param rLayerBounds
436 Initial layer bounds, in view coordinate system
438 SlideViewLayer( const cppcanvas::SpriteCanvasSharedPtr& pCanvas,
439 const basegfx::B2DHomMatrix& rTransform,
440 const basegfx::B2DRange& rLayerBounds,
441 const basegfx::B2DSize& rUserSize,
442 View const* const pParentView) :
443 maSpriteContainer(),
444 maLayerBounds(rLayerBounds),
445 maLayerBoundsPixel(),
446 maClip(),
447 maUserSize(rUserSize),
448 maTransformation(rTransform),
449 mpSpriteCanvas(pCanvas),
450 mpSprite(),
451 mpOutputCanvas(),
452 mpParentView(pParentView)
456 void updateView( const basegfx::B2DHomMatrix& rMatrix,
457 const basegfx::B2DSize& rUserSize )
459 maTransformation = rMatrix;
460 maUserSize = rUserSize;
462 // limit layer bounds to visible screen
463 maLayerBounds.intersect( basegfx::B2DRange(0.0,
464 0.0,
465 maUserSize.getX(),
466 maUserSize.getY()) );
468 basegfx::B2IRange const& rNewLayerPixel(
469 getLayerBoundsPixel(maLayerBounds,
470 maTransformation) );
471 if( rNewLayerPixel != maLayerBoundsPixel )
473 // re-gen sprite with new size
474 mpOutputCanvas.reset();
475 mpSprite.reset();
479 virtual ::com::sun::star::geometry::IntegerSize2D getTranslationOffset() const SAL_OVERRIDE
481 basegfx::B2DRectangle aTmpRect;
482 canvas::tools::calcTransformedRectBounds( aTmpRect,
483 maLayerBounds,
484 maTransformation );
485 geometry::IntegerSize2D offset(0, 0);
487 // Add translation according to the origin of aTmpRect. Ignore the
488 // translation when aTmpRect was not properly initialized.
489 if ( ! aTmpRect.isEmpty())
491 offset.Width = basegfx::fround(aTmpRect.getMinX());
492 offset.Height = basegfx::fround(aTmpRect.getMinY());
494 return offset;
497 private:
498 // ViewLayer interface
501 virtual cppcanvas::CustomSpriteSharedPtr createSprite(
502 const ::basegfx::B2DSize& rSpriteSizePixel,
503 double nPriority ) const SAL_OVERRIDE
505 cppcanvas::CustomSpriteSharedPtr pSprite(
506 mpSpriteCanvas->createCustomSprite( rSpriteSizePixel ) );
508 maSpriteContainer.addSprite( pSprite,
509 nPriority );
511 return pSprite;
514 virtual void setPriority( const basegfx::B1DRange& rRange ) SAL_OVERRIDE
516 OSL_ENSURE( !rRange.isEmpty() &&
517 rRange.getMinimum() >= 1.0,
518 "SlideViewLayer::setPriority(): prio MUST be larger than 1.0 (because "
519 "the background layer already lies there)" );
521 maSpriteContainer.setLayerPriority( rRange );
523 if( mpSprite )
524 mpSprite->setPriority( rRange.getMinimum() );
527 virtual basegfx::B2DHomMatrix getTransformation() const SAL_OVERRIDE
529 // Offset given transformation by left, top border of given
530 // range (after transformation through given transformation)
531 basegfx::B2DRectangle aTmpRect;
532 canvas::tools::calcTransformedRectBounds( aTmpRect,
533 maLayerBounds,
534 maTransformation );
536 basegfx::B2DHomMatrix aMatrix( maTransformation );
538 // Add translation according to the origin of aTmpRect. Ignore the
539 // translation when aTmpRect was not properly initialized.
540 if ( ! aTmpRect.isEmpty())
542 aMatrix.translate( -basegfx::fround(aTmpRect.getMinX()),
543 -basegfx::fround(aTmpRect.getMinY()) );
546 return aMatrix;
549 virtual basegfx::B2DHomMatrix getSpriteTransformation() const SAL_OVERRIDE
551 return maTransformation;
554 virtual void clear() const SAL_OVERRIDE
556 // grab canvas - that also lazy-initializes maLayerBoundsPixel
557 cppcanvas::CanvasSharedPtr pCanvas=getCanvas()->clone();
559 // clear whole canvas
560 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
561 clearRect(pCanvas,
562 basegfx::B2IRange(0,0,rSpriteSize.getX(),rSpriteSize.getY()));
565 virtual void clearAll() const SAL_OVERRIDE
567 // grab canvas - that also lazy-initializes maLayerBoundsPixel
568 ::cppcanvas::CanvasSharedPtr pCanvas( getCanvas()->clone() );
570 // clear layer clip, to clear whole area
571 pCanvas->setClip();
573 // clear whole canvas
574 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
575 clearRect(pCanvas,
576 basegfx::B2IRange(0,0,rSpriteSize.getX(),rSpriteSize.getY()));
579 virtual bool isOnView(boost::shared_ptr<View> const& rView) const SAL_OVERRIDE
581 return rView.get() == mpParentView;
584 virtual cppcanvas::CanvasSharedPtr getCanvas() const SAL_OVERRIDE
586 if( !mpOutputCanvas )
588 if( !mpSprite )
590 maLayerBoundsPixel = getLayerBoundsPixel(maLayerBounds,
591 maTransformation);
593 // HACK: ensure at least 1x1 pixel size. clients might
594 // need an actual canvas (e.g. for bound rect
595 // calculations) without rendering anything. Better
596 // solution: introduce something like a reference
597 // canvas for ViewLayers, which is always available.
598 if( maLayerBoundsPixel.isEmpty() )
599 maLayerBoundsPixel = basegfx::B2IRange(0,0,1,1);
601 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
602 mpSprite = mpSpriteCanvas->createCustomSprite(
603 basegfx::B2DVector(sal::static_int_cast<sal_Int32>(rSpriteSize.getX()),
604 sal::static_int_cast<sal_Int32>(rSpriteSize.getY())) );
606 mpSprite->setPriority(
607 maSpriteContainer.getLayerPriority().getMinimum() );
609 #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
610 mpSprite->movePixel(
611 basegfx::B2DPoint(maLayerBoundsPixel.getMinimum()) +
612 basegfx::B2DPoint(10,10) );
614 mpSprite->setAlpha(0.5);
615 #else
616 mpSprite->movePixel(
617 basegfx::B2DPoint(maLayerBoundsPixel.getMinimum()) );
619 mpSprite->setAlpha(1.0);
620 #endif
621 mpSprite->show();
624 ENSURE_OR_THROW( mpSprite,
625 "SlideViewLayer::getCanvas(): no layer sprite" );
627 mpOutputCanvas = mpSprite->getContentCanvas();
629 ENSURE_OR_THROW( mpOutputCanvas,
630 "SlideViewLayer::getCanvas(): sprite doesn't yield a canvas" );
632 // new canvas retrieved - setup transformation and clip
633 mpOutputCanvas->setTransformation( getTransformation() );
634 mpOutputCanvas->setClip(
635 createClipPolygon( maClip,
636 mpOutputCanvas,
637 maUserSize ));
640 return mpOutputCanvas;
643 virtual void setClip( const basegfx::B2DPolyPolygon& rClip ) SAL_OVERRIDE
645 basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
647 if( aNewClip != maClip )
649 maClip = aNewClip;
651 if(mpOutputCanvas )
652 mpOutputCanvas->setClip(
653 createClipPolygon( maClip,
654 mpOutputCanvas,
655 maUserSize ));
659 virtual bool resize( const ::basegfx::B2DRange& rArea ) SAL_OVERRIDE
661 const bool bRet( maLayerBounds != rArea );
662 maLayerBounds = rArea;
663 updateView( maTransformation,
664 maUserSize );
666 return bRet;
673 typedef cppu::WeakComponentImplHelper2<
674 ::com::sun::star::util::XModifyListener,
675 ::com::sun::star::awt::XPaintListener> SlideViewBase;
677 /** SlideView class
679 This class implements the View interface, encapsulating
680 <em>one</em> view a slideshow is displayed on.
682 class SlideView : private cppu::BaseMutex,
683 public SlideViewBase,
684 public UnoView
686 public:
687 SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
688 EventQueue& rEventQueue,
689 EventMultiplexer& rEventMultiplexer );
690 void updateCanvas();
692 private:
693 // View:
694 virtual ViewLayerSharedPtr createViewLayer( const basegfx::B2DRange& rLayerBounds ) const SAL_OVERRIDE;
695 virtual bool updateScreen() const SAL_OVERRIDE;
696 virtual bool paintScreen() const SAL_OVERRIDE;
697 virtual void setViewSize( const ::basegfx::B2DSize& ) SAL_OVERRIDE;
698 virtual void setCursorShape( sal_Int16 nPointerShape ) SAL_OVERRIDE;
700 // ViewLayer interface
701 virtual bool isOnView(boost::shared_ptr<View> const& rView) const SAL_OVERRIDE;
702 virtual void clear() const SAL_OVERRIDE;
703 virtual void clearAll() const SAL_OVERRIDE;
704 virtual cppcanvas::CanvasSharedPtr getCanvas() const SAL_OVERRIDE;
705 virtual cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& rSpriteSizePixel,
706 double nPriority ) const SAL_OVERRIDE;
707 virtual void setPriority( const basegfx::B1DRange& rRange ) SAL_OVERRIDE;
708 virtual geometry::IntegerSize2D getTranslationOffset() const SAL_OVERRIDE;
709 virtual ::basegfx::B2DHomMatrix getTransformation() const SAL_OVERRIDE;
710 virtual basegfx::B2DHomMatrix getSpriteTransformation() const SAL_OVERRIDE;
711 virtual void setClip( const ::basegfx::B2DPolyPolygon& rClip ) SAL_OVERRIDE;
712 virtual bool resize( const ::basegfx::B2DRange& rArea ) SAL_OVERRIDE;
714 // UnoView:
715 virtual void _dispose() SAL_OVERRIDE;
716 virtual uno::Reference<presentation::XSlideShowView> getUnoView()const SAL_OVERRIDE;
717 virtual void setIsSoundEnabled (const bool bValue) SAL_OVERRIDE;
718 virtual bool isSoundEnabled() const SAL_OVERRIDE;
720 // XEventListener:
721 virtual void SAL_CALL disposing( lang::EventObject const& evt )
722 throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
723 // XModifyListener:
724 virtual void SAL_CALL modified( const lang::EventObject& aEvent )
725 throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
726 // XPaintListener:
727 virtual void SAL_CALL windowPaint( const awt::PaintEvent& e )
728 throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
730 // WeakComponentImplHelperBase:
731 virtual void SAL_CALL disposing() SAL_OVERRIDE;
733 void updateClip();
735 private:
736 typedef std::vector< boost::weak_ptr<SlideViewLayer> > ViewLayerVector;
738 /// Prune viewlayers from deceased ones, optionally update them
739 void pruneLayers( bool bWithViewLayerUpdate=false ) const;
741 /** Max fill level of maViewLayers, before we try to prune it from
742 deceased layers
744 enum{ LAYER_ULLAGE=8 };
746 uno::Reference<presentation::XSlideShowView> mxView;
747 cppcanvas::SpriteCanvasSharedPtr mpCanvas;
749 EventMultiplexer& mrEventMultiplexer;
750 EventQueue& mrEventQueue;
752 mutable LayerSpriteContainer maSprites;
753 mutable ViewLayerVector maViewLayers;
755 basegfx::B2DPolyPolygon maClip;
757 basegfx::B2DHomMatrix maViewTransform;
758 basegfx::B2DSize maUserSize;
759 bool mbIsSoundEnabled;
763 SlideView::SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
764 EventQueue& rEventQueue,
765 EventMultiplexer& rEventMultiplexer ) :
766 SlideViewBase( m_aMutex ),
767 mxView( xView ),
768 mpCanvas(),
769 mrEventMultiplexer( rEventMultiplexer ),
770 mrEventQueue( rEventQueue ),
771 maSprites(),
772 maViewLayers(),
773 maClip(),
774 maViewTransform(),
775 maUserSize( 1.0, 1.0 ), // default size: one-by-one rectangle
776 mbIsSoundEnabled(true)
778 // take care not constructing any UNO references to this _inside_
779 // ctor, shift that code to createSlideView()!
780 ENSURE_OR_THROW( mxView.is(),
781 "SlideView::SlideView(): Invalid view" );
783 mpCanvas = cppcanvas::VCLFactory::createSpriteCanvas(
784 xView->getCanvas() );
785 ENSURE_OR_THROW( mpCanvas,
786 "Could not create cppcanvas" );
788 geometry::AffineMatrix2D aViewTransform(
789 xView->getTransformation() );
791 if( basegfx::fTools::equalZero(
792 basegfx::B2DVector(aViewTransform.m00,
793 aViewTransform.m10).getLength()) ||
794 basegfx::fTools::equalZero(
795 basegfx::B2DVector(aViewTransform.m01,
796 aViewTransform.m11).getLength()) )
798 OSL_FAIL( "SlideView::SlideView(): Singular matrix!" );
800 canvas::tools::setIdentityAffineMatrix2D(aViewTransform);
803 basegfx::unotools::homMatrixFromAffineMatrix(
804 maViewTransform, aViewTransform );
806 // once and forever: set fixed prio to this 'layer' (we're always
807 // the background layer)
808 maSprites.setLayerPriority( basegfx::B1DRange(0.0,1.0) );
811 void SlideView::disposing()
813 osl::MutexGuard aGuard( m_aMutex );
815 maViewLayers.clear();
816 maSprites.clear();
817 mpCanvas.reset();
819 // additionally, also de-register from XSlideShowView
820 if (mxView.is())
822 mxView->removeTransformationChangedListener( this );
823 mxView->removePaintListener( this );
824 mxView.clear();
828 ViewLayerSharedPtr SlideView::createViewLayer( const basegfx::B2DRange& rLayerBounds ) const
830 osl::MutexGuard aGuard( m_aMutex );
832 ENSURE_OR_THROW( mpCanvas,
833 "SlideView::createViewLayer(): Disposed" );
835 const std::size_t nNumLayers( maViewLayers.size() );
837 // avoid filling up layer vector with lots of deceased layer weak
838 // ptrs
839 if( nNumLayers > LAYER_ULLAGE )
840 pruneLayers();
842 boost::shared_ptr<SlideViewLayer> pViewLayer( new SlideViewLayer(mpCanvas,
843 getTransformation(),
844 rLayerBounds,
845 maUserSize,
846 this) );
847 maViewLayers.push_back( pViewLayer );
849 return pViewLayer;
852 bool SlideView::updateScreen() const
854 osl::MutexGuard aGuard( m_aMutex );
856 ENSURE_OR_RETURN_FALSE( mpCanvas.get(),
857 "SlideView::updateScreen(): Disposed" );
859 return mpCanvas->updateScreen( false );
862 bool SlideView::paintScreen() const
864 osl::MutexGuard aGuard( m_aMutex );
866 ENSURE_OR_RETURN_FALSE( mpCanvas.get(),
867 "SlideView::paintScreen(): Disposed" );
869 return mpCanvas->updateScreen( true );
872 void SlideView::clear() const
874 osl::MutexGuard aGuard( m_aMutex );
876 OSL_ENSURE( mxView.is() && mpCanvas,
877 "SlideView::clear(): Disposed" );
878 if( !mxView.is() || !mpCanvas )
879 return;
881 // keep layer clip
882 clearRect(getCanvas()->clone(),
883 getLayerBoundsPixel(
884 basegfx::B2DRange(0,0,
885 maUserSize.getX(),
886 maUserSize.getY()),
887 getTransformation()));
890 void SlideView::clearAll() const
892 osl::MutexGuard aGuard( m_aMutex );
894 OSL_ENSURE( mxView.is() && mpCanvas,
895 "SlideView::clear(): Disposed" );
896 if( !mxView.is() || !mpCanvas )
897 return;
899 mpCanvas->clear(); // this is unnecessary, strictly speaking. but
900 // it makes the SlideView behave exactly like a
901 // sprite-based SlideViewLayer, because those
902 // are created from scratch after a resize
904 // clear whole view
905 mxView->clear();
908 void SlideView::setViewSize( const basegfx::B2DSize& rSize )
910 osl::MutexGuard aGuard( m_aMutex );
912 maUserSize = rSize;
913 updateCanvas();
916 void SlideView::setCursorShape( sal_Int16 nPointerShape )
918 osl::MutexGuard const guard( m_aMutex );
920 if (mxView.is())
921 mxView->setMouseCursor( nPointerShape );
924 bool SlideView::isOnView(boost::shared_ptr<View> const& rView) const
926 return rView.get() == this;
929 cppcanvas::CanvasSharedPtr SlideView::getCanvas() const
931 osl::MutexGuard aGuard( m_aMutex );
933 ENSURE_OR_THROW( mpCanvas,
934 "SlideView::getCanvas(): Disposed" );
936 return mpCanvas;
939 cppcanvas::CustomSpriteSharedPtr SlideView::createSprite(
940 const basegfx::B2DSize& rSpriteSizePixel,
941 double nPriority ) const
943 osl::MutexGuard aGuard( m_aMutex );
945 ENSURE_OR_THROW( mpCanvas, "SlideView::createSprite(): Disposed" );
947 cppcanvas::CustomSpriteSharedPtr pSprite(
948 mpCanvas->createCustomSprite( rSpriteSizePixel ) );
950 maSprites.addSprite( pSprite,
951 nPriority );
953 return pSprite;
956 void SlideView::setPriority( const basegfx::B1DRange& /*rRange*/ )
958 osl::MutexGuard aGuard( m_aMutex );
960 OSL_FAIL( "SlideView::setPriority() is a NOOP for slide view - "
961 "content will always be shown in the background" );
964 basegfx::B2DHomMatrix SlideView::getTransformation() const
966 osl::MutexGuard aGuard( m_aMutex );
968 basegfx::B2DHomMatrix aMatrix;
969 aMatrix.scale( 1.0/maUserSize.getX(), 1.0/maUserSize.getY() );
971 return maViewTransform * aMatrix;
974 geometry::IntegerSize2D SlideView::getTranslationOffset() const
976 return mxView->getTranslationOffset();
979 basegfx::B2DHomMatrix SlideView::getSpriteTransformation() const
981 return getTransformation();
984 void SlideView::setClip( const basegfx::B2DPolyPolygon& rClip )
986 osl::MutexGuard aGuard( m_aMutex );
988 basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
990 if( aNewClip != maClip )
992 maClip = aNewClip;
994 updateClip();
998 bool SlideView::resize( const ::basegfx::B2DRange& /*rArea*/ )
1000 osl::MutexGuard aGuard( m_aMutex );
1002 OSL_FAIL( "SlideView::resize(): ignored for the View, can't change size "
1003 "effectively, anyway" );
1005 return false;
1008 uno::Reference<presentation::XSlideShowView> SlideView::getUnoView() const
1010 osl::MutexGuard aGuard( m_aMutex );
1011 return mxView;
1014 void SlideView::setIsSoundEnabled (const bool bValue)
1016 mbIsSoundEnabled = bValue;
1019 bool SlideView::isSoundEnabled() const
1021 return mbIsSoundEnabled;
1024 void SlideView::_dispose()
1026 dispose();
1029 // XEventListener
1030 void SlideView::disposing( lang::EventObject const& evt )
1031 throw (uno::RuntimeException, std::exception)
1033 (void)evt;
1035 // no deregistration necessary anymore, XView has left:
1036 osl::MutexGuard const guard( m_aMutex );
1038 if (mxView.is())
1040 OSL_ASSERT( evt.Source == mxView );
1041 mxView.clear();
1044 dispose();
1047 // XModifyListener
1048 void SlideView::modified( const lang::EventObject& /*aEvent*/ )
1049 throw (uno::RuntimeException, std::exception)
1051 osl::MutexGuard const guard( m_aMutex );
1053 OSL_ENSURE( mxView.is(), "SlideView::modified(): "
1054 "Disposed, but event received from XSlideShowView?!");
1056 if( !mxView.is() )
1057 return;
1059 geometry::AffineMatrix2D aViewTransform(
1060 mxView->getTransformation() );
1062 if( basegfx::fTools::equalZero(
1063 basegfx::B2DVector(aViewTransform.m00,
1064 aViewTransform.m10).getLength()) ||
1065 basegfx::fTools::equalZero(
1066 basegfx::B2DVector(aViewTransform.m01,
1067 aViewTransform.m11).getLength()) )
1069 OSL_FAIL( "SlideView::modified(): Singular matrix!" );
1071 canvas::tools::setIdentityAffineMatrix2D(aViewTransform);
1074 // view transformation really changed?
1075 basegfx::B2DHomMatrix aNewTransform;
1076 basegfx::unotools::homMatrixFromAffineMatrix(
1077 aNewTransform,
1078 aViewTransform );
1080 if( aNewTransform == maViewTransform )
1081 return; // No change, nothing to do
1083 maViewTransform = aNewTransform;
1085 updateCanvas();
1087 // notify view change. Don't call EventMultiplexer directly, this
1088 // might not be the main thread!
1089 mrEventQueue.addEvent(
1090 makeEvent( boost::bind( (bool (EventMultiplexer::*)(
1091 const uno::Reference<presentation::XSlideShowView>&))
1092 &EventMultiplexer::notifyViewChanged,
1093 boost::ref(mrEventMultiplexer), mxView ),
1094 "EventMultiplexer::notifyViewChanged"));
1097 // XPaintListener
1098 void SlideView::windowPaint( const awt::PaintEvent& /*e*/ )
1099 throw (uno::RuntimeException, std::exception)
1101 osl::MutexGuard aGuard( m_aMutex );
1103 OSL_ENSURE( mxView.is() && mpCanvas, "Disposed, but event received?!" );
1105 // notify view clobbering. Don't call EventMultiplexer directly,
1106 // this might not be the main thread!
1107 mrEventQueue.addEvent(
1108 makeEvent( boost::bind( &EventMultiplexer::notifyViewClobbered,
1109 boost::ref(mrEventMultiplexer), mxView ),
1110 "EventMultiplexer::notifyViewClobbered") );
1113 void SlideView::updateCanvas()
1115 OSL_ENSURE( mpCanvas,
1116 "SlideView::updateCanvasTransform(): Disposed" );
1118 if( !mpCanvas || !mxView.is())
1119 return;
1121 clearAll();
1122 mpCanvas->setTransformation( getTransformation() );
1123 mpCanvas->setClip(
1124 createClipPolygon( maClip,
1125 mpCanvas,
1126 maUserSize ));
1128 // forward update to viewlayers
1129 pruneLayers( true );
1132 void SlideView::updateClip()
1134 OSL_ENSURE( mpCanvas,
1135 "SlideView::updateClip(): Disposed" );
1137 if( !mpCanvas )
1138 return;
1140 mpCanvas->setClip(
1141 createClipPolygon( maClip,
1142 mpCanvas,
1143 maUserSize ));
1145 pruneLayers( false );
1148 void SlideView::pruneLayers( bool bWithViewLayerUpdate ) const
1150 ViewLayerVector aValidLayers;
1152 const basegfx::B2DHomMatrix& rCurrTransform(
1153 getTransformation() );
1155 // check all layers for validity, and retain only the live ones
1156 ViewLayerVector::const_iterator aCurr( maViewLayers.begin() );
1157 const ViewLayerVector::const_iterator aEnd( maViewLayers.end() );
1158 while( aCurr != aEnd )
1160 boost::shared_ptr< SlideViewLayer > pCurrLayer( aCurr->lock() );
1162 if( pCurrLayer )
1164 aValidLayers.push_back( pCurrLayer );
1166 if( bWithViewLayerUpdate )
1167 pCurrLayer->updateView( rCurrTransform,
1168 maUserSize );
1171 ++aCurr;
1174 // replace layer list with pruned one
1175 maViewLayers.swap( aValidLayers );
1178 } // anonymous namespace
1180 UnoViewSharedPtr createSlideView( uno::Reference< presentation::XSlideShowView> const& xView,
1181 EventQueue& rEventQueue,
1182 EventMultiplexer& rEventMultiplexer )
1184 boost::shared_ptr<SlideView> const that(
1185 comphelper::make_shared_from_UNO(
1186 new SlideView(xView,
1187 rEventQueue,
1188 rEventMultiplexer)));
1190 // register listeners with XSlideShowView
1191 xView->addTransformationChangedListener( that.get() );
1192 xView->addPaintListener( that.get() );
1194 // set new transformation
1195 that->updateCanvas();
1197 return that;
1200 } // namespace internal
1201 } // namespace slideshow
1203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */