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 <impanmvw.hxx>
23 #include <vcl/virdev.hxx>
24 #include <vcl/window.hxx>
25 #include <tools/helpers.hxx>
29 ImplAnimView::ImplAnimView( Animation
* pParent
, OutputDevice
* pOut
,
30 const Point
& rPt
, const Size
& rSz
,
32 OutputDevice
* pFirstFrameOutDev
) :
34 mpRenderContext ( pFirstFrameOutDev
? pFirstFrameOutDev
: pOut
),
35 mnExtraData ( nExtraData
),
38 maSzPix ( mpRenderContext
->LogicToPixel( maSz
) ),
39 maClip ( mpRenderContext
->GetClipRegion() ),
40 mpBackground ( VclPtr
<VirtualDevice
>::Create() ),
41 mpRestore ( VclPtr
<VirtualDevice
>::Create() ),
42 meLastDisposal ( Disposal::Back
),
45 mbIsMirroredHorizontally ( maSz
.Width() < 0 ),
46 mbIsMirroredVertically ( maSz
.Height() < 0 )
48 Animation::ImplIncAnimCount();
50 // Mirrored horizontally?
51 if( mbIsMirroredHorizontally
)
53 maDispPt
.setX( maPt
.X() + maSz
.Width() + 1 );
54 maDispSz
.setWidth( -maSz
.Width() );
55 maSzPix
.setWidth( -maSzPix
.Width() );
59 maDispPt
.setX( maPt
.X() );
60 maDispSz
.setWidth( maSz
.Width() );
63 // Mirrored vertically?
64 if( mbIsMirroredVertically
)
66 maDispPt
.setY( maPt
.Y() + maSz
.Height() + 1 );
67 maDispSz
.setHeight( -maSz
.Height() );
68 maSzPix
.setHeight( -maSzPix
.Height() );
72 maDispPt
.setY( maPt
.Y() );
73 maDispSz
.setHeight( maSz
.Height() );
77 mpBackground
->SetOutputSizePixel( maSzPix
);
78 mpRenderContext
->SaveBackground(*mpBackground
, maDispPt
, maDispSz
, maSzPix
);
80 // Initialize drawing to actual position
81 drawToPos( mpParent
->ImplGetCurPos() );
83 // If first frame OutputDevice is set, update variables now for real OutputDevice
84 if( pFirstFrameOutDev
)
86 mpRenderContext
= pOut
;
87 maClip
= mpRenderContext
->GetClipRegion();
91 ImplAnimView::~ImplAnimView()
93 mpBackground
.disposeAndClear();
94 mpRestore
.disposeAndClear();
96 Animation::ImplDecAnimCount();
99 bool ImplAnimView::matches( OutputDevice
* pOut
, long nExtraData
) const
105 if( ( mnExtraData
== nExtraData
) && ( !pOut
|| ( pOut
== mpRenderContext
) ) )
108 else if( !pOut
|| ( pOut
== mpRenderContext
) )
114 void ImplAnimView::getPosSize( const AnimationBitmap
& rAnimationBitmap
, Point
& rPosPix
, Size
& rSizePix
)
116 const Size
& rAnmSize
= mpParent
->GetDisplaySizePixel();
117 Point
aPt2( rAnimationBitmap
.maPositionPixel
.X() + rAnimationBitmap
.maSizePixel
.Width() - 1,
118 rAnimationBitmap
.maPositionPixel
.Y() + rAnimationBitmap
.maSizePixel
.Height() - 1 );
119 double fFactX
, fFactY
;
121 // calculate x scaling
122 if( rAnmSize
.Width() > 1 )
123 fFactX
= static_cast<double>( maSzPix
.Width() - 1 ) / ( rAnmSize
.Width() - 1 );
127 // calculate y scaling
128 if( rAnmSize
.Height() > 1 )
129 fFactY
= static_cast<double>( maSzPix
.Height() - 1 ) / ( rAnmSize
.Height() - 1 );
133 rPosPix
.setX( FRound( rAnimationBitmap
.maPositionPixel
.X() * fFactX
) );
134 rPosPix
.setY( FRound( rAnimationBitmap
.maPositionPixel
.Y() * fFactY
) );
136 aPt2
.setX( FRound( aPt2
.X() * fFactX
) );
137 aPt2
.setY( FRound( aPt2
.Y() * fFactY
) );
139 rSizePix
.setWidth( aPt2
.X() - rPosPix
.X() + 1 );
140 rSizePix
.setHeight( aPt2
.Y() - rPosPix
.Y() + 1 );
142 // Mirrored horizontally?
143 if( mbIsMirroredHorizontally
)
144 rPosPix
.setX( maSzPix
.Width() - 1 - aPt2
.X() );
146 // Mirrored vertically?
147 if( mbIsMirroredVertically
)
148 rPosPix
.setY( maSzPix
.Height() - 1 - aPt2
.Y() );
151 void ImplAnimView::drawToPos( sal_uLong nPos
)
153 VclPtr
<vcl::RenderContext
> pRenderContext
= mpRenderContext
;
155 std::unique_ptr
<PaintBufferGuard
> pGuard
;
156 if (mpRenderContext
->GetOutDevType() == OUTDEV_WINDOW
)
158 vcl::Window
* pWindow
= static_cast<vcl::Window
*>(mpRenderContext
.get());
159 pGuard
.reset(new PaintBufferGuard(pWindow
->ImplGetWindowImpl()->mpFrameData
, pWindow
));
160 pRenderContext
= pGuard
->GetRenderContext();
163 ScopedVclPtrInstance
<VirtualDevice
> aVDev
;
164 std::unique_ptr
<vcl::Region
> xOldClip(!maClip
.IsNull() ? new vcl::Region( pRenderContext
->GetClipRegion() ) : nullptr);
166 aVDev
->SetOutputSizePixel( maSzPix
, false );
167 nPos
= std::min( nPos
, static_cast<sal_uLong
>(mpParent
->Count()) - 1 );
169 for( sal_uLong i
= 0; i
<= nPos
; i
++ )
170 draw( i
, aVDev
.get() );
173 pRenderContext
->SetClipRegion( maClip
);
175 pRenderContext
->DrawOutDev( maDispPt
, maDispSz
, Point(), maSzPix
, *aVDev
);
177 pGuard
->SetPaintRect(tools::Rectangle(maDispPt
, maDispSz
));
180 pRenderContext
->SetClipRegion(*xOldClip
);
183 void ImplAnimView::draw( sal_uLong nPos
, VirtualDevice
* pVDev
)
185 VclPtr
<vcl::RenderContext
> pRenderContext
= mpRenderContext
;
187 std::unique_ptr
<PaintBufferGuard
> pGuard
;
188 if (!pVDev
&& mpRenderContext
->GetOutDevType() == OUTDEV_WINDOW
)
190 vcl::Window
* pWindow
= static_cast<vcl::Window
*>(mpRenderContext
.get());
191 pGuard
.reset(new PaintBufferGuard(pWindow
->ImplGetWindowImpl()->mpFrameData
, pWindow
));
192 pRenderContext
= pGuard
->GetRenderContext();
195 tools::Rectangle
aOutRect( pRenderContext
->PixelToLogic( Point() ), pRenderContext
->GetOutputSize() );
197 // check, if output lies out of display
198 if( aOutRect
.Intersection( tools::Rectangle( maDispPt
, maDispSz
) ).IsEmpty() )
200 else if( !mbIsPaused
)
202 VclPtr
<VirtualDevice
> pDev
;
207 const sal_uLong nLastPos
= mpParent
->Count() - 1;
208 mnActPos
= std::min( nPos
, nLastPos
);
209 const AnimationBitmap
& rAnimationBitmap
= mpParent
->Get( static_cast<sal_uInt16
>( mnActPos
) );
211 getPosSize( rAnimationBitmap
, aPosPix
, aSizePix
);
213 // Mirrored horizontally?
214 if( mbIsMirroredHorizontally
)
216 aBmpPosPix
.setX( aPosPix
.X() + aSizePix
.Width() - 1 );
217 aBmpSizePix
.setWidth( -aSizePix
.Width() );
221 aBmpPosPix
.setX( aPosPix
.X() );
222 aBmpSizePix
.setWidth( aSizePix
.Width() );
225 // Mirrored vertically?
226 if( mbIsMirroredVertically
)
228 aBmpPosPix
.setY( aPosPix
.Y() + aSizePix
.Height() - 1 );
229 aBmpSizePix
.setHeight( -aSizePix
.Height() );
233 aBmpPosPix
.setY( aPosPix
.Y() );
234 aBmpSizePix
.setHeight( aSizePix
.Height() );
240 pDev
= VclPtr
<VirtualDevice
>::Create();
241 pDev
->SetOutputSizePixel( maSzPix
, false );
242 pDev
->DrawOutDev( Point(), maSzPix
, maDispPt
, maDispSz
, *pRenderContext
);
247 // restore background after each run
250 meLastDisposal
= Disposal::Back
;
256 if( ( Disposal::Not
!= meLastDisposal
) && maRestSz
.Width() && maRestSz
.Height() )
258 if( Disposal::Back
== meLastDisposal
)
259 pDev
->DrawOutDev( maRestPt
, maRestSz
, maRestPt
, maRestSz
, *mpBackground
);
261 pDev
->DrawOutDev( maRestPt
, maRestSz
, Point(), maRestSz
, *mpRestore
);
264 meLastDisposal
= rAnimationBitmap
.meDisposal
;
268 // What do we need to restore the next time?
269 // Put it into a bitmap if needed, else delete
270 // SaveBitmap to conserve memory
271 if( ( meLastDisposal
== Disposal::Back
) || ( meLastDisposal
== Disposal::Not
) )
272 mpRestore
->SetOutputSizePixel( Size( 1, 1 ), false );
275 mpRestore
->SetOutputSizePixel( maRestSz
, false );
276 mpRestore
->DrawOutDev( Point(), maRestSz
, aPosPix
, aSizePix
, *pDev
);
279 pDev
->DrawBitmapEx( aBmpPosPix
, aBmpSizePix
, rAnimationBitmap
.maBitmapEx
);
283 std::unique_ptr
<vcl::Region
> xOldClip(!maClip
.IsNull() ? new vcl::Region( pRenderContext
->GetClipRegion() ) : nullptr);
286 pRenderContext
->SetClipRegion( maClip
);
288 pRenderContext
->DrawOutDev( maDispPt
, maDispSz
, Point(), maSzPix
, *pDev
);
290 pGuard
->SetPaintRect(tools::Rectangle(maDispPt
, maDispSz
));
294 pRenderContext
->SetClipRegion(*xOldClip
);
298 pDev
.disposeAndClear();
300 if( pRenderContext
->GetOutDevType() == OUTDEV_WINDOW
)
301 static_cast<vcl::Window
*>( pRenderContext
.get() )->Flush();
306 void ImplAnimView::repaint()
308 const bool bOldPause
= mbIsPaused
;
310 mpRenderContext
->SaveBackground(*mpBackground
, maDispPt
, maDispSz
, maSzPix
);
313 drawToPos( mnActPos
);
314 mbIsPaused
= bOldPause
;
317 AInfo
* ImplAnimView::createAInfo() const
319 AInfo
* pAInfo
= new AInfo
;
321 pAInfo
->aStartOrg
= maPt
;
322 pAInfo
->aStartSize
= maSz
;
323 pAInfo
->pOutDev
= mpRenderContext
;
324 pAInfo
->pViewData
= const_cast<ImplAnimView
*>(this);
325 pAInfo
->nExtraData
= mnExtraData
;
326 pAInfo
->bPause
= mbIsPaused
;
331 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */