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