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