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 <tools/diagnose_ex.h>
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 <cppuhelper/implementationentry.hxx>
32 #include <cppuhelper/interfacecontainer.h>
33 #include <comphelper/make_shared_from_uno.hxx>
35 #include <cppcanvas/spritecanvas.hxx>
36 #include <cppcanvas/customsprite.hxx>
37 #include <cppcanvas/vclfactory.hxx>
38 #include <cppcanvas/basegfxfactory.hxx>
40 #include <basegfx/range/b1drange.hxx>
41 #include <basegfx/range/b2drange.hxx>
42 #include <basegfx/range/b2irange.hxx>
43 #include <basegfx/point/b2dpoint.hxx>
44 #include <basegfx/polygon/b2dpolygon.hxx>
45 #include <basegfx/matrix/b2dhommatrix.hxx>
46 #include <basegfx/polygon/b2dpolygontools.hxx>
47 #include <basegfx/polygon/b2dpolypolygontools.hxx>
48 #include <basegfx/utils/canvastools.hxx>
49 #include <basegfx/polygon/b2dpolygonclipper.hxx>
50 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
52 #include <com/sun/star/presentation/XSlideShow.hpp>
53 #include <com/sun/star/rendering/CompositeOperation.hpp>
60 using namespace com::sun::star
;
67 /** Sprite entry, to store sprite plus priority
69 The operator<() defines a strict weak ordering of sprites, sort
70 key is the sprite priority.
74 SpriteEntry( const cppcanvas::CustomSpriteSharedPtr
& rSprite
,
81 bool operator<(const SpriteEntry
& rRHS
) const
83 return mnPriority
< rRHS
.mnPriority
;
86 std::weak_ptr
< cppcanvas::CustomSprite
> mpSprite
;
90 typedef std::vector
< SpriteEntry
> SpriteVector
;
93 /** Create a clip polygon for slide views
96 Clip to set (can be empty)
99 Canvas to create the clip polygon for
102 The size of the view. Note that the returned clip will
103 <em>always</em> clip to at least the rect defined herein.
105 @return the view clip polygon, in view coordinates, which is
106 guaranteed to at least clip to the view size.
108 basegfx::B2DPolyPolygon
createClipPolygon( const basegfx::B2DPolyPolygon
& rClip
,
109 const cppcanvas::CanvasSharedPtr
& /*rCanvas*/,
110 const basegfx::B2DSize
& rUserSize
)
112 // setup canvas clipping
113 // =====================
116 const basegfx::B2DRange
aClipRange(0, 0, rUserSize
.getX(), rUserSize
.getY());
120 return basegfx::utils::clipPolyPolygonOnRange(rClip
, aClipRange
, true, false);
124 return basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aClipRange
));
128 /** Prepare given clip polygon to be stored as the current clip
130 Note that this is separate from createClipPolygon(), to allow
131 SlideView implementations to store this intermediate result
132 (createClipPolygon() has to be called every time the view size
135 basegfx::B2DPolyPolygon
prepareClip( const basegfx::B2DPolyPolygon
& rClip
)
137 basegfx::B2DPolyPolygon
aClip( rClip
);
139 // TODO(P2): unnecessary, once XCanvas is correctly handling this
140 // AW: Should be no longer necessary; tools are now bezier-safe
141 if( aClip
.areControlPointsUsed() )
142 aClip
= basegfx::utils::adaptiveSubdivideByAngle( aClip
);
144 // normalize polygon, preparation for clipping
146 aClip
= basegfx::utils::correctOrientations(aClip
);
147 aClip
= basegfx::utils::solveCrossovers(aClip
);
148 aClip
= basegfx::utils::stripNeutralPolygons(aClip
);
149 aClip
= basegfx::utils::stripDispensablePolygons(aClip
);
155 void clearRect( ::cppcanvas::CanvasSharedPtr
const& pCanvas
,
156 basegfx::B2IRange
const& rArea
)
158 // convert clip polygon to device coordinate system
159 ::basegfx::B2DPolyPolygon
const* pClipPoly( pCanvas
->getClip() );
162 ::basegfx::B2DPolyPolygon
aClipPoly( *pClipPoly
);
163 aClipPoly
.transform( pCanvas
->getTransformation() );
164 pCanvas
->setClip( aClipPoly
);
167 // set transformation to identitiy (->device pixel)
168 pCanvas
->setTransformation( ::basegfx::B2DHomMatrix() );
170 // #i42440# Fill the _full_ background in
171 // black. Since we had to extend the bitmap by one
172 // pixel, and the bitmap is initialized white,
173 // depending on the slide content a one pixel wide
174 // line will show to the bottom and the right.
175 const ::basegfx::B2DPolygon
aPoly(
176 ::basegfx::utils::createPolygonFromRect(
177 basegfx::B2DRange(rArea
)));
179 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly(
180 ::cppcanvas::BaseGfxFactory::createPolyPolygon( pCanvas
, aPoly
) );
184 pPolyPoly
->setCompositeOp( css::rendering::CompositeOperation::SOURCE
);
185 pPolyPoly
->setRGBAFillColor( 0xFFFFFF00U
);
189 #if defined(DBG_UTIL)
190 ::cppcanvas::CanvasSharedPtr
pCliplessCanvas( pCanvas
->clone() );
191 pCliplessCanvas
->setClip();
193 if( pCanvas
->getClip() )
195 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly2(
196 ::cppcanvas::BaseGfxFactory::createPolyPolygon( pCliplessCanvas
, aPoly
));
199 pPolyPoly2
->setRGBALineColor( 0x008000FFU
);
206 /** Get bounds in pixel
209 Bound rect, in user space coordinates
211 @param rTransformation
212 User space to device pixel transformation
214 @return the layer bounds in pixel, extended by one pixel to the
217 basegfx::B2IRange
getLayerBoundsPixel( basegfx::B2DRange
const& rLayerBounds
,
218 basegfx::B2DHomMatrix
const& rTransformation
)
220 ::basegfx::B2DRange aTmpRect
;
221 ::canvas::tools::calcTransformedRectBounds( aTmpRect
,
225 if( aTmpRect
.isEmpty() )
226 return ::basegfx::B2IRange();
228 // #i42440# Returned layer size is one pixel too small, as
229 // rendering happens one pixel to the right and below the
230 // actual bound rect.
231 return ::basegfx::B2IRange( ::basegfx::fround(aTmpRect
.getMinX()),
232 ::basegfx::fround(aTmpRect
.getMinY()),
233 ::basegfx::fround(aTmpRect
.getMaxX()) + 1,
234 ::basegfx::fround(aTmpRect
.getMaxY()) + 1 );
238 /** Container class for sprites issued by a ViewLayer
240 This class handles the sprite prioritization issues, that are
241 needed for layer sprites (e.g. the need to re-prioritize sprites
242 when the layer changes prio).
244 class LayerSpriteContainer
246 /** Max fill level of maSprites, before we try to prune it from
249 enum{ SPRITE_ULLAGE
=256 };
251 /** All sprites that have been issued by this container (pruned
252 from time to time, for invalid references). This vector is
253 kept sorted with increasing sprite priority.
255 SpriteVector maSprites
;
257 /// Priority of this layer, relative to other view layers
258 basegfx::B1DRange maLayerPrioRange
;
260 double getSpritePriority( std::size_t nSpriteNum
) const
262 // divide the available layer range equally between all
263 // sprites, assign upper bound of individual sprite range as
264 // sprite prio (the layer itself gets assigned the lower bound
265 // of sprite 0's individual range):
267 // | layer 0 | layer 1 | ...
268 // | sprite 0 | sprite 1 | sprite 0 | sprite 1 | ...
269 return maLayerPrioRange
.getMinimum() + maLayerPrioRange
.getRange()*(nSpriteNum
+1)/(maSprites
.size()+1);
272 /** Rescan sprite vector, and remove deceased sprites (and reset
276 Iterator to the first entry to rescan
280 SpriteVector aValidSprites
;
282 // check all sprites for validity and set new priority
283 for( const auto& rSprite
: maSprites
)
285 cppcanvas::CustomSpriteSharedPtr
pCurrSprite( rSprite
.mpSprite
.lock() );
289 // only copy still valid sprites over to the refreshed
291 aValidSprites
.push_back( rSprite
);
293 pCurrSprite
->setPriority(
294 getSpritePriority( aValidSprites
.size()-1 ));
298 // replace sprite list with pruned one
299 maSprites
.swap( aValidSprites
);
303 LayerSpriteContainer() :
309 const basegfx::B1DRange
& getLayerPriority() const
311 return maLayerPrioRange
;
314 void setLayerPriority( const basegfx::B1DRange
& rRange
)
316 if( rRange
!= maLayerPrioRange
)
318 maLayerPrioRange
= rRange
;
320 // prune and recalc sprite prios
325 void addSprite( const cppcanvas::CustomSpriteSharedPtr
& pSprite
,
331 SpriteEntry
aEntry( pSprite
,nPriority
);
333 // insert new sprite, such that vector stays sorted
334 SpriteVector::iterator
aInsertPos(
336 std::lower_bound( maSprites
.begin(),
341 const std::size_t nNumSprites( maSprites
.size() );
342 if( nNumSprites
> SPRITE_ULLAGE
||
343 maSprites
.end() - aInsertPos
> 1 )
345 // updateSprites() also updates all sprite prios
350 // added sprite to the end, and not too many sprites in
351 // vector - perform optimized update (only need to set
352 // prio). This basically caters for the common case of
353 // iterated character animations, which generate lots of
354 // sprites, all added to the end.
355 pSprite
->setPriority(
356 getSpritePriority( nNumSprites
-1 ));
367 /** This class provides layers for a slide view
369 Layers are used to render animations with the correct z order -
370 because sprites are always in front of the static canvas
371 background, shapes that must appear <em<before</em> an animation
372 must also be displayed as a sprite.
374 Each layer has a priority assigned to it (valid range [0,1]), which
375 also affects all sprites created for this specific layer - i.e. if
376 the layer priority changes, the sprites change z order together
379 class SlideViewLayer
: public ViewLayer
381 /// Smart container for all sprites issued by this layer
382 mutable LayerSpriteContainer maSpriteContainer
;
384 /// Bounds of this layer in user space coordinates
385 basegfx::B2DRange maLayerBounds
;
387 /// Bounds of this layer in device pixel
388 mutable basegfx::B2IRange maLayerBoundsPixel
;
390 /// Current clip polygon in user coordinates
391 basegfx::B2DPolyPolygon maClip
;
393 /// Current size of the view in user coordinates
394 basegfx::B2DSize maUserSize
;
396 /// Current overall view transformation
397 basegfx::B2DHomMatrix maTransformation
;
399 /// 'parent' canvas, this viewlayer is associated with
400 const cppcanvas::SpriteCanvasSharedPtr mpSpriteCanvas
;
402 /** output surface (necessarily a sprite, won't otherwise be able
403 to display anything <em>before</em> other sprites)
405 mutable cppcanvas::CustomSpriteSharedPtr mpSprite
;
407 /// actual output canvas retrieved from a sprite
408 mutable cppcanvas::CanvasSharedPtr mpOutputCanvas
;
410 /// ptr back to owning view. needed for isOnView() method
411 View
const* const mpParentView
;
414 /** Create a new layer
417 Sprite canvas to create the layer on
420 Initial overall canvas transformation
423 Initial layer bounds, in view coordinate system
425 SlideViewLayer( const cppcanvas::SpriteCanvasSharedPtr
& pCanvas
,
426 const basegfx::B2DHomMatrix
& rTransform
,
427 const basegfx::B2DRange
& rLayerBounds
,
428 const basegfx::B2DSize
& rUserSize
,
429 View
const* const pParentView
) :
431 maLayerBounds(rLayerBounds
),
432 maLayerBoundsPixel(),
434 maUserSize(rUserSize
),
435 maTransformation(rTransform
),
436 mpSpriteCanvas(pCanvas
),
439 mpParentView(pParentView
)
443 SlideViewLayer(const SlideViewLayer
&) = delete;
444 SlideViewLayer
& operator=(const SlideViewLayer
&) = delete;
446 void updateView( const basegfx::B2DHomMatrix
& rMatrix
,
447 const basegfx::B2DSize
& rUserSize
)
449 maTransformation
= rMatrix
;
450 maUserSize
= rUserSize
;
452 // limit layer bounds to visible screen
453 maLayerBounds
.intersect( basegfx::B2DRange(0.0,
456 maUserSize
.getY()) );
458 basegfx::B2IRange
const& rNewLayerPixel(
459 getLayerBoundsPixel(maLayerBounds
,
461 if( rNewLayerPixel
!= maLayerBoundsPixel
)
463 // re-gen sprite with new size
464 mpOutputCanvas
.reset();
469 virtual css::geometry::IntegerSize2D
getTranslationOffset() const override
471 basegfx::B2DRectangle aTmpRect
;
472 canvas::tools::calcTransformedRectBounds( aTmpRect
,
475 geometry::IntegerSize2D
offset(0, 0);
477 // Add translation according to the origin of aTmpRect. Ignore the
478 // translation when aTmpRect was not properly initialized.
479 if ( ! aTmpRect
.isEmpty())
481 offset
.Width
= basegfx::fround(aTmpRect
.getMinX());
482 offset
.Height
= basegfx::fround(aTmpRect
.getMinY());
488 // ViewLayer interface
491 virtual cppcanvas::CustomSpriteSharedPtr
createSprite(
492 const ::basegfx::B2DSize
& rSpriteSizePixel
,
493 double nPriority
) const override
495 cppcanvas::CustomSpriteSharedPtr
pSprite(
496 mpSpriteCanvas
->createCustomSprite( rSpriteSizePixel
) );
498 maSpriteContainer
.addSprite( pSprite
,
504 virtual void setPriority( const basegfx::B1DRange
& rRange
) override
506 OSL_ENSURE( !rRange
.isEmpty() &&
507 rRange
.getMinimum() >= 1.0,
508 "SlideViewLayer::setPriority(): prio MUST be larger than 1.0 (because "
509 "the background layer already lies there)" );
511 maSpriteContainer
.setLayerPriority( rRange
);
514 mpSprite
->setPriority( rRange
.getMinimum() );
517 virtual basegfx::B2DHomMatrix
getTransformation() const override
519 // Offset given transformation by left, top border of given
520 // range (after transformation through given transformation)
521 basegfx::B2DRectangle aTmpRect
;
522 canvas::tools::calcTransformedRectBounds( aTmpRect
,
526 basegfx::B2DHomMatrix
aMatrix( maTransformation
);
528 // Add translation according to the origin of aTmpRect. Ignore the
529 // translation when aTmpRect was not properly initialized.
530 if ( ! aTmpRect
.isEmpty())
532 aMatrix
.translate( -basegfx::fround(aTmpRect
.getMinX()),
533 -basegfx::fround(aTmpRect
.getMinY()) );
539 virtual basegfx::B2DHomMatrix
getSpriteTransformation() const override
541 return maTransformation
;
544 virtual void clear() const override
546 // grab canvas - that also lazy-initializes maLayerBoundsPixel
547 cppcanvas::CanvasSharedPtr pCanvas
=getCanvas()->clone();
549 // clear whole canvas
550 const basegfx::B2I64Tuple
& rSpriteSize(maLayerBoundsPixel
.getRange());
552 basegfx::B2IRange(0,0,rSpriteSize
.getX(),rSpriteSize
.getY()));
555 virtual void clearAll() const override
557 // grab canvas - that also lazy-initializes maLayerBoundsPixel
558 ::cppcanvas::CanvasSharedPtr
pCanvas( getCanvas()->clone() );
560 // clear layer clip, to clear whole area
563 // clear whole canvas
564 const basegfx::B2I64Tuple
& rSpriteSize(maLayerBoundsPixel
.getRange());
566 basegfx::B2IRange(0,0,rSpriteSize
.getX(),rSpriteSize
.getY()));
569 virtual bool isOnView(std::shared_ptr
<View
> const& rView
) const override
571 return rView
.get() == mpParentView
;
574 virtual cppcanvas::CanvasSharedPtr
getCanvas() const override
576 if( !mpOutputCanvas
)
580 maLayerBoundsPixel
= getLayerBoundsPixel(maLayerBounds
,
583 // HACK: ensure at least 1x1 pixel size. clients might
584 // need an actual canvas (e.g. for bound rect
585 // calculations) without rendering anything. Better
586 // solution: introduce something like a reference
587 // canvas for ViewLayers, which is always available.
588 if( maLayerBoundsPixel
.isEmpty() )
589 maLayerBoundsPixel
= basegfx::B2IRange(0,0,1,1);
591 const basegfx::B2I64Tuple
& rSpriteSize(maLayerBoundsPixel
.getRange());
592 mpSprite
= mpSpriteCanvas
->createCustomSprite(
593 basegfx::B2DVector(sal::static_int_cast
<sal_Int32
>(rSpriteSize
.getX()),
594 sal::static_int_cast
<sal_Int32
>(rSpriteSize
.getY())) );
596 mpSprite
->setPriority(
597 maSpriteContainer
.getLayerPriority().getMinimum() );
599 #if defined(DBG_UTIL)
601 basegfx::B2DPoint(maLayerBoundsPixel
.getMinimum()) +
602 basegfx::B2DPoint(10,10) );
604 mpSprite
->setAlpha(0.5);
607 basegfx::B2DPoint(maLayerBoundsPixel
.getMinimum()) );
609 mpSprite
->setAlpha(1.0);
614 ENSURE_OR_THROW( mpSprite
,
615 "SlideViewLayer::getCanvas(): no layer sprite" );
617 mpOutputCanvas
= mpSprite
->getContentCanvas();
619 ENSURE_OR_THROW( mpOutputCanvas
,
620 "SlideViewLayer::getCanvas(): sprite doesn't yield a canvas" );
622 // new canvas retrieved - setup transformation and clip
623 mpOutputCanvas
->setTransformation( getTransformation() );
624 mpOutputCanvas
->setClip(
625 createClipPolygon( maClip
,
630 return mpOutputCanvas
;
633 virtual void setClip( const basegfx::B2DPolyPolygon
& rClip
) override
635 basegfx::B2DPolyPolygon aNewClip
= prepareClip( rClip
);
637 if( aNewClip
!= maClip
)
642 mpOutputCanvas
->setClip(
643 createClipPolygon( maClip
,
649 virtual bool resize( const ::basegfx::B2DRange
& rArea
) override
651 const bool bRet( maLayerBounds
!= rArea
);
652 maLayerBounds
= rArea
;
653 updateView( maTransformation
,
661 typedef cppu::WeakComponentImplHelper
<
662 css::util::XModifyListener
,
663 css::awt::XPaintListener
> SlideViewBase
;
667 This class implements the View interface, encapsulating
668 <em>one</em> view a slideshow is displayed on.
670 class SlideView
: private cppu::BaseMutex
,
671 public SlideViewBase
,
675 SlideView( const uno::Reference
<presentation::XSlideShowView
>& xView
,
676 EventQueue
& rEventQueue
,
677 EventMultiplexer
& rEventMultiplexer
);
682 virtual ViewLayerSharedPtr
createViewLayer( const basegfx::B2DRange
& rLayerBounds
) const override
;
683 virtual bool updateScreen() const override
;
684 virtual bool paintScreen() const override
;
685 virtual void setViewSize( const ::basegfx::B2DSize
& ) override
;
686 virtual void setCursorShape( sal_Int16 nPointerShape
) override
;
688 // ViewLayer interface
689 virtual bool isOnView(std::shared_ptr
<View
> const& rView
) const override
;
690 virtual void clear() const override
;
691 virtual void clearAll() const override
;
692 virtual cppcanvas::CanvasSharedPtr
getCanvas() const override
;
693 virtual cppcanvas::CustomSpriteSharedPtr
createSprite( const ::basegfx::B2DSize
& rSpriteSizePixel
,
694 double nPriority
) const override
;
695 virtual void setPriority( const basegfx::B1DRange
& rRange
) override
;
696 virtual geometry::IntegerSize2D
getTranslationOffset() const override
;
697 virtual ::basegfx::B2DHomMatrix
getTransformation() const override
;
698 virtual basegfx::B2DHomMatrix
getSpriteTransformation() const override
;
699 virtual void setClip( const ::basegfx::B2DPolyPolygon
& rClip
) override
;
700 virtual bool resize( const ::basegfx::B2DRange
& rArea
) override
;
703 virtual void _dispose() override
;
704 virtual uno::Reference
<presentation::XSlideShowView
> getUnoView()const override
;
705 virtual void setIsSoundEnabled (const bool bValue
) override
;
706 virtual bool isSoundEnabled() const override
;
709 virtual void SAL_CALL
disposing( lang::EventObject
const& evt
) override
;
711 virtual void SAL_CALL
modified( const lang::EventObject
& aEvent
) override
;
713 virtual void SAL_CALL
windowPaint( const awt::PaintEvent
& e
) override
;
715 // WeakComponentImplHelperBase:
716 virtual void SAL_CALL
disposing() override
;
721 typedef std::vector
< std::weak_ptr
<SlideViewLayer
> > ViewLayerVector
;
723 /// Prune viewlayers from deceased ones, optionally update them
724 void pruneLayers( bool bWithViewLayerUpdate
=false ) const;
726 /** Max fill level of maViewLayers, before we try to prune it from
729 enum{ LAYER_ULLAGE
=8 };
731 uno::Reference
<presentation::XSlideShowView
> mxView
;
732 cppcanvas::SpriteCanvasSharedPtr mpCanvas
;
734 EventMultiplexer
& mrEventMultiplexer
;
735 EventQueue
& mrEventQueue
;
737 mutable LayerSpriteContainer maSprites
;
738 mutable ViewLayerVector maViewLayers
;
740 basegfx::B2DPolyPolygon maClip
;
742 basegfx::B2DHomMatrix maViewTransform
;
743 basegfx::B2DSize maUserSize
;
744 bool mbIsSoundEnabled
;
748 SlideView::SlideView( const uno::Reference
<presentation::XSlideShowView
>& xView
,
749 EventQueue
& rEventQueue
,
750 EventMultiplexer
& rEventMultiplexer
) :
751 SlideViewBase( m_aMutex
),
754 mrEventMultiplexer( rEventMultiplexer
),
755 mrEventQueue( rEventQueue
),
760 maUserSize( 1.0, 1.0 ), // default size: one-by-one rectangle
761 mbIsSoundEnabled(true)
763 // take care not constructing any UNO references to this _inside_
764 // ctor, shift that code to createSlideView()!
765 ENSURE_OR_THROW( mxView
.is(),
766 "SlideView::SlideView(): Invalid view" );
768 mpCanvas
= cppcanvas::VCLFactory::createSpriteCanvas(
769 xView
->getCanvas() );
770 ENSURE_OR_THROW( mpCanvas
,
771 "Could not create cppcanvas" );
773 geometry::AffineMatrix2D
aViewTransform(
774 xView
->getTransformation() );
776 if( basegfx::fTools::equalZero(
777 basegfx::B2DVector(aViewTransform
.m00
,
778 aViewTransform
.m10
).getLength()) ||
779 basegfx::fTools::equalZero(
780 basegfx::B2DVector(aViewTransform
.m01
,
781 aViewTransform
.m11
).getLength()) )
783 OSL_FAIL( "SlideView::SlideView(): Singular matrix!" );
785 canvas::tools::setIdentityAffineMatrix2D(aViewTransform
);
788 basegfx::unotools::homMatrixFromAffineMatrix(
789 maViewTransform
, aViewTransform
);
791 // once and forever: set fixed prio to this 'layer' (we're always
792 // the background layer)
793 maSprites
.setLayerPriority( basegfx::B1DRange(0.0,1.0) );
796 void SlideView::disposing()
798 osl::MutexGuard
aGuard( m_aMutex
);
800 maViewLayers
.clear();
804 // additionally, also de-register from XSlideShowView
807 mxView
->removeTransformationChangedListener( this );
808 mxView
->removePaintListener( this );
813 ViewLayerSharedPtr
SlideView::createViewLayer( const basegfx::B2DRange
& rLayerBounds
) const
815 osl::MutexGuard
aGuard( m_aMutex
);
817 ENSURE_OR_THROW( mpCanvas
,
818 "SlideView::createViewLayer(): Disposed" );
820 const std::size_t nNumLayers( maViewLayers
.size() );
822 // avoid filling up layer vector with lots of deceased layer weak
824 if( nNumLayers
> LAYER_ULLAGE
)
827 std::shared_ptr
<SlideViewLayer
> xViewLayer( new SlideViewLayer(mpCanvas
,
832 maViewLayers
.push_back(xViewLayer
);
837 bool SlideView::updateScreen() const
839 osl::MutexGuard
aGuard( m_aMutex
);
841 ENSURE_OR_RETURN_FALSE( mpCanvas
.get(),
842 "SlideView::updateScreen(): Disposed" );
844 return mpCanvas
->updateScreen( false );
847 bool SlideView::paintScreen() const
849 osl::MutexGuard
aGuard( m_aMutex
);
851 ENSURE_OR_RETURN_FALSE( mpCanvas
.get(),
852 "SlideView::paintScreen(): Disposed" );
854 return mpCanvas
->updateScreen( true );
857 void SlideView::clear() const
859 osl::MutexGuard
aGuard( m_aMutex
);
861 OSL_ENSURE( mxView
.is() && mpCanvas
,
862 "SlideView::clear(): Disposed" );
863 if( !mxView
.is() || !mpCanvas
)
867 clearRect(getCanvas()->clone(),
869 basegfx::B2DRange(0,0,
872 getTransformation()));
875 void SlideView::clearAll() const
877 osl::MutexGuard
aGuard( m_aMutex
);
879 OSL_ENSURE( mxView
.is() && mpCanvas
,
880 "SlideView::clear(): Disposed" );
881 if( !mxView
.is() || !mpCanvas
)
884 mpCanvas
->clear(); // this is unnecessary, strictly speaking. but
885 // it makes the SlideView behave exactly like a
886 // sprite-based SlideViewLayer, because those
887 // are created from scratch after a resize
893 void SlideView::setViewSize( const basegfx::B2DSize
& rSize
)
895 osl::MutexGuard
aGuard( m_aMutex
);
901 void SlideView::setCursorShape( sal_Int16 nPointerShape
)
903 osl::MutexGuard
const guard( m_aMutex
);
906 mxView
->setMouseCursor( nPointerShape
);
909 bool SlideView::isOnView(std::shared_ptr
<View
> const& rView
) const
911 return rView
.get() == this;
914 cppcanvas::CanvasSharedPtr
SlideView::getCanvas() const
916 osl::MutexGuard
aGuard( m_aMutex
);
918 ENSURE_OR_THROW( mpCanvas
,
919 "SlideView::getCanvas(): Disposed" );
924 cppcanvas::CustomSpriteSharedPtr
SlideView::createSprite(
925 const basegfx::B2DSize
& rSpriteSizePixel
,
926 double nPriority
) const
928 osl::MutexGuard
aGuard( m_aMutex
);
930 ENSURE_OR_THROW( mpCanvas
, "SlideView::createSprite(): Disposed" );
932 cppcanvas::CustomSpriteSharedPtr
pSprite(
933 mpCanvas
->createCustomSprite( rSpriteSizePixel
) );
935 maSprites
.addSprite( pSprite
,
941 void SlideView::setPriority( const basegfx::B1DRange
& /*rRange*/ )
943 osl::MutexGuard
aGuard( m_aMutex
);
945 OSL_FAIL( "SlideView::setPriority() is a NOOP for slide view - "
946 "content will always be shown in the background" );
949 basegfx::B2DHomMatrix
SlideView::getTransformation() const
951 osl::MutexGuard
aGuard( m_aMutex
);
953 basegfx::B2DHomMatrix aMatrix
;
954 aMatrix
.scale( 1.0/maUserSize
.getX(), 1.0/maUserSize
.getY() );
956 return maViewTransform
* aMatrix
;
959 geometry::IntegerSize2D
SlideView::getTranslationOffset() const
961 return mxView
->getTranslationOffset();
964 basegfx::B2DHomMatrix
SlideView::getSpriteTransformation() const
966 return getTransformation();
969 void SlideView::setClip( const basegfx::B2DPolyPolygon
& rClip
)
971 osl::MutexGuard
aGuard( m_aMutex
);
973 basegfx::B2DPolyPolygon aNewClip
= prepareClip( rClip
);
975 if( aNewClip
!= maClip
)
983 bool SlideView::resize( const ::basegfx::B2DRange
& /*rArea*/ )
985 osl::MutexGuard
aGuard( m_aMutex
);
987 OSL_FAIL( "SlideView::resize(): ignored for the View, can't change size "
988 "effectively, anyway" );
993 uno::Reference
<presentation::XSlideShowView
> SlideView::getUnoView() const
995 osl::MutexGuard
aGuard( m_aMutex
);
999 void SlideView::setIsSoundEnabled (const bool bValue
)
1001 mbIsSoundEnabled
= bValue
;
1004 bool SlideView::isSoundEnabled() const
1006 return mbIsSoundEnabled
;
1009 void SlideView::_dispose()
1015 void SlideView::disposing( lang::EventObject
const& evt
)
1017 // no deregistration necessary anymore, XView has left:
1018 osl::MutexGuard
const guard( m_aMutex
);
1022 OSL_ASSERT( evt
.Source
== mxView
);
1029 // silly wrapper to check that event handlers don't touch dead SlideView
1030 struct WeakRefWrapper
1033 uno::WeakReference
<uno::XInterface
> const m_wObj
;
1034 std::function
<void (SlideView
&)> const m_func
;
1036 WeakRefWrapper(SlideView
& rObj
, std::function
<void (SlideView
&)> const& func
)
1038 , m_wObj(static_cast<::cppu::OWeakObject
*>(&rObj
))
1045 uno::Reference
<uno::XInterface
> const xObj(m_wObj
);
1054 void SlideView::modified( const lang::EventObject
& /*aEvent*/ )
1056 osl::MutexGuard
const guard( m_aMutex
);
1058 OSL_ENSURE( mxView
.is(), "SlideView::modified(): "
1059 "Disposed, but event received from XSlideShowView?!");
1064 geometry::AffineMatrix2D
aViewTransform(
1065 mxView
->getTransformation() );
1067 if( basegfx::fTools::equalZero(
1068 basegfx::B2DVector(aViewTransform
.m00
,
1069 aViewTransform
.m10
).getLength()) ||
1070 basegfx::fTools::equalZero(
1071 basegfx::B2DVector(aViewTransform
.m01
,
1072 aViewTransform
.m11
).getLength()) )
1074 OSL_FAIL( "SlideView::modified(): Singular matrix!" );
1076 canvas::tools::setIdentityAffineMatrix2D(aViewTransform
);
1079 // view transformation really changed?
1080 basegfx::B2DHomMatrix aNewTransform
;
1081 basegfx::unotools::homMatrixFromAffineMatrix(
1085 if( aNewTransform
== maViewTransform
)
1086 return; // No change, nothing to do
1088 maViewTransform
= aNewTransform
;
1092 // notify view change. Don't call EventMultiplexer directly, this
1093 // might not be the main thread!
1094 mrEventQueue
.addEvent(
1095 makeEvent( WeakRefWrapper(*this,
1096 [] (SlideView
& rThis
) { rThis
.mrEventMultiplexer
.notifyViewChanged(rThis
.mxView
); }),
1097 "EventMultiplexer::notifyViewChanged"));
1101 void SlideView::windowPaint( const awt::PaintEvent
& /*e*/ )
1103 osl::MutexGuard
aGuard( m_aMutex
);
1105 OSL_ENSURE( mxView
.is() && mpCanvas
, "Disposed, but event received?!" );
1107 // notify view clobbering. Don't call EventMultiplexer directly,
1108 // this might not be the main thread!
1109 mrEventQueue
.addEvent(
1110 makeEvent( WeakRefWrapper(*this,
1111 [] (SlideView
& rThis
) { rThis
.mrEventMultiplexer
.notifyViewClobbered(rThis
.mxView
); }),
1112 "EventMultiplexer::notifyViewClobbered") );
1115 void SlideView::updateCanvas()
1117 OSL_ENSURE( mpCanvas
,
1118 "SlideView::updateCanvasTransform(): Disposed" );
1120 if( !mpCanvas
|| !mxView
.is())
1124 mpCanvas
->setTransformation( getTransformation() );
1126 createClipPolygon( maClip
,
1130 // forward update to viewlayers
1131 pruneLayers( true );
1134 void SlideView::updateClip()
1136 OSL_ENSURE( mpCanvas
,
1137 "SlideView::updateClip(): Disposed" );
1143 createClipPolygon( maClip
,
1150 void SlideView::pruneLayers( bool bWithViewLayerUpdate
) const
1152 ViewLayerVector aValidLayers
;
1154 const basegfx::B2DHomMatrix
& rCurrTransform(
1155 getTransformation() );
1157 // check all layers for validity, and retain only the live ones
1158 for( const auto& rView
: maViewLayers
)
1160 std::shared_ptr
< SlideViewLayer
> xCurrLayer( rView
.lock() );
1164 aValidLayers
.push_back( xCurrLayer
);
1166 if( bWithViewLayerUpdate
)
1167 xCurrLayer
->updateView( rCurrTransform
,
1172 // replace layer list with pruned one
1173 maViewLayers
.swap( aValidLayers
);
1176 } // anonymous namespace
1178 UnoViewSharedPtr
createSlideView( uno::Reference
< presentation::XSlideShowView
> const& xView
,
1179 EventQueue
& rEventQueue
,
1180 EventMultiplexer
& rEventMultiplexer
)
1182 std::shared_ptr
<SlideView
> const that(
1183 comphelper::make_shared_from_UNO(
1184 new SlideView(xView
,
1186 rEventMultiplexer
)));
1188 // register listeners with XSlideShowView
1189 xView
->addTransformationChangedListener( that
.get() );
1190 xView
->addPaintListener( that
.get() );
1192 // set new transformation
1193 that
->updateCanvas();
1198 } // namespace internal
1199 } // namespace slideshow
1201 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */