Bump version to 6.0-36
[LibreOffice.git] / slideshow / source / engine / transitions / slidechangebase.cxx
blob2bbec99404f3028cc27a1e51921d1de469e059cf
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 <tools/diagnose_ex.h>
22 #include <canvas/canvastools.hxx>
23 #include <basegfx/numeric/ftools.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <basegfx/matrix/b2dhommatrixtools.hxx>
27 #include <cppcanvas/basegfxfactory.hxx>
29 #include "slidechangebase.hxx"
30 #include <tools.hxx>
32 #include <algorithm>
34 using namespace com::sun::star;
36 namespace slideshow {
37 namespace internal {
39 SlideChangeBase::SlideChangeBase( boost::optional<SlideSharedPtr> const & leavingSlide,
40 const SlideSharedPtr& pEnteringSlide,
41 const SoundPlayerSharedPtr& pSoundPlayer,
42 const UnoViewContainer& rViewContainer,
43 ScreenUpdater& rScreenUpdater,
44 EventMultiplexer& rEventMultiplexer,
45 bool bCreateLeavingSprites,
46 bool bCreateEnteringSprites ) :
47 mpSoundPlayer( pSoundPlayer ),
48 mrEventMultiplexer(rEventMultiplexer),
49 mrScreenUpdater(rScreenUpdater),
50 maLeavingSlide( leavingSlide ),
51 mpEnteringSlide( pEnteringSlide ),
52 maViewData(),
53 mrViewContainer(rViewContainer),
54 mbCreateLeavingSprites(bCreateLeavingSprites),
55 mbCreateEnteringSprites(bCreateEnteringSprites),
56 mbSpritesVisible(false),
57 mbFinished(false),
58 mbPrefetched(false)
60 ENSURE_OR_THROW(
61 pEnteringSlide,
62 "SlideChangeBase::SlideChangeBase(): Invalid entering slide!" );
65 SlideBitmapSharedPtr SlideChangeBase::getLeavingBitmap( const ViewEntry& rViewEntry ) const
67 if( !rViewEntry.mpLeavingBitmap )
68 rViewEntry.mpLeavingBitmap = createBitmap(rViewEntry.mpView,
69 maLeavingSlide);
71 return rViewEntry.mpLeavingBitmap;
74 SlideBitmapSharedPtr SlideChangeBase::getEnteringBitmap( const ViewEntry& rViewEntry ) const
76 if( !rViewEntry.mpEnteringBitmap )
77 rViewEntry.mpEnteringBitmap = createBitmap( rViewEntry.mpView,
78 boost::optional<SlideSharedPtr>(mpEnteringSlide) );
80 return rViewEntry.mpEnteringBitmap;
83 SlideBitmapSharedPtr SlideChangeBase::createBitmap( const UnoViewSharedPtr& rView,
84 const boost::optional<SlideSharedPtr>& rSlide ) const
86 SlideBitmapSharedPtr pRet;
87 if( !rSlide )
88 return pRet;
90 SlideSharedPtr const & pSlide = *rSlide;
91 if( !pSlide )
93 // TODO(P3): No need to generate a bitmap here. This only made
94 // the code more uniform. Faster would be to simply clear the
95 // sprite to black.
97 // create empty, black-filled bitmap
98 const basegfx::B2ISize slideSizePixel(
99 getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide->getSlideSize() ),
100 rView ));
102 cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
104 // create a bitmap of appropriate size
105 cppcanvas::BitmapSharedPtr pBitmap(
106 cppcanvas::BaseGfxFactory::createBitmap(
107 pCanvas,
108 slideSizePixel ) );
110 ENSURE_OR_THROW(
111 pBitmap,
112 "SlideChangeBase::createBitmap(): Cannot create page bitmap" );
114 cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas(
115 pBitmap->getBitmapCanvas() );
117 ENSURE_OR_THROW( pBitmapCanvas,
118 "SlideChangeBase::createBitmap(): "
119 "Cannot create page bitmap canvas" );
121 // set transformation to identitiy (->device pixel)
122 pBitmapCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
124 // clear bitmap to black
125 fillRect( pBitmapCanvas,
126 ::basegfx::B2DRectangle( 0.0, 0.0,
127 slideSizePixel.getX(),
128 slideSizePixel.getY() ),
129 0x000000FFU );
131 pRet.reset( new SlideBitmap( pBitmap ));
133 else
135 pRet = pSlide->getCurrentSlideBitmap( rView );
138 return pRet;
141 ::basegfx::B2ISize SlideChangeBase::getEnteringSlideSizePixel( const UnoViewSharedPtr& pView ) const
143 return getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide->getSlideSize() ),
144 pView );
147 void SlideChangeBase::renderBitmap(
148 SlideBitmapSharedPtr const & pSlideBitmap,
149 cppcanvas::CanvasSharedPtr const & pCanvas )
151 if( pSlideBitmap && pCanvas )
153 // need to render without any transformation (we
154 // assume device units):
155 const basegfx::B2DHomMatrix viewTransform(
156 pCanvas->getTransformation() );
157 const basegfx::B2DPoint pageOrigin(
158 viewTransform * basegfx::B2DPoint() );
159 const cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
160 pCanvas->clone() );
162 // render at output position, don't modify bitmap object (no move!):
163 const basegfx::B2DHomMatrix transform(basegfx::utils::createTranslateB2DHomMatrix(
164 pageOrigin.getX(), pageOrigin.getY()));
166 pDevicePixelCanvas->setTransformation( transform );
167 pSlideBitmap->draw( pDevicePixelCanvas );
171 void SlideChangeBase::prefetch( const AnimatableShapeSharedPtr&,
172 const ShapeAttributeLayerSharedPtr& )
174 // we're a one-shot activity, and already finished
175 if( mbFinished || mbPrefetched )
176 return;
178 // register ourselves for view change events
179 mrEventMultiplexer.addViewHandler( std::dynamic_pointer_cast<ViewEventHandler>(shared_from_this()) );
181 // init views and create slide bitmaps
182 for( const auto& pView : mrViewContainer )
183 viewAdded( pView );
185 mbPrefetched = true;
188 void SlideChangeBase::start( const AnimatableShapeSharedPtr& rShape,
189 const ShapeAttributeLayerSharedPtr& rLayer )
191 // we're a one-shot activity, and already finished
192 if( mbFinished )
193 return;
195 prefetch(rShape,rLayer); // no-op, if already done
197 // get the subclasses a chance to do any specific initialization before run
198 for ( ViewsVecT::const_iterator aCurr( beginViews() ), aEnd( endViews() ); aCurr != aEnd; ++aCurr )
199 prepareForRun( *aCurr, aCurr->mpView->getCanvas() );
201 // start accompanying sound effect, if any
202 if( mpSoundPlayer )
204 mpSoundPlayer->startPlayback();
205 // xxx todo: for now, presentation.cxx takes care about the slide
206 // #i50492# transition sound object, so just release it here
207 mpSoundPlayer.reset();
211 void SlideChangeBase::end()
213 // we're a one-shot activity, and already finished
214 if( mbFinished )
215 return;
219 // draw fully entered bitmap:
220 ViewsVecT::const_iterator aCurr( beginViews() );
221 const ViewsVecT::const_iterator aEnd( endViews() );
222 while( aCurr != aEnd )
224 // fully clear view content to background color
225 aCurr->mpView->clearAll();
227 const SlideBitmapSharedPtr pSlideBitmap( getEnteringBitmap( *aCurr ));
228 pSlideBitmap->clip( basegfx::B2DPolyPolygon() /* no clipping */ );
229 aCurr->mpView->clearAll();
230 renderBitmap( pSlideBitmap,
231 aCurr->mpView->getCanvas() );
233 ++aCurr;
236 catch( uno::Exception& )
238 // make sure releasing below happens
241 // swap changes to screen
242 mrScreenUpdater.notifyUpdate();
244 // make object dysfunctional
245 mbFinished = true;
246 ViewsVecT().swap(maViewData);
247 maLeavingSlide.reset();
248 mpEnteringSlide.reset();
250 // sprites have been binned above
251 mbSpritesVisible = false;
253 // remove also from event multiplexer, we're dead anyway
254 mrEventMultiplexer.removeViewHandler( std::dynamic_pointer_cast<ViewEventHandler>(shared_from_this()) );
257 bool SlideChangeBase::operator()( double nValue )
259 if( mbFinished )
260 return false;
262 const std::size_t nEntries( maViewData.size() );
263 bool bSpritesVisible( mbSpritesVisible );
265 for( ::std::size_t i=0; i<nEntries; ++i )
267 // calc sprite offsets. The enter/leaving bitmaps are only
268 // as large as the actual slides. For scaled-down
269 // presentations, we have to move the left, top edge of
270 // those bitmaps to the actual position, governed by the
271 // given view transform. The aSpritePosPixel local
272 // variable is already in device coordinate space
273 // (i.e. pixel).
275 ViewEntry& rViewEntry( maViewData[i] );
276 const ::cppcanvas::CanvasSharedPtr& rCanvas( rViewEntry.mpView->getCanvas() );
277 ::cppcanvas::CustomSpriteSharedPtr& rInSprite( rViewEntry.mpInSprite );
278 ::cppcanvas::CustomSpriteSharedPtr& rOutSprite( rViewEntry.mpOutSprite );
280 // TODO(F2): Properly respect clip here.
282 // Might have to be transformed, too.
283 const ::basegfx::B2DHomMatrix aViewTransform(
284 rViewEntry.mpView->getTransformation() );
285 const ::basegfx::B2DPoint aSpritePosPixel(
286 aViewTransform * ::basegfx::B2DPoint() );
288 // move sprite to final output position, in
289 // device coordinates
290 if( rOutSprite )
291 rOutSprite->movePixel( aSpritePosPixel );
292 if( rInSprite )
293 rInSprite->movePixel( aSpritePosPixel );
295 if( !mbSpritesVisible )
297 if( rOutSprite )
299 // only render once: clipping is done
300 // exclusively with the sprite
301 const ::cppcanvas::CanvasSharedPtr pOutContentCanvas(
302 rOutSprite->getContentCanvas() );
303 if( pOutContentCanvas)
305 // TODO(Q2): Use basegfx bitmaps here
307 // TODO(F1): SlideBitmap is not fully portable
308 // between different canvases!
310 // render the content
311 OSL_ASSERT( getLeavingBitmap( rViewEntry ) );
312 if( getLeavingBitmap( rViewEntry ) )
313 getLeavingBitmap( rViewEntry )->draw( pOutContentCanvas );
317 if( rInSprite )
319 // only render once: clipping is done
320 // exclusively with the sprite
321 const ::cppcanvas::CanvasSharedPtr pInContentCanvas(
322 rInSprite->getContentCanvas() );
323 if( pInContentCanvas )
325 // TODO(Q2): Use basegfx bitmaps here
327 // TODO(F1): SlideBitmap is not fully portable
328 // between different canvases!
330 // render the content
331 getEnteringBitmap( rViewEntry )->draw( pInContentCanvas );
336 if( rOutSprite )
337 performOut( rOutSprite, rViewEntry, rCanvas, nValue );
338 if( rInSprite )
339 performIn( rInSprite, rViewEntry, rCanvas, nValue );
341 // finishing deeds for first run.
342 if( !mbSpritesVisible)
344 // enable sprites:
345 if( rOutSprite )
346 rOutSprite->show();
347 if( rInSprite )
348 rInSprite->show();
349 bSpritesVisible = true;
351 } // for_each( sprite )
353 mbSpritesVisible = bSpritesVisible;
354 mrScreenUpdater.notifyUpdate();
356 return true;
359 void SlideChangeBase::prepareForRun(
360 const ViewEntry& /* rViewEntry */,
361 const std::shared_ptr<cppcanvas::Canvas>& /* rDestinationCanvas */ )
365 void SlideChangeBase::performIn(
366 const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
367 const ViewEntry& /*rViewEntry*/,
368 const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
369 double /*t*/ )
373 void SlideChangeBase::performOut(
374 const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
375 const ViewEntry& /*rViewEntry*/,
376 const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
377 double /*t*/ )
381 double SlideChangeBase::getUnderlyingValue() const
383 return 0.0; // though this should be used in concert with
384 // ActivitiesFactory::createSimpleActivity, better
385 // explicitly name our start value.
386 // Permissible range for operator() above is [0,1]
389 void SlideChangeBase::viewAdded( const UnoViewSharedPtr& rView )
391 // we're a one-shot activity, and already finished
392 if( mbFinished )
393 return;
395 maViewData.emplace_back(rView );
397 ViewEntry& rEntry( maViewData.back() );
398 getEnteringBitmap( rEntry );
399 getLeavingBitmap( rEntry );
400 addSprites( rEntry );
403 void SlideChangeBase::viewRemoved( const UnoViewSharedPtr& rView )
405 // we're a one-shot activity, and already finished
406 if( mbFinished )
407 return;
409 // erase corresponding entry from maViewData
410 maViewData.erase(
411 std::remove_if(
412 maViewData.begin(),
413 maViewData.end(),
414 [rView]( const ViewEntry& rViewEntry )
415 { return rView == rViewEntry.getView(); } ),
416 maViewData.end() );
419 void SlideChangeBase::viewChanged( const UnoViewSharedPtr& rView )
421 // we're a one-shot activity, and already finished
422 if( mbFinished )
423 return;
425 // find entry corresponding to modified view
426 ViewsVecT::iterator aModifiedEntry(
427 std::find_if(
428 maViewData.begin(),
429 maViewData.end(),
430 [rView]( const ViewEntry& rViewEntry )
431 { return rView == rViewEntry.getView(); } ) );
433 OSL_ASSERT( aModifiedEntry != maViewData.end() );
434 if( aModifiedEntry == maViewData.end() )
435 return;
437 // clear stale info (both bitmaps and sprites prolly need a
438 // resize)
439 clearViewEntry( *aModifiedEntry );
440 addSprites( *aModifiedEntry );
443 void SlideChangeBase::viewsChanged()
445 // we're a one-shot activity, and already finished
446 if( mbFinished )
447 return;
449 for( auto& rView : maViewData )
451 // clear stale info (both bitmaps and sprites prolly need a
452 // resize)
453 clearViewEntry( rView );
454 addSprites( rView );
458 cppcanvas::CustomSpriteSharedPtr SlideChangeBase::createSprite(
459 UnoViewSharedPtr const & pView,
460 basegfx::B2DSize const & rSpriteSize,
461 double nPrio ) const
463 // TODO(P2): change to bitmapsprite once that's working
464 const cppcanvas::CustomSpriteSharedPtr pSprite(
465 pView->createSprite( rSpriteSize,
466 nPrio ));
468 // alpha default is 0.0, which seems to be
469 // a bad idea when viewing content...
470 pSprite->setAlpha( 1.0 );
471 if (mbSpritesVisible)
472 pSprite->show();
474 return pSprite;
477 void SlideChangeBase::addSprites( ViewEntry& rEntry )
479 if( mbCreateLeavingSprites && maLeavingSlide )
481 // create leaving sprite:
482 const basegfx::B2ISize leavingSlideSizePixel(
483 getLeavingBitmap( rEntry )->getSize() );
485 rEntry.mpOutSprite = createSprite( rEntry.mpView,
486 basegfx::B2DSize( leavingSlideSizePixel ),
487 100 );
490 if( mbCreateEnteringSprites )
492 // create entering sprite:
493 const basegfx::B2ISize enteringSlideSizePixel(
494 getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide->getSlideSize() ),
495 rEntry.mpView ));
497 rEntry.mpInSprite = createSprite( rEntry.mpView,
498 basegfx::B2DSize( enteringSlideSizePixel ),
499 101 );
503 void SlideChangeBase::clearViewEntry( ViewEntry& rEntry )
505 // clear stale info (both bitmaps and sprites prolly need a
506 // resize)
507 rEntry.mpEnteringBitmap.reset();
508 rEntry.mpLeavingBitmap.reset();
509 rEntry.mpInSprite.reset();
510 rEntry.mpOutSprite.reset();
513 } // namespace internal
514 } // namespace presentation
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */