1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
63 using namespace com::sun::star
;
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.
77 SpriteEntry( const cppcanvas::CustomSpriteSharedPtr
& rSprite
,
84 bool operator<(const SpriteEntry
& rRHS
) const
86 return mnPriority
< rRHS
.mnPriority
;
89 boost::weak_ptr
< cppcanvas::CustomSprite
> mpSprite
;
93 typedef std::vector
< SpriteEntry
> SpriteVector
;
96 /** Create a clip polygon for slide views
99 Clip to set (can be empty)
102 Canvas to create the clip polygon for
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 // =====================
119 const basegfx::B2DRange
aClipRange(0, 0, rUserSize
.getX(), rUserSize
.getY());
123 return basegfx::tools::clipPolyPolygonOnRange(rClip
, aClipRange
, true, false);
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
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
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);
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() );
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
) );
187 pPolyPoly
->setCompositeOp( cppcanvas::CanvasGraphic::SOURCE
);
188 pPolyPoly
->setRGBAFillColor( 0xFFFFFF00U
);
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
));
202 pPolyPoly2
->setRGBALineColor( 0x008000FFU
);
209 /** Get bounds in pixel
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
220 basegfx::B2IRange
getLayerBoundsPixel( basegfx::B2DRange
const& rLayerBounds
,
221 basegfx::B2DHomMatrix
const& rTransformation
)
223 ::basegfx::B2DRange aTmpRect
;
224 ::canvas::tools::calcTransformedRectBounds( aTmpRect
,
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
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
281 Iterator to the first entry to rescan
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() );
296 // only copy still valid sprites over to the refreshed
298 aValidSprites
.push_back( *aCurrSprite
);
300 pCurrSprite
->setPriority(
301 getSpritePriority( aValidSprites
.size()-1 ));
307 // replace sprite list with pruned one
308 maSprites
.swap( aValidSprites
);
312 LayerSpriteContainer() :
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
334 void addSprite( const cppcanvas::CustomSpriteSharedPtr
& pSprite
,
340 SpriteEntry
aEntry( pSprite
,nPriority
);
342 // insert new sprite, such that vector stays sorted
343 SpriteVector::iterator
aInsertPos(
345 std::lower_bound( maSprites
.begin(),
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
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 ));
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
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
;
427 /** Create a new layer
430 Sprite canvas to create the layer on
433 Initial overall canvas transformation
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
) :
444 maLayerBounds(rLayerBounds
),
445 maLayerBoundsPixel(),
447 maUserSize(rUserSize
),
448 maTransformation(rTransform
),
449 mpSpriteCanvas(pCanvas
),
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,
466 maUserSize
.getY()) );
468 basegfx::B2IRange
const& rNewLayerPixel(
469 getLayerBoundsPixel(maLayerBounds
,
471 if( rNewLayerPixel
!= maLayerBoundsPixel
)
473 // re-gen sprite with new size
474 mpOutputCanvas
.reset();
479 virtual ::com::sun::star::geometry::IntegerSize2D
getTranslationOffset() const SAL_OVERRIDE
481 basegfx::B2DRectangle aTmpRect
;
482 canvas::tools::calcTransformedRectBounds( aTmpRect
,
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());
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
,
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
);
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
,
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()) );
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());
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
573 // clear whole canvas
574 const basegfx::B2I64Tuple
& rSpriteSize(maLayerBoundsPixel
.getRange());
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
)
590 maLayerBoundsPixel
= getLayerBoundsPixel(maLayerBounds
,
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)
611 basegfx::B2DPoint(maLayerBoundsPixel
.getMinimum()) +
612 basegfx::B2DPoint(10,10) );
614 mpSprite
->setAlpha(0.5);
617 basegfx::B2DPoint(maLayerBoundsPixel
.getMinimum()) );
619 mpSprite
->setAlpha(1.0);
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
,
640 return mpOutputCanvas
;
643 virtual void setClip( const basegfx::B2DPolyPolygon
& rClip
) SAL_OVERRIDE
645 basegfx::B2DPolyPolygon aNewClip
= prepareClip( rClip
);
647 if( aNewClip
!= maClip
)
652 mpOutputCanvas
->setClip(
653 createClipPolygon( maClip
,
659 virtual bool resize( const ::basegfx::B2DRange
& rArea
) SAL_OVERRIDE
661 const bool bRet( maLayerBounds
!= rArea
);
662 maLayerBounds
= rArea
;
663 updateView( maTransformation
,
673 typedef cppu::WeakComponentImplHelper2
<
674 ::com::sun::star::util::XModifyListener
,
675 ::com::sun::star::awt::XPaintListener
> SlideViewBase
;
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
,
687 SlideView( const uno::Reference
<presentation::XSlideShowView
>& xView
,
688 EventQueue
& rEventQueue
,
689 EventMultiplexer
& rEventMultiplexer
);
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
;
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
;
721 virtual void SAL_CALL
disposing( lang::EventObject
const& evt
)
722 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
724 virtual void SAL_CALL
modified( const lang::EventObject
& aEvent
)
725 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
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
;
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
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
),
769 mrEventMultiplexer( rEventMultiplexer
),
770 mrEventQueue( rEventQueue
),
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();
819 // additionally, also de-register from XSlideShowView
822 mxView
->removeTransformationChangedListener( this );
823 mxView
->removePaintListener( this );
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
839 if( nNumLayers
> LAYER_ULLAGE
)
842 boost::shared_ptr
<SlideViewLayer
> pViewLayer( new SlideViewLayer(mpCanvas
,
847 maViewLayers
.push_back( 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
)
882 clearRect(getCanvas()->clone(),
884 basegfx::B2DRange(0,0,
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
)
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
908 void SlideView::setViewSize( const basegfx::B2DSize
& rSize
)
910 osl::MutexGuard
aGuard( m_aMutex
);
916 void SlideView::setCursorShape( sal_Int16 nPointerShape
)
918 osl::MutexGuard
const guard( m_aMutex
);
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" );
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
,
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
)
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" );
1008 uno::Reference
<presentation::XSlideShowView
> SlideView::getUnoView() const
1010 osl::MutexGuard
aGuard( m_aMutex
);
1014 void SlideView::setIsSoundEnabled (const bool bValue
)
1016 mbIsSoundEnabled
= bValue
;
1019 bool SlideView::isSoundEnabled() const
1021 return mbIsSoundEnabled
;
1024 void SlideView::_dispose()
1030 void SlideView::disposing( lang::EventObject
const& evt
)
1031 throw (uno::RuntimeException
, std::exception
)
1035 // no deregistration necessary anymore, XView has left:
1036 osl::MutexGuard
const guard( m_aMutex
);
1040 OSL_ASSERT( evt
.Source
== mxView
);
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?!");
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(
1080 if( aNewTransform
== maViewTransform
)
1081 return; // No change, nothing to do
1083 maViewTransform
= aNewTransform
;
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"));
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())
1122 mpCanvas
->setTransformation( getTransformation() );
1124 createClipPolygon( maClip
,
1128 // forward update to viewlayers
1129 pruneLayers( true );
1132 void SlideView::updateClip()
1134 OSL_ENSURE( mpCanvas
,
1135 "SlideView::updateClip(): Disposed" );
1141 createClipPolygon( maClip
,
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() );
1164 aValidLayers
.push_back( pCurrLayer
);
1166 if( bWithViewLayerUpdate
)
1167 pCurrLayer
->updateView( rCurrTransform
,
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
,
1188 rEventMultiplexer
)));
1190 // register listeners with XSlideShowView
1191 xView
->addTransformationChangedListener( that
.get() );
1192 xView
->addPaintListener( that
.get() );
1194 // set new transformation
1195 that
->updateCanvas();
1200 } // namespace internal
1201 } // namespace slideshow
1203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */