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(const OutputDevice
* pOut
, tools::Long nExtraData
) const
101 return (!pOut
|| pOut
== mpRenderContext
) && (nExtraData
== 0 || nExtraData
== mnExtraData
);
104 void ImplAnimView::getPosSize( const AnimationBitmap
& rAnimationBitmap
, Point
& rPosPix
, Size
& rSizePix
)
106 const Size
& rAnmSize
= mpParent
->GetDisplaySizePixel();
107 Point
aPt2( rAnimationBitmap
.maPositionPixel
.X() + rAnimationBitmap
.maSizePixel
.Width() - 1,
108 rAnimationBitmap
.maPositionPixel
.Y() + rAnimationBitmap
.maSizePixel
.Height() - 1 );
109 double fFactX
, fFactY
;
111 // calculate x scaling
112 if( rAnmSize
.Width() > 1 )
113 fFactX
= static_cast<double>( maSzPix
.Width() - 1 ) / ( rAnmSize
.Width() - 1 );
117 // calculate y scaling
118 if( rAnmSize
.Height() > 1 )
119 fFactY
= static_cast<double>( maSzPix
.Height() - 1 ) / ( rAnmSize
.Height() - 1 );
123 rPosPix
.setX( FRound( rAnimationBitmap
.maPositionPixel
.X() * fFactX
) );
124 rPosPix
.setY( FRound( rAnimationBitmap
.maPositionPixel
.Y() * fFactY
) );
126 aPt2
.setX( FRound( aPt2
.X() * fFactX
) );
127 aPt2
.setY( FRound( aPt2
.Y() * fFactY
) );
129 rSizePix
.setWidth( aPt2
.X() - rPosPix
.X() + 1 );
130 rSizePix
.setHeight( aPt2
.Y() - rPosPix
.Y() + 1 );
132 // Mirrored horizontally?
133 if( mbIsMirroredHorizontally
)
134 rPosPix
.setX( maSzPix
.Width() - 1 - aPt2
.X() );
136 // Mirrored vertically?
137 if( mbIsMirroredVertically
)
138 rPosPix
.setY( maSzPix
.Height() - 1 - aPt2
.Y() );
141 void ImplAnimView::drawToPos( sal_uLong nPos
)
143 VclPtr
<vcl::RenderContext
> pRenderContext
= mpRenderContext
;
145 vcl::PaintBufferGuardPtr pGuard
;
146 if (mpRenderContext
->GetOutDevType() == OUTDEV_WINDOW
)
148 vcl::Window
* pWindow
= static_cast<vcl::WindowOutputDevice
*>(mpRenderContext
.get())->GetOwnerWindow();
149 pGuard
.reset(new vcl::PaintBufferGuard(pWindow
->ImplGetWindowImpl()->mpFrameData
, pWindow
));
150 pRenderContext
= pGuard
->GetRenderContext();
153 ScopedVclPtrInstance
<VirtualDevice
> aVDev
;
154 std::optional
<vcl::Region
> xOldClip
;
155 if (!maClip
.IsNull())
156 xOldClip
= pRenderContext
->GetClipRegion();
158 aVDev
->SetOutputSizePixel( maSzPix
, false );
159 nPos
= std::min( nPos
, static_cast<sal_uLong
>(mpParent
->Count()) - 1 );
161 for( sal_uLong i
= 0; i
<= nPos
; i
++ )
162 draw( i
, aVDev
.get() );
165 pRenderContext
->SetClipRegion( maClip
);
167 pRenderContext
->DrawOutDev( maDispPt
, maDispSz
, Point(), maSzPix
, *aVDev
);
169 pGuard
->SetPaintRect(tools::Rectangle(maDispPt
, maDispSz
));
172 pRenderContext
->SetClipRegion(*xOldClip
);
175 void ImplAnimView::draw( sal_uLong nPos
, VirtualDevice
* pVDev
)
177 VclPtr
<vcl::RenderContext
> pRenderContext
= mpRenderContext
;
179 vcl::PaintBufferGuardPtr pGuard
;
180 if (!pVDev
&& mpRenderContext
->GetOutDevType() == OUTDEV_WINDOW
)
182 vcl::Window
* pWindow
= static_cast<vcl::WindowOutputDevice
*>(mpRenderContext
.get())->GetOwnerWindow();
183 pGuard
.reset(new vcl::PaintBufferGuard(pWindow
->ImplGetWindowImpl()->mpFrameData
, pWindow
));
184 pRenderContext
= pGuard
->GetRenderContext();
187 tools::Rectangle
aOutRect( pRenderContext
->PixelToLogic( Point() ), pRenderContext
->GetOutputSize() );
189 // check, if output lies out of display
190 if( aOutRect
.Intersection( tools::Rectangle( maDispPt
, maDispSz
) ).IsEmpty() )
192 else if( !mbIsPaused
)
194 VclPtr
<VirtualDevice
> pDev
;
199 const sal_uLong nLastPos
= mpParent
->Count() - 1;
200 mnActPos
= std::min( nPos
, nLastPos
);
201 const AnimationBitmap
& rAnimationBitmap
= mpParent
->Get( static_cast<sal_uInt16
>( mnActPos
) );
203 getPosSize( rAnimationBitmap
, aPosPix
, aSizePix
);
205 // Mirrored horizontally?
206 if( mbIsMirroredHorizontally
)
208 aBmpPosPix
.setX( aPosPix
.X() + aSizePix
.Width() - 1 );
209 aBmpSizePix
.setWidth( -aSizePix
.Width() );
213 aBmpPosPix
.setX( aPosPix
.X() );
214 aBmpSizePix
.setWidth( aSizePix
.Width() );
217 // Mirrored vertically?
218 if( mbIsMirroredVertically
)
220 aBmpPosPix
.setY( aPosPix
.Y() + aSizePix
.Height() - 1 );
221 aBmpSizePix
.setHeight( -aSizePix
.Height() );
225 aBmpPosPix
.setY( aPosPix
.Y() );
226 aBmpSizePix
.setHeight( aSizePix
.Height() );
232 pDev
= VclPtr
<VirtualDevice
>::Create();
233 pDev
->SetOutputSizePixel( maSzPix
, false );
234 pDev
->DrawOutDev( Point(), maSzPix
, maDispPt
, maDispSz
, *pRenderContext
);
239 // restore background after each run
242 meLastDisposal
= Disposal::Back
;
248 if( ( Disposal::Not
!= meLastDisposal
) && maRestSz
.Width() && maRestSz
.Height() )
250 if( Disposal::Back
== meLastDisposal
)
251 pDev
->DrawOutDev( maRestPt
, maRestSz
, maRestPt
, maRestSz
, *mpBackground
);
253 pDev
->DrawOutDev( maRestPt
, maRestSz
, Point(), maRestSz
, *mpRestore
);
256 meLastDisposal
= rAnimationBitmap
.meDisposal
;
260 // What do we need to restore the next time?
261 // Put it into a bitmap if needed, else delete
262 // SaveBitmap to conserve memory
263 if( ( meLastDisposal
== Disposal::Back
) || ( meLastDisposal
== Disposal::Not
) )
264 mpRestore
->SetOutputSizePixel( Size( 1, 1 ), false );
267 mpRestore
->SetOutputSizePixel( maRestSz
, false );
268 mpRestore
->DrawOutDev( Point(), maRestSz
, aPosPix
, aSizePix
, *pDev
);
271 pDev
->DrawBitmapEx( aBmpPosPix
, aBmpSizePix
, rAnimationBitmap
.maBitmapEx
);
275 std::optional
<vcl::Region
> xOldClip
;
276 if (!maClip
.IsNull())
277 xOldClip
= pRenderContext
->GetClipRegion();
280 pRenderContext
->SetClipRegion( maClip
);
282 pRenderContext
->DrawOutDev( maDispPt
, maDispSz
, Point(), maSzPix
, *pDev
);
284 pGuard
->SetPaintRect(tools::Rectangle(maDispPt
, maDispSz
));
288 pRenderContext
->SetClipRegion(*xOldClip
);
292 pDev
.disposeAndClear();
293 pRenderContext
->Flush();
298 void ImplAnimView::repaint()
300 const bool bOldPause
= mbIsPaused
;
302 mpRenderContext
->SaveBackground(*mpBackground
, maDispPt
, maDispSz
, maSzPix
);
305 drawToPos( mnActPos
);
306 mbIsPaused
= bOldPause
;
309 AInfo
* ImplAnimView::createAInfo() const
311 AInfo
* pAInfo
= new AInfo
;
313 pAInfo
->aStartOrg
= maPt
;
314 pAInfo
->aStartSize
= maSz
;
315 pAInfo
->pOutDev
= mpRenderContext
;
316 pAInfo
->pViewData
= const_cast<ImplAnimView
*>(this);
317 pAInfo
->nExtraData
= mnExtraData
;
318 pAInfo
->bPause
= mbIsPaused
;
323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */