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 
20 
21 #include <osl/diagnose.hxx>
22 #include <tools/diagnose_ex.h>
23 #include <sal/log.hxx>
24 #include <canvas/canvastools.hxx>
25 #include <cppcanvas/basegfxfactory.hxx>
26 
27 #include <basegfx/matrix/b2dhommatrix.hxx>
28 #include <basegfx/point/b2dpoint.hxx>
29 #include <basegfx/polygon/b2dpolygon.hxx>
30 #include <basegfx/polygon/b2dpolygontools.hxx>
31 #include <basegfx/numeric/ftools.hxx>
32 
33 #include <com/sun/star/awt/SystemPointer.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include <com/sun/star/drawing/XMasterPageTarget.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/container/XEnumerationAccess.hpp>
38 #include <com/sun/star/awt/Rectangle.hpp>
39 #include <com/sun/star/presentation/ParagraphTarget.hpp>
40 #include <com/sun/star/presentation/EffectNodeType.hpp>
41 #include <com/sun/star/drawing/TextAnimationKind.hpp>
42 
43 #include <cppuhelper/exc_hlp.hxx>
44 #include <comphelper/anytostring.hxx>
45 
46 #include <slide.hxx>
47 #include <slideshowcontext.hxx>
48 #include "slideanimations.hxx"
49 #include <doctreenode.hxx>
50 #include <screenupdater.hxx>
51 #include <cursormanager.hxx>
52 #include <shapeimporter.hxx>
53 #include <slideshowexceptions.hxx>
54 #include <eventqueue.hxx>
55 #include <activitiesqueue.hxx>
56 #include "layermanager.hxx"
57 #include "shapemanagerimpl.hxx"
58 #include <usereventqueue.hxx>
59 #include "userpaintoverlay.hxx"
60 #include <event.hxx>
61 #include "targetpropertiescreator.hxx"
62 #include <tools.hxx>
63 
64 #include <iterator>
65 #include <functional>
66 #include <iostream>
67 
68 using namespace ::com::sun::star;
69 
70 
71 namespace slideshow
72 {
73 namespace internal
74 {
75 namespace
76 {
77 
78 class SlideImpl : public Slide,
79                   public CursorManager,
80                   public ViewEventHandler,
81                   public ::osl::DebugBase<SlideImpl>
82 {
83 public:
84     SlideImpl( const uno::Reference<drawing::XDrawPage>&         xDrawPage,
85                const uno::Reference<drawing::XDrawPagesSupplier>&    xDrawPages,
86                const uno::Reference<animations::XAnimationNode>& xRootNode,
87                EventQueue&                                       rEventQueue,
88                EventMultiplexer&                                 rEventMultiplexer,
89                ScreenUpdater&                                    rScreenUpdater,
90                ActivitiesQueue&                                  rActivitiesQueue,
91                UserEventQueue&                                   rUserEventQueue,
92                CursorManager&                                    rCursorManager,
93                MediaFileManager&                                 rMediaFileManager,
94                const UnoViewContainer&                           rViewContainer,
95                const uno::Reference<uno::XComponentContext>&     xContext,
96                const ShapeEventListenerMap&                      rShapeListenerMap,
97                const ShapeCursorMap&                             rShapeCursorMap,
98                const PolyPolygonVector&                          rPolyPolygonVector,
99                RGBColor const&                                   rUserPaintColor,
100                double                                            dUserPaintStrokeWidth,
101                bool                                              bUserPaintEnabled,
102                bool                                              bIntrinsicAnimationsAllowed,
103                bool                                              bDisableAnimationZOrder );
104 
105     virtual ~SlideImpl() override;
106 
107 
108     // Slide interface
109 
110 
111     virtual void prefetch() override;
112     virtual void show( bool ) override;
113     virtual void hide() override;
114 
115     virtual basegfx::B2ISize getSlideSize() const override;
116     virtual uno::Reference<drawing::XDrawPage > getXDrawPage() const override;
117     virtual uno::Reference<animations::XAnimationNode> getXAnimationNode() const override;
118     virtual PolyPolygonVector getPolygons() override;
119     virtual void drawPolygons() const override;
120     virtual bool isPaintOverlayActive() const override;
121     virtual void enablePaintOverlay() override;
122     virtual void update_settings( bool bUserPaintEnabled, RGBColor const& aUserPaintColor, double dUserPaintStrokeWidth ) override;
123 
124 
125     // TODO(F2): Rework SlideBitmap to no longer be based on XBitmap,
126     // but on canvas-independent basegfx bitmaps
127     virtual SlideBitmapSharedPtr getCurrentSlideBitmap( const UnoViewSharedPtr& rView ) const override;
128 
129 
130 private:
131     // ViewEventHandler
132     virtual void viewAdded( const UnoViewSharedPtr& rView ) override;
133     virtual void viewRemoved( const UnoViewSharedPtr& rView ) override;
134     virtual void viewChanged( const UnoViewSharedPtr& rView ) override;
135     virtual void viewsChanged() override;
136 
137     // CursorManager
138     virtual bool requestCursor( sal_Int16 nCursorShape ) override;
139     virtual void resetCursor() override;
140 
141     void activatePaintOverlay();
142     void deactivatePaintOverlay();
143 
144     /** Query whether the slide has animations at all
145 
146         If the slide doesn't have animations, show() displays
147         only static content. If an event is registered with
148         registerSlideEndEvent(), this event will be
149         immediately activated at the end of the show() method.
150 
151         @return true, if this slide has animations, false
152         otherwise
153     */
154     bool isAnimated();
155 
156     /// Set all Shapes to their initial attributes for slideshow
157     bool applyInitialShapeAttributes( const css::uno::Reference< css::animations::XAnimationNode >& xRootAnimationNode );
158 
159     /// Set shapes to attributes corresponding to initial or final state of slide
160     void applyShapeAttributes(
161         const css::uno::Reference< css::animations::XAnimationNode >& xRootAnimationNode,
162         bool bInitial) const;
163 
164     /// Renders current slide content to bitmap
165     SlideBitmapSharedPtr createCurrentSlideBitmap(
166         const UnoViewSharedPtr& rView,
167         ::basegfx::B2ISize const & rSlideSize ) const;
168 
169     /// Prefetch all shapes (not the animations)
170     bool loadShapes();
171 
172     /// Retrieve slide size from XDrawPage
173     basegfx::B2ISize getSlideSizeImpl() const;
174 
175     /// Prefetch show, but don't call applyInitialShapeAttributes()
176     bool implPrefetchShow();
177 
178     /// Add Polygons to the member maPolygons
179     void addPolygons(const PolyPolygonVector& rPolygons);
180 
181     // Types
182     // =====
183 
184     enum SlideAnimationState
185     {
186         CONSTRUCTING_STATE=0,
187         INITIAL_STATE=1,
188         SHOWING_STATE=2,
189         FINAL_STATE=3,
190         SlideAnimationState_NUM_ENTRIES=4
191     };
192 
193     typedef std::vector< SlideBitmapSharedPtr > VectorOfSlideBitmaps;
194     /** Vector of slide bitmaps.
195 
196         Since the bitmap content is sensitive to animation
197         effects, we have an inner vector containing a distinct
198         bitmap for each of the SlideAnimationStates.
199     */
200     typedef ::std::vector< std::pair< UnoViewSharedPtr,
201                                       VectorOfSlideBitmaps > > VectorOfVectorOfSlideBitmaps;
202 
203 
204     // Member variables
205     // ================
206 
207     /// The page model object
208     uno::Reference< drawing::XDrawPage >                mxDrawPage;
209     uno::Reference< drawing::XDrawPagesSupplier >       mxDrawPagesSupplier;
210     uno::Reference< animations::XAnimationNode >        mxRootNode;
211 
212     LayerManagerSharedPtr                               mpLayerManager;
213     std::shared_ptr<ShapeManagerImpl>                 mpShapeManager;
214     std::shared_ptr<SubsettableShapeManager>          mpSubsettableShapeManager;
215 
216     /// Contains common objects needed throughout the slideshow
217     SlideShowContext                                    maContext;
218 
219     /// parent cursor manager
220     CursorManager&                                      mrCursorManager;
221 
222     /// Handles the animation and event generation for us
223     SlideAnimations                                     maAnimations;
224     PolyPolygonVector                                   maPolygons;
225 
226     RGBColor                                            maUserPaintColor;
227     double                                              mdUserPaintStrokeWidth;
228     UserPaintOverlaySharedPtr                           mpPaintOverlay;
229 
230     /// Bitmaps with slide content at various states
231     mutable VectorOfVectorOfSlideBitmaps                maSlideBitmaps;
232 
233     SlideAnimationState                                 meAnimationState;
234 
235     const basegfx::B2ISize                              maSlideSize;
236 
237     sal_Int16                                           mnCurrentCursor;
238 
239     /// True, when intrinsic shape animations are allowed
240     bool const                                          mbIntrinsicAnimationsAllowed;
241 
242     /// True, when user paint overlay is enabled
243     bool                                                mbUserPaintOverlayEnabled;
244 
245     /// True, if initial load of all page shapes succeeded
246     bool                                                mbShapesLoaded;
247 
248     /// True, if initial load of all animation info succeeded
249     bool                                                mbShowLoaded;
250 
251     /** True, if this slide is not static.
252 
253         If this slide has animated content, this variable will
254         be true, and false otherwise.
255     */
256     bool                                                mbHaveAnimations;
257 
258     /** True, if this slide has a main animation sequence.
259 
260         If this slide has animation content, which in turn has
261         a main animation sequence (which must be fully run
262         before EventMultiplexer::notifySlideAnimationsEnd() is
263         called), this member is true.
264     */
265     bool                                                mbMainSequenceFound;
266 
267     /// When true, show() was called. Slide hidden otherwise.
268     bool                                                mbActive;
269 
270     /// When true, enablePaintOverlay was called and mbUserPaintOverlay = true
271     bool                                                mbPaintOverlayActive;
272 
273     /// When true, final state attributes are already applied to shapes
274     bool                                                mbFinalStateApplied;
275 };
276 
277 
slideRenderer(SlideImpl const * pSlide,const UnoViewSharedPtr & rView)278 void slideRenderer( SlideImpl const * pSlide, const UnoViewSharedPtr& rView )
279 {
280     // fully clear view content to background color
281     rView->clearAll();
282 
283     SlideBitmapSharedPtr         pBitmap( pSlide->getCurrentSlideBitmap( rView ) );
284     ::cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
285 
286     const ::basegfx::B2DHomMatrix   aViewTransform( rView->getTransformation() );
287     const ::basegfx::B2DPoint       aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() );
288 
289     // setup a canvas with device coordinate space, the slide
290     // bitmap already has the correct dimension.
291     ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
292     pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
293 
294     // render at given output position
295     pBitmap->move( aOutPosPixel );
296 
297     // clear clip (might have been changed, e.g. from comb
298     // transition)
299     pBitmap->clip( ::basegfx::B2DPolyPolygon() );
300     pBitmap->draw( pDevicePixelCanvas );
301 }
302 
303 
SlideImpl(const uno::Reference<drawing::XDrawPage> & xDrawPage,const uno::Reference<drawing::XDrawPagesSupplier> & xDrawPages,const uno::Reference<animations::XAnimationNode> & xRootNode,EventQueue & rEventQueue,EventMultiplexer & rEventMultiplexer,ScreenUpdater & rScreenUpdater,ActivitiesQueue & rActivitiesQueue,UserEventQueue & rUserEventQueue,CursorManager & rCursorManager,MediaFileManager & rMediaFileManager,const UnoViewContainer & rViewContainer,const uno::Reference<uno::XComponentContext> & xComponentContext,const ShapeEventListenerMap & rShapeListenerMap,const ShapeCursorMap & rShapeCursorMap,const PolyPolygonVector & rPolyPolygonVector,RGBColor const & aUserPaintColor,double dUserPaintStrokeWidth,bool bUserPaintEnabled,bool bIntrinsicAnimationsAllowed,bool bDisableAnimationZOrder)304 SlideImpl::SlideImpl( const uno::Reference< drawing::XDrawPage >&           xDrawPage,
305                       const uno::Reference<drawing::XDrawPagesSupplier>&    xDrawPages,
306                       const uno::Reference< animations::XAnimationNode >&   xRootNode,
307                       EventQueue&                                           rEventQueue,
308                       EventMultiplexer&                                     rEventMultiplexer,
309                       ScreenUpdater&                                        rScreenUpdater,
310                       ActivitiesQueue&                                      rActivitiesQueue,
311                       UserEventQueue&                                       rUserEventQueue,
312                       CursorManager&                                        rCursorManager,
313                       MediaFileManager&                                     rMediaFileManager,
314                       const UnoViewContainer&                               rViewContainer,
315                       const uno::Reference< uno::XComponentContext >&       xComponentContext,
316                       const ShapeEventListenerMap&                          rShapeListenerMap,
317                       const ShapeCursorMap&                                 rShapeCursorMap,
318                       const PolyPolygonVector&                              rPolyPolygonVector,
319                       RGBColor const&                                       aUserPaintColor,
320                       double                                                dUserPaintStrokeWidth,
321                       bool                                                  bUserPaintEnabled,
322                       bool                                                  bIntrinsicAnimationsAllowed,
323                       bool                                                  bDisableAnimationZOrder ) :
324     mxDrawPage( xDrawPage ),
325     mxDrawPagesSupplier( xDrawPages ),
326     mxRootNode( xRootNode ),
327     mpLayerManager( new LayerManager(
328                         rViewContainer,
329                         bDisableAnimationZOrder) ),
330     mpShapeManager( new ShapeManagerImpl(
331                         rEventMultiplexer,
332                         mpLayerManager,
333                         rCursorManager,
334                         rShapeListenerMap,
335                         rShapeCursorMap,
336                         xDrawPage)),
337     mpSubsettableShapeManager( mpShapeManager ),
338     maContext( mpSubsettableShapeManager,
339                rEventQueue,
340                rEventMultiplexer,
341                rScreenUpdater,
342                rActivitiesQueue,
343                rUserEventQueue,
344                *this,
345                rMediaFileManager,
346                rViewContainer,
347                xComponentContext ),
348     mrCursorManager( rCursorManager ),
349     maAnimations( maContext,
350                   basegfx::B2DSize( getSlideSizeImpl() ) ),
351     maPolygons(rPolyPolygonVector),
352     maUserPaintColor(aUserPaintColor),
353     mdUserPaintStrokeWidth(dUserPaintStrokeWidth),
354     mpPaintOverlay(),
355     maSlideBitmaps(),
356     meAnimationState( CONSTRUCTING_STATE ),
357     maSlideSize(getSlideSizeImpl()),
358     mnCurrentCursor( awt::SystemPointer::ARROW ),
359     mbIntrinsicAnimationsAllowed( bIntrinsicAnimationsAllowed ),
360     mbUserPaintOverlayEnabled(bUserPaintEnabled),
361     mbShapesLoaded( false ),
362     mbShowLoaded( false ),
363     mbHaveAnimations( false ),
364     mbMainSequenceFound( false ),
365     mbActive( false ),
366     mbPaintOverlayActive( false ),
367     mbFinalStateApplied( false )
368 {
369     // clone already existing views for slide bitmaps
370     for( const auto& rView : rViewContainer )
371         viewAdded( rView );
372 
373     // register screen update (LayerManager needs to signal pending
374     // updates)
375     maContext.mrScreenUpdater.addViewUpdate(mpShapeManager);
376 }
377 
update_settings(bool bUserPaintEnabled,RGBColor const & aUserPaintColor,double dUserPaintStrokeWidth)378 void SlideImpl::update_settings( bool bUserPaintEnabled, RGBColor const& aUserPaintColor, double dUserPaintStrokeWidth )
379 {
380     maUserPaintColor = aUserPaintColor;
381     mdUserPaintStrokeWidth = dUserPaintStrokeWidth;
382     mbUserPaintOverlayEnabled = bUserPaintEnabled;
383 }
384 
~SlideImpl()385 SlideImpl::~SlideImpl()
386 {
387     if( mpShapeManager )
388     {
389         maContext.mrScreenUpdater.removeViewUpdate(mpShapeManager);
390         mpShapeManager->dispose();
391 
392         // TODO(Q3): Make sure LayerManager (and thus Shapes) dies
393         // first, because SlideShowContext has SubsettableShapeManager
394         // as reference member.
395         mpLayerManager.reset();
396     }
397 }
398 
prefetch()399 void SlideImpl::prefetch()
400 {
401     if( !mxRootNode.is() )
402         return;
403 
404     applyInitialShapeAttributes(mxRootNode);
405 }
406 
show(bool bSlideBackgoundPainted)407 void SlideImpl::show( bool bSlideBackgoundPainted )
408 {
409     if( mbActive )
410         return; // already active
411 
412     if( !mpShapeManager || !mpLayerManager )
413         return; // disposed
414 
415     // set initial shape attributes (e.g. hide shapes that have
416     // 'appear' effect set)
417     if( !applyInitialShapeAttributes(mxRootNode) )
418         return;
419 
420     // activate and take over view - clears view, if necessary
421     mbActive = true;
422     requestCursor( mnCurrentCursor );
423 
424     // enable shape management & event broadcasting for shapes of this
425     // slide. Also enables LayerManager to record updates. Currently,
426     // never let LayerManager render initial slide content, use
427     // buffered slide bitmaps instead.
428     mpShapeManager->activate();
429 
430 
431     // render slide to screen, if requested
432     if( !bSlideBackgoundPainted )
433     {
434         for( const auto& rContext : maContext.mrViewContainer )
435             slideRenderer( this, rContext );
436 
437         maContext.mrScreenUpdater.notifyUpdate();
438     }
439 
440 
441     // fire up animations
442     const bool bIsAnimated( isAnimated() );
443     if( bIsAnimated )
444         maAnimations.start(); // feeds initial events into queue
445 
446     // NOTE: this looks slightly weird, but is indeed correct:
447     // as isAnimated() might return false, _although_ there is
448     // a main sequence (because the animation nodes don't
449     // contain any executable effects), we gotta check both
450     // conditions here.
451     if( !bIsAnimated || !mbMainSequenceFound )
452     {
453         // manually trigger a slide animation end event (we don't have
454         // animations at all, or we don't have a main animation
455         // sequence, but if we had, it'd end now). Note that having
456         // animations alone does not matter here, as only main
457         // sequence animations prevents showing the next slide on
458         // nextEvent().
459         maContext.mrEventMultiplexer.notifySlideAnimationsEnd();
460     }
461 
462     // enable shape-intrinsic animations (drawing layer animations or
463     // GIF animations)
464     if( mbIntrinsicAnimationsAllowed )
465         mpSubsettableShapeManager->notifyIntrinsicAnimationsEnabled();
466 
467     // enable paint overlay, if maUserPaintColor is valid
468     activatePaintOverlay();
469 
470 
471     // from now on, animations might be showing
472     meAnimationState = SHOWING_STATE;
473 }
474 
hide()475 void SlideImpl::hide()
476 {
477     if( !mbActive || !mpShapeManager )
478         return; // already hidden/disposed
479 
480 
481     // from now on, all animations are stopped
482     meAnimationState = FINAL_STATE;
483 
484 
485     // disable user paint overlay under all circumstances,
486     // this slide now ceases to be active.
487     deactivatePaintOverlay();
488 
489 
490     // switch off all shape-intrinsic animations.
491     mpSubsettableShapeManager->notifyIntrinsicAnimationsDisabled();
492 
493     // force-end all SMIL animations, too
494     maAnimations.end();
495 
496 
497     // disable shape management & event broadcasting for shapes of this
498     // slide. Also disables LayerManager.
499     mpShapeManager->deactivate();
500 
501     // vanish from view
502     resetCursor();
503     mbActive = false;
504 }
505 
getSlideSize() const506 basegfx::B2ISize SlideImpl::getSlideSize() const
507 {
508     return maSlideSize;
509 }
510 
getXDrawPage() const511 uno::Reference<drawing::XDrawPage > SlideImpl::getXDrawPage() const
512 {
513     return mxDrawPage;
514 }
515 
getXAnimationNode() const516 uno::Reference<animations::XAnimationNode> SlideImpl::getXAnimationNode() const
517 {
518     return mxRootNode;
519 }
520 
getPolygons()521 PolyPolygonVector SlideImpl::getPolygons()
522 {
523     if(mbPaintOverlayActive)
524         maPolygons = mpPaintOverlay->getPolygons();
525     return maPolygons;
526 }
527 
getCurrentSlideBitmap(const UnoViewSharedPtr & rView) const528 SlideBitmapSharedPtr SlideImpl::getCurrentSlideBitmap( const UnoViewSharedPtr& rView ) const
529 {
530     // search corresponding entry in maSlideBitmaps (which
531     // contains the views as the key)
532     VectorOfVectorOfSlideBitmaps::iterator       aIter;
533     const VectorOfVectorOfSlideBitmaps::iterator aEnd( maSlideBitmaps.end() );
534     if( (aIter=std::find_if( maSlideBitmaps.begin(),
535                              aEnd,
536                              [&rView]
537                              ( const VectorOfVectorOfSlideBitmaps::value_type& cp )
538                              { return rView == cp.first; } ) ) == aEnd )
539     {
540         // corresponding view not found - maybe view was not
541         // added to Slide?
542         ENSURE_OR_THROW( false,
543                           "SlideImpl::getInitialSlideBitmap(): view does not "
544                           "match any of the added ones" );
545     }
546 
547     // ensure that the show is loaded
548     if( !mbShowLoaded )
549     {
550         // only prefetch and init shapes when not done already
551         // (otherwise, at least applyInitialShapeAttributes() will be
552         // called twice for initial slide rendering). Furthermore,
553         // applyInitialShapeAttributes() _always_ performs
554         // initializations, which would be highly unwanted during a
555         // running show. OTOH, a slide whose mbShowLoaded is false is
556         // guaranteed not be running a show.
557 
558         // set initial shape attributes (e.g. hide 'appear' effect
559         // shapes)
560         if( !const_cast<SlideImpl*>(this)->applyInitialShapeAttributes( mxRootNode ) )
561             ENSURE_OR_THROW(false,
562                              "SlideImpl::getCurrentSlideBitmap(): Cannot "
563                              "apply initial attributes");
564     }
565 
566     SlideBitmapSharedPtr&     rBitmap( aIter->second.at( meAnimationState ));
567     const ::basegfx::B2ISize& rSlideSize(
568         getSlideSizePixel( ::basegfx::B2DSize( getSlideSize() ),
569                            rView ));
570 
571     // is the bitmap valid (actually existent, and of correct
572     // size)?
573     if( !rBitmap || rBitmap->getSize() != rSlideSize )
574     {
575         // no bitmap there yet, or wrong size - create one
576         rBitmap = createCurrentSlideBitmap(rView, rSlideSize);
577     }
578 
579     return rBitmap;
580 }
581 
582 
583 // private methods
584 
585 
viewAdded(const UnoViewSharedPtr & rView)586 void SlideImpl::viewAdded( const UnoViewSharedPtr& rView )
587 {
588     maSlideBitmaps.emplace_back( rView,
589                         VectorOfSlideBitmaps(SlideAnimationState_NUM_ENTRIES) );
590 
591     if( mpLayerManager )
592         mpLayerManager->viewAdded( rView );
593 }
594 
viewRemoved(const UnoViewSharedPtr & rView)595 void SlideImpl::viewRemoved( const UnoViewSharedPtr& rView )
596 {
597     if( mpLayerManager )
598         mpLayerManager->viewRemoved( rView );
599 
600     const VectorOfVectorOfSlideBitmaps::iterator aEnd( maSlideBitmaps.end() );
601     maSlideBitmaps.erase(
602         std::remove_if( maSlideBitmaps.begin(),
603                         aEnd,
604                         [&rView]
605                         ( const VectorOfVectorOfSlideBitmaps::value_type& cp )
606                         { return rView == cp.first; } ),
607                         aEnd );
608 }
609 
viewChanged(const UnoViewSharedPtr & rView)610 void SlideImpl::viewChanged( const UnoViewSharedPtr& rView )
611 {
612     // nothing to do for the Slide - getCurrentSlideBitmap() lazily
613     // handles bitmap resizes
614     if( mbActive && mpLayerManager )
615         mpLayerManager->viewChanged(rView);
616 }
617 
viewsChanged()618 void SlideImpl::viewsChanged()
619 {
620     // nothing to do for the Slide - getCurrentSlideBitmap() lazily
621     // handles bitmap resizes
622     if( mbActive && mpLayerManager )
623         mpLayerManager->viewsChanged();
624 }
625 
requestCursor(sal_Int16 nCursorShape)626 bool SlideImpl::requestCursor( sal_Int16 nCursorShape )
627 {
628     mnCurrentCursor = nCursorShape;
629     return mrCursorManager.requestCursor(mnCurrentCursor);
630 }
631 
resetCursor()632 void SlideImpl::resetCursor()
633 {
634     mnCurrentCursor = awt::SystemPointer::ARROW;
635     mrCursorManager.resetCursor();
636 }
637 
isAnimated()638 bool SlideImpl::isAnimated()
639 {
640     // prefetch, but don't apply initial shape attributes
641     if( !implPrefetchShow() )
642         return false;
643 
644     return mbHaveAnimations && maAnimations.isAnimated();
645 }
646 
createCurrentSlideBitmap(const UnoViewSharedPtr & rView,const::basegfx::B2ISize & rBmpSize) const647 SlideBitmapSharedPtr SlideImpl::createCurrentSlideBitmap( const UnoViewSharedPtr&   rView,
648                                                           const ::basegfx::B2ISize& rBmpSize ) const
649 {
650     ENSURE_OR_THROW( rView && rView->getCanvas(),
651                       "SlideImpl::createCurrentSlideBitmap(): Invalid view" );
652     ENSURE_OR_THROW( mpLayerManager,
653                       "SlideImpl::createCurrentSlideBitmap(): Invalid layer manager" );
654     ENSURE_OR_THROW( mbShowLoaded,
655                       "SlideImpl::createCurrentSlideBitmap(): No show loaded" );
656 
657     // tdf#96083 ensure end state settings are applied to shapes once when bitmap gets re-rendered
658     // in that state
659     if(!mbFinalStateApplied && FINAL_STATE == meAnimationState && mxRootNode.is())
660     {
661         const_cast< SlideImpl* >(this)->mbFinalStateApplied = true;
662         applyShapeAttributes(mxRootNode, false);
663     }
664 
665     ::cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
666 
667     // create a bitmap of appropriate size
668     ::cppcanvas::BitmapSharedPtr pBitmap(
669         ::cppcanvas::BaseGfxFactory::createBitmap(
670             pCanvas,
671             rBmpSize ) );
672 
673     ENSURE_OR_THROW( pBitmap,
674                       "SlideImpl::createCurrentSlideBitmap(): Cannot create page bitmap" );
675 
676     ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas( pBitmap->getBitmapCanvas() );
677 
678     ENSURE_OR_THROW( pBitmapCanvas,
679                       "SlideImpl::createCurrentSlideBitmap(): Cannot create page bitmap canvas" );
680 
681     // apply linear part of destination canvas transformation (linear means in this context:
682     // transformation without any translational components)
683     ::basegfx::B2DHomMatrix aLinearTransform( rView->getTransformation() );
684     aLinearTransform.set( 0, 2, 0.0 );
685     aLinearTransform.set( 1, 2, 0.0 );
686     pBitmapCanvas->setTransformation( aLinearTransform );
687 
688     // output all shapes to bitmap
689     initSlideBackground( pBitmapCanvas, rBmpSize );
690     mpLayerManager->renderTo( pBitmapCanvas );
691 
692     return std::make_shared<SlideBitmap>( pBitmap );
693 }
694 
695 class MainSequenceSearcher
696 {
697 public:
MainSequenceSearcher()698     MainSequenceSearcher()
699     {
700         maSearchKey.Name = "node-type";
701         maSearchKey.Value <<= presentation::EffectNodeType::MAIN_SEQUENCE;
702     }
703 
operator ()(const uno::Reference<animations::XAnimationNode> & xChildNode)704     void operator()( const uno::Reference< animations::XAnimationNode >& xChildNode )
705     {
706         uno::Sequence< beans::NamedValue > aUserData( xChildNode->getUserData() );
707 
708         if( findNamedValue( aUserData, maSearchKey ) )
709         {
710             maMainSequence = xChildNode;
711         }
712     }
713 
getMainSequence() const714     const uno::Reference< animations::XAnimationNode >& getMainSequence() const
715     {
716         return maMainSequence;
717     }
718 
719 private:
720     beans::NamedValue                               maSearchKey;
721     uno::Reference< animations::XAnimationNode >    maMainSequence;
722 };
723 
implPrefetchShow()724 bool SlideImpl::implPrefetchShow()
725 {
726     if( mbShowLoaded )
727         return true;
728 
729     ENSURE_OR_RETURN_FALSE( mxDrawPage.is(),
730                        "SlideImpl::implPrefetchShow(): Invalid draw page" );
731     ENSURE_OR_RETURN_FALSE( mpLayerManager,
732                        "SlideImpl::implPrefetchShow(): Invalid layer manager" );
733 
734     // fetch desired page content
735     // ==========================
736 
737     if( !loadShapes() )
738         return false;
739 
740     // New animations framework: import the shape effect info
741     // ======================================================
742 
743     try
744     {
745         if( mxRootNode.is() )
746         {
747             if( !maAnimations.importAnimations( mxRootNode ) )
748             {
749                 OSL_FAIL( "SlideImpl::implPrefetchShow(): have animation nodes, "
750                             "but import animations failed." );
751 
752                 // could not import animation framework,
753                 // _although_ some animation nodes are there -
754                 // this is an error (not finding animations at
755                 // all is okay - might be a static slide)
756                 return false;
757             }
758 
759             // now check whether we've got a main sequence (if
760             // not, we must manually call
761             // EventMultiplexer::notifySlideAnimationsEnd()
762             // above, as e.g. interactive sequences alone
763             // don't block nextEvent() from issuing the next
764             // slide)
765             MainSequenceSearcher aSearcher;
766             if( for_each_childNode( mxRootNode, aSearcher ) )
767                 mbMainSequenceFound = aSearcher.getMainSequence().is();
768 
769             // import successfully done
770             mbHaveAnimations = true;
771         }
772     }
773     catch( uno::RuntimeException& )
774     {
775         throw;
776     }
777     catch( uno::Exception& )
778     {
779         TOOLS_WARN_EXCEPTION( "slideshow", "" );
780         // TODO(E2): Error handling. For now, bail out
781     }
782 
783     mbShowLoaded = true;
784 
785     return true;
786 }
787 
enablePaintOverlay()788 void SlideImpl::enablePaintOverlay()
789 {
790     if( !mbUserPaintOverlayEnabled || !mbPaintOverlayActive )
791     {
792         mbUserPaintOverlayEnabled = true;
793         activatePaintOverlay();
794     }
795 }
796 
activatePaintOverlay()797 void SlideImpl::activatePaintOverlay()
798 {
799     if( mbUserPaintOverlayEnabled || !maPolygons.empty() )
800     {
801         mpPaintOverlay = UserPaintOverlay::create( maUserPaintColor,
802                                                    mdUserPaintStrokeWidth,
803                                                    maContext,
804                                                    maPolygons,
805                                                    mbUserPaintOverlayEnabled );
806         mbPaintOverlayActive = true;
807     }
808 }
809 
drawPolygons() const810 void SlideImpl::drawPolygons() const
811 {
812     if( mpPaintOverlay  )
813         mpPaintOverlay->drawPolygons();
814 }
815 
addPolygons(const PolyPolygonVector & rPolygons)816 void SlideImpl::addPolygons(const PolyPolygonVector& rPolygons)
817 {
818     for (const auto& rxPolygon : rPolygons)
819         maPolygons.push_back(rxPolygon);
820 }
821 
isPaintOverlayActive() const822 bool SlideImpl::isPaintOverlayActive() const
823 {
824     return mbPaintOverlayActive;
825 }
826 
deactivatePaintOverlay()827 void SlideImpl::deactivatePaintOverlay()
828 {
829     if(mbPaintOverlayActive)
830         maPolygons = mpPaintOverlay->getPolygons();
831 
832     mpPaintOverlay.reset();
833     mbPaintOverlayActive = false;
834 }
835 
applyShapeAttributes(const css::uno::Reference<css::animations::XAnimationNode> & xRootAnimationNode,bool bInitial) const836 void SlideImpl::applyShapeAttributes(
837     const css::uno::Reference< css::animations::XAnimationNode >& xRootAnimationNode,
838     bool bInitial) const
839 {
840     const uno::Sequence< animations::TargetProperties > aProps(
841         TargetPropertiesCreator::createTargetProperties( xRootAnimationNode, bInitial ) );
842 
843     // apply extracted values to our shapes
844     for( const auto& rProp : aProps )
845     {
846         sal_Int16                         nParaIndex( -1 );
847         uno::Reference< drawing::XShape > xShape( rProp.Target,
848                                                   uno::UNO_QUERY );
849 
850         if( !xShape.is() )
851         {
852             // not a shape target. Maybe a ParagraphTarget?
853             presentation::ParagraphTarget aParaTarget;
854 
855             if( rProp.Target >>= aParaTarget )
856             {
857                 // yep, ParagraphTarget found - extract shape
858                 // and index
859                 xShape = aParaTarget.Shape;
860                 nParaIndex = aParaTarget.Paragraph;
861             }
862         }
863 
864         if( xShape.is() )
865         {
866             ShapeSharedPtr pShape( mpLayerManager->lookupShape( xShape ) );
867 
868             if( !pShape )
869             {
870                 OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): no shape found for given target" );
871                 continue;
872             }
873 
874             AttributableShapeSharedPtr pAttrShape(
875                 ::std::dynamic_pointer_cast< AttributableShape >( pShape ) );
876 
877             if( !pAttrShape )
878             {
879                 OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): shape found does not "
880                             "implement AttributableShape interface" );
881                 continue;
882             }
883 
884             if( nParaIndex != -1 )
885             {
886                 // our target is a paragraph subset, thus look
887                 // this up first.
888                 const DocTreeNodeSupplier& rNodeSupplier( pAttrShape->getTreeNodeSupplier() );
889 
890                 if( rNodeSupplier.getNumberOfTreeNodes(
891                         DocTreeNode::NodeType::LogicalParagraph ) <= nParaIndex )
892                 {
893                     OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): shape found does not "
894                                 "provide a subset for requested paragraph index" );
895                     continue;
896                 }
897 
898                 pAttrShape = pAttrShape->getSubset(
899                     rNodeSupplier.getTreeNode(
900                         nParaIndex,
901                         DocTreeNode::NodeType::LogicalParagraph ) );
902 
903                 if( !pAttrShape )
904                 {
905                     OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): shape found does not "
906                                 "provide a subset for requested paragraph index" );
907                     continue;
908                 }
909             }
910 
911             const uno::Sequence< beans::NamedValue >& rShapeProps( rProp.Properties );
912             for( const auto& rShapeProp : rShapeProps )
913             {
914                 bool bVisible=false;
915                 if( rShapeProp.Name.equalsIgnoreAsciiCase("visibility") &&
916                     extractValue( bVisible,
917                                   rShapeProp.Value,
918                                   pShape,
919                                   ::basegfx::B2DSize( getSlideSize() ) ))
920                 {
921                     pAttrShape->setVisibility( bVisible );
922                 }
923                 else
924                 {
925                     OSL_FAIL( "SlideImpl::applyInitialShapeAttributes(): Unexpected "
926                                 "(and unimplemented) property encountered" );
927                 }
928             }
929         }
930     }
931 }
932 
applyInitialShapeAttributes(const uno::Reference<animations::XAnimationNode> & xRootAnimationNode)933 bool SlideImpl::applyInitialShapeAttributes(
934     const uno::Reference< animations::XAnimationNode >& xRootAnimationNode )
935 {
936     if( !implPrefetchShow() )
937         return false;
938 
939     if( !xRootAnimationNode.is() )
940     {
941         meAnimationState = INITIAL_STATE;
942 
943         return true; // no animations - no attributes to apply -
944                      // succeeded
945     }
946 
947     applyShapeAttributes(xRootAnimationNode, true);
948 
949     meAnimationState = INITIAL_STATE;
950 
951     return true;
952 }
953 
loadShapes()954 bool SlideImpl::loadShapes()
955 {
956     if( mbShapesLoaded )
957         return true;
958 
959     ENSURE_OR_RETURN_FALSE( mxDrawPage.is(),
960                        "SlideImpl::loadShapes(): Invalid draw page" );
961     ENSURE_OR_RETURN_FALSE( mpLayerManager,
962                        "SlideImpl::loadShapes(): Invalid layer manager" );
963 
964     // fetch desired page content
965     // ==========================
966 
967     // also take master page content
968     uno::Reference< drawing::XDrawPage > xMasterPage;
969     uno::Reference< drawing::XShapes >   xMasterPageShapes;
970     sal_Int32                            nCurrCount(0);
971 
972     uno::Reference< drawing::XMasterPageTarget > xMasterPageTarget( mxDrawPage,
973                                                                     uno::UNO_QUERY );
974     if( xMasterPageTarget.is() )
975     {
976         xMasterPage = xMasterPageTarget->getMasterPage();
977         xMasterPageShapes = xMasterPage;
978 
979         if( xMasterPage.is() && xMasterPageShapes.is() )
980         {
981             // TODO(P2): maybe cache master pages here (or treat the
982             // masterpage as a single metafile. At least currently,
983             // masterpages do not contain animation effects)
984             try
985             {
986                 // load the masterpage shapes
987 
988                 ShapeImporter aMPShapesFunctor( xMasterPage,
989                                                 mxDrawPage,
990                                                 mxDrawPagesSupplier,
991                                                 maContext,
992                                                 0, /* shape num starts at 0 */
993                                                 true );
994 
995                 mpLayerManager->addShape(
996                     aMPShapesFunctor.importBackgroundShape() );
997 
998                 while( !aMPShapesFunctor.isImportDone() )
999                 {
1000                     ShapeSharedPtr const& rShape(
1001                         aMPShapesFunctor.importShape() );
1002                     if( rShape )
1003                         mpLayerManager->addShape( rShape );
1004                 }
1005                 addPolygons(aMPShapesFunctor.getPolygons());
1006 
1007                 nCurrCount = static_cast<sal_Int32>(aMPShapesFunctor.getImportedShapesCount());
1008             }
1009             catch( uno::RuntimeException& )
1010             {
1011                 throw;
1012             }
1013             catch( ShapeLoadFailedException& )
1014             {
1015                 // TODO(E2): Error handling. For now, bail out
1016                 OSL_FAIL( "SlideImpl::loadShapes(): caught ShapeLoadFailedException" );
1017                 return false;
1018 
1019             }
1020             catch( uno::Exception& )
1021             {
1022                 TOOLS_WARN_EXCEPTION( "slideshow", "" );
1023                 return false;
1024             }
1025         }
1026     }
1027 
1028     try
1029     {
1030         // load the normal page shapes
1031 
1032 
1033         ShapeImporter aShapesFunctor( mxDrawPage,
1034                                       mxDrawPage,
1035                                       mxDrawPagesSupplier,
1036                                       maContext,
1037                                       nCurrCount,
1038                                       false );
1039 
1040         while( !aShapesFunctor.isImportDone() )
1041         {
1042             ShapeSharedPtr const& rShape(
1043                 aShapesFunctor.importShape() );
1044             if( rShape )
1045                 mpLayerManager->addShape( rShape );
1046         }
1047         addPolygons(aShapesFunctor.getPolygons());
1048     }
1049     catch( uno::RuntimeException& )
1050     {
1051         throw;
1052     }
1053     catch( ShapeLoadFailedException& )
1054     {
1055         // TODO(E2): Error handling. For now, bail out
1056         OSL_FAIL( "SlideImpl::loadShapes(): caught ShapeLoadFailedException" );
1057         return false;
1058     }
1059     catch( uno::Exception& )
1060     {
1061         TOOLS_WARN_EXCEPTION( "slideshow", "" );
1062         return false;
1063     }
1064 
1065     mbShapesLoaded = true;
1066 
1067     return true;
1068 }
1069 
getSlideSizeImpl() const1070 basegfx::B2ISize SlideImpl::getSlideSizeImpl() const
1071 {
1072     uno::Reference< beans::XPropertySet > xPropSet(
1073         mxDrawPage, uno::UNO_QUERY_THROW );
1074 
1075     sal_Int32 nDocWidth = 0;
1076     sal_Int32 nDocHeight = 0;
1077     xPropSet->getPropertyValue("Width") >>= nDocWidth;
1078     xPropSet->getPropertyValue("Height") >>= nDocHeight;
1079 
1080     return basegfx::B2ISize( nDocWidth, nDocHeight );
1081 }
1082 
1083 } // namespace
1084 
1085 
createSlide(const uno::Reference<drawing::XDrawPage> & xDrawPage,const uno::Reference<drawing::XDrawPagesSupplier> & xDrawPages,const uno::Reference<animations::XAnimationNode> & xRootNode,EventQueue & rEventQueue,EventMultiplexer & rEventMultiplexer,ScreenUpdater & rScreenUpdater,ActivitiesQueue & rActivitiesQueue,UserEventQueue & rUserEventQueue,CursorManager & rCursorManager,MediaFileManager & rMediaFileManager,const UnoViewContainer & rViewContainer,const uno::Reference<uno::XComponentContext> & xComponentContext,const ShapeEventListenerMap & rShapeListenerMap,const ShapeCursorMap & rShapeCursorMap,const PolyPolygonVector & rPolyPolygonVector,RGBColor const & rUserPaintColor,double dUserPaintStrokeWidth,bool bUserPaintEnabled,bool bIntrinsicAnimationsAllowed,bool bDisableAnimationZOrder)1086 SlideSharedPtr createSlide( const uno::Reference< drawing::XDrawPage >&         xDrawPage,
1087                             const uno::Reference<drawing::XDrawPagesSupplier>&  xDrawPages,
1088                             const uno::Reference< animations::XAnimationNode >& xRootNode,
1089                             EventQueue&                                         rEventQueue,
1090                             EventMultiplexer&                                   rEventMultiplexer,
1091                             ScreenUpdater&                                      rScreenUpdater,
1092                             ActivitiesQueue&                                    rActivitiesQueue,
1093                             UserEventQueue&                                     rUserEventQueue,
1094                             CursorManager&                                      rCursorManager,
1095                             MediaFileManager&                                   rMediaFileManager,
1096                             const UnoViewContainer&                             rViewContainer,
1097                             const uno::Reference< uno::XComponentContext >&     xComponentContext,
1098                             const ShapeEventListenerMap&                        rShapeListenerMap,
1099                             const ShapeCursorMap&                               rShapeCursorMap,
1100                             const PolyPolygonVector&                            rPolyPolygonVector,
1101                             RGBColor const&                                     rUserPaintColor,
1102                             double                                              dUserPaintStrokeWidth,
1103                             bool                                                bUserPaintEnabled,
1104                             bool                                                bIntrinsicAnimationsAllowed,
1105                             bool                                                bDisableAnimationZOrder )
1106 {
1107     std::shared_ptr<SlideImpl> pRet( new SlideImpl( xDrawPage, xDrawPages, xRootNode, rEventQueue,
1108                                                       rEventMultiplexer, rScreenUpdater,
1109                                                       rActivitiesQueue, rUserEventQueue,
1110                                                       rCursorManager, rMediaFileManager, rViewContainer,
1111                                                       xComponentContext, rShapeListenerMap,
1112                                                       rShapeCursorMap, rPolyPolygonVector, rUserPaintColor,
1113                                                       dUserPaintStrokeWidth, bUserPaintEnabled,
1114                                                       bIntrinsicAnimationsAllowed,
1115                                                       bDisableAnimationZOrder ));
1116 
1117     rEventMultiplexer.addViewHandler( pRet );
1118 
1119     return pRet;
1120 }
1121 
1122 } // namespace internal
1123 } // namespace slideshow
1124 
1125 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1126