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