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