tdf#153162 Animation load optimization
Loading a big GIF animation can freeze LO for a long time, so: changed getAnimationFromGraphic, it can load parts of a big animation. It can be called several times to load the whole animation. Now it can load animation while it is playing. It may still load smaller animations at once before it is rendered. At first it load frames that sum maximum 5 million pixels. (But minimum 10 frame.) Changed the Graphic parameter to shared_ptr, so it won’t be deleted until the whole animation is loaded. Change-Id: I5ac16d7ee4883dbaefb604cd07757d19e5aa2939 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166608 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com> Tested-by: Caolán McNamara <caolan.mcnamara@collabora.com>
This commit is contained in:
committed by
Caolán McNamara
parent
a600cb4865
commit
89998a744f
@@ -343,6 +343,7 @@ namespace slideshow::internal
|
||||
mxPage( xContainingPage ),
|
||||
maAnimationFrames(), // empty, we don't have no intrinsic animation
|
||||
mnCurrFrame(0),
|
||||
mpGraphicLoader(),
|
||||
mpCurrMtf(),
|
||||
mnCurrMtfLoadFlags( bForeignSource
|
||||
? MTF_LOAD_FOREIGN_SOURCE : MTF_LOAD_NONE ),
|
||||
@@ -418,12 +419,13 @@ namespace slideshow::internal
|
||||
DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape,
|
||||
uno::Reference< drawing::XDrawPage > xContainingPage,
|
||||
double nPrio,
|
||||
const Graphic& rGraphic,
|
||||
std::shared_ptr<Graphic> pGraphic,
|
||||
const SlideShowContext& rContext ) :
|
||||
mxShape( xShape ),
|
||||
mxPage(std::move( xContainingPage )),
|
||||
maAnimationFrames(),
|
||||
mnCurrFrame(0),
|
||||
mpGraphicLoader(),
|
||||
mpCurrMtf(),
|
||||
mnCurrMtfLoadFlags( MTF_LOAD_NONE ),
|
||||
maCurrentShapeUnitBounds(),
|
||||
@@ -450,12 +452,25 @@ namespace slideshow::internal
|
||||
mbDrawingLayerAnim( false ),
|
||||
mbContainsPageField( false )
|
||||
{
|
||||
ENSURE_OR_THROW( rGraphic.IsAnimated(),
|
||||
ENSURE_OR_THROW( pGraphic->IsAnimated(),
|
||||
"DrawShape::DrawShape(): Graphic is no animation" );
|
||||
|
||||
getAnimationFromGraphic( maAnimationFrames,
|
||||
mnAnimationLoopCount,
|
||||
rGraphic );
|
||||
::Animation aAnimation(pGraphic->GetAnimation());
|
||||
const Size aAnimSize(aAnimation.GetDisplaySizePixel());
|
||||
tools::Long nBitmapPixels = aAnimSize.getWidth() * aAnimSize.getHeight();
|
||||
|
||||
tools::Long nFramesToLoad = aAnimation.Count();
|
||||
|
||||
// if the Animation is bigger then 5 million pixels, we do not load the
|
||||
// whole animation now.
|
||||
if (nBitmapPixels * aAnimation.Count() > 5000000)
|
||||
{
|
||||
nFramesToLoad = 5000000 / nBitmapPixels;
|
||||
if (nFramesToLoad < 10)
|
||||
nFramesToLoad = 10;
|
||||
}
|
||||
mpGraphicLoader = ::std::make_unique<DelayedGraphicLoader>(pGraphic);
|
||||
getSomeAnimationFramesFromGraphic(nFramesToLoad);
|
||||
|
||||
ENSURE_OR_THROW( !maAnimationFrames.empty() &&
|
||||
maAnimationFrames.front().mpMtf,
|
||||
@@ -475,6 +490,7 @@ namespace slideshow::internal
|
||||
maAnimationFrames(), // don't copy animations for subsets,
|
||||
// only the current frame!
|
||||
mnCurrFrame(0),
|
||||
mpGraphicLoader(),
|
||||
mpCurrMtf( rSrc.mpCurrMtf ),
|
||||
mnCurrMtfLoadFlags( rSrc.mnCurrMtfLoadFlags ),
|
||||
maCurrentShapeUnitBounds(),
|
||||
@@ -550,13 +566,13 @@ namespace slideshow::internal
|
||||
const uno::Reference< drawing::XShape >& xShape,
|
||||
const uno::Reference< drawing::XDrawPage >& xContainingPage,
|
||||
double nPrio,
|
||||
const Graphic& rGraphic,
|
||||
std::shared_ptr<Graphic> pGraphic,
|
||||
const SlideShowContext& rContext )
|
||||
{
|
||||
DrawShapeSharedPtr pShape( new DrawShape(xShape,
|
||||
xContainingPage,
|
||||
nPrio,
|
||||
rGraphic,
|
||||
pGraphic,
|
||||
rContext) );
|
||||
|
||||
if( pShape->hasIntrinsicAnimation() )
|
||||
@@ -847,6 +863,10 @@ namespace slideshow::internal
|
||||
ENSURE_OR_RETURN_VOID( nCurrFrame < maAnimationFrames.size(),
|
||||
"DrawShape::setIntrinsicAnimationFrame(): frame index out of bounds" );
|
||||
|
||||
// Load 1 more frame if needed. (make sure the current frame is loded)
|
||||
if (mpGraphicLoader)
|
||||
getSomeAnimationFramesFromGraphic(1, nCurrFrame);
|
||||
|
||||
if( mnCurrFrame != nCurrFrame )
|
||||
{
|
||||
mnCurrFrame = nCurrFrame;
|
||||
@@ -1235,6 +1255,34 @@ namespace slideshow::internal
|
||||
{
|
||||
return maSubsetting.getSubsetTreeNode( rParentNode, nNodeIndex, eNodeType );
|
||||
}
|
||||
|
||||
void DrawShape::getSomeAnimationFramesFromGraphic(::std::size_t nFrameCount,
|
||||
::std::size_t nLastToLoad /* = 0*/)
|
||||
{
|
||||
OSL_ASSERT(mpGraphicLoader);
|
||||
|
||||
//load nFrameCount frames or to nLastToLoad
|
||||
::std::size_t nFramesToLoad = nFrameCount;
|
||||
if (nLastToLoad > mpGraphicLoader->mnLoadedFrames + nFrameCount)
|
||||
nFramesToLoad = nLastToLoad - mpGraphicLoader->mnLoadedFrames;
|
||||
|
||||
getAnimationFromGraphic(maAnimationFrames, mnAnimationLoopCount,
|
||||
mpGraphicLoader->mpGraphic, mpGraphicLoader->mpVDev,
|
||||
mpGraphicLoader->mpVDevMask, mpGraphicLoader->mnLoadedFrames,
|
||||
nFramesToLoad);
|
||||
|
||||
// If the Animation is fully loaded, no need to load anymore.
|
||||
if (mpGraphicLoader->mnLoadedFrames >= maAnimationFrames.size())
|
||||
{
|
||||
mpGraphicLoader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
DelayedGraphicLoader::DelayedGraphicLoader(std::shared_ptr<Graphic> pGraphic)
|
||||
: mpGraphic(pGraphic)
|
||||
, mpVDevMask(DeviceFormat::WITHOUT_ALPHA)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "viewshape.hxx"
|
||||
#include <hyperlinkarea.hxx>
|
||||
|
||||
#include <vcl/virdev.hxx>
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
@@ -43,6 +45,22 @@ namespace slideshow::internal
|
||||
class DrawShape;
|
||||
typedef ::std::shared_ptr< DrawShape > DrawShapeSharedPtr;
|
||||
|
||||
/** This Struct store data needed to make Animation from Graphic.
|
||||
If the Animation is too big, we won't load all of it at once.
|
||||
From time to time we load small parts until it is completely loaded.
|
||||
Because of it, we have to keep some data alive until the animation
|
||||
is fully loaded.
|
||||
*/
|
||||
struct DelayedGraphicLoader
|
||||
{
|
||||
sal_uInt16 mnLoadedFrames = 0;
|
||||
::std::shared_ptr<Graphic> mpGraphic;
|
||||
ScopedVclPtrInstance<VirtualDevice> mpVDev;
|
||||
ScopedVclPtrInstance<VirtualDevice> mpVDevMask;
|
||||
|
||||
DelayedGraphicLoader(std::shared_ptr<Graphic> pGraphic);
|
||||
};
|
||||
|
||||
/** This class is the representation of a draw document's
|
||||
XShape, and implements the Shape, AnimatableShape, and
|
||||
AttributableShape interfaces.
|
||||
@@ -107,7 +125,8 @@ namespace slideshow::internal
|
||||
const css::uno::Reference< css::drawing::XShape >& xShape,
|
||||
const css::uno::Reference< css::drawing::XDrawPage >& xContainingPage,
|
||||
double nPrio,
|
||||
const Graphic& rGraphic,
|
||||
std::shared_ptr<Graphic> pGraphic,
|
||||
|
||||
const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
|
||||
|
||||
virtual css::uno::Reference< css::drawing::XShape > getXShape() const override;
|
||||
@@ -199,6 +218,19 @@ namespace slideshow::internal
|
||||
*/
|
||||
GDIMetaFileSharedPtr const & forceScrollTextMetaFile();
|
||||
|
||||
/** extract some Animation Frames from the Graphic
|
||||
set in DelayedGraphicLoader.
|
||||
|
||||
@param nFrameCount
|
||||
Load this many frames.
|
||||
|
||||
@param nLastToLoad
|
||||
If nLastToLoad > nFrameCount + loadedFrames then
|
||||
Load frames until this frame.
|
||||
*/
|
||||
void getSomeAnimationFramesFromGraphic(::std::size_t nFrameCount,
|
||||
::std::size_t nLastToLoad = 0);
|
||||
|
||||
private:
|
||||
/** Create a shape for the given XShape
|
||||
|
||||
@@ -251,7 +283,7 @@ namespace slideshow::internal
|
||||
DrawShape( const css::uno::Reference< css::drawing::XShape >& xShape,
|
||||
css::uno::Reference< css::drawing::XDrawPage > xContainingPage,
|
||||
double nPrio,
|
||||
const Graphic& rGraphic,
|
||||
std::shared_ptr<Graphic> pGraphic,
|
||||
const SlideShowContext& rContext ); // throw ShapeLoadFailedException;
|
||||
|
||||
/** Private copy constructor
|
||||
@@ -282,6 +314,7 @@ namespace slideshow::internal
|
||||
*/
|
||||
mutable VectorOfMtfAnimationFrames maAnimationFrames;
|
||||
::std::size_t mnCurrFrame;
|
||||
::std::unique_ptr<DelayedGraphicLoader> mpGraphicLoader; //to load more Frames later
|
||||
|
||||
/// Metafile of currently active frame (static for shapes w/o intrinsic animation)
|
||||
mutable GDIMetaFileSharedPtr mpCurrMtf;
|
||||
|
||||
@@ -248,101 +248,119 @@ sal_Int32 getNextActionOffset( MetaAction * pCurrAct )
|
||||
|
||||
bool getAnimationFromGraphic( VectorOfMtfAnimationFrames& o_rFrames,
|
||||
sal_uInt32& o_rLoopCount,
|
||||
const Graphic& rGraphic )
|
||||
std::shared_ptr<Graphic> pGraphic,
|
||||
ScopedVclPtrInstance<VirtualDevice>& pVDev,
|
||||
ScopedVclPtrInstance<VirtualDevice>& pVDevMask,
|
||||
sal_uInt16& mnLoadedFrames,
|
||||
sal_uInt16 nFramesToLoad )
|
||||
{
|
||||
o_rFrames.clear();
|
||||
bool bFirstRun = mnLoadedFrames == 0;
|
||||
if (bFirstRun)
|
||||
o_rFrames.clear();
|
||||
|
||||
if( !rGraphic.IsAnimated() )
|
||||
if( !pGraphic->IsAnimated() )
|
||||
return false;
|
||||
|
||||
// some loop invariants
|
||||
::Animation aAnimation( rGraphic.GetAnimation() );
|
||||
::Animation aAnimation( pGraphic->GetAnimation() );
|
||||
const Point aEmptyPoint;
|
||||
const Size aAnimSize( aAnimation.GetDisplaySizePixel() );
|
||||
|
||||
// setup VDev, into which all bitmaps are painted (want to
|
||||
// normalize animations to n bitmaps of same size. An Animation,
|
||||
// though, can contain bitmaps of varying sizes and different
|
||||
// update modes)
|
||||
ScopedVclPtrInstance< VirtualDevice > pVDev;
|
||||
pVDev->SetOutputSizePixel( aAnimSize );
|
||||
pVDev->EnableMapMode( false );
|
||||
if (bFirstRun)
|
||||
{
|
||||
// setup VDev, into which all bitmaps are painted (want to
|
||||
// normalize animations to n bitmaps of same size. An Animation,
|
||||
// though, can contain bitmaps of varying sizes and different
|
||||
// update modes)
|
||||
pVDev->SetOutputSizePixel(aAnimSize);
|
||||
pVDev->EnableMapMode(false);
|
||||
|
||||
// setup mask VDev (alpha VDev is currently rather slow)
|
||||
ScopedVclPtrInstance<VirtualDevice> pVDevMask(DeviceFormat::WITHOUT_ALPHA);
|
||||
pVDevMask->SetOutputSizePixel( aAnimSize );
|
||||
pVDevMask->EnableMapMode( false );
|
||||
// setup mask VDev (alpha VDev is currently rather slow)
|
||||
pVDevMask->SetOutputSizePixel(aAnimSize);
|
||||
pVDevMask->EnableMapMode(false);
|
||||
|
||||
// tdf#156630 make erase calls fill with transparency
|
||||
pVDev->SetBackground( Wallpaper( COL_BLACK ) );
|
||||
pVDevMask->SetBackground( Wallpaper( COL_ALPHA_TRANSPARENT ) );
|
||||
// tdf#156630 make erase calls fill with transparency
|
||||
pVDev->SetBackground(Wallpaper(COL_BLACK));
|
||||
pVDevMask->SetBackground(Wallpaper(COL_ALPHA_TRANSPARENT));
|
||||
|
||||
o_rLoopCount = aAnimation.GetLoopCount();
|
||||
|
||||
for( sal_uInt16 i=0, nCount=aAnimation.Count(); i<nCount; ++i )
|
||||
o_rLoopCount = aAnimation.GetLoopCount();
|
||||
}
|
||||
sal_uInt16 nCount = aAnimation.Count();
|
||||
if (!bFirstRun && mnLoadedFrames + nFramesToLoad < nCount)
|
||||
nCount = mnLoadedFrames + nFramesToLoad;
|
||||
for (sal_uInt16 i = mnLoadedFrames; i < nCount; ++i)
|
||||
{
|
||||
const AnimationFrame& rAnimationFrame( aAnimation.Get(i) );
|
||||
switch(rAnimationFrame.meDisposal)
|
||||
bool bCalculateNow = !bFirstRun || i < nFramesToLoad;
|
||||
if (bCalculateNow)
|
||||
{
|
||||
case Disposal::Not:
|
||||
switch (rAnimationFrame.meDisposal)
|
||||
{
|
||||
pVDev->DrawBitmapEx(rAnimationFrame.maPositionPixel,
|
||||
rAnimationFrame.maBitmapEx);
|
||||
AlphaMask aMask = rAnimationFrame.maBitmapEx.GetAlphaMask();
|
||||
|
||||
if( aMask.IsEmpty() )
|
||||
case Disposal::Not:
|
||||
{
|
||||
const tools::Rectangle aRect(aEmptyPoint,
|
||||
pVDevMask->GetOutputSizePixel());
|
||||
const Wallpaper aWallpaper(COL_BLACK);
|
||||
pVDevMask->DrawWallpaper(aRect,
|
||||
aWallpaper);
|
||||
pVDev->DrawBitmapEx(rAnimationFrame.maPositionPixel,
|
||||
rAnimationFrame.maBitmapEx);
|
||||
AlphaMask aMask = rAnimationFrame.maBitmapEx.GetAlphaMask();
|
||||
|
||||
if (aMask.IsEmpty())
|
||||
{
|
||||
const tools::Rectangle aRect(aEmptyPoint, pVDevMask->GetOutputSizePixel());
|
||||
const Wallpaper aWallpaper(COL_BLACK);
|
||||
pVDevMask->DrawWallpaper(aRect, aWallpaper);
|
||||
}
|
||||
else
|
||||
{
|
||||
BitmapEx aTmpMask(aMask.GetBitmap(), aMask);
|
||||
pVDevMask->DrawBitmapEx(rAnimationFrame.maPositionPixel, aTmpMask);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
case Disposal::Back:
|
||||
{
|
||||
BitmapEx aTmpMask(aMask.GetBitmap(), aMask);
|
||||
pVDevMask->DrawBitmapEx(rAnimationFrame.maPositionPixel,
|
||||
aTmpMask );
|
||||
// #i70772# react on no mask
|
||||
const AlphaMask aMask(rAnimationFrame.maBitmapEx.GetAlphaMask());
|
||||
const Bitmap& rContent(rAnimationFrame.maBitmapEx.GetBitmap());
|
||||
|
||||
pVDevMask->Erase();
|
||||
pVDev->DrawBitmap(rAnimationFrame.maPositionPixel, rContent);
|
||||
|
||||
if (aMask.IsEmpty())
|
||||
{
|
||||
const tools::Rectangle aRect(rAnimationFrame.maPositionPixel,
|
||||
rContent.GetSizePixel());
|
||||
pVDevMask->SetFillColor(COL_BLACK);
|
||||
pVDevMask->SetLineColor();
|
||||
pVDevMask->DrawRect(aRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
pVDevMask->DrawBitmap(rAnimationFrame.maPositionPixel, aMask.GetBitmap());
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Disposal::Back:
|
||||
{
|
||||
// #i70772# react on no mask
|
||||
const AlphaMask aMask(rAnimationFrame.maBitmapEx.GetAlphaMask());
|
||||
const Bitmap & rContent(rAnimationFrame.maBitmapEx.GetBitmap());
|
||||
|
||||
pVDevMask->Erase();
|
||||
pVDev->DrawBitmap(rAnimationFrame.maPositionPixel, rContent);
|
||||
|
||||
if(aMask.IsEmpty())
|
||||
case Disposal::Previous:
|
||||
{
|
||||
const tools::Rectangle aRect(rAnimationFrame.maPositionPixel, rContent.GetSizePixel());
|
||||
pVDevMask->SetFillColor( COL_BLACK);
|
||||
pVDevMask->SetLineColor();
|
||||
pVDevMask->DrawRect(aRect);
|
||||
pVDev->DrawBitmapEx(rAnimationFrame.maPositionPixel,
|
||||
rAnimationFrame.maBitmapEx);
|
||||
pVDevMask->DrawBitmap(rAnimationFrame.maPositionPixel,
|
||||
rAnimationFrame.maBitmapEx.GetAlphaMask().GetBitmap());
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
pVDevMask->DrawBitmap(rAnimationFrame.maPositionPixel, aMask.GetBitmap());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Disposal::Previous :
|
||||
{
|
||||
pVDev->DrawBitmapEx(rAnimationFrame.maPositionPixel,
|
||||
rAnimationFrame.maBitmapEx);
|
||||
pVDevMask->DrawBitmap(rAnimationFrame.maPositionPixel,
|
||||
rAnimationFrame.maBitmapEx.GetAlphaMask().GetBitmap());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// extract current aVDev content into a new animation
|
||||
// frame
|
||||
GDIMetaFileSharedPtr pMtf = std::make_shared<GDIMetaFile>();
|
||||
GDIMetaFileSharedPtr pMtf;
|
||||
if (bFirstRun)
|
||||
{
|
||||
pMtf = std::make_shared<GDIMetaFile>();
|
||||
}
|
||||
else
|
||||
{
|
||||
pMtf = o_rFrames[i].mpMtf;
|
||||
}
|
||||
bool useAlphaMask = false;
|
||||
#if defined(MACOSX) || defined(IOS)
|
||||
useAlphaMask = true;
|
||||
@@ -351,52 +369,58 @@ bool getAnimationFromGraphic( VectorOfMtfAnimationFrames& o_rFrames,
|
||||
if( SkiaHelper::isVCLSkiaEnabled())
|
||||
useAlphaMask = true;
|
||||
#endif
|
||||
if( useAlphaMask )
|
||||
if (bCalculateNow)
|
||||
{
|
||||
AlphaMask aAlphaMask(pVDevMask->GetBitmap(aEmptyPoint, aAnimSize));
|
||||
pMtf->AddAction(
|
||||
new MetaBmpExAction( aEmptyPoint,
|
||||
BitmapEx(
|
||||
pVDev->GetBitmap(
|
||||
aEmptyPoint,
|
||||
aAnimSize ),
|
||||
aAlphaMask)));
|
||||
if( useAlphaMask )
|
||||
{
|
||||
AlphaMask aAlphaMask(pVDevMask->GetBitmap(aEmptyPoint, aAnimSize));
|
||||
pMtf->AddAction(
|
||||
new MetaBmpExAction( aEmptyPoint,
|
||||
BitmapEx(
|
||||
pVDev->GetBitmap(
|
||||
aEmptyPoint,
|
||||
aAnimSize ),
|
||||
aAlphaMask)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Bitmap aAlphaMask = pVDevMask->GetBitmap(aEmptyPoint, aAnimSize);
|
||||
aAlphaMask.Invert(); // convert from transparency to alpha
|
||||
pMtf->AddAction(
|
||||
new MetaBmpExAction( aEmptyPoint,
|
||||
BitmapEx(
|
||||
pVDev->GetBitmap(
|
||||
aEmptyPoint,
|
||||
aAnimSize ),
|
||||
aAlphaMask)));
|
||||
}
|
||||
mnLoadedFrames = i+1;
|
||||
}
|
||||
else
|
||||
if (bFirstRun)
|
||||
{
|
||||
Bitmap aAlphaMask = pVDevMask->GetBitmap(aEmptyPoint, aAnimSize);
|
||||
aAlphaMask.Invert(); // convert from transparency to alpha
|
||||
pMtf->AddAction(
|
||||
new MetaBmpExAction( aEmptyPoint,
|
||||
BitmapEx(
|
||||
pVDev->GetBitmap(
|
||||
aEmptyPoint,
|
||||
aAnimSize ),
|
||||
aAlphaMask)));
|
||||
// setup mtf dimensions and pref map mode (for
|
||||
// simplicity, keep it all in pixel. the metafile
|
||||
// renderer scales it down to (1, 1) box anyway)
|
||||
pMtf->SetPrefMapMode(MapMode());
|
||||
pMtf->SetPrefSize(aAnimSize);
|
||||
|
||||
// Take care of special value for MultiPage TIFFs. ATM these shall just
|
||||
// show their first page for _quite_ some time.
|
||||
sal_Int32 nWaitTime100thSeconds(rAnimationFrame.mnWait);
|
||||
if (ANIMATION_TIMEOUT_ON_CLICK == nWaitTime100thSeconds)
|
||||
{
|
||||
// ATM the huge value would block the timer, so use a long
|
||||
// time to show first page (whole day)
|
||||
nWaitTime100thSeconds = 100 * 60 * 60 * 24;
|
||||
}
|
||||
|
||||
// There are animated GIFs with no WaitTime set. Take 0.1 sec, the
|
||||
// same duration that is used by the edit view.
|
||||
if (nWaitTime100thSeconds == 0)
|
||||
nWaitTime100thSeconds = 10;
|
||||
|
||||
o_rFrames.emplace_back(pMtf, nWaitTime100thSeconds / 100.0);
|
||||
}
|
||||
|
||||
// setup mtf dimensions and pref map mode (for
|
||||
// simplicity, keep it all in pixel. the metafile
|
||||
// renderer scales it down to (1, 1) box anyway)
|
||||
pMtf->SetPrefMapMode( MapMode() );
|
||||
pMtf->SetPrefSize( aAnimSize );
|
||||
|
||||
// Take care of special value for MultiPage TIFFs. ATM these shall just
|
||||
// show their first page for _quite_ some time.
|
||||
sal_Int32 nWaitTime100thSeconds(rAnimationFrame.mnWait);
|
||||
if( ANIMATION_TIMEOUT_ON_CLICK == nWaitTime100thSeconds )
|
||||
{
|
||||
// ATM the huge value would block the timer, so use a long
|
||||
// time to show first page (whole day)
|
||||
nWaitTime100thSeconds = 100 * 60 * 60 * 24;
|
||||
}
|
||||
|
||||
// There are animated GIFs with no WaitTime set. Take 0.1 sec, the
|
||||
// same duration that is used by the edit view.
|
||||
if( nWaitTime100thSeconds == 0 )
|
||||
nWaitTime100thSeconds = 10;
|
||||
|
||||
o_rFrames.emplace_back( pMtf, nWaitTime100thSeconds / 100.0 );
|
||||
}
|
||||
|
||||
return !o_rFrames.empty();
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <basegfx/range/b2drectangle.hxx>
|
||||
|
||||
#include <vcl/virdev.hxx>
|
||||
|
||||
#include <tools.hxx>
|
||||
|
||||
#include <utility>
|
||||
@@ -101,6 +103,8 @@ namespace slideshow::internal
|
||||
sal_Int32 getNextActionOffset( MetaAction * pCurrAct );
|
||||
|
||||
/** Extract a vector of animation frames from given Graphic.
|
||||
It can be used to extract only a few frames, and can be
|
||||
called later to extract more. (If the Animation is big)
|
||||
|
||||
@param o_rFrames
|
||||
Resulting vector of animated metafiles
|
||||
@@ -108,12 +112,28 @@ namespace slideshow::internal
|
||||
@param o_rLoopCount
|
||||
Number of times the bitmap animation shall be repeated
|
||||
|
||||
@param rGraphic
|
||||
@param pGraphic
|
||||
Input graphic object, to extract animations from
|
||||
|
||||
@param pVDev, pVDevMask
|
||||
Virtual devices. We don't want to create new everytime we load some frames.
|
||||
|
||||
@param nLoadedFrames
|
||||
The count of loaded Frames.
|
||||
|
||||
@param nFramesToLoad
|
||||
The count of Frames need to be extracted now.
|
||||
Bigger nFramesToLoad not result an error, the function will
|
||||
stop extracting at the end of the animation anyway.
|
||||
*/
|
||||
|
||||
bool getAnimationFromGraphic(VectorOfMtfAnimationFrames& o_rFrames,
|
||||
sal_uInt32& o_rLoopCount,
|
||||
const Graphic& rGraphic);
|
||||
std::shared_ptr<Graphic> pGraphic,
|
||||
ScopedVclPtrInstance<VirtualDevice> &pVDev,
|
||||
ScopedVclPtrInstance<VirtualDevice> &pVDevMask,
|
||||
sal_uInt16& nLoadedFrames,
|
||||
sal_uInt16 nFramesToLoad);
|
||||
|
||||
/** Retrieve scroll text animation rectangles from given metafile
|
||||
|
||||
|
||||
@@ -311,9 +311,8 @@ ShapeSharedPtr ShapeImporter::createShape(
|
||||
// fetch readily transformed and color-modified
|
||||
// graphic
|
||||
|
||||
|
||||
Graphic aGraphic(
|
||||
xGraphicObject->GetTransformedGraphic(
|
||||
std::shared_ptr<Graphic> pGraphic
|
||||
= ::std::make_shared<Graphic>(xGraphicObject->GetTransformedGraphic(
|
||||
xGraphicObject->GetPrefSize(),
|
||||
xGraphicObject->GetPrefMapMode(),
|
||||
aGraphAttrs ) );
|
||||
@@ -321,7 +320,7 @@ ShapeSharedPtr ShapeImporter::createShape(
|
||||
return DrawShape::create( xCurrShape,
|
||||
mxPage,
|
||||
mnAscendingPrio,
|
||||
aGraphic,
|
||||
pGraphic,
|
||||
mrContext );
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user