LibreOffice Module slideshow (master) 1
slideview.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
22
23#include <eventqueue.hxx>
24#include <eventmultiplexer.hxx>
25#include <slideview.hxx>
26#include <delayevent.hxx>
27#include <unoview.hxx>
28
32
37
49
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>
54
55#include <memory>
56#include <utility>
57#include <vector>
58#include <algorithm>
59
60using namespace com::sun::star;
61
62namespace slideshow::internal {
63
64namespace {
65
71struct SpriteEntry
72{
73 SpriteEntry( const cppcanvas::CustomSpriteSharedPtr& rSprite,
74 double nPrio ) :
75 mpSprite( rSprite ),
76 mnPriority( nPrio )
77 {
78 }
79
80 bool operator<(const SpriteEntry& rRHS) const
81 {
82 return mnPriority < rRHS.mnPriority;
83 }
84
85 std::weak_ptr< cppcanvas::CustomSprite > mpSprite;
86 double mnPriority;
87};
88
89typedef std::vector< SpriteEntry > SpriteVector;
90
91
107basegfx::B2DPolyPolygon createClipPolygon( const basegfx::B2DPolyPolygon& rClip,
108 const cppcanvas::CanvasSharedPtr& /*rCanvas*/,
109 const basegfx::B2DSize& rUserSize )
110{
111 // setup canvas clipping
112 // =====================
113
114 // AW: Simplified
115 const basegfx::B2DRange aClipRange(0, 0, rUserSize.getWidth(), rUserSize.getHeight());
116
117 if(rClip.count())
118 {
119 return basegfx::utils::clipPolyPolygonOnRange(rClip, aClipRange, true, false);
120 }
121 else
122 {
124 }
125}
126
134basegfx::B2DPolyPolygon prepareClip( const basegfx::B2DPolyPolygon& rClip )
135{
136 basegfx::B2DPolyPolygon aClip( rClip );
137
138 // normalize polygon, preparation for clipping
139 // in updateCanvas()
141 aClip = basegfx::utils::solveCrossovers(aClip);
144
145 return aClip;
146}
147
148
149void clearRect( ::cppcanvas::CanvasSharedPtr const& pCanvas,
150 basegfx::B2IRange const& rArea )
151{
152 // convert clip polygon to device coordinate system
153 ::basegfx::B2DPolyPolygon const* pClipPoly( pCanvas->getClip() );
154 if( pClipPoly )
155 {
156 ::basegfx::B2DPolyPolygon aClipPoly( *pClipPoly );
157 aClipPoly.transform( pCanvas->getTransformation() );
158 pCanvas->setClip( aClipPoly );
159 }
160
161 // set transformation to identity (->device pixel)
162 pCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
163
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)));
172
175
176 if( pPolyPoly )
177 {
178 pPolyPoly->setCompositeOp( css::rendering::CompositeOperation::SOURCE );
179 pPolyPoly->setRGBAFillColor( 0xFFFFFF00U );
180 pPolyPoly->draw();
181 }
182
183#if defined(DBG_UTIL)
184 ::cppcanvas::CanvasSharedPtr pCliplessCanvas( pCanvas->clone() );
185 pCliplessCanvas->setClip();
186
187 if( pCanvas->getClip() )
188 {
190 ::cppcanvas::BaseGfxFactory::createPolyPolygon( pCliplessCanvas, aPoly ));
191 if( pPolyPoly2 )
192 {
193 pPolyPoly2->setRGBALineColor( 0x008000FFU );
194 pPolyPoly2->draw();
195 }
196 }
197#endif
198}
199
211basegfx::B2IRange getLayerBoundsPixel( basegfx::B2DRange const& rLayerBounds,
212 basegfx::B2DHomMatrix const& rTransformation )
213{
214 ::basegfx::B2DRange aTmpRect;
215 ::canvas::tools::calcTransformedRectBounds( aTmpRect,
216 rLayerBounds,
217 rTransformation );
218
219 if( aTmpRect.isEmpty() )
220 return ::basegfx::B2IRange();
221
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 );
229}
230
231
238class LayerSpriteContainer
239{
243 enum{ SPRITE_ULLAGE=256 };
244
249 SpriteVector maSprites;
250
253
254 double getSpritePriority( std::size_t nSpriteNum ) const
255 {
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):
260
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);
264 }
265
272 void updateSprites()
273 {
274 SpriteVector aValidSprites;
275
276 // check all sprites for validity and set new priority
277 for( const auto& rSprite : maSprites )
278 {
279 cppcanvas::CustomSpriteSharedPtr pCurrSprite( rSprite.mpSprite.lock() );
280
281 if( pCurrSprite )
282 {
283 // only copy still valid sprites over to the refreshed
284 // sprite vector.
285 aValidSprites.push_back( rSprite );
286
287 pCurrSprite->setPriority(
288 getSpritePriority( aValidSprites.size()-1 ));
289 }
290 }
291
292 // replace sprite list with pruned one
293 maSprites.swap( aValidSprites );
294 }
295
296public:
297 LayerSpriteContainer() :
298 maSprites(),
300 {
301 }
302
303 const basegfx::B1DRange& getLayerPriority() const
304 {
305 return maLayerPrioRange;
306 }
307
308 void setLayerPriority( const basegfx::B1DRange& rRange )
309 {
310 if( rRange != maLayerPrioRange )
311 {
312 maLayerPrioRange = rRange;
313
314 // prune and recalc sprite prios
315 updateSprites();
316 }
317 }
318
319 void addSprite( const cppcanvas::CustomSpriteSharedPtr& pSprite,
320 double nPriority )
321 {
322 if( !pSprite )
323 return;
324
325 SpriteEntry aEntry( pSprite,nPriority );
326
327 // insert new sprite, such that vector stays sorted
328 SpriteVector::iterator aInsertPos(
329 maSprites.insert(
330 std::lower_bound( maSprites.begin(),
331 maSprites.end(),
332 aEntry ),
333 aEntry ));
334
335 const std::size_t nNumSprites( maSprites.size() );
336 if( nNumSprites > SPRITE_ULLAGE ||
337 maSprites.end() - aInsertPos > 1 )
338 {
339 // updateSprites() also updates all sprite prios
340 updateSprites();
341 }
342 else
343 {
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 ));
351 }
352 }
353
354 void clear()
355 {
356 maSprites.clear();
357 }
358};
359
360
373class SlideViewLayer : public ViewLayer
374{
376 mutable LayerSpriteContainer maSpriteContainer;
377
380
383
386
389
392
395
400
403
405 View const* const mpParentView;
406
407public:
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),
427 maClip(),
428 maUserSize(rUserSize),
429 maTransformation(std::move(aTransform)),
430 mpSpriteCanvas(std::move(pCanvas)),
431 mpSprite(),
433 mpParentView(pParentView)
434 {
435 }
436
437 SlideViewLayer(const SlideViewLayer&) = delete;
438 SlideViewLayer& operator=(const SlideViewLayer&) = delete;
439
440 void updateView( const basegfx::B2DHomMatrix& rMatrix,
441 const basegfx::B2DSize& rUserSize )
442 {
443 maTransformation = rMatrix;
444 maUserSize = rUserSize;
445
446 // limit layer bounds to visible screen
448 0.0,
451
452 basegfx::B2IRange const& rNewLayerPixel(
453 getLayerBoundsPixel(maLayerBounds,
455 if( rNewLayerPixel != maLayerBoundsPixel )
456 {
457 // re-gen sprite with new size
458 mpOutputCanvas.reset();
459 mpSprite.reset();
460 }
461 }
462
463 virtual css::geometry::IntegerSize2D getTranslationOffset() const override
464 {
465 basegfx::B2DRectangle aTmpRect;
469 geometry::IntegerSize2D offset(0, 0);
470
471 // Add translation according to the origin of aTmpRect. Ignore the
472 // translation when aTmpRect was not properly initialized.
473 if ( ! aTmpRect.isEmpty())
474 {
475 offset.Width = basegfx::fround(aTmpRect.getMinX());
476 offset.Height = basegfx::fround(aTmpRect.getMinY());
477 }
478 return offset;
479 }
480
481private:
482 // ViewLayer interface
483
484
485 virtual cppcanvas::CustomSpriteSharedPtr createSprite(
486 const ::basegfx::B2DSize& rSpriteSizePixel,
487 double nPriority ) const override
488 {
490 mpSpriteCanvas->createCustomSprite( rSpriteSizePixel ) );
491
492 maSpriteContainer.addSprite( pSprite,
493 nPriority );
494
495 return pSprite;
496 }
497
498 virtual void setPriority( const basegfx::B1DRange& rRange ) override
499 {
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)" );
504
505 maSpriteContainer.setLayerPriority( rRange );
506
507 if( mpSprite )
508 mpSprite->setPriority( rRange.getMinimum() );
509 }
510
511 virtual basegfx::B2DHomMatrix getTransformation() const override
512 {
513 // Offset given transformation by left, top border of given
514 // range (after transformation through given transformation)
515 basegfx::B2DRectangle aTmpRect;
519
521
522 // Add translation according to the origin of aTmpRect. Ignore the
523 // translation when aTmpRect was not properly initialized.
524 if ( ! aTmpRect.isEmpty())
525 {
526 aMatrix.translate( -basegfx::fround(aTmpRect.getMinX()),
527 -basegfx::fround(aTmpRect.getMinY()) );
528 }
529
530 return aMatrix;
531 }
532
533 virtual basegfx::B2DHomMatrix getSpriteTransformation() const override
534 {
535 return maTransformation;
536 }
537
538 virtual void clear() const override
539 {
540 // grab canvas - that also lazy-initializes maLayerBoundsPixel
541 cppcanvas::CanvasSharedPtr pCanvas=getCanvas()->clone();
542
543 // clear whole canvas
544 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
545 clearRect(pCanvas,
546 basegfx::B2IRange(0,0,rSpriteSize.getX(),rSpriteSize.getY()));
547 }
548
549 virtual void clearAll() const override
550 {
551 // grab canvas - that also lazy-initializes maLayerBoundsPixel
552 ::cppcanvas::CanvasSharedPtr pCanvas( getCanvas()->clone() );
553
554 // clear layer clip, to clear whole area
555 pCanvas->setClip();
556
557 // clear whole canvas
558 const basegfx::B2I64Tuple& rSpriteSize(maLayerBoundsPixel.getRange());
559 clearRect(pCanvas,
560 basegfx::B2IRange(0,0,rSpriteSize.getX(),rSpriteSize.getY()));
561 }
562
563 virtual bool isOnView(ViewSharedPtr const& rView) const override
564 {
565 return rView.get() == mpParentView;
566 }
567
568 virtual cppcanvas::CanvasSharedPtr getCanvas() const override
569 {
570 if( !mpOutputCanvas )
571 {
572 if( !mpSprite )
573 {
574 maLayerBoundsPixel = getLayerBoundsPixel(maLayerBounds,
576
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.
584
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())) );
589
590 mpSprite->setPriority(
591 maSpriteContainer.getLayerPriority().getMinimum() );
592
593#if defined(DBG_UTIL)
594 mpSprite->movePixel(
596 basegfx::B2DPoint(10,10) );
597
598 mpSprite->setAlpha(0.5);
599#else
600 mpSprite->movePixel(
602
603 mpSprite->setAlpha(1.0);
604#endif
605 mpSprite->show();
606 }
607
609 "SlideViewLayer::getCanvas(): no layer sprite" );
610
611 mpOutputCanvas = mpSprite->getContentCanvas();
612
614 "SlideViewLayer::getCanvas(): sprite doesn't yield a canvas" );
615
616 // new canvas retrieved - setup transformation and clip
617 mpOutputCanvas->setTransformation( getTransformation() );
618 mpOutputCanvas->setClip(
619 createClipPolygon( maClip,
621 maUserSize ));
622 }
623
624 return mpOutputCanvas;
625 }
626
627 virtual void setClip( const basegfx::B2DPolyPolygon& rClip ) override
628 {
629 basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
630
631 if( aNewClip != maClip )
632 {
633 maClip = aNewClip;
634
635 if(mpOutputCanvas )
636 mpOutputCanvas->setClip(
637 createClipPolygon( maClip,
639 maUserSize ));
640 }
641 }
642
643 virtual bool resize( const ::basegfx::B2DRange& rArea ) override
644 {
645 const bool bRet( maLayerBounds != rArea );
646 maLayerBounds = rArea;
647 updateView( maTransformation,
648 maUserSize );
649
650 return bRet;
651 }
652};
653
654
655typedef cppu::WeakComponentImplHelper<
656 css::util::XModifyListener,
657 css::awt::XPaintListener> SlideViewBase;
658
664class SlideView : private cppu::BaseMutex,
665 public SlideViewBase,
666 public UnoView
667{
668public:
669 SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
670 EventQueue& rEventQueue,
671 EventMultiplexer& rEventMultiplexer );
672 void updateCanvas();
673
674private:
675 // View:
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;
681
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;
695
696 // UnoView:
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;
701
702 // XEventListener:
703 virtual void SAL_CALL disposing( lang::EventObject const& evt ) override;
704 // XModifyListener:
705 virtual void SAL_CALL modified( const lang::EventObject& aEvent ) override;
706 // XPaintListener:
707 virtual void SAL_CALL windowPaint( const awt::PaintEvent& e ) override;
708
709 // WeakComponentImplHelperBase:
710 virtual void SAL_CALL disposing() override;
711
712 void updateClip();
713
714private:
715 typedef std::vector< std::weak_ptr<SlideViewLayer> > ViewLayerVector;
716
718 void pruneLayers( bool bWithViewLayerUpdate=false ) const;
719
723 enum{ LAYER_ULLAGE=8 };
724
725 uno::Reference<presentation::XSlideShowView> mxView;
727
728 EventMultiplexer& mrEventMultiplexer;
729 EventQueue& mrEventQueue;
730
731 mutable LayerSpriteContainer maSprites;
732 mutable ViewLayerVector maViewLayers;
733
735
739};
740
741
742SlideView::SlideView( const uno::Reference<presentation::XSlideShowView>& xView,
743 EventQueue& rEventQueue,
744 EventMultiplexer& rEventMultiplexer ) :
745 SlideViewBase( m_aMutex ),
746 mxView( xView ),
747 mpCanvas(),
748 mrEventMultiplexer( rEventMultiplexer ),
749 mrEventQueue( rEventQueue ),
750 maSprites(),
751 maViewLayers(),
752 maClip(),
754 maUserSize( 1.0, 1.0 ), // default size: one-by-one rectangle
755 mbIsSoundEnabled(true)
756{
757 // take care not constructing any UNO references to this _inside_
758 // ctor, shift that code to createSlideView()!
760 "SlideView::SlideView(): Invalid view" );
761
763 xView->getCanvas() );
765 "Could not create cppcanvas" );
766
767 geometry::AffineMatrix2D aViewTransform(
768 xView->getTransformation() );
769
771 basegfx::B2DVector(aViewTransform.m00,
772 aViewTransform.m10).getLength()) ||
774 basegfx::B2DVector(aViewTransform.m01,
775 aViewTransform.m11).getLength()) )
776 {
777 OSL_FAIL( "SlideView::SlideView(): Singular matrix!" );
778
780 }
781
783 maViewTransform, aViewTransform );
784
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) );
788}
789
790void SlideView::disposing()
791{
792 osl::MutexGuard aGuard( m_aMutex );
793
794 maViewLayers.clear();
795 maSprites.clear();
796 mpCanvas.reset();
797
798 // additionally, also de-register from XSlideShowView
799 if (mxView.is())
800 {
801 mxView->removeTransformationChangedListener( this );
802 mxView->removePaintListener( this );
803 mxView.clear();
804 }
805}
806
807ViewLayerSharedPtr SlideView::createViewLayer( const basegfx::B2DRange& rLayerBounds ) const
808{
809 osl::MutexGuard aGuard( m_aMutex );
810
812 "SlideView::createViewLayer(): Disposed" );
813
814 const std::size_t nNumLayers( maViewLayers.size() );
815
816 // avoid filling up layer vector with lots of deceased layer weak
817 // ptrs
818 if( nNumLayers > LAYER_ULLAGE )
819 pruneLayers();
820
821 auto xViewLayer = std::make_shared<SlideViewLayer>(mpCanvas,
822 getTransformation(),
823 rLayerBounds,
825 this);
826 maViewLayers.push_back(xViewLayer);
827
828 return xViewLayer;
829}
830
831bool SlideView::updateScreen() const
832{
833 osl::MutexGuard aGuard( m_aMutex );
834
836 "SlideView::updateScreen(): Disposed" );
837
838 return mpCanvas->updateScreen( false );
839}
840
841bool SlideView::paintScreen() const
842{
843 osl::MutexGuard aGuard( m_aMutex );
844
846 "SlideView::paintScreen(): Disposed" );
847
848 return mpCanvas->updateScreen( true );
849}
850
851void SlideView::clear() const
852{
853 osl::MutexGuard aGuard( m_aMutex );
854
855 OSL_ENSURE( mxView.is() && mpCanvas,
856 "SlideView::clear(): Disposed" );
857 if( !mxView.is() || !mpCanvas )
858 return;
859
860 // keep layer clip
861 clearRect(getCanvas()->clone(),
862 getLayerBoundsPixel(
866 getTransformation()));
867}
868
869void SlideView::clearAll() const
870{
871 osl::MutexGuard aGuard( m_aMutex );
872
873 OSL_ENSURE( mxView.is() && mpCanvas,
874 "SlideView::clear(): Disposed" );
875 if( !mxView.is() || !mpCanvas )
876 return;
877
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
882
883 // clear whole view
884 mxView->clear();
885}
886
887void SlideView::setViewSize( const basegfx::B2DSize& rSize )
888{
889 osl::MutexGuard aGuard( m_aMutex );
890
891 maUserSize = rSize;
892 updateCanvas();
893}
894
895void SlideView::setCursorShape( sal_Int16 nPointerShape )
896{
897 osl::MutexGuard const guard( m_aMutex );
898
899 if (mxView.is())
900 mxView->setMouseCursor( nPointerShape );
901}
902
903bool SlideView::isOnView(ViewSharedPtr const& rView) const
904{
905 return rView.get() == this;
906}
907
908cppcanvas::CanvasSharedPtr SlideView::getCanvas() const
909{
910 osl::MutexGuard aGuard( m_aMutex );
911
913 "SlideView::getCanvas(): Disposed" );
914
915 return mpCanvas;
916}
917
918cppcanvas::CustomSpriteSharedPtr SlideView::createSprite(
919 const basegfx::B2DSize& rSpriteSizePixel,
920 double nPriority ) const
921{
922 osl::MutexGuard aGuard( m_aMutex );
923
924 ENSURE_OR_THROW( mpCanvas, "SlideView::createSprite(): Disposed" );
925
927 mpCanvas->createCustomSprite( rSpriteSizePixel ) );
928
929 maSprites.addSprite( pSprite,
930 nPriority );
931
932 return pSprite;
933}
934
935void SlideView::setPriority( const basegfx::B1DRange& /*rRange*/ )
936{
937 OSL_FAIL( "SlideView::setPriority() is a NOOP for slide view - "
938 "content will always be shown in the background" );
939}
940
941basegfx::B2DHomMatrix SlideView::getTransformation() const
942{
943 osl::MutexGuard aGuard( m_aMutex );
944
945 basegfx::B2DHomMatrix aMatrix;
946 aMatrix.scale( 1.0 / maUserSize.getWidth(), 1.0 / maUserSize.getHeight() );
947
948 return maViewTransform * aMatrix;
949}
950
951geometry::IntegerSize2D SlideView::getTranslationOffset() const
952{
953 return mxView->getTranslationOffset();
954}
955
957{
958 return getTransformation();
959}
960
961void SlideView::setClip( const basegfx::B2DPolyPolygon& rClip )
962{
963 osl::MutexGuard aGuard( m_aMutex );
964
965 basegfx::B2DPolyPolygon aNewClip = prepareClip( rClip );
966
967 if( aNewClip != maClip )
968 {
969 maClip = aNewClip;
970
971 updateClip();
972 }
973}
974
975bool SlideView::resize( const ::basegfx::B2DRange& /*rArea*/ )
976{
977 OSL_FAIL( "SlideView::resize(): ignored for the View, can't change size "
978 "effectively, anyway" );
979
980 return false;
981}
982
983uno::Reference<presentation::XSlideShowView> SlideView::getUnoView() const
984{
985 osl::MutexGuard aGuard( m_aMutex );
986 return mxView;
987}
988
989void SlideView::setIsSoundEnabled (const bool bValue)
990{
991 mbIsSoundEnabled = bValue;
992}
993
994bool SlideView::isSoundEnabled() const
995{
996 return mbIsSoundEnabled;
997}
998
999void SlideView::_dispose()
1000{
1001 dispose();
1002}
1003
1004// XEventListener
1005void SlideView::disposing( lang::EventObject const& evt )
1006{
1007 // no deregistration necessary anymore, XView has left:
1008 osl::MutexGuard const guard( m_aMutex );
1009
1010 if (mxView.is())
1011 {
1012 OSL_ASSERT( evt.Source == mxView );
1013 mxView.clear();
1014 }
1015
1016 dispose();
1017}
1018
1019// silly wrapper to check that event handlers don't touch dead SlideView
1020struct WeakRefWrapper
1021{
1022 SlideView & m_rObj;
1023 uno::WeakReference<uno::XInterface> const m_wObj;
1024 std::function<void (SlideView&)> const m_func;
1025
1026 WeakRefWrapper(SlideView & rObj, std::function<void (SlideView&)> func)
1027 : m_rObj(rObj)
1028 , m_wObj(rObj.getXWeak())
1029 , m_func(std::move(func))
1030 {
1031 }
1032
1033 void operator()()
1034 {
1035 uno::Reference<uno::XInterface> const xObj(m_wObj);
1036 if (xObj.is())
1037 {
1038 m_func(m_rObj);
1039 }
1040 }
1041};
1042
1043// XModifyListener
1044void SlideView::modified( const lang::EventObject& /*aEvent*/ )
1045{
1046 osl::MutexGuard const guard( m_aMutex );
1047
1048 OSL_ENSURE( mxView.is(), "SlideView::modified(): "
1049 "Disposed, but event received from XSlideShowView?!");
1050
1051 if( !mxView.is() )
1052 return;
1053
1054 geometry::AffineMatrix2D aViewTransform(
1055 mxView->getTransformation() );
1056
1058 basegfx::B2DVector(aViewTransform.m00,
1059 aViewTransform.m10).getLength()) ||
1061 basegfx::B2DVector(aViewTransform.m01,
1062 aViewTransform.m11).getLength()) )
1063 {
1064 OSL_FAIL( "SlideView::modified(): Singular matrix!" );
1065
1067 }
1068
1069 // view transformation really changed?
1070 basegfx::B2DHomMatrix aNewTransform;
1072 aNewTransform,
1073 aViewTransform );
1074
1075 if( aNewTransform == maViewTransform )
1076 return; // No change, nothing to do
1077
1078 maViewTransform = aNewTransform;
1079
1080 updateCanvas();
1081
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"));
1088}
1089
1090// XPaintListener
1091void SlideView::windowPaint( const awt::PaintEvent& /*e*/ )
1092{
1093 osl::MutexGuard aGuard( m_aMutex );
1094
1095 OSL_ENSURE( mxView.is() && mpCanvas, "Disposed, but event received?!" );
1096
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") );
1103}
1104
1105void SlideView::updateCanvas()
1106{
1107 OSL_ENSURE( mpCanvas,
1108 "SlideView::updateCanvasTransform(): Disposed" );
1109
1110 if( !mpCanvas || !mxView.is())
1111 return;
1112
1113 clearAll();
1114 mpCanvas->setTransformation( getTransformation() );
1115 mpCanvas->setClip(
1116 createClipPolygon( maClip,
1117 mpCanvas,
1118 maUserSize ));
1119
1120 // forward update to viewlayers
1121 pruneLayers( true );
1122}
1123
1124void SlideView::updateClip()
1125{
1126 OSL_ENSURE( mpCanvas,
1127 "SlideView::updateClip(): Disposed" );
1128
1129 if( !mpCanvas )
1130 return;
1131
1132 mpCanvas->setClip(
1133 createClipPolygon( maClip,
1134 mpCanvas,
1135 maUserSize ));
1136
1137 pruneLayers();
1138}
1139
1140void SlideView::pruneLayers( bool bWithViewLayerUpdate ) const
1141{
1142 ViewLayerVector aValidLayers;
1143
1144 const basegfx::B2DHomMatrix& rCurrTransform(
1145 getTransformation() );
1146
1147 // check all layers for validity, and retain only the live ones
1148 for( const auto& rView : maViewLayers )
1149 {
1150 std::shared_ptr< SlideViewLayer > xCurrLayer( rView.lock() );
1151
1152 if ( xCurrLayer )
1153 {
1154 aValidLayers.push_back( xCurrLayer );
1155
1156 if( bWithViewLayerUpdate )
1157 xCurrLayer->updateView( rCurrTransform,
1158 maUserSize );
1159 }
1160 }
1161
1162 // replace layer list with pruned one
1163 maViewLayers.swap( aValidLayers );
1164}
1165
1166} // anonymous namespace
1167
1169 EventQueue& rEventQueue,
1170 EventMultiplexer& rEventMultiplexer )
1171{
1172 std::shared_ptr<SlideView> const that(
1174 new SlideView(xView,
1175 rEventQueue,
1176 rEventMultiplexer)));
1177
1178 // register listeners with XSlideShowView
1179 xView->addTransformationChangedListener( that.get() );
1180 xView->addPaintListener( that.get() );
1181
1182 // set new transformation
1183 that->updateCanvas();
1184
1185 return that;
1186}
1187
1188} // namespace slideshow
1189
1190/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double getRange() const
bool isEmpty() const
double getMinimum() const
void scale(double fX, double fY)
sal_uInt32 count() const
double getLength() const
B2IPoint getMinimum() const
B2I64Tuple getRange() const
TYPE getMaxX() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getMaxY() const
void intersect(const Range2D &rRange)
bool isEmpty() const
TYPE getWidth() const
TYPE getHeight() const
static PolyPolygonSharedPtr createPolyPolygon(const CanvasSharedPtr &, const ::basegfx::B2DPolygon &rPoly)
static SpriteCanvasSharedPtr createSpriteCanvas(const vcl::Window &rVCLWindow)
This class multiplexes user-activated and slide-show global events.
This class handles events in a presentation.
Definition: eventqueue.hxx:41
T * clone(T *const other)
#define makeEvent(f, d)
Definition: delayevent.hxx:131
#define ENSURE_OR_RETURN_FALSE(c, m)
#define ENSURE_OR_THROW(c, m)
std::mutex m_aMutex
DECL_LISTENERMULTIPLEXER_END void SAL_CALL windowPaint(const css::awt::PaintEvent &e) override
bool equalZero(const T &rfVal)
::basegfx::B2DHomMatrix & homMatrixFromAffineMatrix(::basegfx::B2DHomMatrix &output, const geometry::AffineMatrix2D &input)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
B2DPolyPolygon correctOrientations(const B2DPolyPolygon &rCandidate)
B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon &rCandidate)
B2DPolyPolygon solveCrossovers(const B2DPolyPolygon &rCandidate, size_t *pPointLimit=nullptr)
B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon &rCandidate, bool bKeepAboveZero=false)
B2IRange fround(const B2DRange &rRange)
::basegfx::B2DRange & calcTransformedRectBounds(::basegfx::B2DRange &o_Rect, const ::basegfx::B2DRange &i_Rect, const ::basegfx::B2DHomMatrix &i_Transformation)
geometry::AffineMatrix2D & setIdentityAffineMatrix2D(geometry::AffineMatrix2D &matrix)
std::shared_ptr< T > make_shared_from_UNO(T *p)
std::shared_ptr< ::cppcanvas::CustomSprite > CustomSpriteSharedPtr
std::shared_ptr< PolyPolygon > PolyPolygonSharedPtr
std::shared_ptr< ::cppcanvas::SpriteCanvas > SpriteCanvasSharedPtr
std::shared_ptr< Canvas > CanvasSharedPtr
std::shared_ptr< View > ViewSharedPtr
Definition: view.hxx:80
std::shared_ptr< ViewLayer > ViewLayerSharedPtr
Definition: viewlayer.hxx:168
UnoViewSharedPtr createSlideView(uno::Reference< presentation::XSlideShowView > const &xView, EventQueue &rEventQueue, EventMultiplexer &rEventMultiplexer)
Definition: slideview.cxx:1168
std::shared_ptr< UnoView > UnoViewSharedPtr
::basegfx::B2DHomMatrix getSpriteTransformation(const ::basegfx::B2DVector &rPixelSize, const ::basegfx::B2DVector &rOrigSize, const ShapeAttributeLayerSharedPtr &pAttr)
Definition: tools.cxx:474
void dispose()
basegfx::B2DRange maLayerBounds
Bounds of this layer in user space coordinates.
Definition: slideview.cxx:379
basegfx::B1DRange maLayerPrioRange
Priority of this layer, relative to other view layers.
Definition: slideview.cxx:252
basegfx::B2DHomMatrix maViewTransform
Definition: slideview.cxx:736
cppcanvas::SpriteCanvasSharedPtr mpCanvas
Definition: slideview.cxx:726
basegfx::B2IRange maLayerBoundsPixel
Bounds of this layer in device pixel.
Definition: slideview.cxx:382
basegfx::B2DHomMatrix maTransformation
Current overall view transformation.
Definition: slideview.cxx:391
LayerSpriteContainer maSpriteContainer
Smart container for all sprites issued by this layer.
Definition: slideview.cxx:376
EventMultiplexer & mrEventMultiplexer
Definition: slideview.cxx:728
basegfx::B2DSize maUserSize
Current size of the view in user coordinates.
Definition: slideview.cxx:388
std::weak_ptr< cppcanvas::CustomSprite > mpSprite
output surface (necessarily a sprite, won't otherwise be able to display anything before other sprite...
Definition: slideview.cxx:85
View const *const mpParentView
ptr back to owning view. needed for isOnView() method
Definition: slideview.cxx:405
ViewLayerVector maViewLayers
Definition: slideview.cxx:732
SlideView & m_rObj
Definition: slideview.cxx:1022
EventQueue & mrEventQueue
Definition: slideview.cxx:729
bool mbIsSoundEnabled
Definition: slideview.cxx:738
const cppcanvas::SpriteCanvasSharedPtr mpSpriteCanvas
'parent' canvas, this viewlayer is associated with
Definition: slideview.cxx:394
cppcanvas::CanvasSharedPtr mpOutputCanvas
actual output canvas retrieved from a sprite
Definition: slideview.cxx:402
SpriteVector maSprites
All sprites that have been issued by this container (pruned from time to time, for invalid references...
Definition: slideview.cxx:249
double mnPriority
Definition: slideview.cxx:86
std::function< void(SlideView &)> const m_func
Definition: slideview.cxx:1024
basegfx::B2DPolyPolygon maClip
Current clip polygon in user coordinates.
Definition: slideview.cxx:385
uno::WeakReference< uno::XInterface > const m_wObj
Definition: slideview.cxx:1023
uno::Reference< presentation::XSlideShowView > mxView
Definition: slideview.cxx:725
bool operator<(const wwFont &r1, const wwFont &r2)