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