1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_slideshow.hxx"
30 
31 // must be first
32 #include <canvas/debug.hxx>
33 #include <tools/diagnose_ex.h>
34 
35 #include <animatedsprite.hxx>
36 
37 #include <cppcanvas/canvas.hxx>
38 #include <canvas/canvastools.hxx>
39 
40 #include <basegfx/vector/b2dvector.hxx>
41 #include <basegfx/point/b2dpoint.hxx>
42 #include <basegfx/matrix/b2dhommatrix.hxx>
43 #include <basegfx/numeric/ftools.hxx>
44 
45 
46 using namespace ::com::sun::star;
47 
48 namespace slideshow
49 {
50     namespace internal
51     {
52         AnimatedSprite::AnimatedSprite( const ViewLayerSharedPtr&	rViewLayer,
53                                         const ::basegfx::B2DSize& 	rSpriteSizePixel,
54                                         double                      nSpritePrio ) :
55             mpViewLayer( rViewLayer ),
56             mpSprite(),
57             maEffectiveSpriteSizePixel( rSpriteSizePixel ),
58             maContentPixelOffset(),
59             mnSpritePrio(nSpritePrio),
60             mnAlpha(0.0),
61             maPosPixel(),
62             maClip(),
63             maTransform(),
64             mbSpriteVisible( false )
65         {
66             ENSURE_OR_THROW( mpViewLayer, "AnimatedSprite::AnimatedSprite(): Invalid view layer" );
67 
68             // Add half a pixel tolerance to sprite size, since we later on compare
69             // against it in resize(). And view transformations will almost never yield
70             // the same data bits when transforming to device coordinates
71             maEffectiveSpriteSizePixel += ::basegfx::B2DSize(0.5, 0.5);
72 
73             mpSprite = mpViewLayer->createSprite( maEffectiveSpriteSizePixel,
74                                                   mnSpritePrio );
75 
76             ENSURE_OR_THROW( mpSprite, "AnimatedSprite::AnimatedSprite(): Could not create sprite" );
77         }
78 
79         ::cppcanvas::CanvasSharedPtr AnimatedSprite::getContentCanvas() const
80         {
81             ENSURE_OR_THROW( mpViewLayer->getCanvas(), "AnimatedSprite::getContentCanvas(): No view layer canvas" );
82 
83             const ::cppcanvas::CanvasSharedPtr pContentCanvas( mpSprite->getContentCanvas() );
84             pContentCanvas->clear();
85 
86             // extract linear part of canvas view transformation
87             // (linear means: without translational components). The
88             // only translation that is imposed at the view transform
89             // is the local content pixel offset.
90             //
91             // We can apply that directly here, no need to call
92             // aLinearTransform.translate(), since, as said above, the
93             // last column of aLinearTransform is assumed [0 0 1]
94             ::basegfx::B2DHomMatrix aLinearTransform( mpViewLayer->getTransformation() );
95             aLinearTransform.set( 0, 2, maContentPixelOffset.getX() );
96             aLinearTransform.set( 1, 2, maContentPixelOffset.getY() );
97 
98             // apply linear part of canvas view transformation to sprite canvas
99             pContentCanvas->setTransformation( aLinearTransform );
100 
101             return pContentCanvas;
102         }
103 
104         bool AnimatedSprite::resize( const ::basegfx::B2DSize& rSpriteSizePixel )
105         {
106             // Enlarge or reduce the sprite size, if necessary.  This
107             // method employs a strategy similar to container, when
108             // allocating memory: size is doubled or halved everytime
109             // the limit is reached. This makes for amortized constant
110             // time in runtime complexity. Note that we take exact
111             // powers of two here, since several HW-accelerated canvas
112             // implementations are limited to such sprite sizes
113             // (otherwise, those implementations would internally
114             // round up, too, wasting precious mem).
115             ::basegfx::B2DSize	aNewSize( maEffectiveSpriteSizePixel );
116             bool				bNeedResize( false );
117 
118             if( rSpriteSizePixel.getX() > maEffectiveSpriteSizePixel.getX() ||
119                 rSpriteSizePixel.getX() < 0.5*maEffectiveSpriteSizePixel.getX() )
120             {
121                 // enlarge or shrink width
122                 aNewSize.setX( ::canvas::tools::nextPow2( ::basegfx::fround(rSpriteSizePixel.getX()) ) );
123                 bNeedResize = true;
124             }
125 
126             if( rSpriteSizePixel.getY() > maEffectiveSpriteSizePixel.getY() ||
127                 rSpriteSizePixel.getY() < 0.5*maEffectiveSpriteSizePixel.getY() )
128             {
129                 // enlarge or shrink height, by doubling it
130                 aNewSize.setY( ::canvas::tools::nextPow2( ::basegfx::fround(rSpriteSizePixel.getY()) ) );
131                 bNeedResize = true;
132             }
133 
134             if( bNeedResize )
135             {
136                 // as the old sprite might have already been altered
137                 // (and therefore been placed in the update list of
138                 // the spritecanvas for this frame), must hide it
139                 // here, to ensure it's not visible on screen any
140                 // longer.
141                 mpSprite->hide();
142 
143                 maEffectiveSpriteSizePixel = aNewSize;
144                 mpSprite = mpViewLayer->createSprite( maEffectiveSpriteSizePixel,
145                                                       mnSpritePrio );
146 
147                 ENSURE_OR_THROW( mpSprite,
148                                   "AnimatedSprite::resize(): Could not create new sprite" );
149 
150                 // set attributes similar to previous sprite
151                 if( mpSprite && mbSpriteVisible )
152                 {
153                     mpSprite->show();
154                     mpSprite->setAlpha( mnAlpha );
155 
156                     if( maPosPixel )
157                         mpSprite->movePixel( *maPosPixel );
158 
159                     if( maClip )
160                         mpSprite->setClip( *maClip );
161                 }
162             }
163 
164 			return mpSprite;
165         }
166 
167         void AnimatedSprite::setPixelOffset( const ::basegfx::B2DSize& rPixelOffset )
168         {
169             maContentPixelOffset = rPixelOffset;
170         }
171 
172         ::basegfx::B2DSize AnimatedSprite::getPixelOffset() const
173         {
174             return maContentPixelOffset;
175         }
176 
177         void AnimatedSprite::movePixel( const ::basegfx::B2DPoint& rNewPos )
178         {
179             maPosPixel.reset( rNewPos );
180             mpSprite->movePixel( rNewPos );
181         }
182 
183         void AnimatedSprite::setAlpha( double nAlpha )
184         {
185             mnAlpha = nAlpha;
186             mpSprite->setAlpha( nAlpha );
187         }
188 
189         void AnimatedSprite::clip( const ::basegfx::B2DPolyPolygon& rClip )
190         {
191             maClip.reset( rClip );
192             mpSprite->setClipPixel( rClip );
193         }
194 
195         void AnimatedSprite::clip()
196         {
197             maClip.reset();
198             mpSprite->setClip();
199         }
200 
201         void AnimatedSprite::transform( const ::basegfx::B2DHomMatrix& rTransform )
202         {
203             maTransform.reset( rTransform );
204             mpSprite->transform( rTransform );
205         }
206 
207 		void AnimatedSprite::setPriority( double nPrio )
208 		{
209             mpSprite->setPriority( nPrio );
210 		}
211 
212         void AnimatedSprite::hide()
213         {
214             mpSprite->hide();
215             mbSpriteVisible = false;
216         }
217 
218         void AnimatedSprite::show()
219         {
220             mbSpriteVisible = true;
221             mpSprite->show();
222         }
223 
224     }
225 }
226