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 <canvas/debug.hxx>
28 #include <tools/diagnose_ex.h>
29 
30 #include <comphelper/anytostring.hxx>
31 #include <cppuhelper/exc_hlp.hxx>
32 #include <basegfx/numeric/ftools.hxx>
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <basegfx/polygon/b2dpolypolygontools.hxx>
35 
36 #include <com/sun/star/animations/TransitionType.hpp>
37 #include <com/sun/star/animations/TransitionSubType.hpp>
38 
39 #include "transitionfactory.hxx"
40 #include "transitiontools.hxx"
41 #include "parametricpolypolygonfactory.hxx"
42 #include "animationfactory.hxx"
43 #include "clippingfunctor.hxx"
44 
45 #include <boost/bind.hpp>
46 
47 
48 using namespace ::com::sun::star;
49 
50 namespace slideshow {
51 namespace internal {
52 
53 /***************************************************
54  ***                                             ***
55  ***          Shape Transition Effects           ***
56  ***                                             ***
57  ***************************************************/
58 
59 namespace {
60 
61 class ClippingAnimation : public NumberAnimation
62 {
63 public:
64     ClippingAnimation(
65         const ParametricPolyPolygonSharedPtr&   rPolygon,
66         const ShapeManagerSharedPtr&            rShapeManager,
67         const TransitionInfo&                   rTransitionInfo,
68         bool                                    bDirectionForward,
69         bool                                    bModeIn );
70 
71     ~ClippingAnimation();
72 
73     // Animation interface
74     // -------------------
75     virtual void prefetch( const AnimatableShapeSharedPtr&     rShape,
76                            const ShapeAttributeLayerSharedPtr& rAttrLayer );
77     virtual void start( const AnimatableShapeSharedPtr& 	rShape,
78                         const ShapeAttributeLayerSharedPtr& rAttrLayer );
79     virtual void end();
80 
81     // NumberAnimation interface
82     // -----------------------
83     virtual bool operator()( double nValue );
84     virtual double getUnderlyingValue() const;
85 
86 private:
87     void end_();
88 
89     AnimatableShapeSharedPtr           mpShape;
90     ShapeAttributeLayerSharedPtr       mpAttrLayer;
91     ShapeManagerSharedPtr              mpShapeManager;
92     ClippingFunctor					   maClippingFunctor;
93     bool							   mbSpriteActive;
94 };
95 
96 ClippingAnimation::ClippingAnimation(
97     const ParametricPolyPolygonSharedPtr&   rPolygon,
98     const ShapeManagerSharedPtr&            rShapeManager,
99     const TransitionInfo&                   rTransitionInfo,
100     bool                                    bDirectionForward,
101     bool                                    bModeIn ) :
102         mpShape(),
103         mpAttrLayer(),
104         mpShapeManager( rShapeManager ),
105         maClippingFunctor( rPolygon,
106                            rTransitionInfo,
107                            bDirectionForward,
108                            bModeIn ),
109         mbSpriteActive(false)
110 {
111     ENSURE_OR_THROW(
112         rShapeManager,
113         "ClippingAnimation::ClippingAnimation(): Invalid ShapeManager" );
114 }
115 
116 ClippingAnimation::~ClippingAnimation()
117 {
118     try
119     {
120         end_();
121     }
122     catch (uno::Exception &)
123     {
124         OSL_ENSURE( false, rtl::OUStringToOString(
125                         comphelper::anyToString(
126                             cppu::getCaughtException() ),
127                         RTL_TEXTENCODING_UTF8 ).getStr() );
128     }
129 }
130 
131 void ClippingAnimation::prefetch( const AnimatableShapeSharedPtr&,
132                                   const ShapeAttributeLayerSharedPtr& )
133 {
134 }
135 
136 void ClippingAnimation::start( const AnimatableShapeSharedPtr& 		rShape,
137                                const ShapeAttributeLayerSharedPtr& 	rAttrLayer )
138 {
139     OSL_ENSURE( !mpShape,
140                 "ClippingAnimation::start(): Shape already set" );
141     OSL_ENSURE( !mpAttrLayer,
142                 "ClippingAnimation::start(): Attribute layer already set" );
143 
144     mpShape = rShape;
145     mpAttrLayer = rAttrLayer;
146 
147     ENSURE_OR_THROW( rShape,
148                       "ClippingAnimation::start(): Invalid shape" );
149     ENSURE_OR_THROW( rAttrLayer,
150                       "ClippingAnimation::start(): Invalid attribute layer" );
151 
152     mpShape = rShape;
153     mpAttrLayer = rAttrLayer;
154 
155     if( !mbSpriteActive )
156     {
157         mpShapeManager->enterAnimationMode( mpShape );
158         mbSpriteActive = true;
159     }
160 }
161 
162 void ClippingAnimation::end()
163 {
164     end_();
165 }
166 
167 void ClippingAnimation::end_()
168 {
169     if( mbSpriteActive )
170     {
171         mbSpriteActive = false;
172         mpShapeManager->leaveAnimationMode( mpShape );
173 
174         if( mpShape->isContentChanged() )
175             mpShapeManager->notifyShapeUpdate( mpShape );
176     }
177 }
178 
179 bool ClippingAnimation::operator()( double nValue )
180 {
181     ENSURE_OR_RETURN_FALSE(
182         mpAttrLayer && mpShape,
183         "ClippingAnimation::operator(): Invalid ShapeAttributeLayer" );
184 
185     // set new clip
186     mpAttrLayer->setClip( maClippingFunctor( nValue,
187                                              mpShape->getDomBounds().getRange() ) );
188 
189     if( mpShape->isContentChanged() )
190         mpShapeManager->notifyShapeUpdate( mpShape );
191 
192     return true;
193 }
194 
195 double ClippingAnimation::getUnderlyingValue() const
196 {
197     ENSURE_OR_THROW(
198         mpAttrLayer,
199         "ClippingAnimation::getUnderlyingValue(): Invalid ShapeAttributeLayer" );
200 
201     return 0.0;     // though this should be used in concert with
202 				    // ActivitiesFactory::createSimpleActivity, better
203     				// explicitely name our start value.
204 				    // Permissible range for operator() above is [0,1]
205 }
206 
207 } // anon namespace
208 
209 
210 AnimationActivitySharedPtr TransitionFactory::createShapeTransition(
211     const ActivitiesFactory::CommonParameters&          rParms,
212     const AnimatableShapeSharedPtr&                     rShape,
213     const ShapeManagerSharedPtr&                        rShapeManager,
214     const ::basegfx::B2DVector&                         rSlideSize,
215     uno::Reference< animations::XTransitionFilter > const& xTransition )
216 {
217     return createShapeTransition( rParms,
218                                   rShape,
219                                   rShapeManager,
220                                   rSlideSize,
221                                   xTransition,
222                                   xTransition->getTransition(),
223                                   xTransition->getSubtype() );
224 }
225 
226 AnimationActivitySharedPtr TransitionFactory::createShapeTransition(
227     const ActivitiesFactory::CommonParameters& 				rParms,
228     const AnimatableShapeSharedPtr& 						rShape,
229     const ShapeManagerSharedPtr& 							rShapeManager,
230     const ::basegfx::B2DVector&                             rSlideSize,
231     ::com::sun::star::uno::Reference<
232     	::com::sun::star::animations::XTransitionFilter > const& xTransition,
233     sal_Int16               								nType,
234     sal_Int16               								nSubType )
235 {
236     ENSURE_OR_THROW(
237         xTransition.is(),
238         "TransitionFactory::createShapeTransition(): Invalid XTransition" );
239 
240     const TransitionInfo* pTransitionInfo(
241         getTransitionInfo( nType, nSubType ) );
242 
243     AnimationActivitySharedPtr pGeneratedActivity;
244     if( pTransitionInfo != NULL )
245     {
246         switch( pTransitionInfo->meTransitionClass )
247         {
248             default:
249             case TransitionInfo::TRANSITION_INVALID:
250                 OSL_ENSURE( false,
251                             "TransitionFactory::createShapeTransition(): Invalid transition type. "
252                             "Don't ask me for a 0 TransitionType, have no XTransitionFilter node instead!" );
253                 return AnimationActivitySharedPtr();
254 
255 
256             case TransitionInfo::TRANSITION_CLIP_POLYPOLYGON:
257             {
258                 // generate parametric poly-polygon
259                 ParametricPolyPolygonSharedPtr pPoly(
260                     ParametricPolyPolygonFactory::createClipPolyPolygon(
261                         nType, nSubType ) );
262 
263                 // create a clip activity from that
264                 pGeneratedActivity = ActivitiesFactory::createSimpleActivity(
265                     rParms,
266                     NumberAnimationSharedPtr(
267                         new ClippingAnimation(
268                             pPoly,
269                             rShapeManager,
270                             *pTransitionInfo,
271                             xTransition->getDirection(),
272                             xTransition->getMode() ) ),
273                     true );
274             }
275             break;
276 
277             case TransitionInfo::TRANSITION_SPECIAL:
278             {
279                 switch( nType )
280                 {
281                     case animations::TransitionType::RANDOM:
282                     {
283                         // select randomly one of the effects from the
284                         // TransitionFactoryTable
285 
286                         const TransitionInfo* pRandomTransitionInfo( getRandomTransitionInfo() );
287 
288                         ENSURE_OR_THROW( pRandomTransitionInfo != NULL,
289                                           "TransitionFactory::createShapeTransition(): Got invalid random transition info" );
290 
291                         ENSURE_OR_THROW( pRandomTransitionInfo->mnTransitionType != animations::TransitionType::RANDOM,
292                                           "TransitionFactory::createShapeTransition(): Got random again for random input!" );
293 
294                         // and recurse
295                         pGeneratedActivity = createShapeTransition( rParms,
296                                                                     rShape,
297                                                                     rShapeManager,
298                                                                     rSlideSize,
299                                                                     xTransition,
300                                                                     pRandomTransitionInfo->mnTransitionType,
301                                                                     pRandomTransitionInfo->mnTransitionSubType );
302                     }
303                     break;
304 
305                     // TODO(F3): Implement slidewipe for shape
306                     case animations::TransitionType::SLIDEWIPE:
307                     {
308                         sal_Int16 nBarWipeSubType(0);
309                         bool	  bDirectionForward(true);
310 
311                         // map slidewipe to BARWIPE, for now
312                         switch( nSubType )
313                         {
314                             case animations::TransitionSubType::FROMLEFT:
315                                 nBarWipeSubType = animations::TransitionSubType::LEFTTORIGHT;
316                                 bDirectionForward = true;
317                                 break;
318 
319                             case animations::TransitionSubType::FROMRIGHT:
320                                 nBarWipeSubType = animations::TransitionSubType::LEFTTORIGHT;
321                                 bDirectionForward = false;
322                                 break;
323 
324                             case animations::TransitionSubType::FROMTOP:
325                                 nBarWipeSubType = animations::TransitionSubType::TOPTOBOTTOM;
326                                 bDirectionForward = true;
327                                 break;
328 
329                             case animations::TransitionSubType::FROMBOTTOM:
330                                 nBarWipeSubType = animations::TransitionSubType::TOPTOBOTTOM;
331                                 bDirectionForward = false;
332                                 break;
333 
334                             default:
335                                 ENSURE_OR_THROW( false,
336                                                   "TransitionFactory::createShapeTransition(): Unexpected subtype for SLIDEWIPE" );
337                                 break;
338                         }
339 
340                         // generate parametric poly-polygon
341                         ParametricPolyPolygonSharedPtr pPoly(
342                             ParametricPolyPolygonFactory::createClipPolyPolygon(
343                                 animations::TransitionType::BARWIPE,
344                                 nBarWipeSubType ) );
345 
346                         // create a clip activity from that
347                         pGeneratedActivity = ActivitiesFactory::createSimpleActivity(
348                             rParms,
349                             NumberAnimationSharedPtr(
350                                 new ClippingAnimation(
351                                     pPoly,
352                                     rShapeManager,
353                                     *getTransitionInfo( animations::TransitionType::BARWIPE,
354                                                         nBarWipeSubType ),
355                                     bDirectionForward,
356                                     xTransition->getMode() ) ),
357                             true );
358                     }
359                     break;
360 
361                     default:
362                     {
363                         // TODO(F1): Check whether there's anything left, anyway,
364                         // for _shape_ transitions. AFAIK, there are no special
365                         // effects for shapes...
366 
367                         // for now, map all to fade effect
368                         pGeneratedActivity = ActivitiesFactory::createSimpleActivity(
369                             rParms,
370                             AnimationFactory::createNumberPropertyAnimation(
371                                 ::rtl::OUString(
372                                     RTL_CONSTASCII_USTRINGPARAM("Opacity") ),
373                                 rShape,
374                                 rShapeManager,
375                                 rSlideSize ),
376                             xTransition->getMode() );
377                     }
378                     break;
379                 }
380             }
381             break;
382         }
383     }
384 
385     if( !pGeneratedActivity )
386     {
387         // No animation generated, maybe no table entry for given
388         // transition?
389         OSL_TRACE(
390             "TransitionFactory::createShapeTransition(): Unknown type/subtype (%d/%d) "
391             "combination encountered",
392             xTransition->getTransition(),
393             xTransition->getSubtype() );
394         OSL_ENSURE(
395             false,
396             "TransitionFactory::createShapeTransition(): Unknown type/subtype "
397             "combination encountered" );
398     }
399 
400     return pGeneratedActivity;
401 }
402 
403 }
404 }
405