LibreOffice Module slideshow (master) 1
slidechangebase.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
25
26#include "slidechangebase.hxx"
27#include <tools.hxx>
28
29#include <algorithm>
30#include <utility>
31
32using namespace com::sun::star;
33
34namespace slideshow::internal {
35
36SlideChangeBase::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)
56{
58 pEnteringSlide,
59 "SlideChangeBase::SlideChangeBase(): Invalid entering slide!" );
60}
61
62SlideBitmapSharedPtr SlideChangeBase::getLeavingBitmap( const ViewEntry& rViewEntry ) const
63{
64 if( !rViewEntry.mpLeavingBitmap )
65 rViewEntry.mpLeavingBitmap = createBitmap(rViewEntry.mpView,
66 maLeavingSlide);
67
68 return rViewEntry.mpLeavingBitmap;
69}
70
71SlideBitmapSharedPtr SlideChangeBase::getEnteringBitmap( const ViewEntry& rViewEntry ) const
72{
73 if( !rViewEntry.mpEnteringBitmap )
74 rViewEntry.mpEnteringBitmap = createBitmap( rViewEntry.mpView,
75 std::optional<SlideSharedPtr>(mpEnteringSlide) );
76
77 return rViewEntry.mpEnteringBitmap;
78}
79
80SlideBitmapSharedPtr SlideChangeBase::createBitmap( const UnoViewSharedPtr& rView,
81 const std::optional<SlideSharedPtr>& rSlide ) const
82{
84 if( !rSlide )
85 return pRet;
86
87 SlideSharedPtr const & pSlide = *rSlide;
88 if( !pSlide )
89 {
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.
93
94 // create empty, black-filled bitmap
95 auto aSlideSize = mpEnteringSlide->getSlideSize();
96 auto aVector = getSlideSizePixel(basegfx::B2DVector(aSlideSize.getWidth(), aSlideSize.getHeight()), rView);
97 const basegfx::B2ISize slideSizePixel(aVector.getX(), aVector.getY());
98
99 cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
100
101 // create a bitmap of appropriate size
104 pCanvas,
105 slideSizePixel ) );
106
108 pBitmap,
109 "SlideChangeBase::createBitmap(): Cannot create page bitmap" );
110
112 pBitmap->getBitmapCanvas() );
113
114 ENSURE_OR_THROW( pBitmapCanvas,
115 "SlideChangeBase::createBitmap(): "
116 "Cannot create page bitmap canvas" );
117
118 // set transformation to identity (->device pixel)
119 pBitmapCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
120
121 // clear bitmap to black
122 fillRect( pBitmapCanvas,
123 ::basegfx::B2DRectangle( 0.0, 0.0,
124 slideSizePixel.getWidth(),
125 slideSizePixel.getHeight() ),
126 0x000000FFU );
127
128 pRet = std::make_shared<SlideBitmap>( pBitmap );
129 }
130 else
131 {
132 pRet = pSlide->getCurrentSlideBitmap( rView );
133 }
134
135 return pRet;
136}
137
138::basegfx::B2ISize SlideChangeBase::getEnteringSlideSizePixel( const UnoViewSharedPtr& pView ) const
139{
140 auto aSlideSize = mpEnteringSlide->getSlideSize();
141 auto aSlideSizePixel = getSlideSizePixel( basegfx::B2DVector(aSlideSize.getWidth(), aSlideSize.getHeight()), pView);
142 return {aSlideSizePixel.getX(), aSlideSizePixel.getY() };
143}
144
145void SlideChangeBase::renderBitmap(
146 SlideBitmapSharedPtr const & pSlideBitmap,
147 cppcanvas::CanvasSharedPtr const & pCanvas )
148{
149 if( !(pSlideBitmap && pCanvas) )
150 return;
151
152 // need to render without any transformation (we
153 // assume device units):
154 const basegfx::B2DHomMatrix viewTransform(
155 pCanvas->getTransformation() );
156 const basegfx::B2DPoint pageOrigin(
157 viewTransform * basegfx::B2DPoint() );
158 const cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
159 pCanvas->clone() );
160
161 // render at output position, don't modify bitmap object (no move!):
163 pageOrigin.getX(), pageOrigin.getY()));
164
165 pDevicePixelCanvas->setTransformation( transform );
166 pSlideBitmap->draw( pDevicePixelCanvas );
167}
168
169void SlideChangeBase::prefetch()
170{
171 // we're a one-shot activity, and already finished
172 if( mbFinished || mbPrefetched )
173 return;
174
175 // register ourselves for view change events
176 mrEventMultiplexer.addViewHandler( std::dynamic_pointer_cast<ViewEventHandler>(shared_from_this()) );
177
178 // init views and create slide bitmaps
179 for( const auto& pView : mrViewContainer )
180 viewAdded( pView );
181
182 mbPrefetched = true;
183}
184
185void SlideChangeBase::start( const AnimatableShapeSharedPtr& /*rShape*/,
186 const ShapeAttributeLayerSharedPtr& /*rLayer*/ )
187{
188 // we're a one-shot activity, and already finished
189 if( mbFinished )
190 return;
191
192 prefetch(); // no-op, if already done
193
194 // get the subclasses a chance to do any specific initialization before run
195 for ( ViewsVecT::const_iterator aCurr( beginViews() ), aEnd( endViews() ); aCurr != aEnd; ++aCurr )
196 prepareForRun( *aCurr, aCurr->mpView->getCanvas() );
197
198 // start accompanying sound effect, if any
199 if( mpSoundPlayer )
200 {
201 mpSoundPlayer->startPlayback();
202 // xxx todo: for now, presentation.cxx takes care about the slide
203 // #i50492# transition sound object, so just release it here
204 mpSoundPlayer.reset();
205 }
206}
207
208void SlideChangeBase::end()
209{
210 // we're a one-shot activity, and already finished
211 if( mbFinished )
212 return;
213
214 try
215 {
216 // draw fully entered bitmap:
217 ViewsVecT::const_iterator aCurr( beginViews() );
218 const ViewsVecT::const_iterator aEnd( endViews() );
219 while( aCurr != aEnd )
220 {
221 // fully clear view content to background color
222 aCurr->mpView->clearAll();
223
224 const SlideBitmapSharedPtr pSlideBitmap( getEnteringBitmap( *aCurr ));
225 pSlideBitmap->clip( basegfx::B2DPolyPolygon() /* no clipping */ );
226 aCurr->mpView->clearAll();
227 renderBitmap( pSlideBitmap,
228 aCurr->mpView->getCanvas() );
229
230 ++aCurr;
231 }
232 }
233 catch( uno::Exception& )
234 {
235 // make sure releasing below happens
236 }
237
238 // swap changes to screen
239 mrScreenUpdater.notifyUpdate();
240
241 // make object dysfunctional
242 mbFinished = true;
243 ViewsVecT().swap(maViewData);
244 maLeavingSlide.reset();
245 mpEnteringSlide.reset();
246
247 // sprites have been binned above
248 mbSpritesVisible = false;
249
250 // remove also from event multiplexer, we're dead anyway
251 mrEventMultiplexer.removeViewHandler( std::dynamic_pointer_cast<ViewEventHandler>(shared_from_this()) );
252}
253
254bool SlideChangeBase::operator()( double nValue )
255{
256 if( mbFinished )
257 return false;
258
259 const std::size_t nEntries( maViewData.size() );
260 bool bSpritesVisible( mbSpritesVisible );
261
262 for( ::std::size_t i=0; i<nEntries; ++i )
263 {
264 // calc sprite offsets. The enter/leaving bitmaps are only
265 // as large as the actual slides. For scaled-down
266 // presentations, we have to move the left, top edge of
267 // those bitmaps to the actual position, governed by the
268 // given view transform. The aSpritePosPixel local
269 // variable is already in device coordinate space
270 // (i.e. pixel).
271
272 ViewEntry& rViewEntry( maViewData[i] );
273 const ::cppcanvas::CanvasSharedPtr& rCanvas( rViewEntry.mpView->getCanvas() );
274 ::cppcanvas::CustomSpriteSharedPtr& rInSprite( rViewEntry.mpInSprite );
275 ::cppcanvas::CustomSpriteSharedPtr& rOutSprite( rViewEntry.mpOutSprite );
276
277 // TODO(F2): Properly respect clip here.
278
279 // Might have to be transformed, too.
280 const ::basegfx::B2DHomMatrix aViewTransform(
281 rViewEntry.mpView->getTransformation() );
282 const ::basegfx::B2DPoint aSpritePosPixel(
283 aViewTransform * ::basegfx::B2DPoint() );
284
285 // move sprite to final output position, in
286 // device coordinates
287 if( rOutSprite )
288 rOutSprite->movePixel( aSpritePosPixel );
289 if( rInSprite )
290 rInSprite->movePixel( aSpritePosPixel );
291
292 if( !mbSpritesVisible )
293 {
294 if( rOutSprite )
295 {
296 // only render once: clipping is done
297 // exclusively with the sprite
298 const ::cppcanvas::CanvasSharedPtr pOutContentCanvas(
299 rOutSprite->getContentCanvas() );
300 if( pOutContentCanvas)
301 {
302 // TODO(Q2): Use basegfx bitmaps here
303
304 // TODO(F1): SlideBitmap is not fully portable
305 // between different canvases!
306
307 // render the content
308 OSL_ASSERT( getLeavingBitmap( rViewEntry ) );
309 if( getLeavingBitmap( rViewEntry ) )
310 getLeavingBitmap( rViewEntry )->draw( pOutContentCanvas );
311 }
312 }
313
314 if( rInSprite )
315 {
316 // only render once: clipping is done
317 // exclusively with the sprite
318 const ::cppcanvas::CanvasSharedPtr pInContentCanvas(
319 rInSprite->getContentCanvas() );
320 if( pInContentCanvas )
321 {
322 // TODO(Q2): Use basegfx bitmaps here
323
324 // TODO(F1): SlideBitmap is not fully portable
325 // between different canvases!
326
327 // render the content
328 getEnteringBitmap( rViewEntry )->draw( pInContentCanvas );
329 }
330 }
331 }
332
333 if( rOutSprite )
334 performOut( rOutSprite, rViewEntry, rCanvas, nValue );
335 if( rInSprite )
336 performIn( rInSprite, rViewEntry, rCanvas, nValue );
337
338 // finishing deeds for first run.
339 if( !mbSpritesVisible)
340 {
341 // enable sprites:
342 if( rOutSprite )
343 rOutSprite->show();
344 if( rInSprite )
345 rInSprite->show();
346 bSpritesVisible = true;
347 }
348 } // for_each( sprite )
349
350 mbSpritesVisible = bSpritesVisible;
351 mrScreenUpdater.notifyUpdate();
352
353 return true;
354}
355
356void SlideChangeBase::prepareForRun(
357 const ViewEntry& /* rViewEntry */,
358 const cppcanvas::CanvasSharedPtr& /* rDestinationCanvas */ )
359{
360}
361
362void SlideChangeBase::performIn(
363 const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
364 const ViewEntry& /*rViewEntry*/,
365 const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
366 double /*t*/ )
367{
368}
369
370void SlideChangeBase::performOut(
371 const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
372 const ViewEntry& /*rViewEntry*/,
373 const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
374 double /*t*/ )
375{
376}
377
378double SlideChangeBase::getUnderlyingValue() const
379{
380 return 0.0; // though this should be used in concert with
381 // ActivitiesFactory::createSimpleActivity, better
382 // explicitly name our start value.
383 // Permissible range for operator() above is [0,1]
384}
385
386void SlideChangeBase::viewAdded( const UnoViewSharedPtr& rView )
387{
388 // we're a one-shot activity, and already finished
389 if( mbFinished )
390 return;
391
392 maViewData.emplace_back(rView );
393
394 ViewEntry& rEntry( maViewData.back() );
395 getEnteringBitmap( rEntry );
396 getLeavingBitmap( rEntry );
397 addSprites( rEntry );
398}
399
400void SlideChangeBase::viewRemoved( const UnoViewSharedPtr& rView )
401{
402 // we're a one-shot activity, and already finished
403 if( mbFinished )
404 return;
405
406 // erase corresponding entry from maViewData
407 maViewData.erase(
408 std::remove_if(
409 maViewData.begin(),
410 maViewData.end(),
411 [rView]( const ViewEntry& rViewEntry )
412 { return rView == rViewEntry.getView(); } ),
413 maViewData.end() );
414}
415
416void SlideChangeBase::viewChanged( const UnoViewSharedPtr& rView )
417{
418 // we're a one-shot activity, and already finished
419 if( mbFinished )
420 return;
421
422 // find entry corresponding to modified view
423 ViewsVecT::iterator aModifiedEntry(
424 std::find_if(
425 maViewData.begin(),
426 maViewData.end(),
427 [rView]( const ViewEntry& rViewEntry )
428 { return rView == rViewEntry.getView(); } ) );
429
430 OSL_ASSERT( aModifiedEntry != maViewData.end() );
431 if( aModifiedEntry == maViewData.end() )
432 return;
433
434 // clear stale info (both bitmaps and sprites prolly need a
435 // resize)
436 clearViewEntry( *aModifiedEntry );
437 addSprites( *aModifiedEntry );
438}
439
440void SlideChangeBase::viewsChanged()
441{
442 // we're a one-shot activity, and already finished
443 if( mbFinished )
444 return;
445
446 for( auto& rView : maViewData )
447 {
448 // clear stale info (both bitmaps and sprites prolly need a
449 // resize)
450 clearViewEntry( rView );
451 addSprites( rView );
452 }
453}
454
455cppcanvas::CustomSpriteSharedPtr SlideChangeBase::createSprite(
456 UnoViewSharedPtr const & pView,
457 basegfx::B2DSize const & rSpriteSize,
458 double nPrio ) const
459{
460 // TODO(P2): change to bitmapsprite once that's working
462 pView->createSprite( rSpriteSize,
463 nPrio ));
464
465 // alpha default is 0.0, which seems to be
466 // a bad idea when viewing content...
467 pSprite->setAlpha( 1.0 );
468 if (mbSpritesVisible)
469 pSprite->show();
470
471 return pSprite;
472}
473
474void SlideChangeBase::addSprites( ViewEntry& rEntry )
475{
476 if( mbCreateLeavingSprites && maLeavingSlide )
477 {
478 // create leaving sprite:
479 const basegfx::B2ISize leavingSlideSizePixel(
480 getLeavingBitmap( rEntry )->getSize() );
481
482 rEntry.mpOutSprite = createSprite( rEntry.mpView,
483 basegfx::B2DSize( leavingSlideSizePixel ),
484 100 );
485 }
486
487 if( mbCreateEnteringSprites )
488 {
489 // create entering sprite:
490 auto aSlideSizePixel = getSlideSizePixel(basegfx::B2DVector(mpEnteringSlide->getSlideSize().getWidth(), mpEnteringSlide->getSlideSize().getHeight()), rEntry.mpView);
491 const basegfx::B2ISize enteringSlideSizePixel(aSlideSizePixel.getX(), aSlideSizePixel.getY());
492
493 rEntry.mpInSprite = createSprite( rEntry.mpView,
494 basegfx::B2DSize( enteringSlideSizePixel ),
495 101 );
496 }
497}
498
499void SlideChangeBase::clearViewEntry( ViewEntry& rEntry )
500{
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();
507}
508
509} // namespace presentation
510
511/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
TYPE getWidth() const
TYPE getHeight() const
TYPE getX() const
TYPE getY() const
static BitmapSharedPtr createBitmap(const CanvasSharedPtr &, const ::basegfx::B2ISize &rSize)
::std::vector< ViewEntry > ViewsVecT
SlideChangeBase(const SlideChangeBase &)=delete
#define ENSURE_OR_THROW(c, m)
sal_Int16 nValue
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
std::shared_ptr< ::cppcanvas::CustomSprite > CustomSpriteSharedPtr
std::shared_ptr< BitmapCanvas > BitmapCanvasSharedPtr
std::shared_ptr< ::cppcanvas::Bitmap > BitmapSharedPtr
std::shared_ptr< Canvas > CanvasSharedPtr
int i
::std::shared_ptr< AnimatableShape > AnimatableShapeSharedPtr
::std::shared_ptr< SoundPlayer > SoundPlayerSharedPtr
::std::shared_ptr< SlideBitmap > SlideBitmapSharedPtr
Definition: slidebitmap.hxx:76
::std::shared_ptr< ShapeAttributeLayer > ShapeAttributeLayerSharedPtr
basegfx::B2IVector getSlideSizePixel(const basegfx::B2DVector &rSlideSize, const UnoViewSharedPtr &pView)
Definition: tools.cxx:758
void fillRect(const ::cppcanvas::CanvasSharedPtr &rCanvas, const ::basegfx::B2DRectangle &rRect, ::cppcanvas::IntSRGBA aFillColor)
Definition: tools.cxx:657
::std::shared_ptr< Slide > SlideSharedPtr
Definition: slide.hxx:148
std::shared_ptr< UnoView > UnoViewSharedPtr
EventMultiplexer & mrEventMultiplexer
Definition: slideview.cxx:728
std::shared_ptr< cppcanvas::CustomSprite > mpOutSprite
outgoing slide sprite
UnoViewSharedPtr mpView
The view this entry is for.
std::shared_ptr< cppcanvas::CustomSprite > mpInSprite
incoming slide sprite
SlideBitmapSharedPtr mpLeavingBitmap
outgoing slide bitmap
SlideBitmapSharedPtr mpEnteringBitmap
incoming slide bitmap