Update ooo320-m1
[ooovba.git] / slideshow / source / engine / slideview.cxx
blob13d18281586f3f1b032f9b1246572350f2877c43
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: slideview.cxx,v $
10 * $Revision: 1.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 #include "precompiled_slideshow.hxx"
32 #include <canvas/debug.hxx>
33 #include <tools/diagnose_ex.h>
34 #include <canvas/canvastools.hxx>
36 #include "eventqueue.hxx"
37 #include "eventmultiplexer.hxx"
38 #include "slideview.hxx"
39 #include "delayevent.hxx"
40 #include "unoview.hxx"
42 #include <rtl/instance.hxx>
43 #include <cppuhelper/basemutex.hxx>
44 #include <cppuhelper/compbase2.hxx>
45 #include <cppuhelper/implementationentry.hxx>
46 #include <cppuhelper/interfacecontainer.h>
47 #include <comphelper/make_shared_from_uno.hxx>
49 #include <cppcanvas/spritecanvas.hxx>
50 #include <cppcanvas/customsprite.hxx>
51 #include <cppcanvas/vclfactory.hxx>
52 #include <cppcanvas/basegfxfactory.hxx>
54 #include <tools/debug.hxx>
56 #include <basegfx/range/b1drange.hxx>
57 #include <basegfx/range/b2drange.hxx>
58 #include <basegfx/range/b2irange.hxx>
59 #include <basegfx/point/b2dpoint.hxx>
60 #include <basegfx/polygon/b2dpolygon.hxx>
61 #include <basegfx/matrix/b2dhommatrix.hxx>
62 #include <basegfx/polygon/b2dpolygontools.hxx>
63 #include <basegfx/polygon/b2dpolypolygontools.hxx>
64 #include <basegfx/tools/canvastools.hxx>
65 #include <basegfx/polygon/b2dpolygonclipper.hxx>
66 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
68 #include <com/sun/star/presentation/XSlideShow.hpp>
70 #include <boost/noncopyable.hpp>
71 #include <boost/bind.hpp>
72 #include <boost/weak_ptr.hpp>
74 #include <vector>
75 #include <iterator>
76 #include <algorithm>
78 using namespace com::sun::star;
80 namespace slideshow {
81 namespace internal {
83 namespace {
85 struct StaticUnitRectPoly : public rtl::StaticWithInit<basegfx::B2DPolygon, StaticUnitRectPoly>
87 basegfx::B2DPolygon operator()()
89 return basegfx::tools::createPolygonFromRect(
90 basegfx::B2DRectangle( 0.0, 0.0,
91 1.0, 1.0 ) );
95 /** Sprite entry, to store sprite plus priority
97 The operator<() defines a strict weak ordering of sprites, sort
98 key is the sprite priority.
100 struct SpriteEntry
102 SpriteEntry( const cppcanvas::CustomSpriteSharedPtr& rSprite,
103 double nPrio ) :
104 mpSprite( rSprite ),
105 mnPriority( nPrio )
109 bool operator<(const SpriteEntry& rRHS) const
111 return mnPriority < rRHS.mnPriority;
114 boost::weak_ptr< cppcanvas::CustomSprite > mpSprite;
115 double mnPriority;
118 typedef std::vector< SpriteEntry > SpriteVector;
121 /** Create a clip polygon for slide views
123 @param rClip
124 Clip to set (can be empty)
126 @param rCanvas
127 Canvas to create the clip polygon for
129 @param rUserSize
130 The size of the view. Note that the returned clip will
131 <em>always</em> clip to at least the rect defined herein.
133 @return the view clip polygon, in view coordinates, which is
134 guaranteed to at least clip to the view size.
136 basegfx::B2DPolyPolygon createClipPolygon( const basegfx::B2DPolyPolygon& rClip,
137 const cppcanvas::CanvasSharedPtr& /*rCanvas*/,
138 const basegfx::B2DSize& rUserSize )
140 // setup canvas clipping
141 // =====================
143 // AW: Simplified
144 const basegfx::B2DRange aClipRange(0, 0, rUserSize.getX(), rUserSize.getY());
146 if(rClip.count())
148 return basegfx::tools::clipPolyPolygonOnRange(rClip, aClipRange, true, false);
150 else
152 return basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aClipRange));
156 /** Prepare given clip polygon to be stored as the current clip
158 Note that this is separate from createClipPolygon(), to allow
159 SlideView implementations to store this intermediate result
160 (createClipPolygon() has to be called every time the view size
161 changes)
163 basegfx::B2DPolyPolygon prepareClip( const basegfx::B2DPolyPolygon& rClip )
165 basegfx::B2DPolyPolygon aClip( rClip );
167 // TODO(P2): unnecessary, once XCanvas is correctly handling this
168 // AW: Should be no longer necessary; tools are now bezier-safe
169 if( aClip.areControlPointsUsed() )
170 aClip = basegfx::tools::adaptiveSubdivideByAngle( aClip );
172 // normalize polygon, preparation for clipping
173 // in updateCanvas()
174 aClip = basegfx::tools::correctOrientations(aClip);
175 aClip = basegfx::tools::solveCrossovers(aClip);
176 aClip = basegfx::tools::stripNeutralPolygons(aClip);
177 aClip = basegfx::tools::stripDispensablePolygons(aClip, false);
179 return aClip;
183 void clearRect( ::cppcanvas::CanvasSharedPtr const& pCanvas,
184 basegfx::B2IRange const& rArea )
186 // convert clip polygon to device coordinate system
187 ::basegfx::B2DPolyPolygon const* pClipPoly( pCanvas->getClip() );
188 if( pClipPoly )
190 ::basegfx::B2DPolyPolygon aClipPoly( *pClipPoly );
191 aClipPoly.transform( pCanvas->getTransformation() );
192 pCanvas->setClip( aClipPoly );
195 // set transformation to identitiy (->device pixel)
196 pCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
198 // #i42440# Fill the _full_ background in
199 // black. Since we had to extend the bitmap by one
200 // pixel, and the bitmap is initialized white,
201 // depending on the slide content a one pixel wide
202 // line will show to the bottom and the right.
203 const ::basegfx::B2DPolygon aPoly(
204 ::basegfx::tools::createPolygonFromRect(
205 basegfx::B2DRange(rArea)));
207 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
208 ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( pCanvas,
209 aPoly ) );
211 if( pPolyPoly )
213 pPolyPoly->setCompositeOp( cppcanvas::CanvasGraphic::SOURCE );
214 pPolyPoly->setRGBAFillColor( 0x00000000U );
215 pPolyPoly->draw();
218 #if defined(VERBOSE) && defined(DBG_UTIL)
219 ::cppcanvas::CanvasSharedPtr pCliplessCanvas( pCanvas->clone() );
220 pCliplessCanvas->setClip();
222 if( pCanvas->getClip() )
224 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly2(
225 ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( pCliplessCanvas,
226 *(pCanvas->getClip()) ));
227 if( pPolyPoly2 )
229 pPolyPoly2->setRGBALineColor( 0x008000FFU );
230 pPolyPoly2->draw();
233 #endif
236 /** Get bounds in pixel
238 @param rLayerBounds
239 Bound rect, in user space coordinates
241 @param rTransformation
242 User space to device pixel transformation
244 @return the layer bounds in pixel, extended by one pixel to the
245 right and bottom
247 basegfx::B2IRange getLayerBoundsPixel( basegfx::B2DRange const& rLayerBounds,
248 basegfx::B2DHomMatrix const& rTransformation )
250 ::basegfx::B2DRange aTmpRect;
251 ::canvas::tools::calcTransformedRectBounds( aTmpRect,
252 rLayerBounds,
253 rTransformation );
255 if( aTmpRect.isEmpty() )
256 return ::basegfx::B2IRange();
258 // #i42440# Returned layer size is one pixel too small, as
259 // rendering happens one pixel to the right and below the
260 // actual bound rect.
261 return ::basegfx::B2IRange( ::basegfx::fround(aTmpRect.getMinX()),
262 ::basegfx::fround(aTmpRect.getMinY()),
263 ::basegfx::fround(aTmpRect.getMaxX()) + 1,
264 ::basegfx::fround(aTmpRect.getMaxY()) + 1 );
268 // ----------------------------------------------------------------
270 /** Container class for sprites issued by a ViewLayer
272 This class handles the sprite prioritization issues, that are
273 needed for layer sprites (e.g. the need to re-prioritize sprites
274 when the layer changes prio).
276 class LayerSpriteContainer
278 /** Max fill level of maSprites, before we try to prune it from
279 deceased sprites
281 enum{ SPRITE_ULLAGE=256 };
283 /** All sprites that have been issued by this container (pruned
284 from time to time, for invalid references). This vector is
285 kept sorted with increasing sprite priority.
287 SpriteVector maSprites;
289 /// Priority of this layer, relative to other view layers
290 basegfx::B1DRange maLayerPrioRange;
292 double getSpritePriority( std::size_t nSpriteNum ) const
294 // divide the available layer range equally between all
295 // sprites, assign upper bound of individual sprite range as
296 // sprite prio (the layer itself gets assigned the lower bound
297 // of sprite 0's individual range):
299 // | layer 0 | layer 1 | ...
300 // | sprite 0 | sprite 1 | sprite 0 | sprite 1 | ...
301 return maLayerPrioRange.getMinimum() + maLayerPrioRange.getRange()*(nSpriteNum+1)/(maSprites.size()+1);
304 /** Rescan sprite vector, and remove deceased sprites (and reset
305 sprite prio)
307 @param aBegin
308 Iterator to the first entry to rescan
310 void updateSprites()
312 SpriteVector aValidSprites;
314 // check all sprites for validity and set new priority
315 SpriteVector::iterator aCurrSprite( maSprites.begin() );
316 const SpriteVector::iterator aEnd( maSprites.end() );
317 while( aCurrSprite != aEnd )
319 cppcanvas::CustomSpriteSharedPtr pCurrSprite( aCurrSprite->mpSprite.lock() );
321 if( pCurrSprite )
323 // only copy still valid sprites over to the refreshed
324 // sprite vector.
325 aValidSprites.push_back( *aCurrSprite );
327 pCurrSprite->setPriority(
328 getSpritePriority( aValidSprites.size()-1 ));
331 ++aCurrSprite;
334 // replace sprite list with pruned one
335 maSprites.swap( aValidSprites );
338 public:
339 LayerSpriteContainer() :
340 maSprites(),
341 maLayerPrioRange()
345 basegfx::B1DRange getLayerPriority() const
347 return maLayerPrioRange;
350 void setLayerPriority( const basegfx::B1DRange& rRange )
352 if( rRange != maLayerPrioRange )
354 maLayerPrioRange = rRange;
356 // prune and recalc sprite prios
357 updateSprites();
361 void addSprite( const cppcanvas::CustomSpriteSharedPtr& pSprite,
362 double nPriority )
364 if( !pSprite )
365 return;
367 SpriteEntry aEntry( pSprite,nPriority );
369 // insert new sprite, such that vector stays sorted
370 SpriteVector::iterator aInsertPos(
371 maSprites.insert(
372 std::lower_bound( maSprites.begin(),
373 maSprites.end(),
374 aEntry ),
375 aEntry ));
377 const std::size_t nNumSprites( maSprites.size() );
378 if( nNumSprites > SPRITE_ULLAGE ||
379 maSprites.end() - aInsertPos > 1 )
381 // updateSprites() also updates all sprite prios
382 updateSprites();
384 else
386 // added sprite to the end, and not too many sprites in
387 // vector - perform optimized update (only need to set
388 // prio). This basically caters for the common case of
389 // iterated character animations, which generate lots of
390 // sprites, all added to the end.
391 pSprite->setPriority(
392 getSpritePriority( nNumSprites-1 ));
396 void clear()
398 maSprites.clear();
403 // ----------------------------------------------------------------
406 /** This class provides layers for a slide view
408 Layers are used to render animations with the correct z order -
409 because sprites are always in front of the static canvas
410 background, shapes that must appear <em<before</em> an animation
411 must also be displayed as a sprite.
413 Each layer has a priority assigned to it (valid range [0,1]), which
414 also affects all sprites created for this specific layer - i.e. if
415 the layer priority changes, the sprites change z order together
416 with their parent.
418 class SlideViewLayer : public ViewLayer,
419 private boost::noncopyable
421 /// Smart container for all sprites issued by this layer
422 mutable LayerSpriteContainer maSpriteContainer;
424 /// Bounds of this layer in user space coordinates
425 basegfx::B2DRange maLayerBounds;
427 /// Bounds of this layer in device pixel
428 mutable basegfx::B2IRange maLayerBoundsPixel;
430 /// Current clip polygon in user coordinates
431 basegfx::B2DPolyPolygon maClip;
433 /// Current size of the view in user coordinates
434 basegfx::B2DSize maUserSize;
436 /// Current overall view transformation
437 basegfx::B2DHomMatrix maTransformation;
439 /// 'parent' canvas, this viewlayer is associated with
440 const cppcanvas::SpriteCanvasSharedPtr mpSpriteCanvas;
442 /** output surface (necessarily a sprite, won't otherwise be able
443 to display anything <em>before</em> other sprites)
445 mutable cppcanvas::CustomSpriteSharedPtr mpSprite;
447 /// actual output canvas retrieved from a sprite
448 mutable cppcanvas::CanvasSharedPtr mpOutputCanvas;
450 /// ptr back to owning view. needed for isOnView() method
451 View const* const mpParentView;
453 public:
454 /** Create a new layer
456 @param pCanvas
457 Sprite canvas to create the layer on
459 @param rTransform
460 Initial overall canvas transformation
462 @param rLayerBounds
463 Initial layer bounds, in view coordinate system
465 SlideViewLayer( const cppcanvas::SpriteCanvasSharedPtr& pCanvas,
466 const basegfx::B2DHomMatrix& rTransform,
467 const basegfx::B2DRange& rLayerBounds,
468 const basegfx::B2DSize& rUserSize,
469 View const* const pParentView) :
470 maSpriteContainer(),
471 maLayerBounds(rLayerBounds),
472 maLayerBoundsPixel(),
473 maClip(),
474 maUserSize(rUserSize),
475 maTransformation(rTransform),
476 mpSpriteCanvas(pCanvas),
477 mpSprite(),
478 mpOutputCanvas(),
479 mpParentView(pParentView)
483 void updateView( const basegfx::B2DHomMatrix& rMatrix,
484 const basegfx::B2DSize& rUserSize )
486 maTransformation = rMatrix;
487 maUserSize = rUserSize;
489 // limit layer bounds to visible screen
490 maLayerBounds.intersect( basegfx::B2DRange(0.0,
491 0.0,
492 maUserSize.getX(),
493 maUserSize.getY()) );
495 basegfx::B2IRange const& rNewLayerPixel(
496 getLayerBoundsPixel(maLayerBounds,
497 maTransformation) );
498 if( rNewLayerPixel != maLayerBoundsPixel )
500 // re-gen sprite with new size
501 mpOutputCanvas.reset();
502 mpSprite.reset();
506 private:
507 // ViewLayer interface
508 // ----------------------------------------------
510 virtual cppcanvas::CustomSpriteSharedPtr createSprite(
511 const ::basegfx::B2DSize& rSpriteSizePixel,
512 double nPriority ) const
514 cppcanvas::CustomSpriteSharedPtr pSprite(
515 mpSpriteCanvas->createCustomSprite( rSpriteSizePixel ) );
517 maSpriteContainer.addSprite( pSprite,
518 nPriority );
520 return pSprite;
523 virtual void setPriority( const basegfx::B1DRange& rRange )
525 OSL_ENSURE( !rRange.isEmpty() &&
526 rRange.getMinimum() >= 1.0,
527 "SlideViewLayer::setPriority(): prio MUST be larger than 1.0 (because "
528 "the background layer already lies there)" );
530 maSpriteContainer.setLayerPriority( rRange );
532 if( mpSprite )
533 mpSprite->setPriority( rRange.getMinimum() );
536 virtual basegfx::B2DHomMatrix getTransformation() const
538 // Offset given transformation by left, top border of given
539 // range (after transformation through given transformation)
540 basegfx::B2DRectangle aTmpRect;
541 canvas::tools::calcTransformedRectBounds( aTmpRect,
542 maLayerBounds,
543 maTransformation );
545 basegfx::B2DHomMatrix aMatrix( maTransformation );
547 // Add translation according to the origin of aTmpRect. Ignore the
548 // translation when aTmpRect was not properly initialized.
549 if ( ! aTmpRect.isEmpty())
551 aMatrix.translate( -basegfx::fround(aTmpRect.getMinX()),
552 -basegfx::fround(aTmpRect.getMinY()) );
555 return aMatrix;
558 virtual basegfx::B2DHomMatrix getSpriteTransformation() const
560 return maTransformation;
563 virtual void clear() const
565 // keep layer clip
566 clearRect(getCanvas()->clone(),
567 maLayerBoundsPixel);
570 virtual void clearAll() const
572 ::cppcanvas::CanvasSharedPtr pCanvas( getCanvas()->clone() );
574 // clear layer clip, to clear whole area
575 pCanvas->setClip();
577 clearRect(pCanvas,
578 maLayerBoundsPixel);
581 virtual bool isOnView(boost::shared_ptr<View> const& rView) const
583 return rView.get() == mpParentView;
586 virtual cppcanvas::CanvasSharedPtr getCanvas() const
588 if( !mpOutputCanvas )
590 if( !mpSprite )
592 maLayerBoundsPixel = getLayerBoundsPixel(maLayerBounds,
593 maTransformation);
595 // HACK: ensure at least 1x1 pixel size. clients might
596 // need an actual canvas (e.g. for bound rect
597 // calculations) without rendering anything. Better
598 // solution: introduce something like a reference
599 // canvas for ViewLayers, which is always available.
600 if( maLayerBoundsPixel.isEmpty() )
601 maLayerBoundsPixel = basegfx::B2IRange(0,0,1,1);
603 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
604 mpSprite = mpSpriteCanvas->createCustomSprite(
605 basegfx::B2DVector(sal::static_int_cast<sal_Int32>(rSpriteSize.getX()),
606 sal::static_int_cast<sal_Int32>(rSpriteSize.getY())) );
608 mpSprite->setPriority(
609 maSpriteContainer.getLayerPriority().getMinimum() );
611 #if defined(VERBOSE) && defined(DBG_UTIL)
612 mpSprite->movePixel(
613 basegfx::B2DPoint(maLayerBoundsPixel.getMinimum()) +
614 basegfx::B2DPoint(10,10) );
616 mpSprite->setAlpha(0.5);
617 #else
618 mpSprite->movePixel(
619 basegfx::B2DPoint(maLayerBoundsPixel.getMinimum()) );
621 mpSprite->setAlpha(1.0);
622 #endif
623 mpSprite->show();
626 ENSURE_OR_THROW( mpSprite,
627 "SlideViewLayer::getCanvas(): no layer sprite" );
629 mpOutputCanvas = mpSprite->getContentCanvas();
631 ENSURE_OR_THROW( mpOutputCanvas,
632 "SlideViewLayer::getCanvas(): sprite doesn't yield a canvas" );
634 // new canvas retrieved - setup transformation and clip
635 mpOutputCanvas->setTransformation( getTransformation() );
636 mpOutputCanvas->setClip(
637 createClipPolygon( maClip,
638 mpOutputCanvas,
639 maUserSize ));
642 return mpOutputCanvas;
645 virtual void setClip( const basegfx::B2DPolyPolygon& rClip )
647 basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
649 if( aNewClip != maClip )
651 maClip = aNewClip;
653 if(mpOutputCanvas )
654 mpOutputCanvas->setClip(
655 createClipPolygon( maClip,
656 mpOutputCanvas,
657 maUserSize ));
661 virtual bool resize( const ::basegfx::B2DRange& rArea )
663 const bool bRet( maLayerBounds != rArea );
664 maLayerBounds = rArea;
665 updateView( maTransformation,
666 maUserSize );
668 return bRet;
673 // ---------------------------------------------------------
675 typedef cppu::WeakComponentImplHelper2<
676 ::com::sun::star::util::XModifyListener,
677 ::com::sun::star::awt::XPaintListener> SlideViewBase;
679 /** SlideView class
681 This class implements the View interface, encapsulating
682 <em>one</em> view a slideshow is displayed on.
684 class SlideView : private cppu::BaseMutex,
685 public SlideViewBase,
686 public UnoView
688 public:
689 SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
690 EventQueue& rEventQueue,
691 EventMultiplexer& rEventMultiplexer );
692 void updateCanvas();
694 private:
695 // View:
696 virtual ViewLayerSharedPtr createViewLayer( const basegfx::B2DRange& rLayerBounds ) const;
697 virtual bool updateScreen() const;
698 virtual bool paintScreen() const;
699 virtual void setViewSize( const ::basegfx::B2DSize& );
700 virtual void setCursorShape( sal_Int16 nPointerShape );
702 // ViewLayer interface
703 virtual bool isOnView(boost::shared_ptr<View> const& rView) const;
704 virtual void clear() const;
705 virtual void clearAll() const;
706 virtual cppcanvas::CanvasSharedPtr getCanvas() const;
707 virtual cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& rSpriteSizePixel,
708 double nPriority ) const;
709 virtual void setPriority( const basegfx::B1DRange& rRange );
710 virtual ::basegfx::B2DHomMatrix getTransformation() const;
711 virtual basegfx::B2DHomMatrix getSpriteTransformation() const;
712 virtual void setClip( const ::basegfx::B2DPolyPolygon& rClip );
713 virtual bool resize( const ::basegfx::B2DRange& rArea );
715 // UnoView:
716 virtual void _dispose();
717 virtual uno::Reference<presentation::XSlideShowView> getUnoView()const;
718 virtual void setIsSoundEnabled (const bool bValue);
719 virtual bool isSoundEnabled (void) const;
721 // XEventListener:
722 virtual void SAL_CALL disposing( lang::EventObject const& evt )
723 throw (uno::RuntimeException);
724 // XModifyListener:
725 virtual void SAL_CALL modified( const lang::EventObject& aEvent )
726 throw (uno::RuntimeException);
727 // XPaintListener:
728 virtual void SAL_CALL windowPaint( const awt::PaintEvent& e )
729 throw (uno::RuntimeException);
731 // WeakComponentImplHelperBase:
732 virtual void SAL_CALL disposing();
734 void updateClip();
736 private:
737 typedef std::vector< boost::weak_ptr<SlideViewLayer> > ViewLayerVector;
739 /// Prune viewlayers from deceased ones, optionally update them
740 void pruneLayers( bool bWithViewLayerUpdate=false ) const;
742 /** Max fill level of maViewLayers, before we try to prune it from
743 deceased layers
745 enum{ LAYER_ULLAGE=8 };
747 uno::Reference<presentation::XSlideShowView> mxView;
748 cppcanvas::SpriteCanvasSharedPtr mpCanvas;
750 EventMultiplexer& mrEventMultiplexer;
751 EventQueue& mrEventQueue;
753 mutable LayerSpriteContainer maSprites;
754 mutable ViewLayerVector maViewLayers;
756 basegfx::B2DPolyPolygon maClip;
758 basegfx::B2DHomMatrix maViewTransform;
759 basegfx::B2DSize maUserSize;
760 bool mbIsSoundEnabled;
764 SlideView::SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
765 EventQueue& rEventQueue,
766 EventMultiplexer& rEventMultiplexer ) :
767 SlideViewBase( m_aMutex ),
768 mxView( xView ),
769 mpCanvas(),
770 mrEventMultiplexer( rEventMultiplexer ),
771 mrEventQueue( rEventQueue ),
772 maSprites(),
773 maViewLayers(),
774 maClip(),
775 maViewTransform(),
776 maUserSize( 1.0, 1.0 ), // default size: one-by-one rectangle
777 mbIsSoundEnabled(true)
779 // take care not constructing any UNO references to this _inside_
780 // ctor, shift that code to createSlideView()!
781 ENSURE_OR_THROW( mxView.is(),
782 "SlideView::SlideView(): Invalid view" );
784 mpCanvas = cppcanvas::VCLFactory::getInstance().createSpriteCanvas(
785 xView->getCanvas() );
786 ENSURE_OR_THROW( mpCanvas,
787 "Could not create cppcanvas" );
789 geometry::AffineMatrix2D aViewTransform(
790 xView->getTransformation() );
792 if( basegfx::fTools::equalZero(
793 basegfx::B2DVector(aViewTransform.m00,
794 aViewTransform.m10).getLength()) ||
795 basegfx::fTools::equalZero(
796 basegfx::B2DVector(aViewTransform.m01,
797 aViewTransform.m11).getLength()) )
799 OSL_ENSURE( false,
800 "SlideView::SlideView(): Singular matrix!" );
802 canvas::tools::setIdentityAffineMatrix2D(aViewTransform);
805 basegfx::unotools::homMatrixFromAffineMatrix(
806 maViewTransform, aViewTransform );
808 // once and forever: set fixed prio to this 'layer' (we're always
809 // the background layer)
810 maSprites.setLayerPriority( basegfx::B1DRange(0.0,1.0) );
813 void SlideView::disposing()
815 osl::MutexGuard aGuard( m_aMutex );
817 maViewLayers.clear();
818 maSprites.clear();
819 mpCanvas.reset();
821 // additionally, also de-register from XSlideShowView
822 if (mxView.is())
824 mxView->removeTransformationChangedListener( this );
825 mxView->removePaintListener( this );
826 mxView.clear();
830 ViewLayerSharedPtr SlideView::createViewLayer( const basegfx::B2DRange& rLayerBounds ) const
832 osl::MutexGuard aGuard( m_aMutex );
834 ENSURE_OR_THROW( mpCanvas,
835 "SlideView::createViewLayer(): Disposed" );
837 const std::size_t nNumLayers( maViewLayers.size() );
839 // avoid filling up layer vector with lots of deceased layer weak
840 // ptrs
841 if( nNumLayers > LAYER_ULLAGE )
842 pruneLayers();
844 boost::shared_ptr<SlideViewLayer> pViewLayer( new SlideViewLayer(mpCanvas,
845 getTransformation(),
846 rLayerBounds,
847 maUserSize,
848 this) );
849 maViewLayers.push_back( pViewLayer );
851 return pViewLayer;
854 bool SlideView::updateScreen() const
856 osl::MutexGuard aGuard( m_aMutex );
858 ENSURE_OR_RETURN( mpCanvas.get(),
859 "SlideView::updateScreen(): Disposed" );
861 return mpCanvas->updateScreen( false );
864 bool SlideView::paintScreen() const
866 osl::MutexGuard aGuard( m_aMutex );
868 ENSURE_OR_RETURN( mpCanvas.get(),
869 "SlideView::paintScreen(): Disposed" );
871 return mpCanvas->updateScreen( true );
874 void SlideView::clear() const
876 osl::MutexGuard aGuard( m_aMutex );
878 OSL_ENSURE( mxView.is() && mpCanvas,
879 "SlideView::clear(): Disposed" );
880 if( !mxView.is() || !mpCanvas )
881 return;
883 // keep layer clip
884 clearRect(getCanvas()->clone(),
885 getLayerBoundsPixel(
886 basegfx::B2DRange(0,0,
887 maUserSize.getX(),
888 maUserSize.getY()),
889 getTransformation()));
892 void SlideView::clearAll() const
894 osl::MutexGuard aGuard( m_aMutex );
896 OSL_ENSURE( mxView.is() && mpCanvas,
897 "SlideView::clear(): Disposed" );
898 if( !mxView.is() || !mpCanvas )
899 return;
901 // clear whole view
902 mxView->clear();
905 void SlideView::setViewSize( const basegfx::B2DSize& rSize )
907 osl::MutexGuard aGuard( m_aMutex );
909 maUserSize = rSize;
910 updateCanvas();
913 void SlideView::setCursorShape( sal_Int16 nPointerShape )
915 osl::MutexGuard const guard( m_aMutex );
917 if (mxView.is())
918 mxView->setMouseCursor( nPointerShape );
921 bool SlideView::isOnView(boost::shared_ptr<View> const& rView) const
923 return rView.get() == this;
926 cppcanvas::CanvasSharedPtr SlideView::getCanvas() const
928 osl::MutexGuard aGuard( m_aMutex );
930 ENSURE_OR_THROW( mpCanvas,
931 "SlideView::getCanvas(): Disposed" );
933 return mpCanvas;
936 cppcanvas::CustomSpriteSharedPtr SlideView::createSprite(
937 const basegfx::B2DSize& rSpriteSizePixel,
938 double nPriority ) const
940 osl::MutexGuard aGuard( m_aMutex );
942 ENSURE_OR_THROW( mpCanvas, "SlideView::createSprite(): Disposed" );
944 cppcanvas::CustomSpriteSharedPtr pSprite(
945 mpCanvas->createCustomSprite( rSpriteSizePixel ) );
947 maSprites.addSprite( pSprite,
948 nPriority );
950 return pSprite;
953 void SlideView::setPriority( const basegfx::B1DRange& /*rRange*/ )
955 osl::MutexGuard aGuard( m_aMutex );
957 OSL_ENSURE( false,
958 "SlideView::setPriority() is a NOOP for slide view - "
959 "content will always be shown in the background" );
962 basegfx::B2DHomMatrix SlideView::getTransformation() const
964 osl::MutexGuard aGuard( m_aMutex );
966 basegfx::B2DHomMatrix aMatrix;
967 aMatrix.scale( 1.0/maUserSize.getX(), 1.0/maUserSize.getY() );
969 return maViewTransform * aMatrix;
972 basegfx::B2DHomMatrix SlideView::getSpriteTransformation() const
974 return getTransformation();
977 void SlideView::setClip( const basegfx::B2DPolyPolygon& rClip )
979 osl::MutexGuard aGuard( m_aMutex );
981 basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
983 if( aNewClip != maClip )
985 maClip = aNewClip;
987 updateClip();
991 bool SlideView::resize( const ::basegfx::B2DRange& /*rArea*/ )
993 osl::MutexGuard aGuard( m_aMutex );
995 OSL_ENSURE( false,
996 "SlideView::resize(): ignored for the View, can't change size "
997 "effectively, anyway" );
999 return false;
1002 uno::Reference<presentation::XSlideShowView> SlideView::getUnoView() const
1004 osl::MutexGuard aGuard( m_aMutex );
1005 return mxView;
1008 void SlideView::setIsSoundEnabled (const bool bValue)
1010 mbIsSoundEnabled = bValue;
1013 bool SlideView::isSoundEnabled (void) const
1015 return mbIsSoundEnabled;
1018 void SlideView::_dispose()
1020 dispose();
1023 // XEventListener
1024 void SlideView::disposing( lang::EventObject const& evt )
1025 throw (uno::RuntimeException)
1027 (void)evt;
1029 // no deregistration necessary anymore, XView has left:
1030 osl::MutexGuard const guard( m_aMutex );
1032 if (mxView.is())
1034 OSL_ASSERT( evt.Source == mxView );
1035 mxView.clear();
1038 dispose();
1041 // XModifyListener
1042 void SlideView::modified( const lang::EventObject& /*aEvent*/ )
1043 throw (uno::RuntimeException)
1045 osl::MutexGuard const guard( m_aMutex );
1047 OSL_ENSURE( mxView.is(), "SlideView::modified(): "
1048 "Disposed, but event received from XSlideShowView?!");
1050 if( !mxView.is() )
1051 return;
1053 geometry::AffineMatrix2D aViewTransform(
1054 mxView->getTransformation() );
1056 if( basegfx::fTools::equalZero(
1057 basegfx::B2DVector(aViewTransform.m00,
1058 aViewTransform.m10).getLength()) ||
1059 basegfx::fTools::equalZero(
1060 basegfx::B2DVector(aViewTransform.m01,
1061 aViewTransform.m11).getLength()) )
1063 OSL_ENSURE( false,
1064 "SlideView::modified(): Singular matrix!" );
1066 canvas::tools::setIdentityAffineMatrix2D(aViewTransform);
1069 // view transformation really changed?
1070 basegfx::B2DHomMatrix aNewTransform;
1071 basegfx::unotools::homMatrixFromAffineMatrix(
1072 aNewTransform,
1073 aViewTransform );
1075 if( aNewTransform == maViewTransform )
1076 return; // No change, nothing to do
1078 maViewTransform = aNewTransform;
1080 updateCanvas();
1082 // notify view change. Don't call EventMultiplexer directly, this
1083 // might not be the main thread!
1084 mrEventQueue.addEvent(
1085 makeEvent( boost::bind( (bool (EventMultiplexer::*)(
1086 const uno::Reference<presentation::XSlideShowView>&))
1087 &EventMultiplexer::notifyViewChanged,
1088 boost::ref(mrEventMultiplexer), mxView )));
1091 // XPaintListener
1092 void SlideView::windowPaint( const awt::PaintEvent& /*e*/ )
1093 throw (uno::RuntimeException)
1095 osl::MutexGuard aGuard( m_aMutex );
1097 OSL_ENSURE( mxView.is() && mpCanvas, "Disposed, but event received?!" );
1099 // notify view clobbering. Don't call EventMultiplexer directly,
1100 // this might not be the main thread!
1101 mrEventQueue.addEvent(
1102 makeEvent( boost::bind( &EventMultiplexer::notifyViewClobbered,
1103 boost::ref(mrEventMultiplexer), mxView ) ) );
1106 void SlideView::updateCanvas()
1108 OSL_ENSURE( mpCanvas,
1109 "SlideView::updateCanvasTransform(): Disposed" );
1111 if( !mpCanvas || !mxView.is())
1112 return;
1114 mpCanvas->clear(); // this is unnecessary, strictly speaking. but
1115 // it makes the SlideView behave exactly like a
1116 // sprite-based SlideViewLayer, because those
1117 // are created from scratch after a resize
1118 clearAll();
1119 mpCanvas->setTransformation( getTransformation() );
1120 mpCanvas->setClip(
1121 createClipPolygon( maClip,
1122 mpCanvas,
1123 maUserSize ));
1125 // forward update to viewlayers
1126 pruneLayers( true );
1129 void SlideView::updateClip()
1131 OSL_ENSURE( mpCanvas,
1132 "SlideView::updateClip(): Disposed" );
1134 if( !mpCanvas )
1135 return;
1137 mpCanvas->setClip(
1138 createClipPolygon( maClip,
1139 mpCanvas,
1140 maUserSize ));
1142 pruneLayers( false );
1145 void SlideView::pruneLayers( bool bWithViewLayerUpdate ) const
1147 ViewLayerVector aValidLayers;
1149 const basegfx::B2DHomMatrix& rCurrTransform(
1150 getTransformation() );
1152 // check all layers for validity, and retain only the live ones
1153 ViewLayerVector::const_iterator aCurr( maViewLayers.begin() );
1154 const ViewLayerVector::const_iterator aEnd( maViewLayers.end() );
1155 while( aCurr != aEnd )
1157 boost::shared_ptr< SlideViewLayer > pCurrLayer( aCurr->lock() );
1159 if( pCurrLayer )
1161 aValidLayers.push_back( pCurrLayer );
1163 if( bWithViewLayerUpdate )
1164 pCurrLayer->updateView( rCurrTransform,
1165 maUserSize );
1168 ++aCurr;
1171 // replace layer list with pruned one
1172 maViewLayers.swap( aValidLayers );
1175 } // anonymous namespace
1177 UnoViewSharedPtr createSlideView( uno::Reference< presentation::XSlideShowView> const& xView,
1178 EventQueue& rEventQueue,
1179 EventMultiplexer& rEventMultiplexer )
1181 boost::shared_ptr<SlideView> const that(
1182 comphelper::make_shared_from_UNO(
1183 new SlideView(xView,
1184 rEventQueue,
1185 rEventMultiplexer)));
1187 // register listeners with XSlideShowView
1188 xView->addTransformationChangedListener( that.get() );
1189 xView->addPaintListener( that.get() );
1191 // set new transformation
1192 that->updateCanvas();
1194 return that;
1197 } // namespace internal
1198 } // namespace slideshow