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