android: Update app-specific/MIME type icons
[LibreOffice.git] / slideshow / source / engine / transitions / slidechangebase.cxx
blob6c8a0ec9eef40709b5d1fb629f3c99b69ed75082
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 <comphelper/diagnose_ex.hxx>
22 #include <basegfx/matrix/b2dhommatrixtools.hxx>
23 #include <cppcanvas/basegfxfactory.hxx>
24 #include <cppcanvas/customsprite.hxx>
26 #include "slidechangebase.hxx"
27 #include <tools.hxx>
29 #include <algorithm>
30 #include <utility>
32 using namespace com::sun::star;
34 namespace slideshow::internal {
36 SlideChangeBase::SlideChangeBase( std::optional<SlideSharedPtr> leavingSlide,
37 const SlideSharedPtr& pEnteringSlide,
38 SoundPlayerSharedPtr pSoundPlayer,
39 const UnoViewContainer& rViewContainer,
40 ScreenUpdater& rScreenUpdater,
41 EventMultiplexer& rEventMultiplexer,
42 bool bCreateLeavingSprites,
43 bool bCreateEnteringSprites ) :
44 mpSoundPlayer(std::move( pSoundPlayer )),
45 mrEventMultiplexer(rEventMultiplexer),
46 mrScreenUpdater(rScreenUpdater),
47 maLeavingSlide(std::move( leavingSlide )),
48 mpEnteringSlide( pEnteringSlide ),
49 maViewData(),
50 mrViewContainer(rViewContainer),
51 mbCreateLeavingSprites(bCreateLeavingSprites),
52 mbCreateEnteringSprites(bCreateEnteringSprites),
53 mbSpritesVisible(false),
54 mbFinished(false),
55 mbPrefetched(false)
57 ENSURE_OR_THROW(
58 pEnteringSlide,
59 "SlideChangeBase::SlideChangeBase(): Invalid entering slide!" );
62 SlideBitmapSharedPtr SlideChangeBase::getLeavingBitmap( const ViewEntry& rViewEntry ) const
64 if( !rViewEntry.mpLeavingBitmap )
65 rViewEntry.mpLeavingBitmap = createBitmap(rViewEntry.mpView,
66 maLeavingSlide);
68 return rViewEntry.mpLeavingBitmap;
71 SlideBitmapSharedPtr SlideChangeBase::getEnteringBitmap( const ViewEntry& rViewEntry ) const
73 if( !rViewEntry.mpEnteringBitmap )
74 rViewEntry.mpEnteringBitmap = createBitmap( rViewEntry.mpView,
75 std::optional<SlideSharedPtr>(mpEnteringSlide) );
77 return rViewEntry.mpEnteringBitmap;
80 SlideBitmapSharedPtr SlideChangeBase::createBitmap( const UnoViewSharedPtr& rView,
81 const std::optional<SlideSharedPtr>& rSlide ) const
83 SlideBitmapSharedPtr pRet;
84 if( !rSlide )
85 return pRet;
87 SlideSharedPtr const & pSlide = *rSlide;
88 if( !pSlide )
90 // TODO(P3): No need to generate a bitmap here. This only made
91 // the code more uniform. Faster would be to simply clear the
92 // sprite to black.
94 // create empty, black-filled bitmap
95 const basegfx::B2ISize slideSizePixel(
96 getSlideSizePixel( basegfx::B2DVector( mpEnteringSlide->getSlideSize() ),
97 rView ));
99 cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
101 // create a bitmap of appropriate size
102 cppcanvas::BitmapSharedPtr pBitmap(
103 cppcanvas::BaseGfxFactory::createBitmap(
104 pCanvas,
105 slideSizePixel ) );
107 ENSURE_OR_THROW(
108 pBitmap,
109 "SlideChangeBase::createBitmap(): Cannot create page bitmap" );
111 cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas(
112 pBitmap->getBitmapCanvas() );
114 ENSURE_OR_THROW( pBitmapCanvas,
115 "SlideChangeBase::createBitmap(): "
116 "Cannot create page bitmap canvas" );
118 // set transformation to identity (->device pixel)
119 pBitmapCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
121 // clear bitmap to black
122 fillRect( pBitmapCanvas,
123 ::basegfx::B2DRectangle( 0.0, 0.0,
124 slideSizePixel.getX(),
125 slideSizePixel.getY() ),
126 0x000000FFU );
128 pRet = std::make_shared<SlideBitmap>( pBitmap );
130 else
132 pRet = pSlide->getCurrentSlideBitmap( rView );
135 return pRet;
138 ::basegfx::B2ISize SlideChangeBase::getEnteringSlideSizePixel( const UnoViewSharedPtr& pView ) const
140 return getSlideSizePixel( basegfx::B2DVector(mpEnteringSlide->getSlideSize().getX(), mpEnteringSlide->getSlideSize().getY()),
141 pView );
144 void SlideChangeBase::renderBitmap(
145 SlideBitmapSharedPtr const & pSlideBitmap,
146 cppcanvas::CanvasSharedPtr const & pCanvas )
148 if( !(pSlideBitmap && pCanvas) )
149 return;
151 // need to render without any transformation (we
152 // assume device units):
153 const basegfx::B2DHomMatrix viewTransform(
154 pCanvas->getTransformation() );
155 const basegfx::B2DPoint pageOrigin(
156 viewTransform * basegfx::B2DPoint() );
157 const cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
158 pCanvas->clone() );
160 // render at output position, don't modify bitmap object (no move!):
161 const basegfx::B2DHomMatrix transform(basegfx::utils::createTranslateB2DHomMatrix(
162 pageOrigin.getX(), pageOrigin.getY()));
164 pDevicePixelCanvas->setTransformation( transform );
165 pSlideBitmap->draw( pDevicePixelCanvas );
168 void SlideChangeBase::prefetch()
170 // we're a one-shot activity, and already finished
171 if( mbFinished || mbPrefetched )
172 return;
174 // register ourselves for view change events
175 mrEventMultiplexer.addViewHandler( std::dynamic_pointer_cast<ViewEventHandler>(shared_from_this()) );
177 // init views and create slide bitmaps
178 for( const auto& pView : mrViewContainer )
179 viewAdded( pView );
181 mbPrefetched = true;
184 void SlideChangeBase::start( const AnimatableShapeSharedPtr& /*rShape*/,
185 const ShapeAttributeLayerSharedPtr& /*rLayer*/ )
187 // we're a one-shot activity, and already finished
188 if( mbFinished )
189 return;
191 prefetch(); // no-op, if already done
193 // get the subclasses a chance to do any specific initialization before run
194 for ( ViewsVecT::const_iterator aCurr( beginViews() ), aEnd( endViews() ); aCurr != aEnd; ++aCurr )
195 prepareForRun( *aCurr, aCurr->mpView->getCanvas() );
197 // start accompanying sound effect, if any
198 if( mpSoundPlayer )
200 mpSoundPlayer->startPlayback();
201 // xxx todo: for now, presentation.cxx takes care about the slide
202 // #i50492# transition sound object, so just release it here
203 mpSoundPlayer.reset();
207 void SlideChangeBase::end()
209 // we're a one-shot activity, and already finished
210 if( mbFinished )
211 return;
215 // draw fully entered bitmap:
216 ViewsVecT::const_iterator aCurr( beginViews() );
217 const ViewsVecT::const_iterator aEnd( endViews() );
218 while( aCurr != aEnd )
220 // fully clear view content to background color
221 aCurr->mpView->clearAll();
223 const SlideBitmapSharedPtr pSlideBitmap( getEnteringBitmap( *aCurr ));
224 pSlideBitmap->clip( basegfx::B2DPolyPolygon() /* no clipping */ );
225 aCurr->mpView->clearAll();
226 renderBitmap( pSlideBitmap,
227 aCurr->mpView->getCanvas() );
229 ++aCurr;
232 catch( uno::Exception& )
234 // make sure releasing below happens
237 // swap changes to screen
238 mrScreenUpdater.notifyUpdate();
240 // make object dysfunctional
241 mbFinished = true;
242 ViewsVecT().swap(maViewData);
243 maLeavingSlide.reset();
244 mpEnteringSlide.reset();
246 // sprites have been binned above
247 mbSpritesVisible = false;
249 // remove also from event multiplexer, we're dead anyway
250 mrEventMultiplexer.removeViewHandler( std::dynamic_pointer_cast<ViewEventHandler>(shared_from_this()) );
253 bool SlideChangeBase::operator()( double nValue )
255 if( mbFinished )
256 return false;
258 const std::size_t nEntries( maViewData.size() );
259 bool bSpritesVisible( mbSpritesVisible );
261 for( ::std::size_t i=0; i<nEntries; ++i )
263 // calc sprite offsets. The enter/leaving bitmaps are only
264 // as large as the actual slides. For scaled-down
265 // presentations, we have to move the left, top edge of
266 // those bitmaps to the actual position, governed by the
267 // given view transform. The aSpritePosPixel local
268 // variable is already in device coordinate space
269 // (i.e. pixel).
271 ViewEntry& rViewEntry( maViewData[i] );
272 const ::cppcanvas::CanvasSharedPtr& rCanvas( rViewEntry.mpView->getCanvas() );
273 ::cppcanvas::CustomSpriteSharedPtr& rInSprite( rViewEntry.mpInSprite );
274 ::cppcanvas::CustomSpriteSharedPtr& rOutSprite( rViewEntry.mpOutSprite );
276 // TODO(F2): Properly respect clip here.
278 // Might have to be transformed, too.
279 const ::basegfx::B2DHomMatrix aViewTransform(
280 rViewEntry.mpView->getTransformation() );
281 const ::basegfx::B2DPoint aSpritePosPixel(
282 aViewTransform * ::basegfx::B2DPoint() );
284 // move sprite to final output position, in
285 // device coordinates
286 if( rOutSprite )
287 rOutSprite->movePixel( aSpritePosPixel );
288 if( rInSprite )
289 rInSprite->movePixel( aSpritePosPixel );
291 if( !mbSpritesVisible )
293 if( rOutSprite )
295 // only render once: clipping is done
296 // exclusively with the sprite
297 const ::cppcanvas::CanvasSharedPtr pOutContentCanvas(
298 rOutSprite->getContentCanvas() );
299 if( pOutContentCanvas)
301 // TODO(Q2): Use basegfx bitmaps here
303 // TODO(F1): SlideBitmap is not fully portable
304 // between different canvases!
306 // render the content
307 OSL_ASSERT( getLeavingBitmap( rViewEntry ) );
308 if( getLeavingBitmap( rViewEntry ) )
309 getLeavingBitmap( rViewEntry )->draw( pOutContentCanvas );
313 if( rInSprite )
315 // only render once: clipping is done
316 // exclusively with the sprite
317 const ::cppcanvas::CanvasSharedPtr pInContentCanvas(
318 rInSprite->getContentCanvas() );
319 if( pInContentCanvas )
321 // TODO(Q2): Use basegfx bitmaps here
323 // TODO(F1): SlideBitmap is not fully portable
324 // between different canvases!
326 // render the content
327 getEnteringBitmap( rViewEntry )->draw( pInContentCanvas );
332 if( rOutSprite )
333 performOut( rOutSprite, rViewEntry, rCanvas, nValue );
334 if( rInSprite )
335 performIn( rInSprite, rViewEntry, rCanvas, nValue );
337 // finishing deeds for first run.
338 if( !mbSpritesVisible)
340 // enable sprites:
341 if( rOutSprite )
342 rOutSprite->show();
343 if( rInSprite )
344 rInSprite->show();
345 bSpritesVisible = true;
347 } // for_each( sprite )
349 mbSpritesVisible = bSpritesVisible;
350 mrScreenUpdater.notifyUpdate();
352 return true;
355 void SlideChangeBase::prepareForRun(
356 const ViewEntry& /* rViewEntry */,
357 const cppcanvas::CanvasSharedPtr& /* rDestinationCanvas */ )
361 void SlideChangeBase::performIn(
362 const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
363 const ViewEntry& /*rViewEntry*/,
364 const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
365 double /*t*/ )
369 void SlideChangeBase::performOut(
370 const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
371 const ViewEntry& /*rViewEntry*/,
372 const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
373 double /*t*/ )
377 double SlideChangeBase::getUnderlyingValue() const
379 return 0.0; // though this should be used in concert with
380 // ActivitiesFactory::createSimpleActivity, better
381 // explicitly name our start value.
382 // Permissible range for operator() above is [0,1]
385 void SlideChangeBase::viewAdded( const UnoViewSharedPtr& rView )
387 // we're a one-shot activity, and already finished
388 if( mbFinished )
389 return;
391 maViewData.emplace_back(rView );
393 ViewEntry& rEntry( maViewData.back() );
394 getEnteringBitmap( rEntry );
395 getLeavingBitmap( rEntry );
396 addSprites( rEntry );
399 void SlideChangeBase::viewRemoved( const UnoViewSharedPtr& rView )
401 // we're a one-shot activity, and already finished
402 if( mbFinished )
403 return;
405 // erase corresponding entry from maViewData
406 maViewData.erase(
407 std::remove_if(
408 maViewData.begin(),
409 maViewData.end(),
410 [rView]( const ViewEntry& rViewEntry )
411 { return rView == rViewEntry.getView(); } ),
412 maViewData.end() );
415 void SlideChangeBase::viewChanged( const UnoViewSharedPtr& rView )
417 // we're a one-shot activity, and already finished
418 if( mbFinished )
419 return;
421 // find entry corresponding to modified view
422 ViewsVecT::iterator aModifiedEntry(
423 std::find_if(
424 maViewData.begin(),
425 maViewData.end(),
426 [rView]( const ViewEntry& rViewEntry )
427 { return rView == rViewEntry.getView(); } ) );
429 OSL_ASSERT( aModifiedEntry != maViewData.end() );
430 if( aModifiedEntry == maViewData.end() )
431 return;
433 // clear stale info (both bitmaps and sprites prolly need a
434 // resize)
435 clearViewEntry( *aModifiedEntry );
436 addSprites( *aModifiedEntry );
439 void SlideChangeBase::viewsChanged()
441 // we're a one-shot activity, and already finished
442 if( mbFinished )
443 return;
445 for( auto& rView : maViewData )
447 // clear stale info (both bitmaps and sprites prolly need a
448 // resize)
449 clearViewEntry( rView );
450 addSprites( rView );
454 cppcanvas::CustomSpriteSharedPtr SlideChangeBase::createSprite(
455 UnoViewSharedPtr const & pView,
456 basegfx::B2DSize const & rSpriteSize,
457 double nPrio ) const
459 // TODO(P2): change to bitmapsprite once that's working
460 const cppcanvas::CustomSpriteSharedPtr pSprite(
461 pView->createSprite( rSpriteSize,
462 nPrio ));
464 // alpha default is 0.0, which seems to be
465 // a bad idea when viewing content...
466 pSprite->setAlpha( 1.0 );
467 if (mbSpritesVisible)
468 pSprite->show();
470 return pSprite;
473 void SlideChangeBase::addSprites( ViewEntry& rEntry )
475 if( mbCreateLeavingSprites && maLeavingSlide )
477 // create leaving sprite:
478 const basegfx::B2ISize leavingSlideSizePixel(
479 getLeavingBitmap( rEntry )->getSize() );
481 rEntry.mpOutSprite = createSprite( rEntry.mpView,
482 basegfx::B2DSize( leavingSlideSizePixel ),
483 100 );
486 if( mbCreateEnteringSprites )
488 // create entering sprite:
489 const basegfx::B2ISize enteringSlideSizePixel(
490 getSlideSizePixel( basegfx::B2DVector( mpEnteringSlide->getSlideSize() ),
491 rEntry.mpView ));
493 rEntry.mpInSprite = createSprite( rEntry.mpView,
494 basegfx::B2DSize( enteringSlideSizePixel ),
495 101 );
499 void SlideChangeBase::clearViewEntry( ViewEntry& rEntry )
501 // clear stale info (both bitmaps and sprites prolly need a
502 // resize)
503 rEntry.mpEnteringBitmap.reset();
504 rEntry.mpLeavingBitmap.reset();
505 rEntry.mpInSprite.reset();
506 rEntry.mpOutSprite.reset();
509 } // namespace presentation
511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */