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