bump product version to 5.0.4.1
[LibreOffice.git] / slideshow / source / engine / transitions / slidechangebase.cxx
blobd78361ff5b97ccce557c64b260ba5ef426993397
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
23 #include <canvas/canvastools.hxx>
24 #include <basegfx/numeric/ftools.hxx>
25 #include <basegfx/polygon/b2dpolygontools.hxx>
26 #include <basegfx/polygon/b2dpolypolygontools.hxx>
27 #include <basegfx/matrix/b2dhommatrixtools.hxx>
28 #include <cppcanvas/basegfxfactory.hxx>
30 #include "slidechangebase.hxx"
31 #include "tools.hxx"
33 #include <boost/bind.hpp>
34 #include <algorithm>
36 using namespace com::sun::star;
38 namespace slideshow {
39 namespace internal {
41 SlideChangeBase::SlideChangeBase( boost::optional<SlideSharedPtr> const & leavingSlide,
42 const SlideSharedPtr& pEnteringSlide,
43 const SoundPlayerSharedPtr& pSoundPlayer,
44 const UnoViewContainer& rViewContainer,
45 ScreenUpdater& rScreenUpdater,
46 EventMultiplexer& rEventMultiplexer,
47 bool bCreateLeavingSprites,
48 bool bCreateEnteringSprites ) :
49 mpSoundPlayer( pSoundPlayer ),
50 mrEventMultiplexer(rEventMultiplexer),
51 mrScreenUpdater(rScreenUpdater),
52 maLeavingSlide( leavingSlide ),
53 mpEnteringSlide( pEnteringSlide ),
54 maViewData(),
55 mrViewContainer(rViewContainer),
56 mbCreateLeavingSprites(bCreateLeavingSprites),
57 mbCreateEnteringSprites(bCreateEnteringSprites),
58 mbSpritesVisible(false),
59 mbFinished(false),
60 mbPrefetched(false)
62 ENSURE_OR_THROW(
63 pEnteringSlide,
64 "SlideChangeBase::SlideChangeBase(): Invalid entering slide!" );
67 SlideBitmapSharedPtr SlideChangeBase::getLeavingBitmap( const ViewEntry& rViewEntry ) const
69 if( !rViewEntry.mpLeavingBitmap )
70 rViewEntry.mpLeavingBitmap = createBitmap(rViewEntry.mpView,
71 maLeavingSlide);
73 return rViewEntry.mpLeavingBitmap;
76 SlideBitmapSharedPtr SlideChangeBase::getEnteringBitmap( const ViewEntry& rViewEntry ) const
78 if( !rViewEntry.mpEnteringBitmap )
79 rViewEntry.mpEnteringBitmap = createBitmap( rViewEntry.mpView,
80 boost::optional<SlideSharedPtr>(mpEnteringSlide) );
82 return rViewEntry.mpEnteringBitmap;
85 SlideBitmapSharedPtr SlideChangeBase::createBitmap( const UnoViewSharedPtr& rView,
86 const boost::optional<SlideSharedPtr>& rSlide ) const
88 SlideBitmapSharedPtr pRet;
89 if( !rSlide )
90 return pRet;
92 SlideSharedPtr const & pSlide = *rSlide;
93 if( !pSlide )
95 // TODO(P3): No need to generate a bitmap here. This only made
96 // the code more uniform. Faster would be to simply clear the
97 // sprite to black.
99 // create empty, black-filled bitmap
100 const basegfx::B2ISize slideSizePixel(
101 getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide->getSlideSize() ),
102 rView ));
104 cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
106 // create a bitmap of appropriate size
107 cppcanvas::BitmapSharedPtr pBitmap(
108 cppcanvas::BaseGfxFactory::createBitmap(
109 pCanvas,
110 slideSizePixel ) );
112 ENSURE_OR_THROW(
113 pBitmap,
114 "SlideChangeBase::createBitmap(): Cannot create page bitmap" );
116 cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas(
117 pBitmap->getBitmapCanvas() );
119 ENSURE_OR_THROW( pBitmapCanvas,
120 "SlideChangeBase::createBitmap(): "
121 "Cannot create page bitmap canvas" );
123 // set transformation to identitiy (->device pixel)
124 pBitmapCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
126 // clear bitmap to black
127 fillRect( pBitmapCanvas,
128 ::basegfx::B2DRectangle( 0.0, 0.0,
129 slideSizePixel.getX(),
130 slideSizePixel.getY() ),
131 0x000000FFU );
133 pRet.reset( new SlideBitmap( pBitmap ));
135 else
137 pRet = pSlide->getCurrentSlideBitmap( rView );
140 return pRet;
143 ::basegfx::B2ISize SlideChangeBase::getEnteringSlideSizePixel( const UnoViewSharedPtr& pView ) const
145 return getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide->getSlideSize() ),
146 pView );
149 void SlideChangeBase::renderBitmap(
150 SlideBitmapSharedPtr const & pSlideBitmap,
151 cppcanvas::CanvasSharedPtr const & pCanvas )
153 if( pSlideBitmap && pCanvas )
155 // need to render without any transformation (we
156 // assume device units):
157 const basegfx::B2DHomMatrix viewTransform(
158 pCanvas->getTransformation() );
159 const basegfx::B2DPoint pageOrigin(
160 viewTransform * basegfx::B2DPoint() );
161 const cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
162 pCanvas->clone() );
164 // render at output position, don't modify bitmap object (no move!):
165 const basegfx::B2DHomMatrix transform(basegfx::tools::createTranslateB2DHomMatrix(
166 pageOrigin.getX(), pageOrigin.getY()));
168 pDevicePixelCanvas->setTransformation( transform );
169 pSlideBitmap->draw( pDevicePixelCanvas );
173 void SlideChangeBase::prefetch( const AnimatableShapeSharedPtr&,
174 const ShapeAttributeLayerSharedPtr& )
176 // we're a one-shot activity, and already finished
177 if( mbFinished || mbPrefetched )
178 return;
180 // register ourselves for view change events
181 mrEventMultiplexer.addViewHandler( shared_from_this() );
183 // init views and create slide bitmaps
184 std::for_each( mrViewContainer.begin(),
185 mrViewContainer.end(),
186 boost::bind( &SlideChangeBase::viewAdded,
187 this,
188 _1 ));
190 mbPrefetched = true;
193 void SlideChangeBase::start( const AnimatableShapeSharedPtr& rShape,
194 const ShapeAttributeLayerSharedPtr& rLayer )
196 // we're a one-shot activity, and already finished
197 if( mbFinished )
198 return;
200 prefetch(rShape,rLayer); // no-op, if already done
202 // get the subclasses a chance to do any specific initialization before run
203 for ( ViewsVecT::const_iterator aCurr( beginViews() ), aEnd( endViews() ); aCurr != aEnd; ++aCurr )
204 prepareForRun( *aCurr, aCurr->mpView->getCanvas() );
206 // start accompanying sound effect, if any
207 if( mpSoundPlayer )
209 mpSoundPlayer->startPlayback();
210 // xxx todo: for now, presentation.cxx takes care about the slide
211 // #i50492# transition sound object, so just release it here
212 mpSoundPlayer.reset();
216 void SlideChangeBase::end()
218 // we're a one-shot activity, and already finished
219 if( mbFinished )
220 return;
224 // draw fully entered bitmap:
225 ViewsVecT::const_iterator aCurr( beginViews() );
226 const ViewsVecT::const_iterator aEnd( endViews() );
227 while( aCurr != aEnd )
229 // fully clear view content to background color
230 aCurr->mpView->clearAll();
232 const SlideBitmapSharedPtr pSlideBitmap( getEnteringBitmap( *aCurr ));
233 pSlideBitmap->clip( basegfx::B2DPolyPolygon() /* no clipping */ );
234 aCurr->mpView->clearAll();
235 renderBitmap( pSlideBitmap,
236 aCurr->mpView->getCanvas() );
238 ++aCurr;
241 catch( uno::Exception& )
243 // make sure releasing below happens
246 // swap changes to screen
247 mrScreenUpdater.notifyUpdate();
249 // make object dysfunctional
250 mbFinished = true;
251 ViewsVecT().swap(maViewData);
252 maLeavingSlide.reset();
253 mpEnteringSlide.reset();
255 // sprites have been binned above
256 mbSpritesVisible = false;
258 // remove also from event multiplexer, we're dead anyway
259 mrEventMultiplexer.removeViewHandler( shared_from_this() );
262 bool SlideChangeBase::operator()( double nValue )
264 if( mbFinished )
265 return false;
267 const std::size_t nEntries( maViewData.size() );
268 bool bSpritesVisible( mbSpritesVisible );
270 for( ::std::size_t i=0; i<nEntries; ++i )
272 // calc sprite offsets. The enter/leaving bitmaps are only
273 // as large as the actual slides. For scaled-down
274 // presentations, we have to move the left, top edge of
275 // those bitmaps to the actual position, governed by the
276 // given view transform. The aSpritePosPixel local
277 // variable is already in device coordinate space
278 // (i.e. pixel).
280 ViewEntry& rViewEntry( maViewData[i] );
281 const ::cppcanvas::CanvasSharedPtr& rCanvas( rViewEntry.mpView->getCanvas() );
282 ::cppcanvas::CustomSpriteSharedPtr& rInSprite( rViewEntry.mpInSprite );
283 ::cppcanvas::CustomSpriteSharedPtr& rOutSprite( rViewEntry.mpOutSprite );
285 // TODO(F2): Properly respect clip here.
287 // Might have to be transformed, too.
288 const ::basegfx::B2DHomMatrix aViewTransform(
289 rViewEntry.mpView->getTransformation() );
290 const ::basegfx::B2DPoint aSpritePosPixel(
291 aViewTransform * ::basegfx::B2DPoint() );
293 // move sprite to final output position, in
294 // device coordinates
295 if( rOutSprite )
296 rOutSprite->movePixel( aSpritePosPixel );
297 if( rInSprite )
298 rInSprite->movePixel( aSpritePosPixel );
300 if( !mbSpritesVisible )
302 if( rOutSprite )
304 // only render once: clipping is done
305 // exclusively with the sprite
306 const ::cppcanvas::CanvasSharedPtr pOutContentCanvas(
307 rOutSprite->getContentCanvas() );
308 if( pOutContentCanvas)
310 // TODO(Q2): Use basegfx bitmaps here
312 // TODO(F1): SlideBitmap is not fully portable
313 // between different canvases!
315 // render the content
316 OSL_ASSERT( getLeavingBitmap( rViewEntry ) );
317 if( getLeavingBitmap( rViewEntry ) )
318 getLeavingBitmap( rViewEntry )->draw( pOutContentCanvas );
322 if( rInSprite )
324 // only render once: clipping is done
325 // exclusively with the sprite
326 const ::cppcanvas::CanvasSharedPtr pInContentCanvas(
327 rInSprite->getContentCanvas() );
328 if( pInContentCanvas )
330 // TODO(Q2): Use basegfx bitmaps here
332 // TODO(F1): SlideBitmap is not fully portable
333 // between different canvases!
335 // render the content
336 getEnteringBitmap( rViewEntry )->draw( pInContentCanvas );
341 if( rOutSprite )
342 performOut( rOutSprite, rViewEntry, rCanvas, nValue );
343 if( rInSprite )
344 performIn( rInSprite, rViewEntry, rCanvas, nValue );
346 // finishing deeds for first run.
347 if( !mbSpritesVisible)
349 // enable sprites:
350 if( rOutSprite )
351 rOutSprite->show();
352 if( rInSprite )
353 rInSprite->show();
354 bSpritesVisible = true;
356 } // for_each( sprite )
358 mbSpritesVisible = bSpritesVisible;
359 mrScreenUpdater.notifyUpdate();
361 return true;
364 void SlideChangeBase::prepareForRun(
365 const ViewEntry& /* rViewEntry */,
366 const boost::shared_ptr<cppcanvas::Canvas>& /* rDestinationCanvas */ )
370 void SlideChangeBase::performIn(
371 const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
372 const ViewEntry& /*rViewEntry*/,
373 const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
374 double /*t*/ )
378 void SlideChangeBase::performOut(
379 const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
380 const ViewEntry& /*rViewEntry*/,
381 const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
382 double /*t*/ )
386 double SlideChangeBase::getUnderlyingValue() const
388 return 0.0; // though this should be used in concert with
389 // ActivitiesFactory::createSimpleActivity, better
390 // explicitly name our start value.
391 // Permissible range for operator() above is [0,1]
394 void SlideChangeBase::viewAdded( const UnoViewSharedPtr& rView )
396 // we're a one-shot activity, and already finished
397 if( mbFinished )
398 return;
400 maViewData.push_back( ViewEntry(rView) );
402 ViewEntry& rEntry( maViewData.back() );
403 getEnteringBitmap( rEntry );
404 getLeavingBitmap( rEntry );
405 addSprites( rEntry );
408 void SlideChangeBase::viewRemoved( const UnoViewSharedPtr& rView )
410 // we're a one-shot activity, and already finished
411 if( mbFinished )
412 return;
414 // erase corresponding entry from maViewData
415 maViewData.erase(
416 std::remove_if(
417 maViewData.begin(),
418 maViewData.end(),
419 boost::bind(
420 std::equal_to<UnoViewSharedPtr>(),
421 rView,
422 // select view:
423 boost::bind( &ViewEntry::getView, _1 ))),
424 maViewData.end() );
427 void SlideChangeBase::viewChanged( const UnoViewSharedPtr& rView )
429 // we're a one-shot activity, and already finished
430 if( mbFinished )
431 return;
433 // find entry corresponding to modified view
434 ViewsVecT::iterator aModifiedEntry(
435 std::find_if(
436 maViewData.begin(),
437 maViewData.end(),
438 boost::bind(
439 std::equal_to<UnoViewSharedPtr>(),
440 rView,
441 // select view:
442 boost::bind( &ViewEntry::getView, _1 ) )));
444 OSL_ASSERT( aModifiedEntry != maViewData.end() );
445 if( aModifiedEntry == maViewData.end() )
446 return;
448 // clear stale info (both bitmaps and sprites prolly need a
449 // resize)
450 clearViewEntry( *aModifiedEntry );
451 addSprites( *aModifiedEntry );
454 void SlideChangeBase::viewsChanged()
456 // we're a one-shot activity, and already finished
457 if( mbFinished )
458 return;
460 ViewsVecT::iterator aIter( maViewData.begin() );
461 ViewsVecT::iterator const aEnd ( maViewData.end() );
462 while( aIter != aEnd )
464 // clear stale info (both bitmaps and sprites prolly need a
465 // resize)
466 clearViewEntry( *aIter );
467 addSprites( *aIter );
469 ++aIter;
473 cppcanvas::CustomSpriteSharedPtr SlideChangeBase::createSprite(
474 UnoViewSharedPtr const & pView,
475 basegfx::B2DSize const & rSpriteSize,
476 double nPrio ) const
478 // TODO(P2): change to bitmapsprite once that's working
479 const cppcanvas::CustomSpriteSharedPtr pSprite(
480 pView->createSprite( rSpriteSize,
481 nPrio ));
483 // alpha default is 0.0, which seems to be
484 // a bad idea when viewing content...
485 pSprite->setAlpha( 1.0 );
486 if (mbSpritesVisible)
487 pSprite->show();
489 return pSprite;
492 void SlideChangeBase::addSprites( ViewEntry& rEntry )
494 if( mbCreateLeavingSprites && maLeavingSlide )
496 // create leaving sprite:
497 const basegfx::B2ISize leavingSlideSizePixel(
498 getLeavingBitmap( rEntry )->getSize() );
500 rEntry.mpOutSprite = createSprite( rEntry.mpView,
501 basegfx::B2DSize( leavingSlideSizePixel ),
502 100 );
505 if( mbCreateEnteringSprites )
507 // create entering sprite:
508 const basegfx::B2ISize enteringSlideSizePixel(
509 getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide->getSlideSize() ),
510 rEntry.mpView ));
512 rEntry.mpInSprite = createSprite( rEntry.mpView,
513 basegfx::B2DSize( enteringSlideSizePixel ),
514 101 );
518 void SlideChangeBase::clearViewEntry( ViewEntry& rEntry )
520 // clear stale info (both bitmaps and sprites prolly need a
521 // resize)
522 rEntry.mpEnteringBitmap.reset();
523 rEntry.mpLeavingBitmap.reset();
524 rEntry.mpInSprite.reset();
525 rEntry.mpOutSprite.reset();
528 } // namespace internal
529 } // namespace presentation
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */