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_canvas.hxx"
26 
27 #include <ctype.h> // don't ask. msdev breaks otherwise...
28 #include <canvas/debug.hxx>
29 #include <canvas/verbosetrace.hxx>
30 #include <tools/diagnose_ex.h>
31 
32 #include <rtl/logfile.hxx>
33 #include <rtl/math.hxx>
34 
35 #include <canvas/canvastools.hxx>
36 
37 #include <basegfx/matrix/b2dhommatrix.hxx>
38 #include <basegfx/point/b2dpoint.hxx>
39 #include <basegfx/tools/canvastools.hxx>
40 #include <basegfx/numeric/ftools.hxx>
41 #include <basegfx/polygon/b2dpolypolygontools.hxx>
42 #include <basegfx/polygon/b2dpolygontools.hxx>
43 #include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx>
44 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
45 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
46 
47 #include "dx_canvascustomsprite.hxx"
48 #include "dx_spritehelper.hxx"
49 #include "dx_impltools.hxx"
50 
51 #include <memory>
52 
53 using namespace ::com::sun::star;
54 
55 namespace dxcanvas
56 {
SpriteHelper()57     SpriteHelper::SpriteHelper() :
58         mpSpriteCanvas(),
59         mpBitmap(),
60         mbTextureDirty( true ),
61         mbShowSpriteBounds( false )
62     {
63     }
64 
init(const geometry::RealSize2D & rSpriteSize,const SpriteCanvasRef & rSpriteCanvas,const IDXRenderModuleSharedPtr & rRenderModule,const DXSurfaceBitmapSharedPtr rBitmap,bool bShowSpriteBounds)65     void SpriteHelper::init( const geometry::RealSize2D&	 rSpriteSize,
66                              const SpriteCanvasRef&			 rSpriteCanvas,
67                              const IDXRenderModuleSharedPtr& rRenderModule,
68                              const DXSurfaceBitmapSharedPtr	 rBitmap,
69                              bool							 bShowSpriteBounds )
70     {
71         ENSURE_OR_THROW( rSpriteCanvas.get() &&
72                           rRenderModule &&
73                           rBitmap,
74                           "SpriteHelper::init(): Invalid device, sprite canvas or surface" );
75 
76         mpSpriteCanvas     = rSpriteCanvas;
77         mpBitmap           = rBitmap;
78         mbTextureDirty     = true;
79         mbShowSpriteBounds = bShowSpriteBounds;
80 
81         // also init base class
82         CanvasCustomSpriteHelper::init( rSpriteSize,
83                                         rSpriteCanvas.get() );
84     }
85 
disposing()86     void SpriteHelper::disposing()
87     {
88         mpBitmap.reset();
89         mpSpriteCanvas.clear();
90 
91         // forward to parent
92         CanvasCustomSpriteHelper::disposing();
93     }
94 
polyPolygonFromXPolyPolygon2D(uno::Reference<rendering::XPolyPolygon2D> & xPoly) const95     ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const
96     {
97         return tools::polyPolygonFromXPolyPolygon2D( xPoly );
98     }
99 
needRedraw() const100     bool SpriteHelper::needRedraw() const
101     {
102         if( !mpBitmap ||
103             !mpSpriteCanvas.get() )
104         {
105             return false; // we're disposed, no redraw necessary
106         }
107 
108         if( !isActive() ||
109             ::basegfx::fTools::equalZero( getAlpha() ) )
110         {
111             return false; // sprite is invisible
112         }
113 
114         return true;
115     }
116 
redraw(bool & io_bSurfaceDirty) const117     void SpriteHelper::redraw( bool& io_bSurfaceDirty ) const
118     {
119         if( !mpBitmap ||
120             !mpSpriteCanvas.get() )
121         {
122             return; // we're disposed
123         }
124 
125         const ::basegfx::B2DPoint& rPos( getPosPixel() );
126         const double               fAlpha( getAlpha() );
127 
128 		if( isActive() &&
129             !::basegfx::fTools::equalZero( fAlpha ) )
130         {
131 
132 			// TODO(Q2): For the time being, Device does not take a target
133 			// surface, but always unconditionally renders to the
134 			// background buffer.
135 
136 			// log output pos in device pixel
137 			VERBOSE_TRACE( "SpriteHelper::redraw(): output pos is (%f, %f)",
138                            rPos.getX(),
139                            rPos.getY() );
140 
141 			const double                                       fAlpha( getAlpha() );
142 			const ::basegfx::B2DVector&                        rSize( getSizePixel() );
143 			const ::basegfx::B2DHomMatrix&                     rTransform( getTransformation() );
144 			const uno::Reference< rendering::XPolyPolygon2D >& xClip( getClip() );
145 
146 			mbTextureDirty   = false;
147 			io_bSurfaceDirty = false; // state taken, and processed.
148 
149 			::basegfx::B2DPolyPolygon	aClipPath; // empty for no clip
150 			bool						bIsClipRectangular( false ); // false, if no
151 																	// clip, or clip
152 																	// is complex
153 
154 			// setup and apply clip (if any)
155 			// =================================
156 
157 			if( xClip.is() )
158 			{
159 				aClipPath = tools::polyPolygonFromXPolyPolygon2D( xClip );
160 
161 				const sal_Int32 nNumClipPolygons( aClipPath.count() );
162 				if( nNumClipPolygons )
163 				{
164 					// TODO(P2): hold rectangle attribute directly
165 					// at the XPolyPolygon2D
166 
167 					// check whether the clip is rectangular
168 					if( nNumClipPolygons == 1 )
169 						if( ::basegfx::tools::isRectangle( aClipPath.getB2DPolygon( 0 ) ) )
170 							bIsClipRectangular = true;
171 				}
172 			}
173 
174 			const ::basegfx::B2DRectangle aSourceRect( 0.0,
175                                                        0.0,
176                                                        rSize.getX(),
177                                                        rSize.getY() );
178 
179 			// draw simple rectangular area if no clip is set.
180 			if( !aClipPath.count() )
181 			{
182 				mpBitmap->draw(fAlpha,rPos,rTransform);
183 			}
184 			else if( bIsClipRectangular )
185 			{
186 				// apply a simple rect clip
187 				// ========================
188 
189 				::basegfx::B2DRectangle aClipBounds(
190 					::basegfx::tools::getRange( aClipPath ) );
191 				aClipBounds.intersect( aSourceRect );
192 
193 				mpBitmap->draw(fAlpha,rPos,aClipBounds,rTransform);
194 			}
195 			else
196 			{
197 				// apply clip the hard way
198 				// =======================
199 
200 				mpBitmap->draw(fAlpha,rPos,aClipPath,rTransform);
201 			}
202 
203 			if( mbShowSpriteBounds )
204 			{
205 				if( aClipPath.count() )
206 				{
207 					// TODO(F2): Re-enable debug output
208                 }
209 			}
210 		}
211 	}
212 }
213