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