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 <canvas/debug.hxx>
32 #include <canvas/verbosetrace.hxx>
33 #include <tools/diagnose_ex.h>
34 
35 #include <rtl/logfile.hxx>
36 #include <rtl/math.hxx>
37 
38 #include <canvas/canvastools.hxx>
39 
40 #include <basegfx/matrix/b2dhommatrix.hxx>
41 #include <basegfx/point/b2dpoint.hxx>
42 #include <basegfx/tools/canvastools.hxx>
43 #include <basegfx/numeric/ftools.hxx>
44 #include <basegfx/polygon/b2dpolypolygontools.hxx>
45 #include <basegfx/polygon/b2dpolygontools.hxx>
46 #include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx>
47 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
48 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
49 
50 #include "cairo_canvascustomsprite.hxx"
51 #include "cairo_spritehelper.hxx"
52 
53 #include <memory>
54 
55 
56 using namespace ::cairo;
57 using namespace ::com::sun::star;
58 
59 namespace cairocanvas
60 {
61     SpriteHelper::SpriteHelper() :
62         mpSpriteCanvas(),
63         mpBufferSurface(),
64         mbTextureDirty(true)
65     {}
66 
67     void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize,
68                              const SpriteCanvasRef&	     rSpriteCanvas )
69     {
70         ENSURE_OR_THROW( rSpriteCanvas.get(),
71                           "SpriteHelper::init(): Invalid device, sprite canvas or surface" );
72 
73         mpSpriteCanvas     = rSpriteCanvas;
74         mbTextureDirty     = true;
75 
76         // also init base class
77         CanvasCustomSpriteHelper::init( rSpriteSize,
78                                         rSpriteCanvas.get() );
79     }
80 
81 	void SpriteHelper::setSurface( const SurfaceSharedPtr& pBufferSurface )
82 	{
83 		mpBufferSurface = pBufferSurface;
84 	}
85 
86     void SpriteHelper::disposing()
87     {
88         mpBufferSurface.reset();
89         mpSpriteCanvas.clear();
90 
91         // forward to parent
92         CanvasCustomSpriteHelper::disposing();
93     }
94 
95     void SpriteHelper::redraw( const CairoSharedPtr&    pCairo,
96                                const ::basegfx::B2DPoint& rPos,
97                                bool&                      /*io_bSurfacesDirty*/,
98                                bool                       /*bBufferedUpdate*/ ) const
99     {
100 #ifdef CAIRO_CANVAS_PERF_TRACE
101         struct timespec aTimer;
102         mxDevice->startPerfTrace( &aTimer );
103 #endif
104 
105         const double fAlpha( getAlpha() );
106         const ::basegfx::B2DHomMatrix aTransform( getTransformation() );
107 
108         if( isActive() && !::basegfx::fTools::equalZero( fAlpha ) ) {
109             OSL_TRACE ("CanvasCustomSprite::redraw called");
110             if( pCairo ) {
111                 basegfx::B2DVector aSize = getSizePixel();
112                 cairo_save( pCairo.get() );
113 
114                 double fX, fY;
115 
116                 fX = rPos.getX();
117                 fY = rPos.getY();
118 
119                 if( !aTransform.isIdentity() ) {
120                     cairo_matrix_t aMatrix, aInverseMatrix;
121                     cairo_matrix_init( &aMatrix,
122                                        aTransform.get( 0, 0 ), aTransform.get( 1, 0 ), aTransform.get( 0, 1 ),
123                                        aTransform.get( 1, 1 ), aTransform.get( 0, 2 ), aTransform.get( 1, 2 ) );
124 
125                     aMatrix.x0 = basegfx::fround( aMatrix.x0 );
126                     aMatrix.y0 = basegfx::fround( aMatrix.y0 );
127 
128                     cairo_matrix_init( &aInverseMatrix, aMatrix.xx, aMatrix.yx, aMatrix.xy, aMatrix.yy, aMatrix.x0, aMatrix.y0 );
129                     cairo_matrix_invert( &aInverseMatrix );
130                     cairo_matrix_transform_distance( &aInverseMatrix, &fX, &fY );
131 
132                     cairo_set_matrix( pCairo.get(), &aMatrix );
133                 }
134 
135                 fX = basegfx::fround( fX );
136                 fY = basegfx::fround( fY );
137 
138                 cairo_matrix_t aOrigMatrix;
139                 cairo_get_matrix( pCairo.get(), &aOrigMatrix );
140                 cairo_translate( pCairo.get(), fX, fY );
141 
142                 if( getClip().is() )
143                 {
144                     const uno::Reference<rendering::XPolyPolygon2D>& rClip( getClip() );
145 
146                     ::basegfx::B2DPolyPolygon aClipPoly(
147                         ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
148                             rClip ));
149 
150                     doPolyPolygonImplementation( aClipPoly, Clip, pCairo.get(),
151                                                  NULL, SurfaceProviderRef(mpSpriteCanvas.get()),
152                                                  rClip->getFillRule() );
153                 }
154 
155                 OSL_TRACE ("aSize %f x %f position: %f,%f", aSize.getX(), aSize.getY(), fX, fY );
156                 cairo_rectangle( pCairo.get(), 0, 0, floor( aSize.getX() ), floor( aSize.getY() ) );
157                 cairo_clip( pCairo.get() );
158                 cairo_set_matrix( pCairo.get(), &aOrigMatrix );
159 
160                 if( isContentFullyOpaque() )
161                     cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE );
162                 cairo_set_source_surface( pCairo.get(),
163                                           mpBufferSurface->getCairoSurface().get(),
164                                           fX, fY );
165                 if( ::rtl::math::approxEqual( fAlpha, 1.0 ) )
166                     cairo_paint( pCairo.get() );
167                 else
168                     cairo_paint_with_alpha( pCairo.get(), fAlpha );
169 
170                 cairo_restore( pCairo.get() );
171             }
172         }
173 
174 #ifdef CAIRO_CANVAS_PERF_TRACE
175         mxDevice->stopPerfTrace( &aTimer, "sprite redraw" );
176 #endif
177     }
178 
179     ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const
180     {
181         return ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPoly);
182     }
183 }
184