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 <comphelper/diagnose_ex.hxx>
21 #include <canvas/canvastools.hxx>
23 #include <eventqueue.hxx>
24 #include <eventmultiplexer.hxx>
25 #include <slideview.hxx>
26 #include <delayevent.hxx>
27 #include <unoview.hxx>
29 #include <cppuhelper/basemutex.hxx>
30 #include <cppuhelper/compbase.hxx>
31 #include <comphelper/make_shared_from_uno.hxx>
33 #include <cppcanvas/spritecanvas.hxx>
34 #include <cppcanvas/customsprite.hxx>
35 #include <cppcanvas/vclfactory.hxx>
36 #include <cppcanvas/basegfxfactory.hxx>
38 #include <basegfx/range/b1drange.hxx>
39 #include <basegfx/range/b2drange.hxx>
40 #include <basegfx/range/b2irange.hxx>
41 #include <basegfx/point/b2dpoint.hxx>
42 #include <basegfx/polygon/b2dpolygon.hxx>
43 #include <basegfx/matrix/b2dhommatrix.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
45 #include <basegfx/polygon/b2dpolypolygontools.hxx>
46 #include <basegfx/utils/canvastools.hxx>
47 #include <basegfx/polygon/b2dpolygonclipper.hxx>
48 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
50 #include <com/sun/star/awt/XPaintListener.hpp>
51 #include <com/sun/star/presentation/XSlideShowView.hpp>
52 #include <com/sun/star/rendering/CompositeOperation.hpp>
53 #include <com/sun/star/util/XModifyListener.hpp>
60 using namespace com::sun::star
;
62 namespace slideshow::internal
{
66 /** Sprite entry, to store sprite plus priority
68 The operator<() defines a strict weak ordering of sprites, sort
69 key is the sprite priority.
73 SpriteEntry( const cppcanvas::CustomSpriteSharedPtr
& rSprite
,
80 bool operator<(const SpriteEntry
& rRHS
) const
82 return mnPriority
< rRHS
.mnPriority
;
85 std::weak_ptr
< cppcanvas::CustomSprite
> mpSprite
;
89 typedef std::vector
< SpriteEntry
> SpriteVector
;
92 /** Create a clip polygon for slide views
95 Clip to set (can be empty)
98 Canvas to create the clip polygon for
101 The size of the view. Note that the returned clip will
102 <em>always</em> clip to at least the rect defined herein.
104 @return the view clip polygon, in view coordinates, which is
105 guaranteed to at least clip to the view size.
107 basegfx::B2DPolyPolygon
createClipPolygon( const basegfx::B2DPolyPolygon
& rClip
,
108 const cppcanvas::CanvasSharedPtr
& /*rCanvas*/,
109 const basegfx::B2DSize
& rUserSize
)
111 // setup canvas clipping
112 // =====================
115 const basegfx::B2DRange
aClipRange(0, 0, rUserSize
.getWidth(), rUserSize
.getHeight());
119 return basegfx::utils::clipPolyPolygonOnRange(rClip
, aClipRange
, true, false);
123 return basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aClipRange
));
127 /** Prepare given clip polygon to be stored as the current clip
129 Note that this is separate from createClipPolygon(), to allow
130 SlideView implementations to store this intermediate result
131 (createClipPolygon() has to be called every time the view size
134 basegfx::B2DPolyPolygon
prepareClip( const basegfx::B2DPolyPolygon
& rClip
)
136 basegfx::B2DPolyPolygon
aClip( rClip
);
138 // normalize polygon, preparation for clipping
140 aClip
= basegfx::utils::correctOrientations(aClip
);
141 aClip
= basegfx::utils::solveCrossovers(aClip
);
142 aClip
= basegfx::utils::stripNeutralPolygons(aClip
);
143 aClip
= basegfx::utils::stripDispensablePolygons(aClip
);
149 void clearRect( ::cppcanvas::CanvasSharedPtr
const& pCanvas
,
150 basegfx::B2IRange
const& rArea
)
152 // convert clip polygon to device coordinate system
153 ::basegfx::B2DPolyPolygon
const* pClipPoly( pCanvas
->getClip() );
156 ::basegfx::B2DPolyPolygon
aClipPoly( *pClipPoly
);
157 aClipPoly
.transform( pCanvas
->getTransformation() );
158 pCanvas
->setClip( aClipPoly
);
161 // set transformation to identity (->device pixel)
162 pCanvas
->setTransformation( ::basegfx::B2DHomMatrix() );
164 // #i42440# Fill the _full_ background in
165 // black. Since we had to extend the bitmap by one
166 // pixel, and the bitmap is initialized white,
167 // depending on the slide content a one pixel wide
168 // line will show to the bottom and the right.
169 const ::basegfx::B2DPolygon
aPoly(
170 ::basegfx::utils::createPolygonFromRect(
171 basegfx::B2DRange(rArea
)));
173 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly(
174 ::cppcanvas::BaseGfxFactory::createPolyPolygon( pCanvas
, aPoly
) );
178 pPolyPoly
->setCompositeOp( css::rendering::CompositeOperation::SOURCE
);
179 pPolyPoly
->setRGBAFillColor( 0xFFFFFF00U
);
183 #if defined(DBG_UTIL)
184 ::cppcanvas::CanvasSharedPtr
pCliplessCanvas( pCanvas
->clone() );
185 pCliplessCanvas
->setClip();
187 if( pCanvas
->getClip() )
189 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly2(
190 ::cppcanvas::BaseGfxFactory::createPolyPolygon( pCliplessCanvas
, aPoly
));
193 pPolyPoly2
->setRGBALineColor( 0x008000FFU
);
200 /** Get bounds in pixel
203 Bound rect, in user space coordinates
205 @param rTransformation
206 User space to device pixel transformation
208 @return the layer bounds in pixel, extended by one pixel to the
211 basegfx::B2IRange
getLayerBoundsPixel( basegfx::B2DRange
const& rLayerBounds
,
212 basegfx::B2DHomMatrix
const& rTransformation
)
214 ::basegfx::B2DRange aTmpRect
;
215 ::canvas::tools::calcTransformedRectBounds( aTmpRect
,
219 if( aTmpRect
.isEmpty() )
220 return ::basegfx::B2IRange();
222 // #i42440# Returned layer size is one pixel too small, as
223 // rendering happens one pixel to the right and below the
224 // actual bound rect.
225 return ::basegfx::B2IRange( ::basegfx::fround(aTmpRect
.getMinX()),
226 ::basegfx::fround(aTmpRect
.getMinY()),
227 ::basegfx::fround(aTmpRect
.getMaxX()) + 1,
228 ::basegfx::fround(aTmpRect
.getMaxY()) + 1 );
232 /** Container class for sprites issued by a ViewLayer
234 This class handles the sprite prioritization issues, that are
235 needed for layer sprites (e.g. the need to re-prioritize sprites
236 when the layer changes prio).
238 class LayerSpriteContainer
240 /** Max fill level of maSprites, before we try to prune it from
243 enum{ SPRITE_ULLAGE
=256 };
245 /** All sprites that have been issued by this container (pruned
246 from time to time, for invalid references). This vector is
247 kept sorted with increasing sprite priority.
249 SpriteVector maSprites
;
251 /// Priority of this layer, relative to other view layers
252 basegfx::B1DRange maLayerPrioRange
;
254 double getSpritePriority( std::size_t nSpriteNum
) const
256 // divide the available layer range equally between all
257 // sprites, assign upper bound of individual sprite range as
258 // sprite prio (the layer itself gets assigned the lower bound
259 // of sprite 0's individual range):
261 // | layer 0 | layer 1 | ...
262 // | sprite 0 | sprite 1 | sprite 0 | sprite 1 | ...
263 return maLayerPrioRange
.getMinimum() + maLayerPrioRange
.getRange()*(nSpriteNum
+1)/(maSprites
.size()+1);
266 /** Rescan sprite vector, and remove deceased sprites (and reset
270 Iterator to the first entry to rescan
274 SpriteVector aValidSprites
;
276 // check all sprites for validity and set new priority
277 for( const auto& rSprite
: maSprites
)
279 cppcanvas::CustomSpriteSharedPtr
pCurrSprite( rSprite
.mpSprite
.lock() );
283 // only copy still valid sprites over to the refreshed
285 aValidSprites
.push_back( rSprite
);
287 pCurrSprite
->setPriority(
288 getSpritePriority( aValidSprites
.size()-1 ));
292 // replace sprite list with pruned one
293 maSprites
.swap( aValidSprites
);
297 LayerSpriteContainer() :
303 const basegfx::B1DRange
& getLayerPriority() const
305 return maLayerPrioRange
;
308 void setLayerPriority( const basegfx::B1DRange
& rRange
)
310 if( rRange
!= maLayerPrioRange
)
312 maLayerPrioRange
= rRange
;
314 // prune and recalc sprite prios
319 void addSprite( const cppcanvas::CustomSpriteSharedPtr
& pSprite
,
325 SpriteEntry
aEntry( pSprite
,nPriority
);
327 // insert new sprite, such that vector stays sorted
328 SpriteVector::iterator
aInsertPos(
330 std::lower_bound( maSprites
.begin(),
335 const std::size_t nNumSprites( maSprites
.size() );
336 if( nNumSprites
> SPRITE_ULLAGE
||
337 maSprites
.end() - aInsertPos
> 1 )
339 // updateSprites() also updates all sprite prios
344 // added sprite to the end, and not too many sprites in
345 // vector - perform optimized update (only need to set
346 // prio). This basically caters for the common case of
347 // iterated character animations, which generate lots of
348 // sprites, all added to the end.
349 pSprite
->setPriority(
350 getSpritePriority( nNumSprites
-1 ));
361 /** This class provides layers for a slide view
363 Layers are used to render animations with the correct z order -
364 because sprites are always in front of the static canvas
365 background, shapes that must appear <em<before</em> an animation
366 must also be displayed as a sprite.
368 Each layer has a priority assigned to it (valid range [0,1]), which
369 also affects all sprites created for this specific layer - i.e. if
370 the layer priority changes, the sprites change z order together
373 class SlideViewLayer
: public ViewLayer
375 /// Smart container for all sprites issued by this layer
376 mutable LayerSpriteContainer maSpriteContainer
;
378 /// Bounds of this layer in user space coordinates
379 basegfx::B2DRange maLayerBounds
;
381 /// Bounds of this layer in device pixel
382 mutable basegfx::B2IRange maLayerBoundsPixel
;
384 /// Current clip polygon in user coordinates
385 basegfx::B2DPolyPolygon maClip
;
387 /// Current size of the view in user coordinates
388 basegfx::B2DSize maUserSize
;
390 /// Current overall view transformation
391 basegfx::B2DHomMatrix maTransformation
;
393 /// 'parent' canvas, this viewlayer is associated with
394 const cppcanvas::SpriteCanvasSharedPtr mpSpriteCanvas
;
396 /** output surface (necessarily a sprite, won't otherwise be able
397 to display anything <em>before</em> other sprites)
399 mutable cppcanvas::CustomSpriteSharedPtr mpSprite
;
401 /// actual output canvas retrieved from a sprite
402 mutable cppcanvas::CanvasSharedPtr mpOutputCanvas
;
404 /// ptr back to owning view. needed for isOnView() method
405 View
const* const mpParentView
;
408 /** Create a new layer
411 Sprite canvas to create the layer on
414 Initial overall canvas transformation
417 Initial layer bounds, in view coordinate system
419 SlideViewLayer( cppcanvas::SpriteCanvasSharedPtr pCanvas
,
420 basegfx::B2DHomMatrix aTransform
,
421 const basegfx::B2DRange
& rLayerBounds
,
422 const basegfx::B2DSize
& rUserSize
,
423 View
const* const pParentView
) :
425 maLayerBounds(rLayerBounds
),
426 maLayerBoundsPixel(),
428 maUserSize(rUserSize
),
429 maTransformation(std::move(aTransform
)),
430 mpSpriteCanvas(std::move(pCanvas
)),
433 mpParentView(pParentView
)
437 SlideViewLayer(const SlideViewLayer
&) = delete;
438 SlideViewLayer
& operator=(const SlideViewLayer
&) = delete;
440 void updateView( const basegfx::B2DHomMatrix
& rMatrix
,
441 const basegfx::B2DSize
& rUserSize
)
443 maTransformation
= rMatrix
;
444 maUserSize
= rUserSize
;
446 // limit layer bounds to visible screen
447 maLayerBounds
.intersect( basegfx::B2DRange(0.0,
449 maUserSize
.getWidth(),
450 maUserSize
.getHeight()) );
452 basegfx::B2IRange
const& rNewLayerPixel(
453 getLayerBoundsPixel(maLayerBounds
,
455 if( rNewLayerPixel
!= maLayerBoundsPixel
)
457 // re-gen sprite with new size
458 mpOutputCanvas
.reset();
463 virtual css::geometry::IntegerSize2D
getTranslationOffset() const override
465 basegfx::B2DRectangle aTmpRect
;
466 canvas::tools::calcTransformedRectBounds( aTmpRect
,
469 geometry::IntegerSize2D
offset(0, 0);
471 // Add translation according to the origin of aTmpRect. Ignore the
472 // translation when aTmpRect was not properly initialized.
473 if ( ! aTmpRect
.isEmpty())
475 offset
.Width
= basegfx::fround(aTmpRect
.getMinX());
476 offset
.Height
= basegfx::fround(aTmpRect
.getMinY());
482 // ViewLayer interface
485 virtual cppcanvas::CustomSpriteSharedPtr
createSprite(
486 const ::basegfx::B2DSize
& rSpriteSizePixel
,
487 double nPriority
) const override
489 cppcanvas::CustomSpriteSharedPtr
pSprite(
490 mpSpriteCanvas
->createCustomSprite( rSpriteSizePixel
) );
492 maSpriteContainer
.addSprite( pSprite
,
498 virtual void setPriority( const basegfx::B1DRange
& rRange
) override
500 OSL_ENSURE( !rRange
.isEmpty() &&
501 rRange
.getMinimum() >= 1.0,
502 "SlideViewLayer::setPriority(): prio MUST be larger than 1.0 (because "
503 "the background layer already lies there)" );
505 maSpriteContainer
.setLayerPriority( rRange
);
508 mpSprite
->setPriority( rRange
.getMinimum() );
511 virtual basegfx::B2DHomMatrix
getTransformation() const override
513 // Offset given transformation by left, top border of given
514 // range (after transformation through given transformation)
515 basegfx::B2DRectangle aTmpRect
;
516 canvas::tools::calcTransformedRectBounds( aTmpRect
,
520 basegfx::B2DHomMatrix
aMatrix( maTransformation
);
522 // Add translation according to the origin of aTmpRect. Ignore the
523 // translation when aTmpRect was not properly initialized.
524 if ( ! aTmpRect
.isEmpty())
526 aMatrix
.translate( -basegfx::fround(aTmpRect
.getMinX()),
527 -basegfx::fround(aTmpRect
.getMinY()) );
533 virtual basegfx::B2DHomMatrix
getSpriteTransformation() const override
535 return maTransformation
;
538 virtual void clear() const override
540 // grab canvas - that also lazy-initializes maLayerBoundsPixel
541 cppcanvas::CanvasSharedPtr pCanvas
=getCanvas()->clone();
543 // clear whole canvas
544 const basegfx::B2I64Tuple
& rSpriteSize(maLayerBoundsPixel
.getRange());
546 basegfx::B2IRange(0,0,rSpriteSize
.getX(),rSpriteSize
.getY()));
549 virtual void clearAll() const override
551 // grab canvas - that also lazy-initializes maLayerBoundsPixel
552 ::cppcanvas::CanvasSharedPtr
pCanvas( getCanvas()->clone() );
554 // clear layer clip, to clear whole area
557 // clear whole canvas
558 const basegfx::B2I64Tuple
& rSpriteSize(maLayerBoundsPixel
.getRange());
560 basegfx::B2IRange(0,0,rSpriteSize
.getX(),rSpriteSize
.getY()));
563 virtual bool isOnView(ViewSharedPtr
const& rView
) const override
565 return rView
.get() == mpParentView
;
568 virtual cppcanvas::CanvasSharedPtr
getCanvas() const override
570 if( !mpOutputCanvas
)
574 maLayerBoundsPixel
= getLayerBoundsPixel(maLayerBounds
,
577 // HACK: ensure at least 1x1 pixel size. clients might
578 // need an actual canvas (e.g. for bound rect
579 // calculations) without rendering anything. Better
580 // solution: introduce something like a reference
581 // canvas for ViewLayers, which is always available.
582 if( maLayerBoundsPixel
.isEmpty() )
583 maLayerBoundsPixel
= basegfx::B2IRange(0,0,1,1);
585 const basegfx::B2I64Tuple
& rSpriteSize(maLayerBoundsPixel
.getRange());
586 mpSprite
= mpSpriteCanvas
->createCustomSprite(
587 basegfx::B2DSize(sal::static_int_cast
<sal_Int32
>(rSpriteSize
.getX()),
588 sal::static_int_cast
<sal_Int32
>(rSpriteSize
.getY())) );
590 mpSprite
->setPriority(
591 maSpriteContainer
.getLayerPriority().getMinimum() );
593 #if defined(DBG_UTIL)
595 basegfx::B2DPoint(maLayerBoundsPixel
.getMinimum()) +
596 basegfx::B2DPoint(10,10) );
598 mpSprite
->setAlpha(0.5);
601 basegfx::B2DPoint(maLayerBoundsPixel
.getMinimum()) );
603 mpSprite
->setAlpha(1.0);
608 ENSURE_OR_THROW( mpSprite
,
609 "SlideViewLayer::getCanvas(): no layer sprite" );
611 mpOutputCanvas
= mpSprite
->getContentCanvas();
613 ENSURE_OR_THROW( mpOutputCanvas
,
614 "SlideViewLayer::getCanvas(): sprite doesn't yield a canvas" );
616 // new canvas retrieved - setup transformation and clip
617 mpOutputCanvas
->setTransformation( getTransformation() );
618 mpOutputCanvas
->setClip(
619 createClipPolygon( maClip
,
624 return mpOutputCanvas
;
627 virtual void setClip( const basegfx::B2DPolyPolygon
& rClip
) override
629 basegfx::B2DPolyPolygon aNewClip
= prepareClip( rClip
);
631 if( aNewClip
!= maClip
)
636 mpOutputCanvas
->setClip(
637 createClipPolygon( maClip
,
643 virtual bool resize( const ::basegfx::B2DRange
& rArea
) override
645 const bool bRet( maLayerBounds
!= rArea
);
646 maLayerBounds
= rArea
;
647 updateView( maTransformation
,
655 typedef cppu::WeakComponentImplHelper
<
656 css::util::XModifyListener
,
657 css::awt::XPaintListener
> SlideViewBase
;
661 This class implements the View interface, encapsulating
662 <em>one</em> view a slideshow is displayed on.
664 class SlideView
: private cppu::BaseMutex
,
665 public SlideViewBase
,
669 SlideView( const uno::Reference
<presentation::XSlideShowView
>& xView
,
670 EventQueue
& rEventQueue
,
671 EventMultiplexer
& rEventMultiplexer
);
676 virtual ViewLayerSharedPtr
createViewLayer( const basegfx::B2DRange
& rLayerBounds
) const override
;
677 virtual bool updateScreen() const override
;
678 virtual bool paintScreen() const override
;
679 virtual void setViewSize( const ::basegfx::B2DSize
& ) override
;
680 virtual void setCursorShape( sal_Int16 nPointerShape
) override
;
682 // ViewLayer interface
683 virtual bool isOnView(ViewSharedPtr
const& rView
) const override
;
684 virtual void clear() const override
;
685 virtual void clearAll() const override
;
686 virtual cppcanvas::CanvasSharedPtr
getCanvas() const override
;
687 virtual cppcanvas::CustomSpriteSharedPtr
createSprite( const ::basegfx::B2DSize
& rSpriteSizePixel
,
688 double nPriority
) const override
;
689 virtual void setPriority( const basegfx::B1DRange
& rRange
) override
;
690 virtual geometry::IntegerSize2D
getTranslationOffset() const override
;
691 virtual ::basegfx::B2DHomMatrix
getTransformation() const override
;
692 virtual basegfx::B2DHomMatrix
getSpriteTransformation() const override
;
693 virtual void setClip( const ::basegfx::B2DPolyPolygon
& rClip
) override
;
694 virtual bool resize( const ::basegfx::B2DRange
& rArea
) override
;
697 virtual void _dispose() override
;
698 virtual uno::Reference
<presentation::XSlideShowView
> getUnoView()const override
;
699 virtual void setIsSoundEnabled (const bool bValue
) override
;
700 virtual bool isSoundEnabled() const override
;
703 virtual void SAL_CALL
disposing( lang::EventObject
const& evt
) override
;
705 virtual void SAL_CALL
modified( const lang::EventObject
& aEvent
) override
;
707 virtual void SAL_CALL
windowPaint( const awt::PaintEvent
& e
) override
;
709 // WeakComponentImplHelperBase:
710 virtual void SAL_CALL
disposing() override
;
715 typedef std::vector
< std::weak_ptr
<SlideViewLayer
> > ViewLayerVector
;
717 /// Prune viewlayers from deceased ones, optionally update them
718 void pruneLayers( bool bWithViewLayerUpdate
=false ) const;
720 /** Max fill level of maViewLayers, before we try to prune it from
723 enum{ LAYER_ULLAGE
=8 };
725 uno::Reference
<presentation::XSlideShowView
> mxView
;
726 cppcanvas::SpriteCanvasSharedPtr mpCanvas
;
728 EventMultiplexer
& mrEventMultiplexer
;
729 EventQueue
& mrEventQueue
;
731 mutable LayerSpriteContainer maSprites
;
732 mutable ViewLayerVector maViewLayers
;
734 basegfx::B2DPolyPolygon maClip
;
736 basegfx::B2DHomMatrix maViewTransform
;
737 basegfx::B2DSize maUserSize
;
738 bool mbIsSoundEnabled
;
742 SlideView::SlideView( const uno::Reference
<presentation::XSlideShowView
>& xView
,
743 EventQueue
& rEventQueue
,
744 EventMultiplexer
& rEventMultiplexer
) :
745 SlideViewBase( m_aMutex
),
748 mrEventMultiplexer( rEventMultiplexer
),
749 mrEventQueue( rEventQueue
),
754 maUserSize( 1.0, 1.0 ), // default size: one-by-one rectangle
755 mbIsSoundEnabled(true)
757 // take care not constructing any UNO references to this _inside_
758 // ctor, shift that code to createSlideView()!
759 ENSURE_OR_THROW( mxView
.is(),
760 "SlideView::SlideView(): Invalid view" );
762 mpCanvas
= cppcanvas::VCLFactory::createSpriteCanvas(
763 xView
->getCanvas() );
764 ENSURE_OR_THROW( mpCanvas
,
765 "Could not create cppcanvas" );
767 geometry::AffineMatrix2D
aViewTransform(
768 xView
->getTransformation() );
770 if( basegfx::fTools::equalZero(
771 basegfx::B2DVector(aViewTransform
.m00
,
772 aViewTransform
.m10
).getLength()) ||
773 basegfx::fTools::equalZero(
774 basegfx::B2DVector(aViewTransform
.m01
,
775 aViewTransform
.m11
).getLength()) )
777 OSL_FAIL( "SlideView::SlideView(): Singular matrix!" );
779 canvas::tools::setIdentityAffineMatrix2D(aViewTransform
);
782 basegfx::unotools::homMatrixFromAffineMatrix(
783 maViewTransform
, aViewTransform
);
785 // once and forever: set fixed prio to this 'layer' (we're always
786 // the background layer)
787 maSprites
.setLayerPriority( basegfx::B1DRange(0.0,1.0) );
790 void SlideView::disposing()
792 osl::MutexGuard
aGuard( m_aMutex
);
794 maViewLayers
.clear();
798 // additionally, also de-register from XSlideShowView
801 mxView
->removeTransformationChangedListener( this );
802 mxView
->removePaintListener( this );
807 ViewLayerSharedPtr
SlideView::createViewLayer( const basegfx::B2DRange
& rLayerBounds
) const
809 osl::MutexGuard
aGuard( m_aMutex
);
811 ENSURE_OR_THROW( mpCanvas
,
812 "SlideView::createViewLayer(): Disposed" );
814 const std::size_t nNumLayers( maViewLayers
.size() );
816 // avoid filling up layer vector with lots of deceased layer weak
818 if( nNumLayers
> LAYER_ULLAGE
)
821 auto xViewLayer
= std::make_shared
<SlideViewLayer
>(mpCanvas
,
826 maViewLayers
.push_back(xViewLayer
);
831 bool SlideView::updateScreen() const
833 osl::MutexGuard
aGuard( m_aMutex
);
835 ENSURE_OR_RETURN_FALSE( mpCanvas
,
836 "SlideView::updateScreen(): Disposed" );
838 return mpCanvas
->updateScreen( false );
841 bool SlideView::paintScreen() const
843 osl::MutexGuard
aGuard( m_aMutex
);
845 ENSURE_OR_RETURN_FALSE( mpCanvas
,
846 "SlideView::paintScreen(): Disposed" );
848 return mpCanvas
->updateScreen( true );
851 void SlideView::clear() const
853 osl::MutexGuard
aGuard( m_aMutex
);
855 OSL_ENSURE( mxView
.is() && mpCanvas
,
856 "SlideView::clear(): Disposed" );
857 if( !mxView
.is() || !mpCanvas
)
861 clearRect(getCanvas()->clone(),
863 basegfx::B2DRange(0,0,
864 maUserSize
.getWidth(),
865 maUserSize
.getHeight()),
866 getTransformation()));
869 void SlideView::clearAll() const
871 osl::MutexGuard
aGuard( m_aMutex
);
873 OSL_ENSURE( mxView
.is() && mpCanvas
,
874 "SlideView::clear(): Disposed" );
875 if( !mxView
.is() || !mpCanvas
)
878 mpCanvas
->clear(); // this is unnecessary, strictly speaking. but
879 // it makes the SlideView behave exactly like a
880 // sprite-based SlideViewLayer, because those
881 // are created from scratch after a resize
887 void SlideView::setViewSize( const basegfx::B2DSize
& rSize
)
889 osl::MutexGuard
aGuard( m_aMutex
);
895 void SlideView::setCursorShape( sal_Int16 nPointerShape
)
897 osl::MutexGuard
const guard( m_aMutex
);
900 mxView
->setMouseCursor( nPointerShape
);
903 bool SlideView::isOnView(ViewSharedPtr
const& rView
) const
905 return rView
.get() == this;
908 cppcanvas::CanvasSharedPtr
SlideView::getCanvas() const
910 osl::MutexGuard
aGuard( m_aMutex
);
912 ENSURE_OR_THROW( mpCanvas
,
913 "SlideView::getCanvas(): Disposed" );
918 cppcanvas::CustomSpriteSharedPtr
SlideView::createSprite(
919 const basegfx::B2DSize
& rSpriteSizePixel
,
920 double nPriority
) const
922 osl::MutexGuard
aGuard( m_aMutex
);
924 ENSURE_OR_THROW( mpCanvas
, "SlideView::createSprite(): Disposed" );
926 cppcanvas::CustomSpriteSharedPtr
pSprite(
927 mpCanvas
->createCustomSprite( rSpriteSizePixel
) );
929 maSprites
.addSprite( pSprite
,
935 void SlideView::setPriority( const basegfx::B1DRange
& /*rRange*/ )
937 OSL_FAIL( "SlideView::setPriority() is a NOOP for slide view - "
938 "content will always be shown in the background" );
941 basegfx::B2DHomMatrix
SlideView::getTransformation() const
943 osl::MutexGuard
aGuard( m_aMutex
);
945 basegfx::B2DHomMatrix aMatrix
;
946 aMatrix
.scale( 1.0 / maUserSize
.getWidth(), 1.0 / maUserSize
.getHeight() );
948 return maViewTransform
* aMatrix
;
951 geometry::IntegerSize2D
SlideView::getTranslationOffset() const
953 return mxView
->getTranslationOffset();
956 basegfx::B2DHomMatrix
SlideView::getSpriteTransformation() const
958 return getTransformation();
961 void SlideView::setClip( const basegfx::B2DPolyPolygon
& rClip
)
963 osl::MutexGuard
aGuard( m_aMutex
);
965 basegfx::B2DPolyPolygon aNewClip
= prepareClip( rClip
);
967 if( aNewClip
!= maClip
)
975 bool SlideView::resize( const ::basegfx::B2DRange
& /*rArea*/ )
977 OSL_FAIL( "SlideView::resize(): ignored for the View, can't change size "
978 "effectively, anyway" );
983 uno::Reference
<presentation::XSlideShowView
> SlideView::getUnoView() const
985 osl::MutexGuard
aGuard( m_aMutex
);
989 void SlideView::setIsSoundEnabled (const bool bValue
)
991 mbIsSoundEnabled
= bValue
;
994 bool SlideView::isSoundEnabled() const
996 return mbIsSoundEnabled
;
999 void SlideView::_dispose()
1005 void SlideView::disposing( lang::EventObject
const& evt
)
1007 // no deregistration necessary anymore, XView has left:
1008 osl::MutexGuard
const guard( m_aMutex
);
1012 OSL_ASSERT( evt
.Source
== mxView
);
1019 // silly wrapper to check that event handlers don't touch dead SlideView
1020 struct WeakRefWrapper
1023 uno::WeakReference
<uno::XInterface
> const m_wObj
;
1024 std::function
<void (SlideView
&)> const m_func
;
1026 WeakRefWrapper(SlideView
& rObj
, std::function
<void (SlideView
&)> func
)
1028 , m_wObj(rObj
.getXWeak())
1029 , m_func(std::move(func
))
1035 uno::Reference
<uno::XInterface
> const xObj(m_wObj
);
1044 void SlideView::modified( const lang::EventObject
& /*aEvent*/ )
1046 osl::MutexGuard
const guard( m_aMutex
);
1048 OSL_ENSURE( mxView
.is(), "SlideView::modified(): "
1049 "Disposed, but event received from XSlideShowView?!");
1054 geometry::AffineMatrix2D
aViewTransform(
1055 mxView
->getTransformation() );
1057 if( basegfx::fTools::equalZero(
1058 basegfx::B2DVector(aViewTransform
.m00
,
1059 aViewTransform
.m10
).getLength()) ||
1060 basegfx::fTools::equalZero(
1061 basegfx::B2DVector(aViewTransform
.m01
,
1062 aViewTransform
.m11
).getLength()) )
1064 OSL_FAIL( "SlideView::modified(): Singular matrix!" );
1066 canvas::tools::setIdentityAffineMatrix2D(aViewTransform
);
1069 // view transformation really changed?
1070 basegfx::B2DHomMatrix aNewTransform
;
1071 basegfx::unotools::homMatrixFromAffineMatrix(
1075 if( aNewTransform
== maViewTransform
)
1076 return; // No change, nothing to do
1078 maViewTransform
= aNewTransform
;
1082 // notify view change. Don't call EventMultiplexer directly, this
1083 // might not be the main thread!
1084 mrEventQueue
.addEvent(
1085 makeEvent( WeakRefWrapper(*this,
1086 [] (SlideView
& rThis
) { rThis
.mrEventMultiplexer
.notifyViewChanged(rThis
.mxView
); }),
1087 "EventMultiplexer::notifyViewChanged"));
1091 void SlideView::windowPaint( const awt::PaintEvent
& /*e*/ )
1093 osl::MutexGuard
aGuard( m_aMutex
);
1095 OSL_ENSURE( mxView
.is() && mpCanvas
, "Disposed, but event received?!" );
1097 // notify view clobbering. Don't call EventMultiplexer directly,
1098 // this might not be the main thread!
1099 mrEventQueue
.addEvent(
1100 makeEvent( WeakRefWrapper(*this,
1101 [] (SlideView
& rThis
) { rThis
.mrEventMultiplexer
.notifyViewClobbered(rThis
.mxView
); }),
1102 "EventMultiplexer::notifyViewClobbered") );
1105 void SlideView::updateCanvas()
1107 OSL_ENSURE( mpCanvas
,
1108 "SlideView::updateCanvasTransform(): Disposed" );
1110 if( !mpCanvas
|| !mxView
.is())
1114 mpCanvas
->setTransformation( getTransformation() );
1116 createClipPolygon( maClip
,
1120 // forward update to viewlayers
1121 pruneLayers( true );
1124 void SlideView::updateClip()
1126 OSL_ENSURE( mpCanvas
,
1127 "SlideView::updateClip(): Disposed" );
1133 createClipPolygon( maClip
,
1140 void SlideView::pruneLayers( bool bWithViewLayerUpdate
) const
1142 ViewLayerVector aValidLayers
;
1144 const basegfx::B2DHomMatrix
& rCurrTransform(
1145 getTransformation() );
1147 // check all layers for validity, and retain only the live ones
1148 for( const auto& rView
: maViewLayers
)
1150 std::shared_ptr
< SlideViewLayer
> xCurrLayer( rView
.lock() );
1154 aValidLayers
.push_back( xCurrLayer
);
1156 if( bWithViewLayerUpdate
)
1157 xCurrLayer
->updateView( rCurrTransform
,
1162 // replace layer list with pruned one
1163 maViewLayers
.swap( aValidLayers
);
1166 } // anonymous namespace
1168 UnoViewSharedPtr
createSlideView( uno::Reference
< presentation::XSlideShowView
> const& xView
,
1169 EventQueue
& rEventQueue
,
1170 EventMultiplexer
& rEventMultiplexer
)
1172 std::shared_ptr
<SlideView
> const that(
1173 comphelper::make_shared_from_UNO(
1174 new SlideView(xView
,
1176 rEventMultiplexer
)));
1178 // register listeners with XSlideShowView
1179 xView
->addTransformationChangedListener( that
.get() );
1180 xView
->addPaintListener( that
.get() );
1182 // set new transformation
1183 that
->updateCanvas();
1188 } // namespace slideshow
1190 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */