xref: /AOO41X/main/canvas/source/cairo/cairo_canvashelper.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_canvas.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <canvas/debug.hxx>
32*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
33*cdf0e10cSrcweir 
34*cdf0e10cSrcweir #include <rtl/logfile.hxx>
35*cdf0e10cSrcweir #include <rtl/math.hxx>
36*cdf0e10cSrcweir #include <rtl/instance.hxx>
37*cdf0e10cSrcweir 
38*cdf0e10cSrcweir #include <com/sun/star/util/Endianness.hpp>
39*cdf0e10cSrcweir #include <com/sun/star/rendering/TexturingMode.hpp>
40*cdf0e10cSrcweir #include <com/sun/star/rendering/CompositeOperation.hpp>
41*cdf0e10cSrcweir #include <com/sun/star/rendering/RepaintResult.hpp>
42*cdf0e10cSrcweir #include <com/sun/star/rendering/PathCapType.hpp>
43*cdf0e10cSrcweir #include <com/sun/star/rendering/PathJoinType.hpp>
44*cdf0e10cSrcweir #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
45*cdf0e10cSrcweir #include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
46*cdf0e10cSrcweir #include <com/sun/star/rendering/ColorSpaceType.hpp>
47*cdf0e10cSrcweir #include <com/sun/star/rendering/ColorComponentTag.hpp>
48*cdf0e10cSrcweir #include <com/sun/star/rendering/RenderingIntent.hpp>
49*cdf0e10cSrcweir 
50*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
51*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
52*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
53*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx>
54*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
55*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
56*cdf0e10cSrcweir #include <basegfx/tools/keystoplerp.hxx>
57*cdf0e10cSrcweir #include <basegfx/tools/lerp.hxx>
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir #include <comphelper/sequence.hxx>
60*cdf0e10cSrcweir #include <cppuhelper/compbase1.hxx>
61*cdf0e10cSrcweir 
62*cdf0e10cSrcweir #include <canvas/canvastools.hxx>
63*cdf0e10cSrcweir #include <canvas/parametricpolypolygon.hxx>
64*cdf0e10cSrcweir 
65*cdf0e10cSrcweir #include <vcl/canvastools.hxx>
66*cdf0e10cSrcweir #include <vcl/bitmapex.hxx>
67*cdf0e10cSrcweir #include <vcl/bmpacc.hxx>
68*cdf0e10cSrcweir #include <vcl/virdev.hxx>
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir #include "cairo_spritecanvas.hxx"
71*cdf0e10cSrcweir #include "cairo_cachedbitmap.hxx"
72*cdf0e10cSrcweir #include "cairo_canvashelper.hxx"
73*cdf0e10cSrcweir #include "cairo_canvasbitmap.hxx"
74*cdf0e10cSrcweir 
75*cdf0e10cSrcweir #include <boost/tuple/tuple.hpp>
76*cdf0e10cSrcweir #include <algorithm>
77*cdf0e10cSrcweir 
78*cdf0e10cSrcweir using namespace ::cairo;
79*cdf0e10cSrcweir using namespace ::com::sun::star;
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir namespace cairocanvas
82*cdf0e10cSrcweir {
83*cdf0e10cSrcweir     CanvasHelper::CanvasHelper() :
84*cdf0e10cSrcweir         mpSurfaceProvider(NULL),
85*cdf0e10cSrcweir         mpDevice(NULL),
86*cdf0e10cSrcweir 		mpVirtualDevice(),
87*cdf0e10cSrcweir         mbHaveAlpha(),
88*cdf0e10cSrcweir 		mpCairo(),
89*cdf0e10cSrcweir 		mpSurface(),
90*cdf0e10cSrcweir         maSize()
91*cdf0e10cSrcweir     {
92*cdf0e10cSrcweir     }
93*cdf0e10cSrcweir 
94*cdf0e10cSrcweir     void CanvasHelper::disposing()
95*cdf0e10cSrcweir     {
96*cdf0e10cSrcweir 		mpSurface.reset();
97*cdf0e10cSrcweir 		mpCairo.reset();
98*cdf0e10cSrcweir         mpVirtualDevice.reset();
99*cdf0e10cSrcweir         mpDevice = NULL;
100*cdf0e10cSrcweir         mpSurfaceProvider = NULL;
101*cdf0e10cSrcweir     }
102*cdf0e10cSrcweir 
103*cdf0e10cSrcweir     void CanvasHelper::init( const ::basegfx::B2ISize&  rSizePixel,
104*cdf0e10cSrcweir                              SurfaceProvider&           rSurfaceProvider,
105*cdf0e10cSrcweir                              rendering::XGraphicDevice* pDevice )
106*cdf0e10cSrcweir     {
107*cdf0e10cSrcweir         maSize = rSizePixel;
108*cdf0e10cSrcweir         mpSurfaceProvider = &rSurfaceProvider;
109*cdf0e10cSrcweir         mpDevice = pDevice;
110*cdf0e10cSrcweir     }
111*cdf0e10cSrcweir 
112*cdf0e10cSrcweir     void CanvasHelper::setSize( const ::basegfx::B2ISize& rSize )
113*cdf0e10cSrcweir     {
114*cdf0e10cSrcweir         maSize = rSize;
115*cdf0e10cSrcweir     }
116*cdf0e10cSrcweir 
117*cdf0e10cSrcweir     void CanvasHelper::setSurface( const SurfaceSharedPtr& pSurface, bool bHasAlpha )
118*cdf0e10cSrcweir     {
119*cdf0e10cSrcweir         mbHaveAlpha = bHasAlpha;
120*cdf0e10cSrcweir         mpVirtualDevice.reset();
121*cdf0e10cSrcweir 		mpSurface = pSurface;
122*cdf0e10cSrcweir 		mpCairo = pSurface->getCairo();
123*cdf0e10cSrcweir     }
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir     static void setColor( Cairo* pCairo,
126*cdf0e10cSrcweir                           const uno::Sequence<double>& rColor )
127*cdf0e10cSrcweir     {
128*cdf0e10cSrcweir         if( rColor.getLength() > 3 )
129*cdf0e10cSrcweir         {
130*cdf0e10cSrcweir             const double alpha = rColor[3];
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir             cairo_set_source_rgba( pCairo,
133*cdf0e10cSrcweir                                    alpha*rColor[0],
134*cdf0e10cSrcweir                                    alpha*rColor[1],
135*cdf0e10cSrcweir                                    alpha*rColor[2],
136*cdf0e10cSrcweir                                    alpha );
137*cdf0e10cSrcweir         }
138*cdf0e10cSrcweir         else if( rColor.getLength() == 3 )
139*cdf0e10cSrcweir             cairo_set_source_rgb( pCairo,
140*cdf0e10cSrcweir                                   rColor[0],
141*cdf0e10cSrcweir                                   rColor[1],
142*cdf0e10cSrcweir                                   rColor[2] );
143*cdf0e10cSrcweir     }
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir     void CanvasHelper::useStates( const rendering::ViewState& viewState,
146*cdf0e10cSrcweir                                   const rendering::RenderState& renderState,
147*cdf0e10cSrcweir                                   bool bSetColor )
148*cdf0e10cSrcweir     {
149*cdf0e10cSrcweir         Matrix aViewMatrix;
150*cdf0e10cSrcweir         Matrix aRenderMatrix;
151*cdf0e10cSrcweir         Matrix aCombinedMatrix;
152*cdf0e10cSrcweir 
153*cdf0e10cSrcweir         cairo_matrix_init( &aViewMatrix,
154*cdf0e10cSrcweir                            viewState.AffineTransform.m00, viewState.AffineTransform.m10, viewState.AffineTransform.m01,
155*cdf0e10cSrcweir                            viewState.AffineTransform.m11, viewState.AffineTransform.m02, viewState.AffineTransform.m12);
156*cdf0e10cSrcweir         cairo_matrix_init( &aRenderMatrix,
157*cdf0e10cSrcweir                            renderState.AffineTransform.m00, renderState.AffineTransform.m10, renderState.AffineTransform.m01,
158*cdf0e10cSrcweir                            renderState.AffineTransform.m11, renderState.AffineTransform.m02, renderState.AffineTransform.m12);
159*cdf0e10cSrcweir         cairo_matrix_multiply( &aCombinedMatrix, &aRenderMatrix, &aViewMatrix);
160*cdf0e10cSrcweir 
161*cdf0e10cSrcweir         if( viewState.Clip.is() ) {
162*cdf0e10cSrcweir             OSL_TRACE ("view clip");
163*cdf0e10cSrcweir 
164*cdf0e10cSrcweir             aViewMatrix.x0 = basegfx::fround( aViewMatrix.x0 );
165*cdf0e10cSrcweir             aViewMatrix.y0 = basegfx::fround( aViewMatrix.y0 );
166*cdf0e10cSrcweir             cairo_set_matrix( mpCairo.get(), &aViewMatrix );
167*cdf0e10cSrcweir             doPolyPolygonPath( viewState.Clip, Clip );
168*cdf0e10cSrcweir         }
169*cdf0e10cSrcweir 
170*cdf0e10cSrcweir         aCombinedMatrix.x0 = basegfx::fround( aCombinedMatrix.x0 );
171*cdf0e10cSrcweir         aCombinedMatrix.y0 = basegfx::fround( aCombinedMatrix.y0 );
172*cdf0e10cSrcweir         cairo_set_matrix( mpCairo.get(), &aCombinedMatrix );
173*cdf0e10cSrcweir 
174*cdf0e10cSrcweir         if( renderState.Clip.is() ) {
175*cdf0e10cSrcweir             OSL_TRACE ("render clip BEGIN");
176*cdf0e10cSrcweir 
177*cdf0e10cSrcweir             doPolyPolygonPath( renderState.Clip, Clip );
178*cdf0e10cSrcweir             OSL_TRACE ("render clip END");
179*cdf0e10cSrcweir         }
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir         if( bSetColor )
182*cdf0e10cSrcweir             setColor(mpCairo.get(),renderState.DeviceColor);
183*cdf0e10cSrcweir 
184*cdf0e10cSrcweir         cairo_operator_t compositingMode( CAIRO_OPERATOR_OVER );
185*cdf0e10cSrcweir         switch( renderState.CompositeOperation )
186*cdf0e10cSrcweir         {
187*cdf0e10cSrcweir             case rendering::CompositeOperation::CLEAR:
188*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_CLEAR;
189*cdf0e10cSrcweir                 break;
190*cdf0e10cSrcweir             case rendering::CompositeOperation::SOURCE:
191*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_SOURCE;
192*cdf0e10cSrcweir                 break;
193*cdf0e10cSrcweir             case rendering::CompositeOperation::DESTINATION:
194*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_DEST;
195*cdf0e10cSrcweir                 break;
196*cdf0e10cSrcweir             case rendering::CompositeOperation::OVER:
197*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_OVER;
198*cdf0e10cSrcweir                 break;
199*cdf0e10cSrcweir             case rendering::CompositeOperation::UNDER:
200*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_DEST;
201*cdf0e10cSrcweir                 break;
202*cdf0e10cSrcweir             case rendering::CompositeOperation::INSIDE:
203*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_IN;
204*cdf0e10cSrcweir                 break;
205*cdf0e10cSrcweir             case rendering::CompositeOperation::INSIDE_REVERSE:
206*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_OUT;
207*cdf0e10cSrcweir                 break;
208*cdf0e10cSrcweir             case rendering::CompositeOperation::OUTSIDE:
209*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_DEST_OVER;
210*cdf0e10cSrcweir                 break;
211*cdf0e10cSrcweir             case rendering::CompositeOperation::OUTSIDE_REVERSE:
212*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_DEST_OUT;
213*cdf0e10cSrcweir                 break;
214*cdf0e10cSrcweir             case rendering::CompositeOperation::ATOP:
215*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_ATOP;
216*cdf0e10cSrcweir                 break;
217*cdf0e10cSrcweir             case rendering::CompositeOperation::ATOP_REVERSE:
218*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_DEST_ATOP;
219*cdf0e10cSrcweir                 break;
220*cdf0e10cSrcweir             case rendering::CompositeOperation::XOR:
221*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_XOR;
222*cdf0e10cSrcweir                 break;
223*cdf0e10cSrcweir             case rendering::CompositeOperation::ADD:
224*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_ADD;
225*cdf0e10cSrcweir                 break;
226*cdf0e10cSrcweir             case rendering::CompositeOperation::SATURATE:
227*cdf0e10cSrcweir                 compositingMode = CAIRO_OPERATOR_SATURATE;
228*cdf0e10cSrcweir                 break;
229*cdf0e10cSrcweir         }
230*cdf0e10cSrcweir         cairo_set_operator( mpCairo.get(), compositingMode );
231*cdf0e10cSrcweir     }
232*cdf0e10cSrcweir 
233*cdf0e10cSrcweir     void CanvasHelper::clear()
234*cdf0e10cSrcweir     {
235*cdf0e10cSrcweir         OSL_TRACE ("clear whole area: %d x %d", maSize.getX(), maSize.getY() );
236*cdf0e10cSrcweir 
237*cdf0e10cSrcweir         if( mpCairo )
238*cdf0e10cSrcweir         {
239*cdf0e10cSrcweir             cairo_save( mpCairo.get() );
240*cdf0e10cSrcweir 
241*cdf0e10cSrcweir             cairo_identity_matrix( mpCairo.get() );
242*cdf0e10cSrcweir             // this does not really differ from all-zero, as cairo
243*cdf0e10cSrcweir             // internally converts to premultiplied alpha. but anyway,
244*cdf0e10cSrcweir             // this keeps it consistent with the other canvas impls
245*cdf0e10cSrcweir             if( mbHaveAlpha )
246*cdf0e10cSrcweir                 cairo_set_source_rgba( mpCairo.get(), 1.0, 1.0, 1.0, 0.0 );
247*cdf0e10cSrcweir             else
248*cdf0e10cSrcweir                 cairo_set_source_rgb( mpCairo.get(), 1.0, 1.0, 1.0 );
249*cdf0e10cSrcweir             cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
250*cdf0e10cSrcweir 
251*cdf0e10cSrcweir 			cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
252*cdf0e10cSrcweir             cairo_fill( mpCairo.get() );
253*cdf0e10cSrcweir 
254*cdf0e10cSrcweir             cairo_restore( mpCairo.get() );
255*cdf0e10cSrcweir         }
256*cdf0e10cSrcweir     }
257*cdf0e10cSrcweir 
258*cdf0e10cSrcweir     void CanvasHelper::drawPoint( const rendering::XCanvas* 	,
259*cdf0e10cSrcweir                                   const geometry::RealPoint2D& 	,
260*cdf0e10cSrcweir                                   const rendering::ViewState& 	,
261*cdf0e10cSrcweir                                   const rendering::RenderState&	 )
262*cdf0e10cSrcweir     {
263*cdf0e10cSrcweir     }
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir     void CanvasHelper::drawLine( const rendering::XCanvas* 		/*pCanvas*/,
266*cdf0e10cSrcweir                                  const geometry::RealPoint2D& 	aStartPoint,
267*cdf0e10cSrcweir                                  const geometry::RealPoint2D& 	aEndPoint,
268*cdf0e10cSrcweir                                  const rendering::ViewState& 	viewState,
269*cdf0e10cSrcweir                                  const rendering::RenderState& 	renderState )
270*cdf0e10cSrcweir     {
271*cdf0e10cSrcweir 	if( mpCairo ) {
272*cdf0e10cSrcweir 	    cairo_save( mpCairo.get() );
273*cdf0e10cSrcweir 
274*cdf0e10cSrcweir 	    cairo_set_line_width( mpCairo.get(), 1 );
275*cdf0e10cSrcweir 
276*cdf0e10cSrcweir 	    useStates( viewState, renderState, true );
277*cdf0e10cSrcweir 
278*cdf0e10cSrcweir 	    cairo_move_to( mpCairo.get(), aStartPoint.X + 0.5, aStartPoint.Y + 0.5 );
279*cdf0e10cSrcweir 	    cairo_line_to( mpCairo.get(), aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
280*cdf0e10cSrcweir 	    cairo_stroke( mpCairo.get() );
281*cdf0e10cSrcweir 
282*cdf0e10cSrcweir 	    cairo_restore( mpCairo.get() );
283*cdf0e10cSrcweir 	}
284*cdf0e10cSrcweir     }
285*cdf0e10cSrcweir 
286*cdf0e10cSrcweir     void CanvasHelper::drawBezier( const rendering::XCanvas* 			,
287*cdf0e10cSrcweir                                    const geometry::RealBezierSegment2D&	aBezierSegment,
288*cdf0e10cSrcweir                                    const geometry::RealPoint2D& 		aEndPoint,
289*cdf0e10cSrcweir                                    const rendering::ViewState& 			viewState,
290*cdf0e10cSrcweir                                    const rendering::RenderState& 		renderState )
291*cdf0e10cSrcweir     {
292*cdf0e10cSrcweir 	if( mpCairo ) {
293*cdf0e10cSrcweir 	    cairo_save( mpCairo.get() );
294*cdf0e10cSrcweir 
295*cdf0e10cSrcweir 	    cairo_set_line_width( mpCairo.get(), 1 );
296*cdf0e10cSrcweir 
297*cdf0e10cSrcweir 	    useStates( viewState, renderState, true );
298*cdf0e10cSrcweir 
299*cdf0e10cSrcweir 	    cairo_move_to( mpCairo.get(), aBezierSegment.Px + 0.5, aBezierSegment.Py + 0.5 );
300*cdf0e10cSrcweir         cairo_curve_to( mpCairo.get(),
301*cdf0e10cSrcweir                         aBezierSegment.C1x + 0.5, aBezierSegment.C1y + 0.5,
302*cdf0e10cSrcweir                         aBezierSegment.C2x + 0.5, aBezierSegment.C2y + 0.5,
303*cdf0e10cSrcweir                         aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
304*cdf0e10cSrcweir 	    cairo_stroke( mpCairo.get() );
305*cdf0e10cSrcweir 
306*cdf0e10cSrcweir 	    cairo_restore( mpCairo.get() );
307*cdf0e10cSrcweir 	}
308*cdf0e10cSrcweir     }
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir #define CANVASBITMAP_IMPLEMENTATION_NAME "CairoCanvas::CanvasBitmap"
311*cdf0e10cSrcweir #define PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME "Canvas::ParametricPolyPolygon"
312*cdf0e10cSrcweir 
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir     /** surfaceFromXBitmap Create a surface from XBitmap
315*cdf0e10cSrcweir      * @param xBitmap bitmap image that will be used for the surface
316*cdf0e10cSrcweir      * @param bHasAlpha will be set to true if resulting surface has alpha
317*cdf0e10cSrcweir      *
318*cdf0e10cSrcweir      * This is a helper function for the other surfaceFromXBitmap().
319*cdf0e10cSrcweir      * This function tries to create surface from xBitmap by checking if xBitmap is CanvasBitmap or SpriteCanvas.
320*cdf0e10cSrcweir      *
321*cdf0e10cSrcweir      * @return created surface or NULL
322*cdf0e10cSrcweir      **/
323*cdf0e10cSrcweir     static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap )
324*cdf0e10cSrcweir     {
325*cdf0e10cSrcweir 		CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() );
326*cdf0e10cSrcweir 		if( pBitmapImpl )
327*cdf0e10cSrcweir 			return pBitmapImpl->getSurface();
328*cdf0e10cSrcweir 
329*cdf0e10cSrcweir         SurfaceProvider* pSurfaceProvider = dynamic_cast<SurfaceProvider*>( xBitmap.get() );
330*cdf0e10cSrcweir         if( pSurfaceProvider )
331*cdf0e10cSrcweir             return pSurfaceProvider->getSurface();
332*cdf0e10cSrcweir 
333*cdf0e10cSrcweir 		return SurfaceSharedPtr();
334*cdf0e10cSrcweir     }
335*cdf0e10cSrcweir 
336*cdf0e10cSrcweir     static ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap )
337*cdf0e10cSrcweir     {
338*cdf0e10cSrcweir         // TODO(F1): Add support for floating point bitmap formats
339*cdf0e10cSrcweir         uno::Reference<rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap,
340*cdf0e10cSrcweir                                                                   uno::UNO_QUERY_THROW);
341*cdf0e10cSrcweir         ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap(xIntBmp);
342*cdf0e10cSrcweir         if( !!aBmpEx )
343*cdf0e10cSrcweir             return aBmpEx;
344*cdf0e10cSrcweir 
345*cdf0e10cSrcweir         // TODO(F1): extract pixel from XBitmap interface
346*cdf0e10cSrcweir         ENSURE_OR_THROW( false,
347*cdf0e10cSrcweir                          "bitmapExFromXBitmap(): could not extract BitmapEx" );
348*cdf0e10cSrcweir 
349*cdf0e10cSrcweir         return ::BitmapEx();
350*cdf0e10cSrcweir     }
351*cdf0e10cSrcweir 
352*cdf0e10cSrcweir     static bool readAlpha( BitmapReadAccess* pAlphaReadAcc, long nY, const long nWidth, unsigned char* data, long nOff )
353*cdf0e10cSrcweir     {
354*cdf0e10cSrcweir 	bool bIsAlpha = false;
355*cdf0e10cSrcweir 	long nX;
356*cdf0e10cSrcweir 	int nAlpha;
357*cdf0e10cSrcweir 	Scanline pReadScan;
358*cdf0e10cSrcweir 
359*cdf0e10cSrcweir 	nOff += 3;
360*cdf0e10cSrcweir 
361*cdf0e10cSrcweir 	switch( pAlphaReadAcc->GetScanlineFormat() ) {
362*cdf0e10cSrcweir 	case BMP_FORMAT_8BIT_TC_MASK:
363*cdf0e10cSrcweir 	    pReadScan = pAlphaReadAcc->GetScanline( nY );
364*cdf0e10cSrcweir 	    for( nX = 0; nX < nWidth; nX++ ) {
365*cdf0e10cSrcweir 		nAlpha = data[ nOff ] = 255 - ( *pReadScan++ );
366*cdf0e10cSrcweir 		if( nAlpha != 255 )
367*cdf0e10cSrcweir 		    bIsAlpha = true;
368*cdf0e10cSrcweir 		nOff += 4;
369*cdf0e10cSrcweir 	    }
370*cdf0e10cSrcweir 	    break;
371*cdf0e10cSrcweir 	case BMP_FORMAT_8BIT_PAL:
372*cdf0e10cSrcweir 	    pReadScan = pAlphaReadAcc->GetScanline( nY );
373*cdf0e10cSrcweir 	    for( nX = 0; nX < nWidth; nX++ ) {
374*cdf0e10cSrcweir 		nAlpha = data[ nOff ] = 255 - ( pAlphaReadAcc->GetPaletteColor( *pReadScan++ ).GetBlue() );
375*cdf0e10cSrcweir 		if( nAlpha != 255 )
376*cdf0e10cSrcweir 		    bIsAlpha = true;
377*cdf0e10cSrcweir 		nOff += 4;
378*cdf0e10cSrcweir 	    }
379*cdf0e10cSrcweir 	    break;
380*cdf0e10cSrcweir 	default:
381*cdf0e10cSrcweir 	    OSL_TRACE( "fallback to GetColor for alpha - slow, format: %d", pAlphaReadAcc->GetScanlineFormat() );
382*cdf0e10cSrcweir 	    for( nX = 0; nX < nWidth; nX++ ) {
383*cdf0e10cSrcweir 		nAlpha = data[ nOff ] = 255 - pAlphaReadAcc->GetColor( nY, nX ).GetBlue();
384*cdf0e10cSrcweir 		if( nAlpha != 255 )
385*cdf0e10cSrcweir 		    bIsAlpha = true;
386*cdf0e10cSrcweir 		nOff += 4;
387*cdf0e10cSrcweir 	    }
388*cdf0e10cSrcweir 	}
389*cdf0e10cSrcweir 
390*cdf0e10cSrcweir 	return bIsAlpha;
391*cdf0e10cSrcweir     }
392*cdf0e10cSrcweir 
393*cdf0e10cSrcweir 
394*cdf0e10cSrcweir     /** surfaceFromXBitmap Create a surface from XBitmap
395*cdf0e10cSrcweir      * @param xBitmap bitmap image that will be used for the surface
396*cdf0e10cSrcweir      * @param rDevice reference to the device into which we want to draw
397*cdf0e10cSrcweir      * @param data will be filled with alpha data, if xBitmap is alpha/transparent image
398*cdf0e10cSrcweir      * @param bHasAlpha will be set to true if resulting surface has alpha
399*cdf0e10cSrcweir      *
400*cdf0e10cSrcweir      * This function tries various methods for creating a surface from xBitmap. It also uses
401*cdf0e10cSrcweir      * the helper function surfaceFromXBitmap( xBitmap, bHasAlpha )
402*cdf0e10cSrcweir      *
403*cdf0e10cSrcweir      * @return created surface or NULL
404*cdf0e10cSrcweir      **/
405*cdf0e10cSrcweir     static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, const SurfaceProviderRef& rSurfaceProvider, unsigned char*& data, bool& bHasAlpha )
406*cdf0e10cSrcweir     {
407*cdf0e10cSrcweir         bHasAlpha = xBitmap->hasAlpha();
408*cdf0e10cSrcweir 		SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap );
409*cdf0e10cSrcweir 		if( pSurface )
410*cdf0e10cSrcweir 			data = NULL;
411*cdf0e10cSrcweir 		else
412*cdf0e10cSrcweir         {
413*cdf0e10cSrcweir 			::BitmapEx aBmpEx = bitmapExFromXBitmap(xBitmap);
414*cdf0e10cSrcweir 			::Bitmap aBitmap = aBmpEx.GetBitmap();
415*cdf0e10cSrcweir 
416*cdf0e10cSrcweir 			// there's no pixmap for alpha bitmap. we might still
417*cdf0e10cSrcweir 			// use rgb pixmap and only access alpha pixels the
418*cdf0e10cSrcweir 			// slow way. now we just speedup rgb bitmaps
419*cdf0e10cSrcweir 			if( !aBmpEx.IsTransparent() && !aBmpEx.IsAlpha() ) {
420*cdf0e10cSrcweir 				pSurface = rSurfaceProvider->createSurface( aBitmap );
421*cdf0e10cSrcweir 				data = NULL;
422*cdf0e10cSrcweir 				bHasAlpha = false;
423*cdf0e10cSrcweir 			}
424*cdf0e10cSrcweir 
425*cdf0e10cSrcweir 			if( !pSurface ) {
426*cdf0e10cSrcweir                 AlphaMask aAlpha = aBmpEx.GetAlpha();
427*cdf0e10cSrcweir 
428*cdf0e10cSrcweir 				::BitmapReadAccess*	pBitmapReadAcc = aBitmap.AcquireReadAccess();
429*cdf0e10cSrcweir 				::BitmapReadAccess*	pAlphaReadAcc = NULL;
430*cdf0e10cSrcweir 				const long		nWidth = pBitmapReadAcc->Width();
431*cdf0e10cSrcweir 				const long		nHeight = pBitmapReadAcc->Height();
432*cdf0e10cSrcweir 				long nX, nY;
433*cdf0e10cSrcweir 				bool bIsAlpha = false;
434*cdf0e10cSrcweir 
435*cdf0e10cSrcweir 				if( aBmpEx.IsTransparent() || aBmpEx.IsAlpha() )
436*cdf0e10cSrcweir 					pAlphaReadAcc = aAlpha.AcquireReadAccess();
437*cdf0e10cSrcweir 
438*cdf0e10cSrcweir 				data = (unsigned char*) malloc( nWidth*nHeight*4 );
439*cdf0e10cSrcweir 
440*cdf0e10cSrcweir 				long nOff = 0;
441*cdf0e10cSrcweir 				::Color aColor;
442*cdf0e10cSrcweir 				unsigned int nAlpha = 255;
443*cdf0e10cSrcweir 
444*cdf0e10cSrcweir 				for( nY = 0; nY < nHeight; nY++ ) {
445*cdf0e10cSrcweir 					::Scanline pReadScan;
446*cdf0e10cSrcweir 
447*cdf0e10cSrcweir 					switch( pBitmapReadAcc->GetScanlineFormat() ) {
448*cdf0e10cSrcweir 					case BMP_FORMAT_8BIT_PAL:
449*cdf0e10cSrcweir 						pReadScan = pBitmapReadAcc->GetScanline( nY );
450*cdf0e10cSrcweir 						if( pAlphaReadAcc )
451*cdf0e10cSrcweir 							if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
452*cdf0e10cSrcweir 								bIsAlpha = true;
453*cdf0e10cSrcweir 
454*cdf0e10cSrcweir 						for( nX = 0; nX < nWidth; nX++ ) {
455*cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
456*cdf0e10cSrcweir 							if( pAlphaReadAcc )
457*cdf0e10cSrcweir 								nAlpha = data[ nOff++ ];
458*cdf0e10cSrcweir 							else
459*cdf0e10cSrcweir 								nAlpha = data[ nOff++ ] = 255;
460*cdf0e10cSrcweir #else
461*cdf0e10cSrcweir 							if( pAlphaReadAcc )
462*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ];
463*cdf0e10cSrcweir 							else
464*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ] = 255;
465*cdf0e10cSrcweir #endif
466*cdf0e10cSrcweir 							aColor = pBitmapReadAcc->GetPaletteColor( *pReadScan++ );
467*cdf0e10cSrcweir 
468*cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
469*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 );
470*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 );
471*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 );
472*cdf0e10cSrcweir #else
473*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 );
474*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 );
475*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 );
476*cdf0e10cSrcweir 							nOff++;
477*cdf0e10cSrcweir #endif
478*cdf0e10cSrcweir 						}
479*cdf0e10cSrcweir 						break;
480*cdf0e10cSrcweir 					case BMP_FORMAT_24BIT_TC_BGR:
481*cdf0e10cSrcweir 						pReadScan = pBitmapReadAcc->GetScanline( nY );
482*cdf0e10cSrcweir 						if( pAlphaReadAcc )
483*cdf0e10cSrcweir 							if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
484*cdf0e10cSrcweir 								bIsAlpha = true;
485*cdf0e10cSrcweir 
486*cdf0e10cSrcweir 						for( nX = 0; nX < nWidth; nX++ ) {
487*cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
488*cdf0e10cSrcweir 							if( pAlphaReadAcc )
489*cdf0e10cSrcweir 								nAlpha = data[ nOff ];
490*cdf0e10cSrcweir 							else
491*cdf0e10cSrcweir 								nAlpha = data[ nOff ] = 255;
492*cdf0e10cSrcweir 							data[ nOff + 3 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
493*cdf0e10cSrcweir 							data[ nOff + 2 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
494*cdf0e10cSrcweir 							data[ nOff + 1 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
495*cdf0e10cSrcweir 							nOff += 4;
496*cdf0e10cSrcweir #else
497*cdf0e10cSrcweir 							if( pAlphaReadAcc )
498*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ];
499*cdf0e10cSrcweir 							else
500*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ] = 255;
501*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
502*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
503*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
504*cdf0e10cSrcweir 							nOff++;
505*cdf0e10cSrcweir #endif
506*cdf0e10cSrcweir 						}
507*cdf0e10cSrcweir 						break;
508*cdf0e10cSrcweir 					case BMP_FORMAT_24BIT_TC_RGB:
509*cdf0e10cSrcweir 						pReadScan = pBitmapReadAcc->GetScanline( nY );
510*cdf0e10cSrcweir 						if( pAlphaReadAcc )
511*cdf0e10cSrcweir 							if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
512*cdf0e10cSrcweir 								bIsAlpha = true;
513*cdf0e10cSrcweir 
514*cdf0e10cSrcweir 						for( nX = 0; nX < nWidth; nX++ ) {
515*cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
516*cdf0e10cSrcweir 							if( pAlphaReadAcc )
517*cdf0e10cSrcweir 								nAlpha = data[ nOff++ ];
518*cdf0e10cSrcweir 							else
519*cdf0e10cSrcweir 								nAlpha = data[ nOff++ ] = 255;
520*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
521*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
522*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
523*cdf0e10cSrcweir #else
524*cdf0e10cSrcweir 							if( pAlphaReadAcc )
525*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ];
526*cdf0e10cSrcweir 							else
527*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ] = 255;
528*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
529*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
530*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
531*cdf0e10cSrcweir 							pReadScan += 3;
532*cdf0e10cSrcweir 							nOff++;
533*cdf0e10cSrcweir #endif
534*cdf0e10cSrcweir 						}
535*cdf0e10cSrcweir 						break;
536*cdf0e10cSrcweir 					case BMP_FORMAT_32BIT_TC_BGRA:
537*cdf0e10cSrcweir 						pReadScan = pBitmapReadAcc->GetScanline( nY );
538*cdf0e10cSrcweir 						if( pAlphaReadAcc )
539*cdf0e10cSrcweir 							if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
540*cdf0e10cSrcweir 								bIsAlpha = true;
541*cdf0e10cSrcweir 
542*cdf0e10cSrcweir 						for( nX = 0; nX < nWidth; nX++ ) {
543*cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
544*cdf0e10cSrcweir 							if( pAlphaReadAcc )
545*cdf0e10cSrcweir 								nAlpha = data[ nOff++ ];
546*cdf0e10cSrcweir 							else
547*cdf0e10cSrcweir 								nAlpha = data[ nOff++ ] = pReadScan[ 3 ];
548*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
549*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
550*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
551*cdf0e10cSrcweir 							pReadScan += 4;
552*cdf0e10cSrcweir #else
553*cdf0e10cSrcweir 							if( pAlphaReadAcc )
554*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ];
555*cdf0e10cSrcweir 							else
556*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ] = pReadScan[ 3 ];
557*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
558*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
559*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
560*cdf0e10cSrcweir 							pReadScan++;
561*cdf0e10cSrcweir 							nOff++;
562*cdf0e10cSrcweir #endif
563*cdf0e10cSrcweir 						}
564*cdf0e10cSrcweir 						break;
565*cdf0e10cSrcweir 					case BMP_FORMAT_32BIT_TC_RGBA:
566*cdf0e10cSrcweir 						pReadScan = pBitmapReadAcc->GetScanline( nY );
567*cdf0e10cSrcweir 						if( pAlphaReadAcc )
568*cdf0e10cSrcweir 							if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
569*cdf0e10cSrcweir 								bIsAlpha = true;
570*cdf0e10cSrcweir 
571*cdf0e10cSrcweir 						for( nX = 0; nX < nWidth; nX++ ) {
572*cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
573*cdf0e10cSrcweir 							if( pAlphaReadAcc )
574*cdf0e10cSrcweir 								nAlpha = data[ nOff ++ ];
575*cdf0e10cSrcweir 							else
576*cdf0e10cSrcweir 								nAlpha = data[ nOff ++ ] = 255;
577*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
578*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
579*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
580*cdf0e10cSrcweir 							pReadScan++;
581*cdf0e10cSrcweir #else
582*cdf0e10cSrcweir 							if( pAlphaReadAcc )
583*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ];
584*cdf0e10cSrcweir 							else
585*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ] = 255;
586*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
587*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
588*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
589*cdf0e10cSrcweir 							pReadScan += 4;
590*cdf0e10cSrcweir 							nOff++;
591*cdf0e10cSrcweir #endif
592*cdf0e10cSrcweir 						}
593*cdf0e10cSrcweir 						break;
594*cdf0e10cSrcweir 					default:
595*cdf0e10cSrcweir 						OSL_TRACE( "fallback to GetColor - slow, format: %d", pBitmapReadAcc->GetScanlineFormat() );
596*cdf0e10cSrcweir 
597*cdf0e10cSrcweir 						if( pAlphaReadAcc )
598*cdf0e10cSrcweir 							if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
599*cdf0e10cSrcweir 								bIsAlpha = true;
600*cdf0e10cSrcweir 
601*cdf0e10cSrcweir 						for( nX = 0; nX < nWidth; nX++ ) {
602*cdf0e10cSrcweir 							aColor = pBitmapReadAcc->GetColor( nY, nX );
603*cdf0e10cSrcweir 
604*cdf0e10cSrcweir 							// cairo need premultiplied color values
605*cdf0e10cSrcweir 							// TODO(rodo) handle endianess
606*cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
607*cdf0e10cSrcweir 							if( pAlphaReadAcc )
608*cdf0e10cSrcweir 								nAlpha = data[ nOff++ ];
609*cdf0e10cSrcweir 							else
610*cdf0e10cSrcweir 								nAlpha = data[ nOff++ ] = 255;
611*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 );
612*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 );
613*cdf0e10cSrcweir                             data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 );
614*cdf0e10cSrcweir #else
615*cdf0e10cSrcweir 							if( pAlphaReadAcc )
616*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ];
617*cdf0e10cSrcweir 							else
618*cdf0e10cSrcweir 								nAlpha = data[ nOff + 3 ] = 255;
619*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 );
620*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 );
621*cdf0e10cSrcweir 							data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 );
622*cdf0e10cSrcweir 							nOff ++;
623*cdf0e10cSrcweir #endif
624*cdf0e10cSrcweir 						}
625*cdf0e10cSrcweir 					}
626*cdf0e10cSrcweir 				}
627*cdf0e10cSrcweir 
628*cdf0e10cSrcweir 				aBitmap.ReleaseAccess( pBitmapReadAcc );
629*cdf0e10cSrcweir 				if( pAlphaReadAcc )
630*cdf0e10cSrcweir 					aAlpha.ReleaseAccess( pAlphaReadAcc );
631*cdf0e10cSrcweir 
632*cdf0e10cSrcweir 				SurfaceSharedPtr pImageSurface = createSurface(
633*cdf0e10cSrcweir                     CairoSurfaceSharedPtr(
634*cdf0e10cSrcweir                         cairo_image_surface_create_for_data(
635*cdf0e10cSrcweir                             data,
636*cdf0e10cSrcweir                             bIsAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
637*cdf0e10cSrcweir                             nWidth, nHeight, nWidth*4 ),
638*cdf0e10cSrcweir                         &cairo_surface_destroy) );
639*cdf0e10cSrcweir 
640*cdf0e10cSrcweir 				// 		pSurface = rSurfaceProvider->getSurface( ::basegfx::B2ISize( nWidth, nHeight ), bIsAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
641*cdf0e10cSrcweir 				// 		Cairo* pTargetCairo = cairo_create( pSurface );
642*cdf0e10cSrcweir 				// 		cairo_set_source_surface( pTargetCairo, pImageSurface, 0, 0 );
643*cdf0e10cSrcweir 
644*cdf0e10cSrcweir 				// 				    //if( !bIsAlpha )
645*cdf0e10cSrcweir 				// 				    //cairo_set_operator( pTargetCairo, CAIRO_OPERATOR_SOURCE );
646*cdf0e10cSrcweir 
647*cdf0e10cSrcweir 				// 		cairo_paint( pTargetCairo );
648*cdf0e10cSrcweir 				// 		cairo_destroy( pTargetCairo );
649*cdf0e10cSrcweir 				// 		cairo_surface_destroy( pImageSurface );
650*cdf0e10cSrcweir 				pSurface = pImageSurface;
651*cdf0e10cSrcweir 
652*cdf0e10cSrcweir 				bHasAlpha = bIsAlpha;
653*cdf0e10cSrcweir 
654*cdf0e10cSrcweir 				OSL_TRACE("image: %d x %d alpha: %d alphaRead %p", nWidth, nHeight, bIsAlpha, pAlphaReadAcc);
655*cdf0e10cSrcweir 			}
656*cdf0e10cSrcweir 		}
657*cdf0e10cSrcweir 
658*cdf0e10cSrcweir 		return pSurface;
659*cdf0e10cSrcweir     }
660*cdf0e10cSrcweir 
661*cdf0e10cSrcweir     static void addColorStops( Pattern* pPattern, const uno::Sequence< uno::Sequence< double > >& rColors, const uno::Sequence< double >& rStops, bool bReverseStops = false )
662*cdf0e10cSrcweir     {
663*cdf0e10cSrcweir         float stop;
664*cdf0e10cSrcweir         int i;
665*cdf0e10cSrcweir 
666*cdf0e10cSrcweir         OSL_ASSERT( rColors.getLength() == rStops.getLength() );
667*cdf0e10cSrcweir 
668*cdf0e10cSrcweir         for( i = 0; i < rColors.getLength(); i++ ) {
669*cdf0e10cSrcweir             const uno::Sequence< double >& rColor( rColors[i] );
670*cdf0e10cSrcweir             stop = bReverseStops ? 1 - rStops[i] : rStops[i];
671*cdf0e10cSrcweir             if( rColor.getLength() == 3 )
672*cdf0e10cSrcweir                 cairo_pattern_add_color_stop_rgb( pPattern, stop, rColor[0], rColor[1], rColor[2] );
673*cdf0e10cSrcweir             else if( rColor.getLength() == 4 ) {
674*cdf0e10cSrcweir                 double alpha = rColor[3];
675*cdf0e10cSrcweir                 // cairo expects premultiplied alpha
676*cdf0e10cSrcweir                 cairo_pattern_add_color_stop_rgba( pPattern, stop, rColor[0]*alpha, rColor[1]*alpha, rColor[2]*alpha, alpha );
677*cdf0e10cSrcweir             }
678*cdf0e10cSrcweir         }
679*cdf0e10cSrcweir     }
680*cdf0e10cSrcweir 
681*cdf0e10cSrcweir     static uno::Sequence<double> lerp(const uno::Sequence<double>& rLeft, const uno::Sequence<double>& rRight, double fAlpha)
682*cdf0e10cSrcweir     {
683*cdf0e10cSrcweir         if( rLeft.getLength() == 3 )
684*cdf0e10cSrcweir         {
685*cdf0e10cSrcweir             uno::Sequence<double> aRes(3);
686*cdf0e10cSrcweir             aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha);
687*cdf0e10cSrcweir             aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha);
688*cdf0e10cSrcweir             aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha);
689*cdf0e10cSrcweir             return aRes;
690*cdf0e10cSrcweir         }
691*cdf0e10cSrcweir         else if( rLeft.getLength() == 4 )
692*cdf0e10cSrcweir         {
693*cdf0e10cSrcweir             uno::Sequence<double> aRes(4);
694*cdf0e10cSrcweir             aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha);
695*cdf0e10cSrcweir             aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha);
696*cdf0e10cSrcweir             aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha);
697*cdf0e10cSrcweir             aRes[3] = basegfx::tools::lerp(rLeft[3],rRight[3],fAlpha);
698*cdf0e10cSrcweir             return aRes;
699*cdf0e10cSrcweir         }
700*cdf0e10cSrcweir 
701*cdf0e10cSrcweir         return uno::Sequence<double>();
702*cdf0e10cSrcweir     }
703*cdf0e10cSrcweir 
704*cdf0e10cSrcweir     static Pattern* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon& rPolygon )
705*cdf0e10cSrcweir     {
706*cdf0e10cSrcweir 	Pattern* pPattern = NULL;
707*cdf0e10cSrcweir 	const ::canvas::ParametricPolyPolygon::Values aValues = rPolygon.getValues();
708*cdf0e10cSrcweir 	double x0, x1, y0, y1, cx, cy, r0, r1;
709*cdf0e10cSrcweir 
710*cdf0e10cSrcweir // undef macros from vclenum.hxx which conflicts with GradientType enum values
711*cdf0e10cSrcweir #undef GRADIENT_LINEAR
712*cdf0e10cSrcweir #undef GRADIENT_ELLIPTICAL
713*cdf0e10cSrcweir 
714*cdf0e10cSrcweir 	switch( aValues.meType ) {
715*cdf0e10cSrcweir 	case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR:
716*cdf0e10cSrcweir 	    x0 = 0;
717*cdf0e10cSrcweir 	    y0 = 0;
718*cdf0e10cSrcweir 	    x1 = 1;
719*cdf0e10cSrcweir 	    y1 = 0;
720*cdf0e10cSrcweir 	    pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
721*cdf0e10cSrcweir 	    addColorStops( pPattern, aValues.maColors, aValues.maStops );
722*cdf0e10cSrcweir 	    break;
723*cdf0e10cSrcweir 
724*cdf0e10cSrcweir 	case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
725*cdf0e10cSrcweir 	    cx = 0;
726*cdf0e10cSrcweir 	    cy = 0;
727*cdf0e10cSrcweir 	    r0 = 0;
728*cdf0e10cSrcweir 	    r1 = 1;
729*cdf0e10cSrcweir 
730*cdf0e10cSrcweir 	    pPattern = cairo_pattern_create_radial( cx, cy, r0, cy, cy, r1 );
731*cdf0e10cSrcweir 	    addColorStops( pPattern, aValues.maColors, aValues.maStops, true );
732*cdf0e10cSrcweir 	    break;
733*cdf0e10cSrcweir     default:
734*cdf0e10cSrcweir         break;
735*cdf0e10cSrcweir 	}
736*cdf0e10cSrcweir 
737*cdf0e10cSrcweir 	return pPattern;
738*cdf0e10cSrcweir     }
739*cdf0e10cSrcweir 
740*cdf0e10cSrcweir     static void doOperation( Operation aOperation,
741*cdf0e10cSrcweir                              Cairo* pCairo,
742*cdf0e10cSrcweir                              const uno::Sequence< rendering::Texture >* pTextures,
743*cdf0e10cSrcweir                              const SurfaceProviderRef& pDevice,
744*cdf0e10cSrcweir                              const basegfx::B2DRange& rBounds )
745*cdf0e10cSrcweir     {
746*cdf0e10cSrcweir 	switch( aOperation ) {
747*cdf0e10cSrcweir 	case Fill:
748*cdf0e10cSrcweir 		/* TODO: multitexturing */
749*cdf0e10cSrcweir 	    if( pTextures ) {
750*cdf0e10cSrcweir 		const ::com::sun::star::rendering::Texture& aTexture ( (*pTextures)[0] );
751*cdf0e10cSrcweir 		if( aTexture.Bitmap.is() ) {
752*cdf0e10cSrcweir 		    unsigned char* data = NULL;
753*cdf0e10cSrcweir 		    bool bHasAlpha = false;
754*cdf0e10cSrcweir 		    SurfaceSharedPtr pSurface = surfaceFromXBitmap( (*pTextures)[0].Bitmap, pDevice, data, bHasAlpha );
755*cdf0e10cSrcweir 
756*cdf0e10cSrcweir 		    if( pSurface ) {
757*cdf0e10cSrcweir 			cairo_pattern_t* pPattern;
758*cdf0e10cSrcweir 
759*cdf0e10cSrcweir 			cairo_save( pCairo );
760*cdf0e10cSrcweir 
761*cdf0e10cSrcweir 			::com::sun::star::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform );
762*cdf0e10cSrcweir 			Matrix aScaleMatrix, aTextureMatrix, aScaledTextureMatrix;
763*cdf0e10cSrcweir 
764*cdf0e10cSrcweir 			cairo_matrix_init( &aTextureMatrix,
765*cdf0e10cSrcweir 					   aTransform.m00, aTransform.m10, aTransform.m01,
766*cdf0e10cSrcweir 					   aTransform.m11, aTransform.m02, aTransform.m12);
767*cdf0e10cSrcweir 
768*cdf0e10cSrcweir 			geometry::IntegerSize2D aSize = aTexture.Bitmap->getSize();
769*cdf0e10cSrcweir 
770*cdf0e10cSrcweir 			cairo_matrix_init_scale( &aScaleMatrix, 1.0/aSize.Width, 1.0/aSize.Height );
771*cdf0e10cSrcweir 			cairo_matrix_multiply( &aScaledTextureMatrix, &aTextureMatrix, &aScaleMatrix );
772*cdf0e10cSrcweir 			cairo_matrix_invert( &aScaledTextureMatrix );
773*cdf0e10cSrcweir 
774*cdf0e10cSrcweir 			// we don't care about repeat mode yet, so the workaround is disabled for now
775*cdf0e10cSrcweir 			pPattern = cairo_pattern_create_for_surface( pSurface->getCairoSurface().get() );
776*cdf0e10cSrcweir 
777*cdf0e10cSrcweir  			if( aTexture.RepeatModeX == rendering::TexturingMode::REPEAT &&
778*cdf0e10cSrcweir 			    aTexture.RepeatModeY == rendering::TexturingMode::REPEAT )
779*cdf0e10cSrcweir             {
780*cdf0e10cSrcweir 			    cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_REPEAT );
781*cdf0e10cSrcweir             }
782*cdf0e10cSrcweir             else if ( aTexture.RepeatModeX == rendering::TexturingMode::NONE &&
783*cdf0e10cSrcweir                       aTexture.RepeatModeY == rendering::TexturingMode::NONE )
784*cdf0e10cSrcweir             {
785*cdf0e10cSrcweir 			    cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_NONE );
786*cdf0e10cSrcweir             }
787*cdf0e10cSrcweir             else if ( aTexture.RepeatModeX == rendering::TexturingMode::CLAMP &&
788*cdf0e10cSrcweir                       aTexture.RepeatModeY == rendering::TexturingMode::CLAMP )
789*cdf0e10cSrcweir             {
790*cdf0e10cSrcweir 			    cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_PAD );
791*cdf0e10cSrcweir             }
792*cdf0e10cSrcweir 
793*cdf0e10cSrcweir 			aScaledTextureMatrix.x0 = basegfx::fround( aScaledTextureMatrix.x0 );
794*cdf0e10cSrcweir 			aScaledTextureMatrix.y0 = basegfx::fround( aScaledTextureMatrix.y0 );
795*cdf0e10cSrcweir 			cairo_pattern_set_matrix( pPattern, &aScaledTextureMatrix );
796*cdf0e10cSrcweir 
797*cdf0e10cSrcweir 			cairo_set_source( pCairo, pPattern );
798*cdf0e10cSrcweir 			if( !bHasAlpha )
799*cdf0e10cSrcweir 			    cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
800*cdf0e10cSrcweir 			cairo_fill( pCairo );
801*cdf0e10cSrcweir 
802*cdf0e10cSrcweir 			cairo_restore( pCairo );
803*cdf0e10cSrcweir 
804*cdf0e10cSrcweir 			cairo_pattern_destroy( pPattern );
805*cdf0e10cSrcweir 		    }
806*cdf0e10cSrcweir 
807*cdf0e10cSrcweir 		    if( data )
808*cdf0e10cSrcweir 			free( data );
809*cdf0e10cSrcweir 		} else if( aTexture.Gradient.is() ) {
810*cdf0e10cSrcweir 		    uno::Reference< lang::XServiceInfo > xRef( aTexture.Gradient, uno::UNO_QUERY );
811*cdf0e10cSrcweir 
812*cdf0e10cSrcweir 		    OSL_TRACE( "gradient fill" );
813*cdf0e10cSrcweir 		    if( xRef.is() &&
814*cdf0e10cSrcweir 			xRef->getImplementationName().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME ) ) ) ) {
815*cdf0e10cSrcweir 				// TODO(Q1): Maybe use dynamic_cast here
816*cdf0e10cSrcweir 
817*cdf0e10cSrcweir 				// TODO(E1): Return value
818*cdf0e10cSrcweir 				// TODO(F1): FillRule
819*cdf0e10cSrcweir 			OSL_TRACE( "known implementation" );
820*cdf0e10cSrcweir 
821*cdf0e10cSrcweir 			::canvas::ParametricPolyPolygon* pPolyImpl = static_cast< ::canvas::ParametricPolyPolygon* >( aTexture.Gradient.get() );
822*cdf0e10cSrcweir 			::com::sun::star::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform );
823*cdf0e10cSrcweir 			Matrix aTextureMatrix;
824*cdf0e10cSrcweir 
825*cdf0e10cSrcweir 			cairo_matrix_init( &aTextureMatrix,
826*cdf0e10cSrcweir 					   aTransform.m00, aTransform.m10, aTransform.m01,
827*cdf0e10cSrcweir 					   aTransform.m11, aTransform.m02, aTransform.m12);
828*cdf0e10cSrcweir             if( pPolyImpl->getValues().meType == canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR )
829*cdf0e10cSrcweir             {
830*cdf0e10cSrcweir                 // no general path gradient yet in cairo; emulate then
831*cdf0e10cSrcweir                 cairo_save( pCairo );
832*cdf0e10cSrcweir                 cairo_clip( pCairo );
833*cdf0e10cSrcweir 
834*cdf0e10cSrcweir                 // fill bound rect with start color
835*cdf0e10cSrcweir                 cairo_rectangle( pCairo, rBounds.getMinX(), rBounds.getMinY(),
836*cdf0e10cSrcweir                                  rBounds.getWidth(), rBounds.getHeight() );
837*cdf0e10cSrcweir                 setColor(pCairo,pPolyImpl->getValues().maColors[0]);
838*cdf0e10cSrcweir                 cairo_fill(pCairo);
839*cdf0e10cSrcweir 
840*cdf0e10cSrcweir                 cairo_transform( pCairo, &aTextureMatrix );
841*cdf0e10cSrcweir 
842*cdf0e10cSrcweir                 // longest line in gradient bound rect
843*cdf0e10cSrcweir                 const unsigned int nGradientSize(
844*cdf0e10cSrcweir                     static_cast<unsigned int>(
845*cdf0e10cSrcweir                         ::basegfx::B2DVector(rBounds.getMinimum() - rBounds.getMaximum()).getLength() + 1.0 ) );
846*cdf0e10cSrcweir 
847*cdf0e10cSrcweir                 // typical number for pixel of the same color (strip size)
848*cdf0e10cSrcweir                 const unsigned int nStripSize( nGradientSize < 50 ? 2 : 4 );
849*cdf0e10cSrcweir 
850*cdf0e10cSrcweir                 // use at least three steps, and at utmost the number of color
851*cdf0e10cSrcweir                 // steps
852*cdf0e10cSrcweir                 const unsigned int nStepCount(
853*cdf0e10cSrcweir                     ::std::max(
854*cdf0e10cSrcweir                         3U,
855*cdf0e10cSrcweir                         ::std::min(
856*cdf0e10cSrcweir                             nGradientSize / nStripSize,
857*cdf0e10cSrcweir                             128U )) + 1 );
858*cdf0e10cSrcweir 
859*cdf0e10cSrcweir                 const uno::Sequence<double>* pColors=&pPolyImpl->getValues().maColors[0];
860*cdf0e10cSrcweir                 basegfx::tools::KeyStopLerp aLerper(pPolyImpl->getValues().maStops);
861*cdf0e10cSrcweir                 for( unsigned int i=1; i<nStepCount; ++i )
862*cdf0e10cSrcweir                 {
863*cdf0e10cSrcweir                     const double fT( i/double(nStepCount) );
864*cdf0e10cSrcweir 
865*cdf0e10cSrcweir                     std::ptrdiff_t nIndex;
866*cdf0e10cSrcweir                     double fAlpha;
867*cdf0e10cSrcweir                     boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
868*cdf0e10cSrcweir 
869*cdf0e10cSrcweir                     setColor(pCairo, lerp(pColors[nIndex], pColors[nIndex+1], fAlpha));
870*cdf0e10cSrcweir                     cairo_rectangle( pCairo, -1+fT, -1+fT, 2-2*fT, 2-2*fT );
871*cdf0e10cSrcweir                     cairo_fill(pCairo);
872*cdf0e10cSrcweir                 }
873*cdf0e10cSrcweir 
874*cdf0e10cSrcweir                 cairo_restore( pCairo );
875*cdf0e10cSrcweir             }
876*cdf0e10cSrcweir             else
877*cdf0e10cSrcweir             {
878*cdf0e10cSrcweir                 Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl );
879*cdf0e10cSrcweir 
880*cdf0e10cSrcweir                 if( pPattern ) {
881*cdf0e10cSrcweir                     OSL_TRACE( "filling with pattern" );
882*cdf0e10cSrcweir 
883*cdf0e10cSrcweir                     cairo_save( pCairo );
884*cdf0e10cSrcweir 
885*cdf0e10cSrcweir                     cairo_transform( pCairo, &aTextureMatrix );
886*cdf0e10cSrcweir                     cairo_set_source( pCairo, pPattern );
887*cdf0e10cSrcweir                     cairo_fill( pCairo );
888*cdf0e10cSrcweir                     cairo_restore( pCairo );
889*cdf0e10cSrcweir 
890*cdf0e10cSrcweir                     cairo_pattern_destroy( pPattern );
891*cdf0e10cSrcweir                 }
892*cdf0e10cSrcweir 		    }
893*cdf0e10cSrcweir             }
894*cdf0e10cSrcweir 		}
895*cdf0e10cSrcweir 	    } else
896*cdf0e10cSrcweir 		cairo_fill( pCairo );
897*cdf0e10cSrcweir 	    OSL_TRACE("fill");
898*cdf0e10cSrcweir 	break;
899*cdf0e10cSrcweir 	case Stroke:
900*cdf0e10cSrcweir 	    cairo_stroke( pCairo );
901*cdf0e10cSrcweir 	    OSL_TRACE("stroke");
902*cdf0e10cSrcweir 	break;
903*cdf0e10cSrcweir 	case Clip:
904*cdf0e10cSrcweir 	    cairo_clip( pCairo );
905*cdf0e10cSrcweir 	    OSL_TRACE("clip");
906*cdf0e10cSrcweir 	break;
907*cdf0e10cSrcweir 	}
908*cdf0e10cSrcweir     }
909*cdf0e10cSrcweir 
910*cdf0e10cSrcweir     static void clipNULL( Cairo *pCairo )
911*cdf0e10cSrcweir     {
912*cdf0e10cSrcweir 	OSL_TRACE("clipNULL");
913*cdf0e10cSrcweir 	Matrix aOrigMatrix, aIdentityMatrix;
914*cdf0e10cSrcweir 
915*cdf0e10cSrcweir 	/* we set identity matrix here to overcome bug in cairo 0.9.2
916*cdf0e10cSrcweir 	   where XCreatePixmap is called with zero width and height.
917*cdf0e10cSrcweir 
918*cdf0e10cSrcweir 	   it also reaches faster path in cairo clipping code.
919*cdf0e10cSrcweir 	*/
920*cdf0e10cSrcweir 	cairo_matrix_init_identity( &aIdentityMatrix );
921*cdf0e10cSrcweir 	cairo_get_matrix( pCairo, &aOrigMatrix );
922*cdf0e10cSrcweir 	cairo_set_matrix( pCairo, &aIdentityMatrix );
923*cdf0e10cSrcweir 
924*cdf0e10cSrcweir 	cairo_reset_clip( pCairo );
925*cdf0e10cSrcweir 	cairo_rectangle( pCairo, 0, 0, 1, 1 );
926*cdf0e10cSrcweir 	cairo_clip( pCairo );
927*cdf0e10cSrcweir 	cairo_rectangle( pCairo, 2, 0, 1, 1 );
928*cdf0e10cSrcweir 	cairo_clip( pCairo );
929*cdf0e10cSrcweir 
930*cdf0e10cSrcweir 	/* restore the original matrix */
931*cdf0e10cSrcweir 	cairo_set_matrix( pCairo, &aOrigMatrix );
932*cdf0e10cSrcweir     }
933*cdf0e10cSrcweir 
934*cdf0e10cSrcweir     void doPolyPolygonImplementation( ::basegfx::B2DPolyPolygon aPolyPolygon,
935*cdf0e10cSrcweir                                       Operation aOperation,
936*cdf0e10cSrcweir                                       Cairo* pCairo,
937*cdf0e10cSrcweir                                       const uno::Sequence< rendering::Texture >* pTextures,
938*cdf0e10cSrcweir                                       const SurfaceProviderRef& pDevice,
939*cdf0e10cSrcweir                                       rendering::FillRule eFillrule )
940*cdf0e10cSrcweir     {
941*cdf0e10cSrcweir 		if( pTextures )
942*cdf0e10cSrcweir 			ENSURE_ARG_OR_THROW( pTextures->getLength(),
943*cdf0e10cSrcweir 							 "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence");
944*cdf0e10cSrcweir 
945*cdf0e10cSrcweir 	bool bOpToDo = false;
946*cdf0e10cSrcweir 	Matrix aOrigMatrix, aIdentityMatrix;
947*cdf0e10cSrcweir 	double nX, nY, nBX, nBY, nAX, nAY;
948*cdf0e10cSrcweir 
949*cdf0e10cSrcweir 	cairo_get_matrix( pCairo, &aOrigMatrix );
950*cdf0e10cSrcweir 	cairo_matrix_init_identity( &aIdentityMatrix );
951*cdf0e10cSrcweir 	cairo_set_matrix( pCairo, &aIdentityMatrix );
952*cdf0e10cSrcweir 
953*cdf0e10cSrcweir     cairo_set_fill_rule( pCairo,
954*cdf0e10cSrcweir                          eFillrule == rendering::FillRule_EVEN_ODD ?
955*cdf0e10cSrcweir                          CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING );
956*cdf0e10cSrcweir 
957*cdf0e10cSrcweir 	for( sal_uInt32 nPolygonIndex = 0; nPolygonIndex < aPolyPolygon.count(); nPolygonIndex++ ) {
958*cdf0e10cSrcweir 	    ::basegfx::B2DPolygon aPolygon( aPolyPolygon.getB2DPolygon( nPolygonIndex ) );
959*cdf0e10cSrcweir 	    const sal_uInt32 nPointCount( aPolygon.count() );
960*cdf0e10cSrcweir         // to correctly render closed curves, need to output first
961*cdf0e10cSrcweir         // point twice (so output one additional point)
962*cdf0e10cSrcweir 	    const sal_uInt32 nExtendedPointCount( nPointCount +
963*cdf0e10cSrcweir                                               aPolygon.isClosed()*aPolygon.areControlPointsUsed() );
964*cdf0e10cSrcweir 
965*cdf0e10cSrcweir 	    if( nPointCount > 1) {
966*cdf0e10cSrcweir 		bool bIsBezier = aPolygon.areControlPointsUsed();
967*cdf0e10cSrcweir         bool bIsRectangle = ::basegfx::tools::isRectangle( aPolygon );
968*cdf0e10cSrcweir 		::basegfx::B2DPoint aA, aB, aP;
969*cdf0e10cSrcweir 
970*cdf0e10cSrcweir 		for( sal_uInt32 j=0; j < nExtendedPointCount; j++ ) {
971*cdf0e10cSrcweir 		    aP = aPolygon.getB2DPoint( j % nPointCount );
972*cdf0e10cSrcweir 
973*cdf0e10cSrcweir 		    nX = aP.getX();
974*cdf0e10cSrcweir 		    nY = aP.getY();
975*cdf0e10cSrcweir 		    cairo_matrix_transform_point( &aOrigMatrix, &nX, &nY );
976*cdf0e10cSrcweir 
977*cdf0e10cSrcweir  		    if( ! bIsBezier && (bIsRectangle || aOperation == Clip) ) {
978*cdf0e10cSrcweir                 nX = basegfx::fround( nX );
979*cdf0e10cSrcweir                 nY = basegfx::fround( nY );
980*cdf0e10cSrcweir 		    }
981*cdf0e10cSrcweir 
982*cdf0e10cSrcweir 		    if( aOperation == Stroke ) {
983*cdf0e10cSrcweir                 nX += 0.5;
984*cdf0e10cSrcweir                 nY += 0.5;
985*cdf0e10cSrcweir 		    }
986*cdf0e10cSrcweir 
987*cdf0e10cSrcweir             if( j==0 )
988*cdf0e10cSrcweir             {
989*cdf0e10cSrcweir                 cairo_move_to( pCairo, nX, nY );
990*cdf0e10cSrcweir                 OSL_TRACE( "move to %f,%f", nX, nY );
991*cdf0e10cSrcweir             }
992*cdf0e10cSrcweir             else {
993*cdf0e10cSrcweir                 if( bIsBezier ) {
994*cdf0e10cSrcweir                     aA = aPolygon.getNextControlPoint( (j-1) % nPointCount );
995*cdf0e10cSrcweir                     aB = aPolygon.getPrevControlPoint( j % nPointCount );
996*cdf0e10cSrcweir 
997*cdf0e10cSrcweir                     nAX = aA.getX();
998*cdf0e10cSrcweir                     nAY = aA.getY();
999*cdf0e10cSrcweir                     nBX = aB.getX();
1000*cdf0e10cSrcweir                     nBY = aB.getY();
1001*cdf0e10cSrcweir 
1002*cdf0e10cSrcweir                     if( aOperation == Stroke ) {
1003*cdf0e10cSrcweir                         nAX += 0.5;
1004*cdf0e10cSrcweir                         nAY += 0.5;
1005*cdf0e10cSrcweir                         nBX += 0.5;
1006*cdf0e10cSrcweir                         nBY += 0.5;
1007*cdf0e10cSrcweir                     }
1008*cdf0e10cSrcweir                     cairo_matrix_transform_point( &aOrigMatrix, &nAX, &nAY );
1009*cdf0e10cSrcweir                     cairo_matrix_transform_point( &aOrigMatrix, &nBX, &nBY );
1010*cdf0e10cSrcweir                     cairo_curve_to( pCairo, nAX, nAY, nBX, nBY, nX, nY );
1011*cdf0e10cSrcweir                 } else {
1012*cdf0e10cSrcweir                     cairo_line_to( pCairo, nX, nY );
1013*cdf0e10cSrcweir                     OSL_TRACE( "line to %f,%f", nX, nY );
1014*cdf0e10cSrcweir                 }
1015*cdf0e10cSrcweir                 bOpToDo = true;
1016*cdf0e10cSrcweir             }
1017*cdf0e10cSrcweir 		}
1018*cdf0e10cSrcweir 
1019*cdf0e10cSrcweir 		if( aPolygon.isClosed() )
1020*cdf0e10cSrcweir 		    cairo_close_path( pCairo );
1021*cdf0e10cSrcweir 
1022*cdf0e10cSrcweir 		if( aOperation == Fill && pTextures ) {
1023*cdf0e10cSrcweir 		    cairo_set_matrix( pCairo, &aOrigMatrix );
1024*cdf0e10cSrcweir 		    doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
1025*cdf0e10cSrcweir 		    cairo_set_matrix( pCairo, &aIdentityMatrix );
1026*cdf0e10cSrcweir 		}
1027*cdf0e10cSrcweir 	    } else {
1028*cdf0e10cSrcweir 		OSL_TRACE( "empty polygon for op: %d\n", aOperation );
1029*cdf0e10cSrcweir 		if( aOperation == Clip ) {
1030*cdf0e10cSrcweir 		    clipNULL( pCairo );
1031*cdf0e10cSrcweir 
1032*cdf0e10cSrcweir 		    return;
1033*cdf0e10cSrcweir 		}
1034*cdf0e10cSrcweir 	    }
1035*cdf0e10cSrcweir 	}
1036*cdf0e10cSrcweir 	if( bOpToDo && ( aOperation != Fill || !pTextures ) )
1037*cdf0e10cSrcweir 	    doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
1038*cdf0e10cSrcweir 
1039*cdf0e10cSrcweir 	cairo_set_matrix( pCairo, &aOrigMatrix );
1040*cdf0e10cSrcweir 
1041*cdf0e10cSrcweir 	if( aPolyPolygon.count() == 0 && aOperation == Clip )
1042*cdf0e10cSrcweir  	    clipNULL( pCairo );
1043*cdf0e10cSrcweir     }
1044*cdf0e10cSrcweir 
1045*cdf0e10cSrcweir     void CanvasHelper::doPolyPolygonPath( const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1046*cdf0e10cSrcweir 					    Operation aOperation,
1047*cdf0e10cSrcweir                         bool bNoLineJoin,
1048*cdf0e10cSrcweir 					    const uno::Sequence< rendering::Texture >* pTextures,
1049*cdf0e10cSrcweir 					    Cairo* pCairo ) const
1050*cdf0e10cSrcweir     {
1051*cdf0e10cSrcweir         const ::basegfx::B2DPolyPolygon& rPolyPoly(
1052*cdf0e10cSrcweir             ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) );
1053*cdf0e10cSrcweir 
1054*cdf0e10cSrcweir         if( !pCairo )
1055*cdf0e10cSrcweir             pCairo = mpCairo.get();
1056*cdf0e10cSrcweir 
1057*cdf0e10cSrcweir         if(bNoLineJoin && Stroke == aOperation)
1058*cdf0e10cSrcweir         {
1059*cdf0e10cSrcweir             // emulate rendering::PathJoinType::NONE by painting single edges
1060*cdf0e10cSrcweir             for(sal_uInt32 a(0); a < rPolyPoly.count(); a++)
1061*cdf0e10cSrcweir             {
1062*cdf0e10cSrcweir                 const basegfx::B2DPolygon aCandidate(rPolyPoly.getB2DPolygon(a));
1063*cdf0e10cSrcweir                 const sal_uInt32 nPointCount(aCandidate.count());
1064*cdf0e10cSrcweir 
1065*cdf0e10cSrcweir                 if(nPointCount)
1066*cdf0e10cSrcweir                 {
1067*cdf0e10cSrcweir                     const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount + 1: nPointCount);
1068*cdf0e10cSrcweir                     basegfx::B2DPolygon aEdge;
1069*cdf0e10cSrcweir                     aEdge.append(aCandidate.getB2DPoint(0));
1070*cdf0e10cSrcweir                     aEdge.append(basegfx::B2DPoint(0.0, 0.0));
1071*cdf0e10cSrcweir 
1072*cdf0e10cSrcweir                     for(sal_uInt32 b(0); b < nEdgeCount; b++)
1073*cdf0e10cSrcweir 					{
1074*cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((b + 1) % nPointCount);
1075*cdf0e10cSrcweir                         aEdge.setB2DPoint(1, aCandidate.getB2DPoint(nNextIndex));
1076*cdf0e10cSrcweir                         aEdge.setNextControlPoint(0, aCandidate.getNextControlPoint(b));
1077*cdf0e10cSrcweir                         aEdge.setPrevControlPoint(1, aCandidate.getPrevControlPoint(nNextIndex));
1078*cdf0e10cSrcweir 
1079*cdf0e10cSrcweir                         doPolyPolygonImplementation( basegfx::B2DPolyPolygon(aEdge),
1080*cdf0e10cSrcweir                                                      aOperation,
1081*cdf0e10cSrcweir                                                      pCairo, pTextures,
1082*cdf0e10cSrcweir                                                      mpSurfaceProvider,
1083*cdf0e10cSrcweir                                                      xPolyPolygon->getFillRule() );
1084*cdf0e10cSrcweir 
1085*cdf0e10cSrcweir                         // prepare next step
1086*cdf0e10cSrcweir                         aEdge.setB2DPoint(0, aEdge.getB2DPoint(1));
1087*cdf0e10cSrcweir 					}
1088*cdf0e10cSrcweir                 }
1089*cdf0e10cSrcweir             }
1090*cdf0e10cSrcweir         }
1091*cdf0e10cSrcweir         else
1092*cdf0e10cSrcweir         {
1093*cdf0e10cSrcweir             doPolyPolygonImplementation( rPolyPoly, aOperation,
1094*cdf0e10cSrcweir                                          pCairo, pTextures,
1095*cdf0e10cSrcweir                                          mpSurfaceProvider,
1096*cdf0e10cSrcweir                                          xPolyPolygon->getFillRule() );
1097*cdf0e10cSrcweir         }
1098*cdf0e10cSrcweir     }
1099*cdf0e10cSrcweir 
1100*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* 							,
1101*cdf0e10cSrcweir                                                                                  const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1102*cdf0e10cSrcweir                                                                                  const rendering::ViewState& 						viewState,
1103*cdf0e10cSrcweir                                                                                  const rendering::RenderState& 						renderState )
1104*cdf0e10cSrcweir     {
1105*cdf0e10cSrcweir #ifdef CAIRO_CANVAS_PERF_TRACE
1106*cdf0e10cSrcweir         struct timespec aTimer;
1107*cdf0e10cSrcweir         mxDevice->startPerfTrace( &aTimer );
1108*cdf0e10cSrcweir #endif
1109*cdf0e10cSrcweir 
1110*cdf0e10cSrcweir         if( mpCairo ) {
1111*cdf0e10cSrcweir             cairo_save( mpCairo.get() );
1112*cdf0e10cSrcweir 
1113*cdf0e10cSrcweir             cairo_set_line_width( mpCairo.get(), 1 );
1114*cdf0e10cSrcweir 
1115*cdf0e10cSrcweir             useStates( viewState, renderState, true );
1116*cdf0e10cSrcweir             doPolyPolygonPath( xPolyPolygon, Stroke );
1117*cdf0e10cSrcweir 
1118*cdf0e10cSrcweir             cairo_restore( mpCairo.get() );
1119*cdf0e10cSrcweir         } else
1120*cdf0e10cSrcweir             OSL_TRACE ("CanvasHelper called after it was disposed");
1121*cdf0e10cSrcweir 
1122*cdf0e10cSrcweir #ifdef CAIRO_CANVAS_PERF_TRACE
1123*cdf0e10cSrcweir         mxDevice->stopPerfTrace( &aTimer, "drawPolyPolygon" );
1124*cdf0e10cSrcweir #endif
1125*cdf0e10cSrcweir 
1126*cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
1127*cdf0e10cSrcweir     }
1128*cdf0e10cSrcweir 
1129*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* 							,
1130*cdf0e10cSrcweir                                                                                    const uno::Reference< rendering::XPolyPolygon2D >& 	xPolyPolygon,
1131*cdf0e10cSrcweir                                                                                    const rendering::ViewState& 							viewState,
1132*cdf0e10cSrcweir                                                                                    const rendering::RenderState& 						renderState,
1133*cdf0e10cSrcweir                                                                                    const rendering::StrokeAttributes& 					strokeAttributes )
1134*cdf0e10cSrcweir     {
1135*cdf0e10cSrcweir 	#ifdef CAIRO_CANVAS_PERF_TRACE
1136*cdf0e10cSrcweir 	struct timespec aTimer;
1137*cdf0e10cSrcweir 	mxDevice->startPerfTrace( &aTimer );
1138*cdf0e10cSrcweir         #endif
1139*cdf0e10cSrcweir 
1140*cdf0e10cSrcweir 	if( mpCairo ) {
1141*cdf0e10cSrcweir 	    cairo_save( mpCairo.get() );
1142*cdf0e10cSrcweir 
1143*cdf0e10cSrcweir 	    useStates( viewState, renderState, true );
1144*cdf0e10cSrcweir 
1145*cdf0e10cSrcweir         Matrix aMatrix;
1146*cdf0e10cSrcweir         double w = strokeAttributes.StrokeWidth, h = 0;
1147*cdf0e10cSrcweir         cairo_get_matrix( mpCairo.get(), &aMatrix );
1148*cdf0e10cSrcweir         cairo_matrix_transform_distance( &aMatrix, &w, &h );
1149*cdf0e10cSrcweir  	    cairo_set_line_width( mpCairo.get(), w );
1150*cdf0e10cSrcweir 
1151*cdf0e10cSrcweir 	    cairo_set_miter_limit( mpCairo.get(), strokeAttributes.MiterLimit );
1152*cdf0e10cSrcweir 
1153*cdf0e10cSrcweir 	    // FIXME: cairo doesn't handle end cap so far (rodo)
1154*cdf0e10cSrcweir 	    switch( strokeAttributes.StartCapType ) {
1155*cdf0e10cSrcweir             case rendering::PathCapType::BUTT:
1156*cdf0e10cSrcweir                 cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_BUTT );
1157*cdf0e10cSrcweir                 break;
1158*cdf0e10cSrcweir             case rendering::PathCapType::ROUND:
1159*cdf0e10cSrcweir                 cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_ROUND );
1160*cdf0e10cSrcweir                 break;
1161*cdf0e10cSrcweir             case rendering::PathCapType::SQUARE:
1162*cdf0e10cSrcweir                 cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_SQUARE );
1163*cdf0e10cSrcweir                 break;
1164*cdf0e10cSrcweir 	    }
1165*cdf0e10cSrcweir 
1166*cdf0e10cSrcweir         bool bNoLineJoin(false);
1167*cdf0e10cSrcweir 
1168*cdf0e10cSrcweir 	    switch( strokeAttributes.JoinType ) {
1169*cdf0e10cSrcweir             // cairo doesn't have join type NONE so we use MITER as it's pretty close
1170*cdf0e10cSrcweir             case rendering::PathJoinType::NONE:
1171*cdf0e10cSrcweir                 bNoLineJoin = true;
1172*cdf0e10cSrcweir             case rendering::PathJoinType::MITER:
1173*cdf0e10cSrcweir                 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_MITER );
1174*cdf0e10cSrcweir                 break;
1175*cdf0e10cSrcweir             case rendering::PathJoinType::ROUND:
1176*cdf0e10cSrcweir                 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_ROUND );
1177*cdf0e10cSrcweir                 break;
1178*cdf0e10cSrcweir             case rendering::PathJoinType::BEVEL:
1179*cdf0e10cSrcweir                 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_BEVEL );
1180*cdf0e10cSrcweir                 break;
1181*cdf0e10cSrcweir 	    }
1182*cdf0e10cSrcweir 
1183*cdf0e10cSrcweir 	    if( strokeAttributes.DashArray.getLength() > 0 ) {
1184*cdf0e10cSrcweir             double* pDashArray = new double[ strokeAttributes.DashArray.getLength() ];
1185*cdf0e10cSrcweir             for( sal_Int32 i=0; i<strokeAttributes.DashArray.getLength(); i++ )
1186*cdf0e10cSrcweir                 pDashArray[i]=strokeAttributes.DashArray[i];
1187*cdf0e10cSrcweir             cairo_set_dash( mpCairo.get(), pDashArray, strokeAttributes.DashArray.getLength(), 0 );
1188*cdf0e10cSrcweir             delete[] pDashArray;
1189*cdf0e10cSrcweir 	    }
1190*cdf0e10cSrcweir 
1191*cdf0e10cSrcweir 	    // TODO(rodo) use LineArray of strokeAttributes
1192*cdf0e10cSrcweir 
1193*cdf0e10cSrcweir 	    doPolyPolygonPath( xPolyPolygon, Stroke, bNoLineJoin );
1194*cdf0e10cSrcweir 
1195*cdf0e10cSrcweir 	    cairo_restore( mpCairo.get() );
1196*cdf0e10cSrcweir 	} else
1197*cdf0e10cSrcweir 	    OSL_TRACE ("CanvasHelper called after it was disposed");
1198*cdf0e10cSrcweir 
1199*cdf0e10cSrcweir #ifdef CAIRO_CANVAS_PERF_TRACE
1200*cdf0e10cSrcweir 	    mxDevice->stopPerfTrace( &aTimer, "strokePolyPolygon" );
1201*cdf0e10cSrcweir #endif
1202*cdf0e10cSrcweir 
1203*cdf0e10cSrcweir         // TODO(P1): Provide caching here.
1204*cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
1205*cdf0e10cSrcweir     }
1206*cdf0e10cSrcweir 
1207*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* 							,
1208*cdf0e10cSrcweir                                                                                            const uno::Reference< rendering::XPolyPolygon2D >& 	/*xPolyPolygon*/,
1209*cdf0e10cSrcweir                                                                                            const rendering::ViewState& 							/*viewState*/,
1210*cdf0e10cSrcweir                                                                                            const rendering::RenderState& 						/*renderState*/,
1211*cdf0e10cSrcweir                                                                                            const uno::Sequence< rendering::Texture >& 			/*textures*/,
1212*cdf0e10cSrcweir                                                                                            const rendering::StrokeAttributes& 					/*strokeAttributes*/ )
1213*cdf0e10cSrcweir     {
1214*cdf0e10cSrcweir         // TODO
1215*cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
1216*cdf0e10cSrcweir     }
1217*cdf0e10cSrcweir 
1218*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* 							,
1219*cdf0e10cSrcweir                                                                                                 const uno::Reference< rendering::XPolyPolygon2D >&	/*xPolyPolygon*/,
1220*cdf0e10cSrcweir                                                                                                 const rendering::ViewState& 						/*viewState*/,
1221*cdf0e10cSrcweir                                                                                                 const rendering::RenderState& 						/*renderState*/,
1222*cdf0e10cSrcweir                                                                                                 const uno::Sequence< rendering::Texture >& 			/*textures*/,
1223*cdf0e10cSrcweir                                                                                                 const uno::Reference< geometry::XMapping2D >& 		/*xMapping*/,
1224*cdf0e10cSrcweir                                                                                                 const rendering::StrokeAttributes& 					/*strokeAttributes*/ )
1225*cdf0e10cSrcweir     {
1226*cdf0e10cSrcweir         // TODO
1227*cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
1228*cdf0e10cSrcweir     }
1229*cdf0e10cSrcweir 
1230*cdf0e10cSrcweir     uno::Reference< rendering::XPolyPolygon2D >   CanvasHelper::queryStrokeShapes( const rendering::XCanvas* 							,
1231*cdf0e10cSrcweir                                                                                    const uno::Reference< rendering::XPolyPolygon2D >& 	/*xPolyPolygon*/,
1232*cdf0e10cSrcweir                                                                                    const rendering::ViewState& 							/*viewState*/,
1233*cdf0e10cSrcweir                                                                                    const rendering::RenderState& 						/*renderState*/,
1234*cdf0e10cSrcweir                                                                                    const rendering::StrokeAttributes& 					/*strokeAttributes*/ )
1235*cdf0e10cSrcweir     {
1236*cdf0e10cSrcweir         // TODO
1237*cdf0e10cSrcweir         return uno::Reference< rendering::XPolyPolygon2D >(NULL);
1238*cdf0e10cSrcweir     }
1239*cdf0e10cSrcweir 
1240*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* 							,
1241*cdf0e10cSrcweir                                                                                  const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1242*cdf0e10cSrcweir                                                                                  const rendering::ViewState& 						viewState,
1243*cdf0e10cSrcweir                                                                                  const rendering::RenderState& 						renderState )
1244*cdf0e10cSrcweir     {
1245*cdf0e10cSrcweir 	#ifdef CAIRO_CANVAS_PERF_TRACE
1246*cdf0e10cSrcweir 	struct timespec aTimer;
1247*cdf0e10cSrcweir 	mxDevice->startPerfTrace( &aTimer );
1248*cdf0e10cSrcweir         #endif
1249*cdf0e10cSrcweir 
1250*cdf0e10cSrcweir 	if( mpCairo ) {
1251*cdf0e10cSrcweir 	    cairo_save( mpCairo.get() );
1252*cdf0e10cSrcweir 
1253*cdf0e10cSrcweir 	    useStates( viewState, renderState, true );
1254*cdf0e10cSrcweir 	    doPolyPolygonPath( xPolyPolygon, Fill );
1255*cdf0e10cSrcweir 
1256*cdf0e10cSrcweir 	    cairo_restore( mpCairo.get() );
1257*cdf0e10cSrcweir 	} else
1258*cdf0e10cSrcweir 	    OSL_TRACE ("CanvasHelper called after it was disposed");
1259*cdf0e10cSrcweir 
1260*cdf0e10cSrcweir 	#ifdef CAIRO_CANVAS_PERF_TRACE
1261*cdf0e10cSrcweir 	mxDevice->stopPerfTrace( &aTimer, "fillPolyPolygon" );
1262*cdf0e10cSrcweir         #endif
1263*cdf0e10cSrcweir 
1264*cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
1265*cdf0e10cSrcweir     }
1266*cdf0e10cSrcweir 
1267*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* 							,
1268*cdf0e10cSrcweir                                                                                          const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1269*cdf0e10cSrcweir                                                                                          const rendering::ViewState& 						viewState,
1270*cdf0e10cSrcweir                                                                                          const rendering::RenderState& 						renderState,
1271*cdf0e10cSrcweir                                                                                          const uno::Sequence< rendering::Texture >& 		textures )
1272*cdf0e10cSrcweir     {
1273*cdf0e10cSrcweir 	if( mpCairo ) {
1274*cdf0e10cSrcweir 	    cairo_save( mpCairo.get() );
1275*cdf0e10cSrcweir 
1276*cdf0e10cSrcweir 	    useStates( viewState, renderState, true );
1277*cdf0e10cSrcweir 	    doPolyPolygonPath( xPolyPolygon, Fill, false, &textures );
1278*cdf0e10cSrcweir 
1279*cdf0e10cSrcweir 	    cairo_restore( mpCairo.get() );
1280*cdf0e10cSrcweir 	}
1281*cdf0e10cSrcweir 
1282*cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
1283*cdf0e10cSrcweir     }
1284*cdf0e10cSrcweir 
1285*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* 							,
1286*cdf0e10cSrcweir                                                                                               const uno::Reference< rendering::XPolyPolygon2D >& 	/*xPolyPolygon*/,
1287*cdf0e10cSrcweir                                                                                               const rendering::ViewState& 							/*viewState*/,
1288*cdf0e10cSrcweir                                                                                               const rendering::RenderState& 						/*renderState*/,
1289*cdf0e10cSrcweir                                                                                               const uno::Sequence< rendering::Texture >& 			/*textures*/,
1290*cdf0e10cSrcweir                                                                                               const uno::Reference< geometry::XMapping2D >& 		/*xMapping*/ )
1291*cdf0e10cSrcweir     {
1292*cdf0e10cSrcweir         // TODO
1293*cdf0e10cSrcweir         return uno::Reference< rendering::XCachedPrimitive >(NULL);
1294*cdf0e10cSrcweir     }
1295*cdf0e10cSrcweir 
1296*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::implDrawBitmapSurface( const rendering::XCanvas* 	    pCanvas,
1297*cdf0e10cSrcweir                                                                                        const SurfaceSharedPtr&        pInputSurface,
1298*cdf0e10cSrcweir 																					   const rendering::ViewState&      viewState,
1299*cdf0e10cSrcweir 																					   const rendering::RenderState&    renderState,
1300*cdf0e10cSrcweir 																					   const geometry::IntegerSize2D&   rSize,
1301*cdf0e10cSrcweir 																					   bool bModulateColors,
1302*cdf0e10cSrcweir 																					   bool bHasAlpha )
1303*cdf0e10cSrcweir     {
1304*cdf0e10cSrcweir         SurfaceSharedPtr pSurface=pInputSurface;
1305*cdf0e10cSrcweir 		uno::Reference< rendering::XCachedPrimitive > rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1306*cdf0e10cSrcweir         geometry::IntegerSize2D aBitmapSize = rSize;
1307*cdf0e10cSrcweir 
1308*cdf0e10cSrcweir 		if( mpCairo ) {
1309*cdf0e10cSrcweir 			cairo_save( mpCairo.get() );
1310*cdf0e10cSrcweir 
1311*cdf0e10cSrcweir 			cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
1312*cdf0e10cSrcweir 			cairo_clip( mpCairo.get() );
1313*cdf0e10cSrcweir 
1314*cdf0e10cSrcweir 			useStates( viewState, renderState, true );
1315*cdf0e10cSrcweir 
1316*cdf0e10cSrcweir 			//   	    if( !bHasAlpha )
1317*cdf0e10cSrcweir 			//   		cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
1318*cdf0e10cSrcweir 
1319*cdf0e10cSrcweir 			Matrix aMatrix;
1320*cdf0e10cSrcweir 
1321*cdf0e10cSrcweir 			cairo_get_matrix( mpCairo.get(), &aMatrix );
1322*cdf0e10cSrcweir 			if( ! ::rtl::math::approxEqual( aMatrix.xx, 1 ) &&
1323*cdf0e10cSrcweir 				! ::rtl::math::approxEqual( aMatrix.yy, 1 ) &&
1324*cdf0e10cSrcweir 				::rtl::math::approxEqual( aMatrix.x0, 0 ) &&
1325*cdf0e10cSrcweir 				::rtl::math::approxEqual( aMatrix.y0, 0 ) &&
1326*cdf0e10cSrcweir 				basegfx::fround( rSize.Width * aMatrix.xx ) > 8 &&
1327*cdf0e10cSrcweir 				basegfx::fround( rSize.Height* aMatrix.yy ) > 8 )
1328*cdf0e10cSrcweir             {
1329*cdf0e10cSrcweir                 double dWidth, dHeight;
1330*cdf0e10cSrcweir 
1331*cdf0e10cSrcweir                 dWidth = basegfx::fround( rSize.Width * aMatrix.xx );
1332*cdf0e10cSrcweir                 dHeight = basegfx::fround( rSize.Height* aMatrix.yy );
1333*cdf0e10cSrcweir                 aBitmapSize.Width = static_cast<sal_Int32>( dWidth );
1334*cdf0e10cSrcweir                 aBitmapSize.Height = static_cast<sal_Int32>( dHeight );
1335*cdf0e10cSrcweir 
1336*cdf0e10cSrcweir                 SurfaceSharedPtr pScaledSurface = mpSurfaceProvider->createSurface(
1337*cdf0e10cSrcweir                     ::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ),
1338*cdf0e10cSrcweir                     bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
1339*cdf0e10cSrcweir                 CairoSharedPtr pCairo = pScaledSurface->getCairo();
1340*cdf0e10cSrcweir 
1341*cdf0e10cSrcweir                 cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE );
1342*cdf0e10cSrcweir                 // add 0.5px to size to avoid rounding errors in cairo, leading sometimes to random data on the image right/bottom borders
1343*cdf0e10cSrcweir                 cairo_scale( pCairo.get(), (dWidth+0.5)/rSize.Width, (dHeight+0.5)/rSize.Height );
1344*cdf0e10cSrcweir                 cairo_set_source_surface( pCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
1345*cdf0e10cSrcweir                 cairo_paint( pCairo.get() );
1346*cdf0e10cSrcweir 
1347*cdf0e10cSrcweir                 pSurface = pScaledSurface;
1348*cdf0e10cSrcweir 
1349*cdf0e10cSrcweir                 aMatrix.xx = aMatrix.yy = 1;
1350*cdf0e10cSrcweir                 cairo_set_matrix( mpCairo.get(), &aMatrix );
1351*cdf0e10cSrcweir 
1352*cdf0e10cSrcweir                 rv = uno::Reference< rendering::XCachedPrimitive >(
1353*cdf0e10cSrcweir                     new CachedBitmap( pSurface, viewState, renderState,
1354*cdf0e10cSrcweir                                       // cast away const, need to
1355*cdf0e10cSrcweir                                       // change refcount (as this is
1356*cdf0e10cSrcweir                                       // ~invisible to client code,
1357*cdf0e10cSrcweir                                       // still logically const)
1358*cdf0e10cSrcweir                                       const_cast< rendering::XCanvas* >(pCanvas)) );
1359*cdf0e10cSrcweir             }
1360*cdf0e10cSrcweir 
1361*cdf0e10cSrcweir 			if( !bHasAlpha && mbHaveAlpha )
1362*cdf0e10cSrcweir             {
1363*cdf0e10cSrcweir 				double x, y, width, height;
1364*cdf0e10cSrcweir 
1365*cdf0e10cSrcweir 				x = y = 0;
1366*cdf0e10cSrcweir 				width = aBitmapSize.Width;
1367*cdf0e10cSrcweir 				height = aBitmapSize.Height;
1368*cdf0e10cSrcweir 				cairo_matrix_transform_point( &aMatrix, &x, &y );
1369*cdf0e10cSrcweir 				cairo_matrix_transform_distance( &aMatrix, &width, &height );
1370*cdf0e10cSrcweir 
1371*cdf0e10cSrcweir 				// in case the bitmap doesn't have alpha and covers whole area
1372*cdf0e10cSrcweir 				// we try to change surface to plain rgb
1373*cdf0e10cSrcweir 				OSL_TRACE ("chance to change surface to rgb, %f, %f, %f x %f (%d x %d)", x, y, width, height, maSize.getX(), maSize.getY() );
1374*cdf0e10cSrcweir 				if( x <= 0 && y <= 0 && x + width >= maSize.getX() && y + height >= maSize.getY() )
1375*cdf0e10cSrcweir 				{
1376*cdf0e10cSrcweir 					OSL_TRACE ("trying to change surface to rgb");
1377*cdf0e10cSrcweir 					if( mpSurfaceProvider ) {
1378*cdf0e10cSrcweir 						SurfaceSharedPtr pNewSurface = mpSurfaceProvider->changeSurface( false, false );
1379*cdf0e10cSrcweir 
1380*cdf0e10cSrcweir 						if( pNewSurface )
1381*cdf0e10cSrcweir 							setSurface( pNewSurface, false );
1382*cdf0e10cSrcweir 
1383*cdf0e10cSrcweir 						// set state to new mpCairo.get()
1384*cdf0e10cSrcweir 						useStates( viewState, renderState, true );
1385*cdf0e10cSrcweir 						// use the possibly modified matrix
1386*cdf0e10cSrcweir 						cairo_set_matrix( mpCairo.get(), &aMatrix );
1387*cdf0e10cSrcweir 					}
1388*cdf0e10cSrcweir 				}
1389*cdf0e10cSrcweir 			}
1390*cdf0e10cSrcweir 
1391*cdf0e10cSrcweir 			cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
1392*cdf0e10cSrcweir  			if( !bHasAlpha &&
1393*cdf0e10cSrcweir 				::rtl::math::approxEqual( aMatrix.xx, 1 ) &&
1394*cdf0e10cSrcweir 				::rtl::math::approxEqual( aMatrix.yy, 1 ) &&
1395*cdf0e10cSrcweir 				::rtl::math::approxEqual( aMatrix.x0, 0 ) &&
1396*cdf0e10cSrcweir 				::rtl::math::approxEqual( aMatrix.y0, 0 ) )
1397*cdf0e10cSrcweir  				cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
1398*cdf0e10cSrcweir 			cairo_pattern_set_extend( cairo_get_source(mpCairo.get()), CAIRO_EXTEND_PAD );
1399*cdf0e10cSrcweir 			cairo_rectangle( mpCairo.get(), 0, 0, aBitmapSize.Width, aBitmapSize.Height );
1400*cdf0e10cSrcweir 			cairo_clip( mpCairo.get() );
1401*cdf0e10cSrcweir 
1402*cdf0e10cSrcweir             if( bModulateColors )
1403*cdf0e10cSrcweir                 cairo_paint_with_alpha( mpCairo.get(), renderState.DeviceColor[3] );
1404*cdf0e10cSrcweir             else
1405*cdf0e10cSrcweir                 cairo_paint( mpCairo.get() );
1406*cdf0e10cSrcweir 			cairo_restore( mpCairo.get() );
1407*cdf0e10cSrcweir 		} else
1408*cdf0e10cSrcweir 			OSL_TRACE ("CanvasHelper called after it was disposed");
1409*cdf0e10cSrcweir 
1410*cdf0e10cSrcweir         return rv; // uno::Reference< rendering::XCachedPrimitive >(NULL);
1411*cdf0e10cSrcweir     }
1412*cdf0e10cSrcweir 
1413*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* 					pCanvas,
1414*cdf0e10cSrcweir                                                                             const uno::Reference< rendering::XBitmap >& xBitmap,
1415*cdf0e10cSrcweir                                                                             const rendering::ViewState& 				viewState,
1416*cdf0e10cSrcweir                                                                             const rendering::RenderState& 				renderState )
1417*cdf0e10cSrcweir     {
1418*cdf0e10cSrcweir 	#ifdef CAIRO_CANVAS_PERF_TRACE
1419*cdf0e10cSrcweir 	struct timespec aTimer;
1420*cdf0e10cSrcweir 	mxDevice->startPerfTrace( &aTimer );
1421*cdf0e10cSrcweir         #endif
1422*cdf0e10cSrcweir 
1423*cdf0e10cSrcweir 	uno::Reference< rendering::XCachedPrimitive > rv;
1424*cdf0e10cSrcweir 	unsigned char* data = NULL;
1425*cdf0e10cSrcweir 	bool bHasAlpha = false;
1426*cdf0e10cSrcweir 	SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
1427*cdf0e10cSrcweir 	geometry::IntegerSize2D aSize = xBitmap->getSize();
1428*cdf0e10cSrcweir 
1429*cdf0e10cSrcweir 	if( pSurface ) {
1430*cdf0e10cSrcweir 	    rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, false, bHasAlpha );
1431*cdf0e10cSrcweir 
1432*cdf0e10cSrcweir 	    if( data )
1433*cdf0e10cSrcweir 		free( data );
1434*cdf0e10cSrcweir 	} else
1435*cdf0e10cSrcweir 	    rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1436*cdf0e10cSrcweir 
1437*cdf0e10cSrcweir 	#ifdef CAIRO_CANVAS_PERF_TRACE
1438*cdf0e10cSrcweir 	mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1439*cdf0e10cSrcweir         #endif
1440*cdf0e10cSrcweir 
1441*cdf0e10cSrcweir 	return rv;
1442*cdf0e10cSrcweir     }
1443*cdf0e10cSrcweir 
1444*cdf0e10cSrcweir     uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* 						pCanvas,
1445*cdf0e10cSrcweir                                                                                      const uno::Reference< rendering::XBitmap >& 	xBitmap,
1446*cdf0e10cSrcweir                                                                                      const rendering::ViewState& 					viewState,
1447*cdf0e10cSrcweir                                                                                      const rendering::RenderState& 					renderState )
1448*cdf0e10cSrcweir     {
1449*cdf0e10cSrcweir #ifdef CAIRO_CANVAS_PERF_TRACE
1450*cdf0e10cSrcweir         struct timespec aTimer;
1451*cdf0e10cSrcweir         mxDevice->startPerfTrace( &aTimer );
1452*cdf0e10cSrcweir #endif
1453*cdf0e10cSrcweir 
1454*cdf0e10cSrcweir         uno::Reference< rendering::XCachedPrimitive > rv;
1455*cdf0e10cSrcweir         unsigned char* data = NULL;
1456*cdf0e10cSrcweir         bool bHasAlpha = false;
1457*cdf0e10cSrcweir         SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
1458*cdf0e10cSrcweir         geometry::IntegerSize2D aSize = xBitmap->getSize();
1459*cdf0e10cSrcweir 
1460*cdf0e10cSrcweir         if( pSurface ) {
1461*cdf0e10cSrcweir             rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, true, bHasAlpha );
1462*cdf0e10cSrcweir 
1463*cdf0e10cSrcweir             if( data )
1464*cdf0e10cSrcweir                 free( data );
1465*cdf0e10cSrcweir         } else
1466*cdf0e10cSrcweir             rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1467*cdf0e10cSrcweir 
1468*cdf0e10cSrcweir #ifdef CAIRO_CANVAS_PERF_TRACE
1469*cdf0e10cSrcweir         mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1470*cdf0e10cSrcweir #endif
1471*cdf0e10cSrcweir 
1472*cdf0e10cSrcweir         return rv;
1473*cdf0e10cSrcweir     }
1474*cdf0e10cSrcweir 
1475*cdf0e10cSrcweir     uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice()
1476*cdf0e10cSrcweir     {
1477*cdf0e10cSrcweir         return uno::Reference< rendering::XGraphicDevice >(mpDevice);
1478*cdf0e10cSrcweir     }
1479*cdf0e10cSrcweir 
1480*cdf0e10cSrcweir     void CanvasHelper::copyRect( const rendering::XCanvas* 							,
1481*cdf0e10cSrcweir                                  const uno::Reference< rendering::XBitmapCanvas >&	/*sourceCanvas*/,
1482*cdf0e10cSrcweir                                  const geometry::RealRectangle2D& 					/*sourceRect*/,
1483*cdf0e10cSrcweir                                  const rendering::ViewState& 						/*sourceViewState*/,
1484*cdf0e10cSrcweir                                  const rendering::RenderState& 						/*sourceRenderState*/,
1485*cdf0e10cSrcweir                                  const geometry::RealRectangle2D& 					/*destRect*/,
1486*cdf0e10cSrcweir                                  const rendering::ViewState& 						/*destViewState*/,
1487*cdf0e10cSrcweir                                  const rendering::RenderState& 						/*destRenderState*/ )
1488*cdf0e10cSrcweir     {
1489*cdf0e10cSrcweir         // TODO(F2): copyRect NYI
1490*cdf0e10cSrcweir     }
1491*cdf0e10cSrcweir 
1492*cdf0e10cSrcweir     geometry::IntegerSize2D CanvasHelper::getSize()
1493*cdf0e10cSrcweir     {
1494*cdf0e10cSrcweir         if( !mpSurfaceProvider )
1495*cdf0e10cSrcweir             geometry::IntegerSize2D(1, 1); // we're disposed
1496*cdf0e10cSrcweir 
1497*cdf0e10cSrcweir         return ::basegfx::unotools::integerSize2DFromB2ISize( maSize );
1498*cdf0e10cSrcweir     }
1499*cdf0e10cSrcweir 
1500*cdf0e10cSrcweir     uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D&	newSize,
1501*cdf0e10cSrcweir                                                                         sal_Bool 					/*beFast*/ )
1502*cdf0e10cSrcweir     {
1503*cdf0e10cSrcweir #ifdef CAIRO_CANVAS_PERF_TRACE
1504*cdf0e10cSrcweir 		struct timespec aTimer;
1505*cdf0e10cSrcweir 		mxDevice->startPerfTrace( &aTimer );
1506*cdf0e10cSrcweir #endif
1507*cdf0e10cSrcweir 
1508*cdf0e10cSrcweir 		if( mpCairo ) {
1509*cdf0e10cSrcweir 			return uno::Reference< rendering::XBitmap >( new CanvasBitmap( ::basegfx::B2ISize( ::canvas::tools::roundUp( newSize.Width ),
1510*cdf0e10cSrcweir 																							   ::canvas::tools::roundUp( newSize.Height ) ),
1511*cdf0e10cSrcweir 																		   mpSurfaceProvider, mpDevice, false ) );
1512*cdf0e10cSrcweir 		} else
1513*cdf0e10cSrcweir 			OSL_TRACE ("CanvasHelper called after it was disposed");
1514*cdf0e10cSrcweir 
1515*cdf0e10cSrcweir #ifdef CAIRO_CANVAS_PERF_TRACE
1516*cdf0e10cSrcweir 		mxDevice->stopPerfTrace( &aTimer, "getScaledBitmap" );
1517*cdf0e10cSrcweir #endif
1518*cdf0e10cSrcweir 
1519*cdf0e10cSrcweir 		return uno::Reference< rendering::XBitmap >();
1520*cdf0e10cSrcweir     }
1521*cdf0e10cSrcweir 
1522*cdf0e10cSrcweir     uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout&     aLayout,
1523*cdf0e10cSrcweir                                                      const geometry::IntegerRectangle2D& rect )
1524*cdf0e10cSrcweir     {
1525*cdf0e10cSrcweir         if( mpCairo ) {
1526*cdf0e10cSrcweir             aLayout = getMemoryLayout();
1527*cdf0e10cSrcweir 
1528*cdf0e10cSrcweir             const sal_Int32 nWidth( rect.X2 - rect.X1 );
1529*cdf0e10cSrcweir             const sal_Int32 nHeight( rect.Y2 - rect.Y1 );
1530*cdf0e10cSrcweir             uno::Sequence< sal_Int8 > aRes( 4*nWidth*nHeight );
1531*cdf0e10cSrcweir             sal_Int8* pData = aRes.getArray();
1532*cdf0e10cSrcweir             cairo_surface_t* pImageSurface = cairo_image_surface_create_for_data( (unsigned char *) pData,
1533*cdf0e10cSrcweir                                                                                   CAIRO_FORMAT_ARGB32,
1534*cdf0e10cSrcweir                                                                                   nWidth, nHeight, 4*nWidth );
1535*cdf0e10cSrcweir             cairo_t* pCairo = cairo_create( pImageSurface );
1536*cdf0e10cSrcweir             cairo_set_source_surface( pCairo, mpSurface->getCairoSurface().get(), -rect.X1, -rect.Y1);
1537*cdf0e10cSrcweir             cairo_paint( pCairo );
1538*cdf0e10cSrcweir             cairo_destroy( pCairo );
1539*cdf0e10cSrcweir             cairo_surface_destroy( pImageSurface );
1540*cdf0e10cSrcweir 
1541*cdf0e10cSrcweir             aLayout.ScanLines = nHeight;
1542*cdf0e10cSrcweir             aLayout.ScanLineBytes = nWidth*4;
1543*cdf0e10cSrcweir             aLayout.ScanLineStride = aLayout.ScanLineBytes;
1544*cdf0e10cSrcweir 
1545*cdf0e10cSrcweir             return aRes;
1546*cdf0e10cSrcweir         }
1547*cdf0e10cSrcweir 
1548*cdf0e10cSrcweir         return uno::Sequence< sal_Int8 >();
1549*cdf0e10cSrcweir     }
1550*cdf0e10cSrcweir 
1551*cdf0e10cSrcweir     void CanvasHelper::setData( const uno::Sequence< sal_Int8 >& 		/*data*/,
1552*cdf0e10cSrcweir                                 const rendering::IntegerBitmapLayout&   /*bitmapLayout*/,
1553*cdf0e10cSrcweir                                 const geometry::IntegerRectangle2D& 	/*rect*/ )
1554*cdf0e10cSrcweir     {
1555*cdf0e10cSrcweir     }
1556*cdf0e10cSrcweir 
1557*cdf0e10cSrcweir     void CanvasHelper::setPixel( const uno::Sequence< sal_Int8 >&       /*color*/,
1558*cdf0e10cSrcweir                                  const rendering::IntegerBitmapLayout&  /*bitmapLayout*/,
1559*cdf0e10cSrcweir                                  const geometry::IntegerPoint2D&        /*pos*/ )
1560*cdf0e10cSrcweir     {
1561*cdf0e10cSrcweir     }
1562*cdf0e10cSrcweir 
1563*cdf0e10cSrcweir     uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout&   /*bitmapLayout*/,
1564*cdf0e10cSrcweir                                                       const geometry::IntegerPoint2D&   /*pos*/ )
1565*cdf0e10cSrcweir     {
1566*cdf0e10cSrcweir         return uno::Sequence< sal_Int8 >();
1567*cdf0e10cSrcweir     }
1568*cdf0e10cSrcweir 
1569*cdf0e10cSrcweir     uno::Reference< rendering::XBitmapPalette > CanvasHelper::getPalette()
1570*cdf0e10cSrcweir     {
1571*cdf0e10cSrcweir         // TODO(F1): Palette bitmaps NYI
1572*cdf0e10cSrcweir         return uno::Reference< rendering::XBitmapPalette >();
1573*cdf0e10cSrcweir     }
1574*cdf0e10cSrcweir 
1575*cdf0e10cSrcweir     namespace
1576*cdf0e10cSrcweir     {
1577*cdf0e10cSrcweir         class CairoColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace >
1578*cdf0e10cSrcweir         {
1579*cdf0e10cSrcweir         private:
1580*cdf0e10cSrcweir             uno::Sequence< sal_Int8 >  maComponentTags;
1581*cdf0e10cSrcweir             uno::Sequence< sal_Int32 > maBitCounts;
1582*cdf0e10cSrcweir 
1583*cdf0e10cSrcweir             virtual ::sal_Int8 SAL_CALL getType(  ) throw (uno::RuntimeException)
1584*cdf0e10cSrcweir             {
1585*cdf0e10cSrcweir                 return rendering::ColorSpaceType::RGB;
1586*cdf0e10cSrcweir             }
1587*cdf0e10cSrcweir             virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags(  ) throw (uno::RuntimeException)
1588*cdf0e10cSrcweir             {
1589*cdf0e10cSrcweir                 return maComponentTags;
1590*cdf0e10cSrcweir             }
1591*cdf0e10cSrcweir             virtual ::sal_Int8 SAL_CALL getRenderingIntent(  ) throw (uno::RuntimeException)
1592*cdf0e10cSrcweir             {
1593*cdf0e10cSrcweir                 return rendering::RenderingIntent::PERCEPTUAL;
1594*cdf0e10cSrcweir             }
1595*cdf0e10cSrcweir             virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties(  ) throw (uno::RuntimeException)
1596*cdf0e10cSrcweir             {
1597*cdf0e10cSrcweir                 return uno::Sequence< beans::PropertyValue >();
1598*cdf0e10cSrcweir             }
1599*cdf0e10cSrcweir             virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
1600*cdf0e10cSrcweir                                                                         const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
1601*cdf0e10cSrcweir                                                                                                                                                   uno::RuntimeException)
1602*cdf0e10cSrcweir             {
1603*cdf0e10cSrcweir                 // TODO(P3): if we know anything about target
1604*cdf0e10cSrcweir                 // colorspace, this can be greatly sped up
1605*cdf0e10cSrcweir                 uno::Sequence<rendering::ARGBColor> aIntermediate(
1606*cdf0e10cSrcweir                     convertToARGB(deviceColor));
1607*cdf0e10cSrcweir                 return targetColorSpace->convertFromARGB(aIntermediate);
1608*cdf0e10cSrcweir             }
1609*cdf0e10cSrcweir             virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1610*cdf0e10cSrcweir             {
1611*cdf0e10cSrcweir                 const double*  pIn( deviceColor.getConstArray() );
1612*cdf0e10cSrcweir                 const sal_Size nLen( deviceColor.getLength() );
1613*cdf0e10cSrcweir                 ENSURE_ARG_OR_THROW2(nLen%4==0,
1614*cdf0e10cSrcweir                                      "number of channels no multiple of 4",
1615*cdf0e10cSrcweir                                      static_cast<rendering::XColorSpace*>(this), 0);
1616*cdf0e10cSrcweir 
1617*cdf0e10cSrcweir                 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1618*cdf0e10cSrcweir                 rendering::RGBColor* pOut( aRes.getArray() );
1619*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; i+=4 )
1620*cdf0e10cSrcweir                 {
1621*cdf0e10cSrcweir                     const double fAlpha(pIn[3]);
1622*cdf0e10cSrcweir                     if( fAlpha == 0.0 )
1623*cdf0e10cSrcweir                         *pOut++ = rendering::RGBColor(0.0, 0.0, 0.0);
1624*cdf0e10cSrcweir                     else
1625*cdf0e10cSrcweir                         *pOut++ = rendering::RGBColor(pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1626*cdf0e10cSrcweir                     pIn += 4;
1627*cdf0e10cSrcweir                 }
1628*cdf0e10cSrcweir                 return aRes;
1629*cdf0e10cSrcweir             }
1630*cdf0e10cSrcweir             virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1631*cdf0e10cSrcweir             {
1632*cdf0e10cSrcweir                 const double*  pIn( deviceColor.getConstArray() );
1633*cdf0e10cSrcweir                 const sal_Size nLen( deviceColor.getLength() );
1634*cdf0e10cSrcweir                 ENSURE_ARG_OR_THROW2(nLen%4==0,
1635*cdf0e10cSrcweir                                      "number of channels no multiple of 4",
1636*cdf0e10cSrcweir                                      static_cast<rendering::XColorSpace*>(this), 0);
1637*cdf0e10cSrcweir 
1638*cdf0e10cSrcweir                 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1639*cdf0e10cSrcweir                 rendering::ARGBColor* pOut( aRes.getArray() );
1640*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; i+=4 )
1641*cdf0e10cSrcweir                 {
1642*cdf0e10cSrcweir                     const double fAlpha(pIn[3]);
1643*cdf0e10cSrcweir                     if( fAlpha == 0.0 )
1644*cdf0e10cSrcweir                         *pOut++ = rendering::ARGBColor(0.0, 0.0, 0.0, 0.0);
1645*cdf0e10cSrcweir                     else
1646*cdf0e10cSrcweir                         *pOut++ = rendering::ARGBColor(fAlpha,pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1647*cdf0e10cSrcweir                     pIn += 4;
1648*cdf0e10cSrcweir                 }
1649*cdf0e10cSrcweir                 return aRes;
1650*cdf0e10cSrcweir             }
1651*cdf0e10cSrcweir             virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1652*cdf0e10cSrcweir             {
1653*cdf0e10cSrcweir                 const double*  pIn( deviceColor.getConstArray() );
1654*cdf0e10cSrcweir                 const sal_Size nLen( deviceColor.getLength() );
1655*cdf0e10cSrcweir                 ENSURE_ARG_OR_THROW2(nLen%4==0,
1656*cdf0e10cSrcweir                                      "number of channels no multiple of 4",
1657*cdf0e10cSrcweir                                      static_cast<rendering::XColorSpace*>(this), 0);
1658*cdf0e10cSrcweir 
1659*cdf0e10cSrcweir                 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1660*cdf0e10cSrcweir                 rendering::ARGBColor* pOut( aRes.getArray() );
1661*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; i+=4 )
1662*cdf0e10cSrcweir                 {
1663*cdf0e10cSrcweir                     *pOut++ = rendering::ARGBColor(pIn[3],pIn[2],pIn[1],pIn[1]);
1664*cdf0e10cSrcweir                     pIn += 4;
1665*cdf0e10cSrcweir                 }
1666*cdf0e10cSrcweir                 return aRes;
1667*cdf0e10cSrcweir             }
1668*cdf0e10cSrcweir             virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1669*cdf0e10cSrcweir             {
1670*cdf0e10cSrcweir                 const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1671*cdf0e10cSrcweir                 const sal_Size             nLen( rgbColor.getLength() );
1672*cdf0e10cSrcweir 
1673*cdf0e10cSrcweir                 uno::Sequence< double > aRes(nLen*4);
1674*cdf0e10cSrcweir                 double* pColors=aRes.getArray();
1675*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; ++i )
1676*cdf0e10cSrcweir                 {
1677*cdf0e10cSrcweir                     *pColors++ = pIn->Blue;
1678*cdf0e10cSrcweir                     *pColors++ = pIn->Green;
1679*cdf0e10cSrcweir                     *pColors++ = pIn->Red;
1680*cdf0e10cSrcweir                     *pColors++ = 1.0;
1681*cdf0e10cSrcweir                     ++pIn;
1682*cdf0e10cSrcweir                 }
1683*cdf0e10cSrcweir                 return aRes;
1684*cdf0e10cSrcweir             }
1685*cdf0e10cSrcweir             virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1686*cdf0e10cSrcweir             {
1687*cdf0e10cSrcweir                 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1688*cdf0e10cSrcweir                 const sal_Size              nLen( rgbColor.getLength() );
1689*cdf0e10cSrcweir 
1690*cdf0e10cSrcweir                 uno::Sequence< double > aRes(nLen*4);
1691*cdf0e10cSrcweir                 double* pColors=aRes.getArray();
1692*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; ++i )
1693*cdf0e10cSrcweir                 {
1694*cdf0e10cSrcweir                     *pColors++ = pIn->Alpha*pIn->Blue;
1695*cdf0e10cSrcweir                     *pColors++ = pIn->Alpha*pIn->Green;
1696*cdf0e10cSrcweir                     *pColors++ = pIn->Alpha*pIn->Red;
1697*cdf0e10cSrcweir                     *pColors++ = pIn->Alpha;
1698*cdf0e10cSrcweir                     ++pIn;
1699*cdf0e10cSrcweir                 }
1700*cdf0e10cSrcweir                 return aRes;
1701*cdf0e10cSrcweir             }
1702*cdf0e10cSrcweir             virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1703*cdf0e10cSrcweir             {
1704*cdf0e10cSrcweir                 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1705*cdf0e10cSrcweir                 const sal_Size              nLen( rgbColor.getLength() );
1706*cdf0e10cSrcweir 
1707*cdf0e10cSrcweir                 uno::Sequence< double > aRes(nLen*4);
1708*cdf0e10cSrcweir                 double* pColors=aRes.getArray();
1709*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; ++i )
1710*cdf0e10cSrcweir                 {
1711*cdf0e10cSrcweir                     *pColors++ = pIn->Blue;
1712*cdf0e10cSrcweir                     *pColors++ = pIn->Green;
1713*cdf0e10cSrcweir                     *pColors++ = pIn->Red;
1714*cdf0e10cSrcweir                     *pColors++ = pIn->Alpha;
1715*cdf0e10cSrcweir                     ++pIn;
1716*cdf0e10cSrcweir                 }
1717*cdf0e10cSrcweir                 return aRes;
1718*cdf0e10cSrcweir             }
1719*cdf0e10cSrcweir 
1720*cdf0e10cSrcweir             // XIntegerBitmapColorSpace
1721*cdf0e10cSrcweir             virtual ::sal_Int32 SAL_CALL getBitsPerPixel(  ) throw (uno::RuntimeException)
1722*cdf0e10cSrcweir             {
1723*cdf0e10cSrcweir                 return 32;
1724*cdf0e10cSrcweir             }
1725*cdf0e10cSrcweir             virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts(  ) throw (uno::RuntimeException)
1726*cdf0e10cSrcweir             {
1727*cdf0e10cSrcweir                 return maBitCounts;
1728*cdf0e10cSrcweir             }
1729*cdf0e10cSrcweir             virtual ::sal_Int8 SAL_CALL getEndianness(  ) throw (uno::RuntimeException)
1730*cdf0e10cSrcweir             {
1731*cdf0e10cSrcweir                 return util::Endianness::LITTLE;
1732*cdf0e10cSrcweir             }
1733*cdf0e10cSrcweir             virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1734*cdf0e10cSrcweir                                                                                  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
1735*cdf0e10cSrcweir                                                                                                                                                            uno::RuntimeException)
1736*cdf0e10cSrcweir             {
1737*cdf0e10cSrcweir                 if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1738*cdf0e10cSrcweir                 {
1739*cdf0e10cSrcweir                     const sal_Int8* pIn( deviceColor.getConstArray() );
1740*cdf0e10cSrcweir                     const sal_Size  nLen( deviceColor.getLength() );
1741*cdf0e10cSrcweir                     ENSURE_ARG_OR_THROW2(nLen%4==0,
1742*cdf0e10cSrcweir                                          "number of channels no multiple of 4",
1743*cdf0e10cSrcweir                                          static_cast<rendering::XColorSpace*>(this), 0);
1744*cdf0e10cSrcweir 
1745*cdf0e10cSrcweir                     uno::Sequence<double> aRes(nLen);
1746*cdf0e10cSrcweir                     double* pOut( aRes.getArray() );
1747*cdf0e10cSrcweir                     for( sal_Size i=0; i<nLen; i+=4 )
1748*cdf0e10cSrcweir                     {
1749*cdf0e10cSrcweir                         *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1750*cdf0e10cSrcweir                         *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1751*cdf0e10cSrcweir                         *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1752*cdf0e10cSrcweir                         *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1753*cdf0e10cSrcweir                     }
1754*cdf0e10cSrcweir                     return aRes;
1755*cdf0e10cSrcweir                 }
1756*cdf0e10cSrcweir                 else
1757*cdf0e10cSrcweir                 {
1758*cdf0e10cSrcweir                     // TODO(P3): if we know anything about target
1759*cdf0e10cSrcweir                     // colorspace, this can be greatly sped up
1760*cdf0e10cSrcweir                     uno::Sequence<rendering::ARGBColor> aIntermediate(
1761*cdf0e10cSrcweir                         convertIntegerToARGB(deviceColor));
1762*cdf0e10cSrcweir                     return targetColorSpace->convertFromARGB(aIntermediate);
1763*cdf0e10cSrcweir                 }
1764*cdf0e10cSrcweir             }
1765*cdf0e10cSrcweir             virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1766*cdf0e10cSrcweir                                                                                      const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
1767*cdf0e10cSrcweir                                                                                                                                                                             uno::RuntimeException)
1768*cdf0e10cSrcweir             {
1769*cdf0e10cSrcweir                 if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1770*cdf0e10cSrcweir                 {
1771*cdf0e10cSrcweir                     // it's us, so simply pass-through the data
1772*cdf0e10cSrcweir                     return deviceColor;
1773*cdf0e10cSrcweir                 }
1774*cdf0e10cSrcweir                 else
1775*cdf0e10cSrcweir                 {
1776*cdf0e10cSrcweir                     // TODO(P3): if we know anything about target
1777*cdf0e10cSrcweir                     // colorspace, this can be greatly sped up
1778*cdf0e10cSrcweir                     uno::Sequence<rendering::ARGBColor> aIntermediate(
1779*cdf0e10cSrcweir                         convertIntegerToARGB(deviceColor));
1780*cdf0e10cSrcweir                     return targetColorSpace->convertIntegerFromARGB(aIntermediate);
1781*cdf0e10cSrcweir                 }
1782*cdf0e10cSrcweir             }
1783*cdf0e10cSrcweir             virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1784*cdf0e10cSrcweir             {
1785*cdf0e10cSrcweir                 const sal_Int8* pIn( deviceColor.getConstArray() );
1786*cdf0e10cSrcweir                 const sal_Size  nLen( deviceColor.getLength() );
1787*cdf0e10cSrcweir                 ENSURE_ARG_OR_THROW2(nLen%4==0,
1788*cdf0e10cSrcweir                                      "number of channels no multiple of 4",
1789*cdf0e10cSrcweir                                      static_cast<rendering::XColorSpace*>(this), 0);
1790*cdf0e10cSrcweir 
1791*cdf0e10cSrcweir                 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1792*cdf0e10cSrcweir                 rendering::RGBColor* pOut( aRes.getArray() );
1793*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; i+=4 )
1794*cdf0e10cSrcweir                 {
1795*cdf0e10cSrcweir                     const double fAlpha((sal_uInt8)pIn[3]);
1796*cdf0e10cSrcweir                     if( fAlpha )
1797*cdf0e10cSrcweir                         *pOut++ = rendering::RGBColor(
1798*cdf0e10cSrcweir                             pIn[2]/fAlpha,
1799*cdf0e10cSrcweir                             pIn[1]/fAlpha,
1800*cdf0e10cSrcweir                             pIn[0]/fAlpha);
1801*cdf0e10cSrcweir                     else
1802*cdf0e10cSrcweir                         *pOut++ = rendering::RGBColor(0,0,0);
1803*cdf0e10cSrcweir                     pIn += 4;
1804*cdf0e10cSrcweir                 }
1805*cdf0e10cSrcweir                 return aRes;
1806*cdf0e10cSrcweir             }
1807*cdf0e10cSrcweir 
1808*cdf0e10cSrcweir             virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1809*cdf0e10cSrcweir             {
1810*cdf0e10cSrcweir                 const sal_Int8* pIn( deviceColor.getConstArray() );
1811*cdf0e10cSrcweir                 const sal_Size  nLen( deviceColor.getLength() );
1812*cdf0e10cSrcweir                 ENSURE_ARG_OR_THROW2(nLen%4==0,
1813*cdf0e10cSrcweir                                      "number of channels no multiple of 4",
1814*cdf0e10cSrcweir                                      static_cast<rendering::XColorSpace*>(this), 0);
1815*cdf0e10cSrcweir 
1816*cdf0e10cSrcweir                 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1817*cdf0e10cSrcweir                 rendering::ARGBColor* pOut( aRes.getArray() );
1818*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; i+=4 )
1819*cdf0e10cSrcweir                 {
1820*cdf0e10cSrcweir                     const double fAlpha((sal_uInt8)pIn[3]);
1821*cdf0e10cSrcweir                     if( fAlpha )
1822*cdf0e10cSrcweir                         *pOut++ = rendering::ARGBColor(
1823*cdf0e10cSrcweir                             fAlpha/255.0,
1824*cdf0e10cSrcweir                             pIn[2]/fAlpha,
1825*cdf0e10cSrcweir                             pIn[1]/fAlpha,
1826*cdf0e10cSrcweir                             pIn[0]/fAlpha);
1827*cdf0e10cSrcweir                     else
1828*cdf0e10cSrcweir                         *pOut++ = rendering::ARGBColor(0,0,0,0);
1829*cdf0e10cSrcweir                     pIn += 4;
1830*cdf0e10cSrcweir                 }
1831*cdf0e10cSrcweir                 return aRes;
1832*cdf0e10cSrcweir             }
1833*cdf0e10cSrcweir             virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1834*cdf0e10cSrcweir             {
1835*cdf0e10cSrcweir                 const sal_Int8* pIn( deviceColor.getConstArray() );
1836*cdf0e10cSrcweir                 const sal_Size  nLen( deviceColor.getLength() );
1837*cdf0e10cSrcweir                 ENSURE_ARG_OR_THROW2(nLen%4==0,
1838*cdf0e10cSrcweir                                      "number of channels no multiple of 4",
1839*cdf0e10cSrcweir                                      static_cast<rendering::XColorSpace*>(this), 0);
1840*cdf0e10cSrcweir 
1841*cdf0e10cSrcweir                 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1842*cdf0e10cSrcweir                 rendering::ARGBColor* pOut( aRes.getArray() );
1843*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; i+=4 )
1844*cdf0e10cSrcweir                 {
1845*cdf0e10cSrcweir                     *pOut++ = rendering::ARGBColor(
1846*cdf0e10cSrcweir                         vcl::unotools::toDoubleColor(pIn[3]),
1847*cdf0e10cSrcweir                         vcl::unotools::toDoubleColor(pIn[2]),
1848*cdf0e10cSrcweir                         vcl::unotools::toDoubleColor(pIn[1]),
1849*cdf0e10cSrcweir                         vcl::unotools::toDoubleColor(pIn[0]));
1850*cdf0e10cSrcweir                     pIn += 4;
1851*cdf0e10cSrcweir                 }
1852*cdf0e10cSrcweir                 return aRes;
1853*cdf0e10cSrcweir             }
1854*cdf0e10cSrcweir 
1855*cdf0e10cSrcweir             virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1856*cdf0e10cSrcweir             {
1857*cdf0e10cSrcweir                 const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1858*cdf0e10cSrcweir                 const sal_Size             nLen( rgbColor.getLength() );
1859*cdf0e10cSrcweir 
1860*cdf0e10cSrcweir                 uno::Sequence< sal_Int8 > aRes(nLen*4);
1861*cdf0e10cSrcweir                 sal_Int8* pColors=aRes.getArray();
1862*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; ++i )
1863*cdf0e10cSrcweir                 {
1864*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1865*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1866*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1867*cdf0e10cSrcweir                     *pColors++ = 255;
1868*cdf0e10cSrcweir                     ++pIn;
1869*cdf0e10cSrcweir                 }
1870*cdf0e10cSrcweir                 return aRes;
1871*cdf0e10cSrcweir             }
1872*cdf0e10cSrcweir 
1873*cdf0e10cSrcweir             virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1874*cdf0e10cSrcweir             {
1875*cdf0e10cSrcweir                 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1876*cdf0e10cSrcweir                 const sal_Size              nLen( rgbColor.getLength() );
1877*cdf0e10cSrcweir 
1878*cdf0e10cSrcweir                 uno::Sequence< sal_Int8 > aRes(nLen*4);
1879*cdf0e10cSrcweir                 sal_Int8* pColors=aRes.getArray();
1880*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; ++i )
1881*cdf0e10cSrcweir                 {
1882*cdf0e10cSrcweir                     const double fAlpha(pIn->Alpha);
1883*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Blue);
1884*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Green);
1885*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Red);
1886*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(fAlpha);
1887*cdf0e10cSrcweir                     ++pIn;
1888*cdf0e10cSrcweir                 }
1889*cdf0e10cSrcweir                 return aRes;
1890*cdf0e10cSrcweir             }
1891*cdf0e10cSrcweir             virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
1892*cdf0e10cSrcweir             {
1893*cdf0e10cSrcweir                 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1894*cdf0e10cSrcweir                 const sal_Size              nLen( rgbColor.getLength() );
1895*cdf0e10cSrcweir 
1896*cdf0e10cSrcweir                 uno::Sequence< sal_Int8 > aRes(nLen*4);
1897*cdf0e10cSrcweir                 sal_Int8* pColors=aRes.getArray();
1898*cdf0e10cSrcweir                 for( sal_Size i=0; i<nLen; ++i )
1899*cdf0e10cSrcweir                 {
1900*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1901*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1902*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1903*cdf0e10cSrcweir                     *pColors++ = vcl::unotools::toByteColor(pIn->Alpha);
1904*cdf0e10cSrcweir                     ++pIn;
1905*cdf0e10cSrcweir                 }
1906*cdf0e10cSrcweir                 return aRes;
1907*cdf0e10cSrcweir             }
1908*cdf0e10cSrcweir 
1909*cdf0e10cSrcweir         public:
1910*cdf0e10cSrcweir             CairoColorSpace() :
1911*cdf0e10cSrcweir                 maComponentTags(4),
1912*cdf0e10cSrcweir                 maBitCounts(4)
1913*cdf0e10cSrcweir             {
1914*cdf0e10cSrcweir                 sal_Int8*  pTags = maComponentTags.getArray();
1915*cdf0e10cSrcweir                 sal_Int32* pBitCounts = maBitCounts.getArray();
1916*cdf0e10cSrcweir                 pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
1917*cdf0e10cSrcweir                 pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
1918*cdf0e10cSrcweir                 pTags[2] = rendering::ColorComponentTag::RGB_RED;
1919*cdf0e10cSrcweir                 pTags[3] = rendering::ColorComponentTag::PREMULTIPLIED_ALPHA;
1920*cdf0e10cSrcweir 
1921*cdf0e10cSrcweir                 pBitCounts[0] =
1922*cdf0e10cSrcweir                     pBitCounts[1] =
1923*cdf0e10cSrcweir                     pBitCounts[2] =
1924*cdf0e10cSrcweir                     pBitCounts[3] = 8;
1925*cdf0e10cSrcweir             }
1926*cdf0e10cSrcweir         };
1927*cdf0e10cSrcweir 
1928*cdf0e10cSrcweir         struct CairoColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
1929*cdf0e10cSrcweir                                                                      CairoColorSpaceHolder>
1930*cdf0e10cSrcweir         {
1931*cdf0e10cSrcweir             uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
1932*cdf0e10cSrcweir             {
1933*cdf0e10cSrcweir                 return new CairoColorSpace();
1934*cdf0e10cSrcweir             }
1935*cdf0e10cSrcweir         };
1936*cdf0e10cSrcweir     }
1937*cdf0e10cSrcweir 
1938*cdf0e10cSrcweir     rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout()
1939*cdf0e10cSrcweir     {
1940*cdf0e10cSrcweir         if( !mpCairo )
1941*cdf0e10cSrcweir             return rendering::IntegerBitmapLayout(); // we're disposed
1942*cdf0e10cSrcweir 
1943*cdf0e10cSrcweir         const geometry::IntegerSize2D aSize(getSize());
1944*cdf0e10cSrcweir         rendering::IntegerBitmapLayout aLayout;
1945*cdf0e10cSrcweir 
1946*cdf0e10cSrcweir         aLayout.ScanLines = aSize.Height;
1947*cdf0e10cSrcweir         aLayout.ScanLineBytes = aSize.Width*4;
1948*cdf0e10cSrcweir         aLayout.ScanLineStride = aLayout.ScanLineBytes;
1949*cdf0e10cSrcweir         aLayout.PlaneStride = 0;
1950*cdf0e10cSrcweir         aLayout.ColorSpace = CairoColorSpaceHolder::get();
1951*cdf0e10cSrcweir         aLayout.Palette.clear();
1952*cdf0e10cSrcweir         aLayout.IsMsbFirst = sal_False;
1953*cdf0e10cSrcweir 
1954*cdf0e10cSrcweir         return aLayout;
1955*cdf0e10cSrcweir     }
1956*cdf0e10cSrcweir 
1957*cdf0e10cSrcweir     void CanvasHelper::flush() const
1958*cdf0e10cSrcweir     {
1959*cdf0e10cSrcweir     }
1960*cdf0e10cSrcweir 
1961*cdf0e10cSrcweir     bool CanvasHelper::hasAlpha() const
1962*cdf0e10cSrcweir     {
1963*cdf0e10cSrcweir         return mbHaveAlpha;
1964*cdf0e10cSrcweir     }
1965*cdf0e10cSrcweir 
1966*cdf0e10cSrcweir     bool CanvasHelper::repaint( const SurfaceSharedPtr& pSurface,
1967*cdf0e10cSrcweir 								const rendering::ViewState&      viewState,
1968*cdf0e10cSrcweir 								const rendering::RenderState&	 renderState )
1969*cdf0e10cSrcweir     {
1970*cdf0e10cSrcweir 		OSL_TRACE("CanvasHelper::repaint");
1971*cdf0e10cSrcweir 
1972*cdf0e10cSrcweir 		if( mpCairo ) {
1973*cdf0e10cSrcweir 			cairo_save( mpCairo.get() );
1974*cdf0e10cSrcweir 
1975*cdf0e10cSrcweir 			cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
1976*cdf0e10cSrcweir 			cairo_clip( mpCairo.get() );
1977*cdf0e10cSrcweir 
1978*cdf0e10cSrcweir 			useStates( viewState, renderState, true );
1979*cdf0e10cSrcweir 
1980*cdf0e10cSrcweir 			Matrix aMatrix;
1981*cdf0e10cSrcweir 
1982*cdf0e10cSrcweir 			cairo_get_matrix( mpCairo.get(), &aMatrix );
1983*cdf0e10cSrcweir 			aMatrix.xx = aMatrix.yy = 1;
1984*cdf0e10cSrcweir 			cairo_set_matrix( mpCairo.get(), &aMatrix );
1985*cdf0e10cSrcweir 
1986*cdf0e10cSrcweir 			//   	    if( !bHasAlpha )
1987*cdf0e10cSrcweir 			//   		cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
1988*cdf0e10cSrcweir 
1989*cdf0e10cSrcweir 			cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
1990*cdf0e10cSrcweir 			cairo_paint( mpCairo.get() );
1991*cdf0e10cSrcweir 			cairo_restore( mpCairo.get() );
1992*cdf0e10cSrcweir 		}
1993*cdf0e10cSrcweir 
1994*cdf0e10cSrcweir 		return true;
1995*cdf0e10cSrcweir     }
1996*cdf0e10cSrcweir }
1997