1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
33 #include <boost/bind.hpp>
36 using namespace com::sun::star
;
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
),
55 mrViewContainer(rViewContainer
),
56 mbCreateLeavingSprites(bCreateLeavingSprites
),
57 mbCreateEnteringSprites(bCreateEnteringSprites
),
58 mbSpritesVisible(false),
64 "SlideChangeBase::SlideChangeBase(): Invalid entering slide!" );
67 SlideBitmapSharedPtr
SlideChangeBase::getLeavingBitmap( const ViewEntry
& rViewEntry
) const
69 if( !rViewEntry
.mpLeavingBitmap
)
70 rViewEntry
.mpLeavingBitmap
= createBitmap(rViewEntry
.mpView
,
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
;
92 SlideSharedPtr
const & pSlide
= *rSlide
;
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
99 // create empty, black-filled bitmap
100 const basegfx::B2ISize
slideSizePixel(
101 getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide
->getSlideSize() ),
104 cppcanvas::CanvasSharedPtr
pCanvas( rView
->getCanvas() );
106 // create a bitmap of appropriate size
107 cppcanvas::BitmapSharedPtr
pBitmap(
108 cppcanvas::BaseGfxFactory::createBitmap(
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() ),
133 pRet
.reset( new SlideBitmap( pBitmap
));
137 pRet
= pSlide
->getCurrentSlideBitmap( rView
);
143 ::basegfx::B2ISize
SlideChangeBase::getEnteringSlideSizePixel( const UnoViewSharedPtr
& pView
) const
145 return getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide
->getSlideSize() ),
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(
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
)
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
,
193 void SlideChangeBase::start( const AnimatableShapeSharedPtr
& rShape
,
194 const ShapeAttributeLayerSharedPtr
& rLayer
)
196 // we're a one-shot activity, and already finished
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
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
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() );
241 catch( uno::Exception
& )
243 // make sure releasing below happens
246 // swap changes to screen
247 mrScreenUpdater
.notifyUpdate();
249 // make object dysfunctional
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
)
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
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
296 rOutSprite
->movePixel( aSpritePosPixel
);
298 rInSprite
->movePixel( aSpritePosPixel
);
300 if( !mbSpritesVisible
)
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
);
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
);
342 performOut( rOutSprite
, rViewEntry
, rCanvas
, nValue
);
344 performIn( rInSprite
, rViewEntry
, rCanvas
, nValue
);
346 // finishing deeds for first run.
347 if( !mbSpritesVisible
)
354 bSpritesVisible
= true;
356 } // for_each( sprite )
358 mbSpritesVisible
= bSpritesVisible
;
359 mrScreenUpdater
.notifyUpdate();
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*/,
378 void SlideChangeBase::performOut(
379 const cppcanvas::CustomSpriteSharedPtr
& /*rSprite*/,
380 const ViewEntry
& /*rViewEntry*/,
381 const cppcanvas::CanvasSharedPtr
& /*rDestinationCanvas*/,
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
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
414 // erase corresponding entry from maViewData
420 std::equal_to
<UnoViewSharedPtr
>(),
423 boost::bind( &ViewEntry::getView
, _1
))),
427 void SlideChangeBase::viewChanged( const UnoViewSharedPtr
& rView
)
429 // we're a one-shot activity, and already finished
433 // find entry corresponding to modified view
434 ViewsVecT::iterator
aModifiedEntry(
439 std::equal_to
<UnoViewSharedPtr
>(),
442 boost::bind( &ViewEntry::getView
, _1
) )));
444 OSL_ASSERT( aModifiedEntry
!= maViewData
.end() );
445 if( aModifiedEntry
== maViewData
.end() )
448 // clear stale info (both bitmaps and sprites prolly need a
450 clearViewEntry( *aModifiedEntry
);
451 addSprites( *aModifiedEntry
);
454 void SlideChangeBase::viewsChanged()
456 // we're a one-shot activity, and already finished
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
466 clearViewEntry( *aIter
);
467 addSprites( *aIter
);
473 cppcanvas::CustomSpriteSharedPtr
SlideChangeBase::createSprite(
474 UnoViewSharedPtr
const & pView
,
475 basegfx::B2DSize
const & rSpriteSize
,
478 // TODO(P2): change to bitmapsprite once that's working
479 const cppcanvas::CustomSpriteSharedPtr
pSprite(
480 pView
->createSprite( rSpriteSize
,
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
)
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
),
505 if( mbCreateEnteringSprites
)
507 // create entering sprite:
508 const basegfx::B2ISize
enteringSlideSizePixel(
509 getSlideSizePixel( basegfx::B2DSize( mpEnteringSlide
->getSlideSize() ),
512 rEntry
.mpInSprite
= createSprite( rEntry
.mpView
,
513 basegfx::B2DSize( enteringSlideSizePixel
),
518 void SlideChangeBase::clearViewEntry( ViewEntry
& rEntry
)
520 // clear stale info (both bitmaps and sprites prolly need a
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: */