Branch libreoffice-5-0-4
[LibreOffice.git] / canvas / source / cairo / cairo_canvashelper.cxx
blob64686fce6bd05de93c184f92d6278fcb76a3492d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <canvas/debug.hxx>
21 #include <tools/diagnose_ex.h>
23 #include <rtl/math.hxx>
24 #include <rtl/instance.hxx>
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>
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>
47 #include <comphelper/sequence.hxx>
48 #include <cppuhelper/compbase1.hxx>
50 #include <canvas/canvastools.hxx>
51 #include <canvas/parametricpolypolygon.hxx>
53 #include <vcl/canvastools.hxx>
54 #include <vcl/bitmapex.hxx>
55 #include <vcl/bmpacc.hxx>
56 #include <vcl/virdev.hxx>
58 #include "cairo_spritecanvas.hxx"
59 #include "cairo_cachedbitmap.hxx"
60 #include "cairo_canvashelper.hxx"
61 #include "cairo_canvasbitmap.hxx"
63 #include <boost/tuple/tuple.hpp>
64 #include <algorithm>
66 using namespace ::cairo;
67 using namespace ::com::sun::star;
69 namespace cairocanvas
71 CanvasHelper::CanvasHelper() :
72 mpSurfaceProvider(NULL),
73 mpDevice(NULL),
74 mpVirtualDevice(),
75 mbHaveAlpha(),
76 mpCairo(),
77 mpSurface(),
78 maSize()
82 void CanvasHelper::disposing()
84 mpSurface.reset();
85 mpCairo.reset();
86 mpVirtualDevice.disposeAndClear();
87 mpDevice = NULL;
88 mpSurfaceProvider = NULL;
91 void CanvasHelper::init( const ::basegfx::B2ISize& rSizePixel,
92 SurfaceProvider& rSurfaceProvider,
93 rendering::XGraphicDevice* pDevice )
95 maSize = rSizePixel;
96 mpSurfaceProvider = &rSurfaceProvider;
97 mpDevice = pDevice;
100 void CanvasHelper::setSize( const ::basegfx::B2ISize& rSize )
102 maSize = rSize;
105 void CanvasHelper::setSurface( const SurfaceSharedPtr& pSurface, bool bHasAlpha )
107 mbHaveAlpha = bHasAlpha;
108 mpVirtualDevice.disposeAndClear();
109 mpSurface = pSurface;
110 mpCairo = pSurface->getCairo();
113 static void setColor( cairo_t* pCairo,
114 const uno::Sequence<double>& rColor )
116 if( rColor.getLength() > 3 )
118 cairo_set_source_rgba( pCairo,
119 rColor[0],
120 rColor[1],
121 rColor[2],
122 rColor[3] );
124 else if( rColor.getLength() == 3 )
125 cairo_set_source_rgb( pCairo,
126 rColor[0],
127 rColor[1],
128 rColor[2] );
131 void CanvasHelper::useStates( const rendering::ViewState& viewState,
132 const rendering::RenderState& renderState,
133 bool bSetColor )
135 cairo_matrix_t aViewMatrix;
136 cairo_matrix_t aRenderMatrix;
137 cairo_matrix_t aCombinedMatrix;
139 cairo_matrix_init( &aViewMatrix,
140 viewState.AffineTransform.m00, viewState.AffineTransform.m10, viewState.AffineTransform.m01,
141 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 renderState.AffineTransform.m11, renderState.AffineTransform.m02, renderState.AffineTransform.m12);
145 cairo_matrix_multiply( &aCombinedMatrix, &aRenderMatrix, &aViewMatrix);
147 if( viewState.Clip.is() )
149 SAL_INFO( "canvas.cairo", "view clip");
151 aViewMatrix.x0 = basegfx::fround( aViewMatrix.x0 );
152 aViewMatrix.y0 = basegfx::fround( aViewMatrix.y0 );
153 cairo_set_matrix( mpCairo.get(), &aViewMatrix );
154 doPolyPolygonPath( viewState.Clip, Clip );
157 aCombinedMatrix.x0 = basegfx::fround( aCombinedMatrix.x0 );
158 aCombinedMatrix.y0 = basegfx::fround( aCombinedMatrix.y0 );
159 cairo_set_matrix( mpCairo.get(), &aCombinedMatrix );
161 if( renderState.Clip.is() )
163 SAL_INFO( "canvas.cairo", "render clip BEGIN");
165 doPolyPolygonPath( renderState.Clip, Clip );
166 SAL_INFO( "canvas.cairo", "render clip END");
169 if( bSetColor )
170 setColor(mpCairo.get(),renderState.DeviceColor);
172 cairo_operator_t compositingMode( CAIRO_OPERATOR_OVER );
173 switch( renderState.CompositeOperation )
175 case rendering::CompositeOperation::CLEAR:
176 compositingMode = CAIRO_OPERATOR_CLEAR;
177 break;
178 case rendering::CompositeOperation::SOURCE:
179 compositingMode = CAIRO_OPERATOR_SOURCE;
180 break;
181 case rendering::CompositeOperation::DESTINATION:
182 compositingMode = CAIRO_OPERATOR_DEST;
183 break;
184 case rendering::CompositeOperation::OVER:
185 compositingMode = CAIRO_OPERATOR_OVER;
186 break;
187 case rendering::CompositeOperation::UNDER:
188 compositingMode = CAIRO_OPERATOR_DEST;
189 break;
190 case rendering::CompositeOperation::INSIDE:
191 compositingMode = CAIRO_OPERATOR_IN;
192 break;
193 case rendering::CompositeOperation::INSIDE_REVERSE:
194 compositingMode = CAIRO_OPERATOR_OUT;
195 break;
196 case rendering::CompositeOperation::OUTSIDE:
197 compositingMode = CAIRO_OPERATOR_DEST_OVER;
198 break;
199 case rendering::CompositeOperation::OUTSIDE_REVERSE:
200 compositingMode = CAIRO_OPERATOR_DEST_OUT;
201 break;
202 case rendering::CompositeOperation::ATOP:
203 compositingMode = CAIRO_OPERATOR_ATOP;
204 break;
205 case rendering::CompositeOperation::ATOP_REVERSE:
206 compositingMode = CAIRO_OPERATOR_DEST_ATOP;
207 break;
208 case rendering::CompositeOperation::XOR:
209 compositingMode = CAIRO_OPERATOR_XOR;
210 break;
211 case rendering::CompositeOperation::ADD:
212 compositingMode = CAIRO_OPERATOR_ADD;
213 break;
214 case rendering::CompositeOperation::SATURATE:
215 compositingMode = CAIRO_OPERATOR_SATURATE;
216 break;
218 cairo_set_operator( mpCairo.get(), compositingMode );
221 void CanvasHelper::clear()
223 SAL_INFO( "canvas.cairo", "clear whole area: " << maSize.getX() << " x " << maSize.getY() );
225 if( mpCairo )
227 cairo_save( mpCairo.get() );
229 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 if( mbHaveAlpha )
234 cairo_set_source_rgba( mpCairo.get(), 1.0, 1.0, 1.0, 0.0 );
235 else
236 cairo_set_source_rgb( mpCairo.get(), 1.0, 1.0, 1.0 );
237 cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
239 cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
240 cairo_fill( mpCairo.get() );
242 cairo_restore( mpCairo.get() );
246 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 )
252 if( mpCairo )
254 cairo_save( mpCairo.get() );
256 cairo_set_line_width( mpCairo.get(), 1 );
258 useStates( viewState, renderState, true );
260 cairo_move_to( mpCairo.get(), aStartPoint.X + 0.5, aStartPoint.Y + 0.5 );
261 cairo_line_to( mpCairo.get(), aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
262 cairo_stroke( mpCairo.get() );
264 cairo_restore( mpCairo.get() );
268 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 )
274 if( mpCairo )
276 cairo_save( mpCairo.get() );
278 cairo_set_line_width( mpCairo.get(), 1 );
280 useStates( viewState, renderState, true );
282 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 aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
287 cairo_stroke( mpCairo.get() );
289 cairo_restore( mpCairo.get() );
293 #define PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME "Canvas::ParametricPolyPolygon"
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
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.
302 * @return created surface or NULL
304 static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap )
306 CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() );
307 if( pBitmapImpl )
308 return pBitmapImpl->getSurface();
310 SurfaceProvider* pSurfaceProvider = dynamic_cast<SurfaceProvider*>( xBitmap.get() );
311 if( pSurfaceProvider )
312 return pSurfaceProvider->getSurface();
314 return SurfaceSharedPtr();
317 static ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap )
319 // TODO(F1): Add support for floating point bitmap formats
320 uno::Reference<rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap,
321 uno::UNO_QUERY_THROW);
322 ::BitmapEx aBmpEx = vcl::unotools::bitmapExFromXBitmap(xIntBmp);
323 if( !!aBmpEx )
324 return aBmpEx;
326 // TODO(F1): extract pixel from XBitmap interface
327 ENSURE_OR_THROW( false,
328 "bitmapExFromXBitmap(): could not extract BitmapEx" );
330 return ::BitmapEx();
333 static sal_uInt8 lcl_GetColor(BitmapColor const& rColor)
335 sal_uInt8 nTemp(0);
336 if (rColor.IsIndex())
338 nTemp = rColor.GetIndex();
340 else
342 nTemp = rColor.GetBlue();
343 // greyscale expected here, or what would non-grey colors mean?
344 assert(rColor.GetRed() == nTemp && rColor.GetGreen() == nTemp);
346 return nTemp;
349 static bool readAlpha( BitmapReadAccess* pAlphaReadAcc, long nY, const long nWidth, unsigned char* data, long nOff )
351 bool bIsAlpha = false;
352 long nX;
353 int nAlpha;
354 Scanline pReadScan;
356 nOff += 3;
358 switch( pAlphaReadAcc->GetScanlineFormat() )
360 case BMP_FORMAT_8BIT_TC_MASK:
361 pReadScan = pAlphaReadAcc->GetScanline( nY );
362 for( nX = 0; nX < nWidth; nX++ )
364 nAlpha = data[ nOff ] = 255 - ( *pReadScan++ );
365 if( nAlpha != 255 )
366 bIsAlpha = true;
367 nOff += 4;
369 break;
370 case BMP_FORMAT_8BIT_PAL:
371 pReadScan = pAlphaReadAcc->GetScanline( nY );
372 for( nX = 0; nX < nWidth; nX++ )
374 BitmapColor const& rColor(
375 pAlphaReadAcc->GetPaletteColor(*pReadScan));
376 pReadScan++;
377 nAlpha = data[ nOff ] = 255 - lcl_GetColor(rColor);
378 if( nAlpha != 255 )
379 bIsAlpha = true;
380 nOff += 4;
382 break;
383 default:
384 SAL_INFO( "canvas.cairo", "fallback to GetColor for alpha - slow, format: " << pAlphaReadAcc->GetScanlineFormat() );
385 for( nX = 0; nX < nWidth; nX++ )
387 nAlpha = data[ nOff ] = 255 - pAlphaReadAcc->GetColor( nY, nX ).GetIndex();
388 if( nAlpha != 255 )
389 bIsAlpha = true;
390 nOff += 4;
394 return bIsAlpha;
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
404 * This function tries various methods for creating a surface from xBitmap. It also uses
405 * the helper function surfaceFromXBitmap( xBitmap, bHasAlpha )
407 * @return created surface or NULL
409 static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, const SurfaceProviderRef& rSurfaceProvider, unsigned char*& data, bool& bHasAlpha )
411 bHasAlpha = xBitmap->hasAlpha();
412 SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap );
413 if( pSurface )
414 data = NULL;
415 else
417 ::BitmapEx aBmpEx = bitmapExFromXBitmap(xBitmap);
418 ::Bitmap aBitmap = aBmpEx.GetBitmap();
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 if( !aBmpEx.IsTransparent() && !aBmpEx.IsAlpha() )
425 pSurface = rSurfaceProvider->createSurface( aBitmap );
426 data = NULL;
427 bHasAlpha = false;
430 if( !pSurface )
432 AlphaMask aAlpha = aBmpEx.GetAlpha();
434 ::BitmapReadAccess* pBitmapReadAcc = aBitmap.AcquireReadAccess();
435 ::BitmapReadAccess* pAlphaReadAcc = NULL;
436 const long nWidth = pBitmapReadAcc->Width();
437 const long nHeight = pBitmapReadAcc->Height();
438 long nX, nY;
439 bool bIsAlpha = false;
441 if( aBmpEx.IsTransparent() || aBmpEx.IsAlpha() )
442 pAlphaReadAcc = aAlpha.AcquireReadAccess();
444 data = static_cast<unsigned char*>(malloc( nWidth*nHeight*4 ));
446 long nOff = 0;
447 ::Color aColor;
448 unsigned int nAlpha = 255;
450 for( nY = 0; nY < nHeight; nY++ )
452 ::Scanline pReadScan;
454 switch( pBitmapReadAcc->GetScanlineFormat() )
456 case BMP_FORMAT_8BIT_PAL:
457 pReadScan = pBitmapReadAcc->GetScanline( nY );
458 if( pAlphaReadAcc )
459 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
460 bIsAlpha = true;
462 for( nX = 0; nX < nWidth; nX++ )
464 #ifdef OSL_BIGENDIAN
465 if( pAlphaReadAcc )
466 nAlpha = data[ nOff++ ];
467 else
468 nAlpha = data[ nOff++ ] = 255;
469 #else
470 if( pAlphaReadAcc )
471 nAlpha = data[ nOff + 3 ];
472 else
473 nAlpha = data[ nOff + 3 ] = 255;
474 #endif
475 aColor = pBitmapReadAcc->GetPaletteColor( *pReadScan++ );
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 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 );
483 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 );
484 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 );
485 nOff++;
486 #endif
488 break;
489 case BMP_FORMAT_24BIT_TC_BGR:
490 pReadScan = pBitmapReadAcc->GetScanline( nY );
491 if( pAlphaReadAcc )
492 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
493 bIsAlpha = true;
495 for( nX = 0; nX < nWidth; nX++ )
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 if( pAlphaReadAcc )
508 nAlpha = data[ nOff + 3 ];
509 else
510 nAlpha = data[ nOff + 3 ] = 255;
511 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
512 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
513 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
514 nOff++;
515 #endif
517 break;
518 case BMP_FORMAT_24BIT_TC_RGB:
519 pReadScan = pBitmapReadAcc->GetScanline( nY );
520 if( pAlphaReadAcc )
521 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
522 bIsAlpha = true;
524 for( nX = 0; nX < nWidth; nX++ )
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 if( pAlphaReadAcc )
536 nAlpha = data[ nOff + 3 ];
537 else
538 nAlpha = data[ nOff + 3 ] = 255;
539 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
540 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
541 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
542 pReadScan += 3;
543 nOff++;
544 #endif
546 break;
547 case BMP_FORMAT_32BIT_TC_BGRA:
548 pReadScan = pBitmapReadAcc->GetScanline( nY );
549 if( pAlphaReadAcc )
550 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
551 bIsAlpha = true;
553 for( nX = 0; nX < nWidth; nX++ )
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 if( pAlphaReadAcc )
566 nAlpha = data[ nOff + 3 ];
567 else
568 nAlpha = data[ nOff + 3 ] = 255;
569 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
570 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
571 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
572 pReadScan++;
573 nOff++;
574 #endif
576 break;
577 case BMP_FORMAT_32BIT_TC_RGBA:
578 pReadScan = pBitmapReadAcc->GetScanline( nY );
579 if( pAlphaReadAcc )
580 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
581 bIsAlpha = true;
583 for( nX = 0; nX < nWidth; nX++ )
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 if( pAlphaReadAcc )
596 nAlpha = data[ nOff + 3 ];
597 else
598 nAlpha = data[ nOff + 3 ] = 255;
599 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
600 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
601 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
602 pReadScan += 4;
603 nOff++;
604 #endif
606 break;
607 default:
608 SAL_INFO( "canvas.cairo", "fallback to GetColor - slow, format: " << pBitmapReadAcc->GetScanlineFormat() );
610 if( pAlphaReadAcc )
611 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
612 bIsAlpha = true;
614 for( nX = 0; nX < nWidth; nX++ )
616 aColor = pBitmapReadAcc->GetColor( nY, nX );
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 if( pAlphaReadAcc )
630 nAlpha = data[ nOff + 3 ];
631 else
632 nAlpha = data[ nOff + 3 ] = 255;
633 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 );
634 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 );
635 data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 );
636 nOff ++;
637 #endif
642 ::Bitmap::ReleaseAccess( pBitmapReadAcc );
643 if( pAlphaReadAcc )
644 aAlpha.ReleaseAccess( pAlphaReadAcc );
646 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 &cairo_surface_destroy) );
653 pSurface = pImageSurface;
655 bHasAlpha = bIsAlpha;
657 SAL_INFO( "canvas.cairo","image: " << nWidth << " x " << nHeight << " alpha: " << bIsAlpha << " alphaRead " << std::hex << pAlphaReadAcc);
661 return pSurface;
664 static void addColorStops( cairo_pattern_t* pPattern, const uno::Sequence< uno::Sequence< double > >& rColors, const uno::Sequence< double >& rStops, bool bReverseStops = false )
666 int i;
668 OSL_ASSERT( rColors.getLength() == rStops.getLength() );
670 for( i = 0; i < rColors.getLength(); i++ )
672 const uno::Sequence< double >& rColor( rColors[i] );
673 float stop = bReverseStops ? 1 - rStops[i] : rStops[i];
674 if( rColor.getLength() == 3 )
675 cairo_pattern_add_color_stop_rgb( pPattern, stop, rColor[0], rColor[1], rColor[2] );
676 else if( rColor.getLength() == 4 )
678 double alpha = rColor[3];
679 // cairo expects premultiplied alpha
680 cairo_pattern_add_color_stop_rgba( pPattern, stop, rColor[0]*alpha, rColor[1]*alpha, rColor[2]*alpha, alpha );
685 static uno::Sequence<double> lerp(const uno::Sequence<double>& rLeft, const uno::Sequence<double>& rRight, double fAlpha)
687 if( rLeft.getLength() == 3 )
689 uno::Sequence<double> aRes(3);
690 aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha);
691 aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha);
692 aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha);
693 return aRes;
695 else if( rLeft.getLength() == 4 )
697 uno::Sequence<double> aRes(4);
698 aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha);
699 aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha);
700 aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha);
701 aRes[3] = basegfx::tools::lerp(rLeft[3],rRight[3],fAlpha);
702 return aRes;
705 return uno::Sequence<double>();
708 static cairo_pattern_t* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon& rPolygon )
710 cairo_pattern_t* pPattern = NULL;
711 const ::canvas::ParametricPolyPolygon::Values aValues = rPolygon.getValues();
712 double x0, x1, y0, y1, cx, cy, r0, r1;
714 switch( aValues.meType )
716 case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR:
717 x0 = 0;
718 y0 = 0;
719 x1 = 1;
720 y1 = 0;
721 pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
722 addColorStops( pPattern, aValues.maColors, aValues.maStops );
723 break;
725 case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
726 cx = 0;
727 cy = 0;
728 r0 = 0;
729 r1 = 1;
731 pPattern = cairo_pattern_create_radial( cx, cy, r0, cy, cy, r1 );
732 addColorStops( pPattern, aValues.maColors, aValues.maStops, true );
733 break;
734 default:
735 break;
738 return pPattern;
741 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 )
747 switch( aOperation )
749 case Fill:
750 /* TODO: multitexturing */
751 if( pTextures )
753 const ::com::sun::star::rendering::Texture& aTexture ( (*pTextures)[0] );
754 if( aTexture.Bitmap.is() )
756 unsigned char* data = NULL;
757 bool bHasAlpha = false;
758 SurfaceSharedPtr pSurface = surfaceFromXBitmap( (*pTextures)[0].Bitmap, pDevice, data, bHasAlpha );
760 if( pSurface )
762 cairo_pattern_t* pPattern;
764 cairo_save( pCairo );
766 ::com::sun::star::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform );
767 cairo_matrix_t aScaleMatrix, aTextureMatrix, aScaledTextureMatrix;
769 cairo_matrix_init( &aTextureMatrix,
770 aTransform.m00, aTransform.m10, aTransform.m01,
771 aTransform.m11, aTransform.m02, aTransform.m12);
773 geometry::IntegerSize2D aSize = aTexture.Bitmap->getSize();
775 cairo_matrix_init_scale( &aScaleMatrix, 1.0/aSize.Width, 1.0/aSize.Height );
776 cairo_matrix_multiply( &aScaledTextureMatrix, &aTextureMatrix, &aScaleMatrix );
777 cairo_matrix_invert( &aScaledTextureMatrix );
779 // we don't care about repeat mode yet, so the workaround is disabled for now
780 pPattern = cairo_pattern_create_for_surface( pSurface->getCairoSurface().get() );
782 if( aTexture.RepeatModeX == rendering::TexturingMode::REPEAT &&
783 aTexture.RepeatModeY == rendering::TexturingMode::REPEAT )
785 cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_REPEAT );
787 else if ( aTexture.RepeatModeX == rendering::TexturingMode::NONE &&
788 aTexture.RepeatModeY == rendering::TexturingMode::NONE )
790 cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_NONE );
792 else if ( aTexture.RepeatModeX == rendering::TexturingMode::CLAMP &&
793 aTexture.RepeatModeY == rendering::TexturingMode::CLAMP )
795 cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_PAD );
798 aScaledTextureMatrix.x0 = basegfx::fround( aScaledTextureMatrix.x0 );
799 aScaledTextureMatrix.y0 = basegfx::fround( aScaledTextureMatrix.y0 );
800 cairo_pattern_set_matrix( pPattern, &aScaledTextureMatrix );
802 cairo_set_source( pCairo, pPattern );
803 if( !bHasAlpha )
804 cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
805 cairo_fill( pCairo );
807 cairo_restore( pCairo );
809 cairo_pattern_destroy( pPattern );
812 if( data )
813 free( data );
815 else if( aTexture.Gradient.is() )
817 uno::Reference< lang::XServiceInfo > xRef( aTexture.Gradient, uno::UNO_QUERY );
819 SAL_INFO( "canvas.cairo", "gradient fill" );
820 if( xRef.is() && xRef->getImplementationName() == PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME )
822 // TODO(Q1): Maybe use dynamic_cast here
824 // TODO(E1): Return value
825 // TODO(F1): FillRule
826 SAL_INFO( "canvas.cairo", "known implementation" );
828 ::canvas::ParametricPolyPolygon* pPolyImpl = static_cast< ::canvas::ParametricPolyPolygon* >( aTexture.Gradient.get() );
829 ::com::sun::star::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform );
830 cairo_matrix_t aTextureMatrix;
832 cairo_matrix_init( &aTextureMatrix,
833 aTransform.m00, aTransform.m10, aTransform.m01,
834 aTransform.m11, aTransform.m02, aTransform.m12);
835 if( pPolyImpl->getValues().meType == canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR )
837 // no general path gradient yet in cairo; emulate then
838 cairo_save( pCairo );
839 cairo_clip( pCairo );
841 // fill bound rect with start color
842 cairo_rectangle( pCairo, rBounds.getMinX(), rBounds.getMinY(),
843 rBounds.getWidth(), rBounds.getHeight() );
844 setColor(pCairo,pPolyImpl->getValues().maColors[0]);
845 cairo_fill(pCairo);
847 cairo_transform( pCairo, &aTextureMatrix );
849 // longest line in gradient bound rect
850 const unsigned int nGradientSize(
851 static_cast<unsigned int>(
852 ::basegfx::B2DVector(rBounds.getMinimum() - rBounds.getMaximum()).getLength() + 1.0 ) );
854 // typical number for pixel of the same color (strip size)
855 const unsigned int nStripSize( nGradientSize < 50 ? 2 : 4 );
857 // use at least three steps, and at utmost the number of color
858 // steps
859 const unsigned int nStepCount(
860 ::std::max(
862 ::std::min(
863 nGradientSize / nStripSize,
864 128U )) + 1 );
866 const uno::Sequence<double>* pColors=&pPolyImpl->getValues().maColors[0];
867 basegfx::tools::KeyStopLerp aLerper(pPolyImpl->getValues().maStops);
868 for( unsigned int i=1; i<nStepCount; ++i )
870 const double fT( i/double(nStepCount) );
872 std::ptrdiff_t nIndex;
873 double fAlpha;
874 boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
876 setColor(pCairo, lerp(pColors[nIndex], pColors[nIndex+1], fAlpha));
877 cairo_rectangle( pCairo, -1+fT, -1+fT, 2-2*fT, 2-2*fT );
878 cairo_fill(pCairo);
881 cairo_restore( pCairo );
883 else
885 cairo_pattern_t* pPattern = patternFromParametricPolyPolygon( *pPolyImpl );
887 if( pPattern )
889 SAL_INFO( "canvas.cairo", "filling with pattern" );
891 cairo_save( pCairo );
893 cairo_transform( pCairo, &aTextureMatrix );
894 cairo_set_source( pCairo, pPattern );
895 cairo_fill( pCairo );
896 cairo_restore( pCairo );
898 cairo_pattern_destroy( pPattern );
904 else
905 cairo_fill( pCairo );
906 SAL_INFO( "canvas.cairo", "fill");
907 break;
908 case Stroke:
909 cairo_stroke( pCairo );
910 SAL_INFO( "canvas.cairo", "stroke");
911 break;
912 case Clip:
913 cairo_clip( pCairo );
914 SAL_INFO( "canvas.cairo", "clip");
915 break;
919 static void clipNULL( cairo_t *pCairo )
921 SAL_INFO( "canvas.cairo", "clipNULL");
922 cairo_matrix_t aOrigMatrix, aIdentityMatrix;
924 /* we set identity matrix here to overcome bug in cairo 0.9.2
925 where XCreatePixmap is called with zero width and height.
927 it also reaches faster path in cairo clipping code.
929 cairo_matrix_init_identity( &aIdentityMatrix );
930 cairo_get_matrix( pCairo, &aOrigMatrix );
931 cairo_set_matrix( pCairo, &aIdentityMatrix );
933 cairo_reset_clip( pCairo );
934 cairo_rectangle( pCairo, 0, 0, 1, 1 );
935 cairo_clip( pCairo );
936 cairo_rectangle( pCairo, 2, 0, 1, 1 );
937 cairo_clip( pCairo );
939 /* restore the original matrix */
940 cairo_set_matrix( pCairo, &aOrigMatrix );
943 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 )
950 if( pTextures )
951 ENSURE_ARG_OR_THROW( pTextures->getLength(),
952 "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence");
954 bool bOpToDo = false;
955 cairo_matrix_t aOrigMatrix, aIdentityMatrix;
956 double nX, nY, nBX, nBY, nAX, nAY;
958 cairo_get_matrix( pCairo, &aOrigMatrix );
959 cairo_matrix_init_identity( &aIdentityMatrix );
960 cairo_set_matrix( pCairo, &aIdentityMatrix );
962 cairo_set_fill_rule( pCairo,
963 eFillrule == rendering::FillRule_EVEN_ODD ?
964 CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING );
966 for( sal_uInt32 nPolygonIndex = 0; nPolygonIndex < aPolyPolygon.count(); nPolygonIndex++ )
968 ::basegfx::B2DPolygon aPolygon( aPolyPolygon.getB2DPolygon( nPolygonIndex ) );
969 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 const sal_uInt32 nExtendedPointCount( nPointCount +
973 int(aPolygon.isClosed() && aPolygon.areControlPointsUsed()) );
975 if( nPointCount > 1)
977 bool bIsBezier = aPolygon.areControlPointsUsed();
978 bool bIsRectangle = ::basegfx::tools::isRectangle( aPolygon );
979 ::basegfx::B2DPoint aA, aB, aP;
981 for( sal_uInt32 j=0; j < nExtendedPointCount; j++ )
983 aP = aPolygon.getB2DPoint( j % nPointCount );
985 nX = aP.getX();
986 nY = aP.getY();
987 cairo_matrix_transform_point( &aOrigMatrix, &nX, &nY );
989 if( ! bIsBezier && (bIsRectangle || aOperation == Clip) )
991 nX = basegfx::fround( nX );
992 nY = basegfx::fround( nY );
995 if( aOperation == Stroke )
997 nX += 0.5;
998 nY += 0.5;
1001 if( j==0 )
1003 cairo_move_to( pCairo, nX, nY );
1004 SAL_INFO( "canvas.cairo", "move to " << nX << "," << nY );
1006 else
1008 if( bIsBezier )
1010 aA = aPolygon.getNextControlPoint( (j-1) % nPointCount );
1011 aB = aPolygon.getPrevControlPoint( j % nPointCount );
1013 nAX = aA.getX();
1014 nAY = aA.getY();
1015 nBX = aB.getX();
1016 nBY = aB.getY();
1018 cairo_matrix_transform_point( &aOrigMatrix, &nAX, &nAY );
1019 cairo_matrix_transform_point( &aOrigMatrix, &nBX, &nBY );
1021 if( aOperation == Stroke )
1023 nAX += 0.5;
1024 nAY += 0.5;
1025 nBX += 0.5;
1026 nBY += 0.5;
1029 cairo_curve_to( pCairo, nAX, nAY, nBX, nBY, nX, nY );
1031 else
1033 cairo_line_to( pCairo, nX, nY );
1034 SAL_INFO( "canvas.cairo", "line to " << nX << "," << nY );
1036 bOpToDo = true;
1040 if( aPolygon.isClosed() )
1041 cairo_close_path( pCairo );
1044 else
1046 SAL_INFO( "canvas.cairo", "empty polygon for op: " << aOperation );
1047 if( aOperation == Clip )
1049 clipNULL( pCairo );
1051 return;
1056 if( aOperation == Fill && pTextures )
1058 cairo_set_matrix( pCairo, &aOrigMatrix );
1059 doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
1060 cairo_set_matrix( pCairo, &aIdentityMatrix );
1063 if( bOpToDo && ( aOperation != Fill || !pTextures ) )
1064 doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
1066 cairo_set_matrix( pCairo, &aOrigMatrix );
1068 if( aPolyPolygon.count() == 0 && aOperation == Clip )
1069 clipNULL( pCairo );
1072 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
1078 const ::basegfx::B2DPolyPolygon& rPolyPoly(
1079 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) );
1081 if( !pCairo )
1082 pCairo = mpCairo.get();
1084 if(bNoLineJoin && Stroke == aOperation)
1086 // emulate rendering::PathJoinType::NONE by painting single edges
1087 for(sal_uInt32 a(0); a < rPolyPoly.count(); a++)
1089 const basegfx::B2DPolygon aCandidate(rPolyPoly.getB2DPolygon(a));
1090 const sal_uInt32 nPointCount(aCandidate.count());
1092 if(nPointCount)
1094 const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount: nPointCount - 1);
1095 basegfx::B2DPolygon aEdge;
1096 aEdge.append(aCandidate.getB2DPoint(0));
1097 aEdge.append(basegfx::B2DPoint(0.0, 0.0));
1099 for(sal_uInt32 b(0); b < nEdgeCount; b++)
1101 const sal_uInt32 nNextIndex((b + 1) % nPointCount);
1102 aEdge.setB2DPoint(1, aCandidate.getB2DPoint(nNextIndex));
1103 aEdge.setNextControlPoint(0, aCandidate.getNextControlPoint(b % nPointCount));
1104 aEdge.setPrevControlPoint(1, aCandidate.getPrevControlPoint(nNextIndex));
1106 doPolyPolygonImplementation( basegfx::B2DPolyPolygon(aEdge),
1107 aOperation,
1108 pCairo, pTextures,
1109 mpSurfaceProvider,
1110 xPolyPolygon->getFillRule() );
1112 // prepare next step
1113 aEdge.setB2DPoint(0, aEdge.getB2DPoint(1));
1118 else
1120 doPolyPolygonImplementation( rPolyPoly, aOperation,
1121 pCairo, pTextures,
1122 mpSurfaceProvider,
1123 xPolyPolygon->getFillRule() );
1127 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 )
1132 #ifdef CAIRO_CANVAS_PERF_TRACE
1133 struct timespec aTimer;
1134 mxDevice->startPerfTrace( &aTimer );
1135 #endif
1137 if( mpCairo )
1139 cairo_save( mpCairo.get() );
1141 cairo_set_line_width( mpCairo.get(), 1 );
1143 useStates( viewState, renderState, true );
1144 doPolyPolygonPath( xPolyPolygon, Stroke );
1146 cairo_restore( mpCairo.get() );
1148 else
1149 SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1151 #ifdef CAIRO_CANVAS_PERF_TRACE
1152 mxDevice->stopPerfTrace( &aTimer, "drawPolyPolygon" );
1153 #endif
1155 return uno::Reference< rendering::XCachedPrimitive >(NULL);
1158 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 )
1164 #ifdef CAIRO_CANVAS_PERF_TRACE
1165 struct timespec aTimer;
1166 mxDevice->startPerfTrace( &aTimer );
1167 #endif
1169 if( mpCairo )
1171 cairo_save( mpCairo.get() );
1173 useStates( viewState, renderState, true );
1175 cairo_matrix_t aMatrix;
1176 double w = strokeAttributes.StrokeWidth, h = 0;
1177 cairo_get_matrix( mpCairo.get(), &aMatrix );
1178 cairo_matrix_transform_distance( &aMatrix, &w, &h );
1179 cairo_set_line_width( mpCairo.get(), w );
1181 cairo_set_miter_limit( mpCairo.get(), strokeAttributes.MiterLimit );
1183 // FIXME: cairo doesn't handle end cap so far (rodo)
1184 switch( strokeAttributes.StartCapType )
1186 case rendering::PathCapType::BUTT:
1187 cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_BUTT );
1188 break;
1189 case rendering::PathCapType::ROUND:
1190 cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_ROUND );
1191 break;
1192 case rendering::PathCapType::SQUARE:
1193 cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_SQUARE );
1194 break;
1197 bool bNoLineJoin(false);
1199 switch( strokeAttributes.JoinType )
1201 case rendering::PathJoinType::NONE:
1202 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 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_MITER );
1206 break;
1207 case rendering::PathJoinType::ROUND:
1208 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_ROUND );
1209 break;
1210 case rendering::PathJoinType::BEVEL:
1211 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_BEVEL );
1212 break;
1215 if( strokeAttributes.DashArray.getLength() > 0 )
1217 double* pDashArray = new double[ strokeAttributes.DashArray.getLength() ];
1218 for( sal_Int32 i=0; i<strokeAttributes.DashArray.getLength(); i++ )
1219 pDashArray[i] = strokeAttributes.DashArray[i] * w;
1220 cairo_set_dash( mpCairo.get(), pDashArray, strokeAttributes.DashArray.getLength(), 0 );
1221 delete[] pDashArray;
1224 // TODO(rodo) use LineArray of strokeAttributes
1226 doPolyPolygonPath( xPolyPolygon, Stroke, bNoLineJoin );
1228 cairo_restore( mpCairo.get() );
1230 else
1231 SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1233 #ifdef CAIRO_CANVAS_PERF_TRACE
1234 mxDevice->stopPerfTrace( &aTimer, "strokePolyPolygon" );
1235 #endif
1237 // TODO(P1): Provide caching here.
1238 return uno::Reference< rendering::XCachedPrimitive >(NULL);
1241 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*/ )
1248 // TODO
1249 return uno::Reference< rendering::XCachedPrimitive >(NULL);
1252 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*/ )
1260 // TODO
1261 return uno::Reference< rendering::XCachedPrimitive >(NULL);
1264 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*/ )
1270 // TODO
1271 return uno::Reference< rendering::XPolyPolygon2D >(NULL);
1274 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 )
1279 #ifdef CAIRO_CANVAS_PERF_TRACE
1280 struct timespec aTimer;
1281 mxDevice->startPerfTrace( &aTimer );
1282 #endif
1284 if( mpCairo )
1286 cairo_save( mpCairo.get() );
1288 useStates( viewState, renderState, true );
1289 doPolyPolygonPath( xPolyPolygon, Fill );
1291 cairo_restore( mpCairo.get() );
1293 else
1294 SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1296 #ifdef CAIRO_CANVAS_PERF_TRACE
1297 mxDevice->stopPerfTrace( &aTimer, "fillPolyPolygon" );
1298 #endif
1300 return uno::Reference< rendering::XCachedPrimitive >(NULL);
1303 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 )
1309 if( mpCairo )
1311 cairo_save( mpCairo.get() );
1313 useStates( viewState, renderState, true );
1314 doPolyPolygonPath( xPolyPolygon, Fill, false, &textures );
1316 cairo_restore( mpCairo.get() );
1319 return uno::Reference< rendering::XCachedPrimitive >(NULL);
1322 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*/ )
1329 // TODO
1330 return uno::Reference< rendering::XCachedPrimitive >(NULL);
1333 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 )
1341 SurfaceSharedPtr pSurface=pInputSurface;
1342 uno::Reference< rendering::XCachedPrimitive > rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1343 geometry::IntegerSize2D aBitmapSize = rSize;
1345 if( mpCairo )
1347 cairo_save( mpCairo.get() );
1349 cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
1350 cairo_clip( mpCairo.get() );
1352 useStates( viewState, renderState, true );
1354 cairo_matrix_t aMatrix;
1356 cairo_get_matrix( mpCairo.get(), &aMatrix );
1357 if( ! ::rtl::math::approxEqual( aMatrix.xx, 1 ) &&
1358 ! ::rtl::math::approxEqual( aMatrix.yy, 1 ) &&
1359 ::rtl::math::approxEqual( aMatrix.x0, 0 ) &&
1360 ::rtl::math::approxEqual( aMatrix.y0, 0 ) &&
1361 basegfx::fround( rSize.Width * aMatrix.xx ) > 8 &&
1362 basegfx::fround( rSize.Height* aMatrix.yy ) > 8 )
1364 double dWidth, dHeight;
1366 dWidth = basegfx::fround( rSize.Width * aMatrix.xx );
1367 dHeight = basegfx::fround( rSize.Height* aMatrix.yy );
1368 aBitmapSize.Width = static_cast<sal_Int32>( dWidth );
1369 aBitmapSize.Height = static_cast<sal_Int32>( dHeight );
1371 SurfaceSharedPtr pScaledSurface = mpSurfaceProvider->createSurface(
1372 ::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ),
1373 bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
1374 CairoSharedPtr pCairo = pScaledSurface->getCairo();
1376 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 cairo_scale( pCairo.get(), (dWidth+0.5)/rSize.Width, (dHeight+0.5)/rSize.Height );
1379 cairo_set_source_surface( pCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
1380 cairo_paint( pCairo.get() );
1382 pSurface = pScaledSurface;
1384 aMatrix.xx = aMatrix.yy = 1;
1385 cairo_set_matrix( mpCairo.get(), &aMatrix );
1387 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 const_cast< rendering::XCanvas* >(pCanvas)) );
1396 if( !bHasAlpha && mbHaveAlpha )
1398 double x, y, width, height;
1400 x = y = 0;
1401 width = aBitmapSize.Width;
1402 height = aBitmapSize.Height;
1403 cairo_matrix_transform_point( &aMatrix, &x, &y );
1404 cairo_matrix_transform_distance( &aMatrix, &width, &height );
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 if( x <= 0 && y <= 0 && x + width >= maSize.getX() && y + height >= maSize.getY() )
1411 SAL_INFO( "canvas.cairo","trying to change surface to rgb");
1412 if( mpSurfaceProvider ) {
1413 SurfaceSharedPtr pNewSurface = mpSurfaceProvider->changeSurface( false, false );
1415 if( pNewSurface )
1416 setSurface( pNewSurface, false );
1418 // set state to new mpCairo.get()
1419 useStates( viewState, renderState, true );
1420 // use the possibly modified matrix
1421 cairo_set_matrix( mpCairo.get(), &aMatrix );
1426 cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
1427 if( !bHasAlpha &&
1428 ::rtl::math::approxEqual( aMatrix.xx, 1 ) &&
1429 ::rtl::math::approxEqual( aMatrix.yy, 1 ) &&
1430 ::rtl::math::approxEqual( aMatrix.x0, 0 ) &&
1431 ::rtl::math::approxEqual( aMatrix.y0, 0 ) )
1432 cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
1433 cairo_pattern_set_extend( cairo_get_source(mpCairo.get()), CAIRO_EXTEND_PAD );
1434 cairo_rectangle( mpCairo.get(), 0, 0, aBitmapSize.Width, aBitmapSize.Height );
1435 cairo_clip( mpCairo.get() );
1437 if( bModulateColors )
1438 cairo_paint_with_alpha( mpCairo.get(), renderState.DeviceColor[3] );
1439 else
1440 cairo_paint( mpCairo.get() );
1441 cairo_restore( mpCairo.get() );
1443 else
1444 SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1446 return rv; // uno::Reference< rendering::XCachedPrimitive >(NULL);
1449 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 )
1454 #ifdef CAIRO_CANVAS_PERF_TRACE
1455 struct timespec aTimer;
1456 mxDevice->startPerfTrace( &aTimer );
1457 #endif
1459 uno::Reference< rendering::XCachedPrimitive > rv;
1460 unsigned char* data = NULL;
1461 bool bHasAlpha = false;
1462 SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
1463 geometry::IntegerSize2D aSize = xBitmap->getSize();
1465 if( pSurface )
1467 rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, false, bHasAlpha );
1469 if( data )
1470 free( data );
1472 else
1473 rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1475 #ifdef CAIRO_CANVAS_PERF_TRACE
1476 mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1477 #endif
1479 return rv;
1482 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 )
1487 #ifdef CAIRO_CANVAS_PERF_TRACE
1488 struct timespec aTimer;
1489 mxDevice->startPerfTrace( &aTimer );
1490 #endif
1492 uno::Reference< rendering::XCachedPrimitive > rv;
1493 unsigned char* data = NULL;
1494 bool bHasAlpha = false;
1495 SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
1496 geometry::IntegerSize2D aSize = xBitmap->getSize();
1498 if( pSurface )
1500 rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, true, bHasAlpha );
1502 if( data )
1503 free( data );
1505 else
1506 rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1508 #ifdef CAIRO_CANVAS_PERF_TRACE
1509 mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1510 #endif
1512 return rv;
1516 geometry::IntegerSize2D CanvasHelper::getSize()
1518 if( !mpSurfaceProvider )
1519 geometry::IntegerSize2D(1, 1); // we're disposed
1521 return ::basegfx::unotools::integerSize2DFromB2ISize( maSize );
1524 uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D& newSize,
1525 bool /*beFast*/ )
1527 #ifdef CAIRO_CANVAS_PERF_TRACE
1528 struct timespec aTimer;
1529 mxDevice->startPerfTrace( &aTimer );
1530 #endif
1532 if( mpCairo )
1534 return uno::Reference< rendering::XBitmap >( new CanvasBitmap( ::basegfx::B2ISize( ::canvas::tools::roundUp( newSize.Width ),
1535 ::canvas::tools::roundUp( newSize.Height ) ),
1536 mpSurfaceProvider, mpDevice, false ) );
1538 else
1539 SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1541 #ifdef CAIRO_CANVAS_PERF_TRACE
1542 mxDevice->stopPerfTrace( &aTimer, "getScaledBitmap" );
1543 #endif
1545 return uno::Reference< rendering::XBitmap >();
1548 uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& aLayout,
1549 const geometry::IntegerRectangle2D& rect )
1551 if( mpCairo )
1553 const sal_Int32 nWidth( rect.X2 - rect.X1 );
1554 const sal_Int32 nHeight( rect.Y2 - rect.Y1 );
1555 const cairo_format_t eFormat( mbHaveAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24 );
1556 uno::Sequence< sal_Int8 > aRes( 4*nWidth*nHeight );
1557 sal_Int8* pData = aRes.getArray();
1558 cairo_surface_t* pImageSurface = cairo_image_surface_create_for_data( reinterpret_cast<unsigned char *>(pData),
1559 eFormat,
1560 nWidth, nHeight, 4*nWidth );
1561 cairo_t* pCairo = cairo_create( pImageSurface );
1562 cairo_set_source_surface( pCairo, mpSurface->getCairoSurface().get(), -rect.X1, -rect.Y1);
1563 cairo_paint( pCairo );
1564 cairo_destroy( pCairo );
1565 cairo_surface_destroy( pImageSurface );
1567 aLayout = impl_getMemoryLayout( nWidth, nHeight );
1569 return aRes;
1572 return uno::Sequence< sal_Int8 >();
1575 uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/,
1576 const geometry::IntegerPoint2D& /*pos*/ )
1578 return uno::Sequence< sal_Int8 >();
1581 namespace
1583 class CairoColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace >
1585 private:
1586 uno::Sequence< sal_Int8 > maComponentTags;
1587 uno::Sequence< sal_Int32 > maBitCounts;
1589 virtual ::sal_Int8 SAL_CALL getType( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1591 return rendering::ColorSpaceType::RGB;
1593 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1595 return maComponentTags;
1597 virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1599 return rendering::RenderingIntent::PERCEPTUAL;
1601 virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1603 return uno::Sequence< beans::PropertyValue >();
1605 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
1609 // TODO(P3): if we know anything about target
1610 // colorspace, this can be greatly sped up
1611 uno::Sequence<rendering::ARGBColor> aIntermediate(
1612 convertToARGB(deviceColor));
1613 return targetColorSpace->convertFromARGB(aIntermediate);
1615 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1617 const double* pIn( deviceColor.getConstArray() );
1618 const sal_Size nLen( deviceColor.getLength() );
1619 ENSURE_ARG_OR_THROW2(nLen%4==0,
1620 "number of channels no multiple of 4",
1621 static_cast<rendering::XColorSpace*>(this), 0);
1623 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1624 rendering::RGBColor* pOut( aRes.getArray() );
1625 for( sal_Size i=0; i<nLen; i+=4 )
1627 const double fAlpha(pIn[3]);
1628 if( fAlpha == 0.0 )
1629 *pOut++ = rendering::RGBColor(0.0, 0.0, 0.0);
1630 else
1631 *pOut++ = rendering::RGBColor(pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1632 pIn += 4;
1634 return aRes;
1636 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1638 const double* pIn( deviceColor.getConstArray() );
1639 const sal_Size nLen( deviceColor.getLength() );
1640 ENSURE_ARG_OR_THROW2(nLen%4==0,
1641 "number of channels no multiple of 4",
1642 static_cast<rendering::XColorSpace*>(this), 0);
1644 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1645 rendering::ARGBColor* pOut( aRes.getArray() );
1646 for( sal_Size i=0; i<nLen; i+=4 )
1648 const double fAlpha(pIn[3]);
1649 if( fAlpha == 0.0 )
1650 *pOut++ = rendering::ARGBColor(0.0, 0.0, 0.0, 0.0);
1651 else
1652 *pOut++ = rendering::ARGBColor(fAlpha,pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1653 pIn += 4;
1655 return aRes;
1657 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1659 const double* pIn( deviceColor.getConstArray() );
1660 const sal_Size nLen( deviceColor.getLength() );
1661 ENSURE_ARG_OR_THROW2(nLen%4==0,
1662 "number of channels no multiple of 4",
1663 static_cast<rendering::XColorSpace*>(this), 0);
1665 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1666 rendering::ARGBColor* pOut( aRes.getArray() );
1667 for( sal_Size i=0; i<nLen; i+=4 )
1669 *pOut++ = rendering::ARGBColor(pIn[3],pIn[2],pIn[1],pIn[1]);
1670 pIn += 4;
1672 return aRes;
1674 virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1676 const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1677 const sal_Size nLen( rgbColor.getLength() );
1679 uno::Sequence< double > aRes(nLen*4);
1680 double* pColors=aRes.getArray();
1681 for( sal_Size i=0; i<nLen; ++i )
1683 *pColors++ = pIn->Blue;
1684 *pColors++ = pIn->Green;
1685 *pColors++ = pIn->Red;
1686 *pColors++ = 1.0;
1687 ++pIn;
1689 return aRes;
1691 virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1693 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1694 const sal_Size nLen( rgbColor.getLength() );
1696 uno::Sequence< double > aRes(nLen*4);
1697 double* pColors=aRes.getArray();
1698 for( sal_Size i=0; i<nLen; ++i )
1700 *pColors++ = pIn->Alpha*pIn->Blue;
1701 *pColors++ = pIn->Alpha*pIn->Green;
1702 *pColors++ = pIn->Alpha*pIn->Red;
1703 *pColors++ = pIn->Alpha;
1704 ++pIn;
1706 return aRes;
1708 virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1710 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1711 const sal_Size nLen( rgbColor.getLength() );
1713 uno::Sequence< double > aRes(nLen*4);
1714 double* pColors=aRes.getArray();
1715 for( sal_Size i=0; i<nLen; ++i )
1717 *pColors++ = pIn->Blue;
1718 *pColors++ = pIn->Green;
1719 *pColors++ = pIn->Red;
1720 *pColors++ = pIn->Alpha;
1721 ++pIn;
1723 return aRes;
1726 // XIntegerBitmapColorSpace
1727 virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1729 return 32;
1731 virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1733 return maBitCounts;
1735 virtual ::sal_Int8 SAL_CALL getEndianness( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1737 return util::Endianness::LITTLE;
1739 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
1743 if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1745 const sal_Int8* pIn( deviceColor.getConstArray() );
1746 const sal_Size nLen( deviceColor.getLength() );
1747 ENSURE_ARG_OR_THROW2(nLen%4==0,
1748 "number of channels no multiple of 4",
1749 static_cast<rendering::XColorSpace*>(this), 0);
1751 uno::Sequence<double> aRes(nLen);
1752 double* pOut( aRes.getArray() );
1753 for( sal_Size i=0; i<nLen; i+=4 )
1755 *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1756 *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1757 *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1758 *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1760 return aRes;
1762 else
1764 // TODO(P3): if we know anything about target
1765 // colorspace, this can be greatly sped up
1766 uno::Sequence<rendering::ARGBColor> aIntermediate(
1767 convertIntegerToARGB(deviceColor));
1768 return targetColorSpace->convertFromARGB(aIntermediate);
1771 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
1775 if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1777 // it's us, so simply pass-through the data
1778 return deviceColor;
1780 else
1782 // TODO(P3): if we know anything about target
1783 // colorspace, this can be greatly sped up
1784 uno::Sequence<rendering::ARGBColor> aIntermediate(
1785 convertIntegerToARGB(deviceColor));
1786 return targetColorSpace->convertIntegerFromARGB(aIntermediate);
1789 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1790 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1792 const sal_Int8* pIn( deviceColor.getConstArray() );
1793 const sal_Size nLen( deviceColor.getLength() );
1794 ENSURE_ARG_OR_THROW2(nLen%4==0,
1795 "number of channels no multiple of 4",
1796 static_cast<rendering::XColorSpace*>(this), 0);
1798 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1799 rendering::RGBColor* pOut( aRes.getArray() );
1800 for( sal_Size i=0; i<nLen; i+=4 )
1802 const double fAlpha((sal_uInt8)pIn[3]);
1803 if( fAlpha )
1804 *pOut++ = rendering::RGBColor(
1805 pIn[2]/fAlpha,
1806 pIn[1]/fAlpha,
1807 pIn[0]/fAlpha);
1808 else
1809 *pOut++ = rendering::RGBColor(0,0,0);
1810 pIn += 4;
1812 return aRes;
1815 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1816 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1818 const sal_Int8* pIn( deviceColor.getConstArray() );
1819 const sal_Size nLen( deviceColor.getLength() );
1820 ENSURE_ARG_OR_THROW2(nLen%4==0,
1821 "number of channels no multiple of 4",
1822 static_cast<rendering::XColorSpace*>(this), 0);
1824 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1825 rendering::ARGBColor* pOut( aRes.getArray() );
1826 for( sal_Size i=0; i<nLen; i+=4 )
1828 const double fAlpha((sal_uInt8)pIn[3]);
1829 if( fAlpha )
1830 *pOut++ = rendering::ARGBColor(
1831 fAlpha/255.0,
1832 pIn[2]/fAlpha,
1833 pIn[1]/fAlpha,
1834 pIn[0]/fAlpha);
1835 else
1836 *pOut++ = rendering::ARGBColor(0,0,0,0);
1837 pIn += 4;
1839 return aRes;
1841 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1842 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1844 const sal_Int8* pIn( deviceColor.getConstArray() );
1845 const sal_Size nLen( deviceColor.getLength() );
1846 ENSURE_ARG_OR_THROW2(nLen%4==0,
1847 "number of channels no multiple of 4",
1848 static_cast<rendering::XColorSpace*>(this), 0);
1850 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1851 rendering::ARGBColor* pOut( aRes.getArray() );
1852 for( sal_Size i=0; i<nLen; i+=4 )
1854 *pOut++ = rendering::ARGBColor(
1855 vcl::unotools::toDoubleColor(pIn[3]),
1856 vcl::unotools::toDoubleColor(pIn[2]),
1857 vcl::unotools::toDoubleColor(pIn[1]),
1858 vcl::unotools::toDoubleColor(pIn[0]));
1859 pIn += 4;
1861 return aRes;
1864 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor )
1865 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1867 const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1868 const sal_Size nLen( rgbColor.getLength() );
1870 uno::Sequence< sal_Int8 > aRes(nLen*4);
1871 sal_Int8* pColors=aRes.getArray();
1872 for( sal_Size i=0; i<nLen; ++i )
1874 *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1875 *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1876 *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1877 *pColors++ = -1;
1878 ++pIn;
1880 return aRes;
1883 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
1884 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1886 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1887 const sal_Size nLen( rgbColor.getLength() );
1889 uno::Sequence< sal_Int8 > aRes(nLen*4);
1890 sal_Int8* pColors=aRes.getArray();
1891 for( sal_Size i=0; i<nLen; ++i )
1893 const double fAlpha(pIn->Alpha);
1894 *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Blue);
1895 *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Green);
1896 *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Red);
1897 *pColors++ = vcl::unotools::toByteColor(fAlpha);
1898 ++pIn;
1900 return aRes;
1902 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
1903 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1905 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1906 const sal_Size nLen( rgbColor.getLength() );
1908 uno::Sequence< sal_Int8 > aRes(nLen*4);
1909 sal_Int8* pColors=aRes.getArray();
1910 for( sal_Size i=0; i<nLen; ++i )
1912 *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1913 *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1914 *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1915 *pColors++ = vcl::unotools::toByteColor(pIn->Alpha);
1916 ++pIn;
1918 return aRes;
1921 public:
1922 CairoColorSpace() :
1923 maComponentTags(4),
1924 maBitCounts(4)
1926 sal_Int8* pTags = maComponentTags.getArray();
1927 sal_Int32* pBitCounts = maBitCounts.getArray();
1928 pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
1929 pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
1930 pTags[2] = rendering::ColorComponentTag::RGB_RED;
1931 pTags[3] = rendering::ColorComponentTag::PREMULTIPLIED_ALPHA;
1933 pBitCounts[0] =
1934 pBitCounts[1] =
1935 pBitCounts[2] =
1936 pBitCounts[3] = 8;
1940 class CairoNoAlphaColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace >
1942 private:
1943 uno::Sequence< sal_Int8 > maComponentTags;
1944 uno::Sequence< sal_Int32 > maBitCounts;
1946 virtual ::sal_Int8 SAL_CALL getType( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1948 return rendering::ColorSpaceType::RGB;
1950 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1952 return maComponentTags;
1954 virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1956 return rendering::RenderingIntent::PERCEPTUAL;
1958 virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
1960 return uno::Sequence< beans::PropertyValue >();
1962 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
1966 // TODO(P3): if we know anything about target
1967 // colorspace, this can be greatly sped up
1968 uno::Sequence<rendering::ARGBColor> aIntermediate(
1969 convertToARGB(deviceColor));
1970 return targetColorSpace->convertFromARGB(aIntermediate);
1972 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
1974 const double* pIn( deviceColor.getConstArray() );
1975 const sal_Size nLen( deviceColor.getLength() );
1976 ENSURE_ARG_OR_THROW2(nLen%4==0,
1977 "number of channels no multiple of 4",
1978 static_cast<rendering::XColorSpace*>(this), 0);
1980 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1981 rendering::RGBColor* pOut( aRes.getArray() );
1982 for( sal_Size i=0; i<nLen; i+=4 )
1984 *pOut++ = rendering::RGBColor(pIn[2], pIn[1], pIn[0]);
1985 pIn += 4;
1987 return aRes;
1989 uno::Sequence< rendering::ARGBColor > impl_convertToARGB( const uno::Sequence< double >& deviceColor )
1991 const double* pIn( deviceColor.getConstArray() );
1992 const sal_Size nLen( deviceColor.getLength() );
1993 ENSURE_ARG_OR_THROW2(nLen%4==0,
1994 "number of channels no multiple of 4",
1995 static_cast<rendering::XColorSpace*>(this), 0);
1997 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1998 rendering::ARGBColor* pOut( aRes.getArray() );
1999 for( sal_Size i=0; i<nLen; i+=4 )
2001 *pOut++ = rendering::ARGBColor(1.0, pIn[2], pIn[1], pIn[0]);
2002 pIn += 4;
2004 return aRes;
2006 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2008 return impl_convertToARGB( deviceColor );
2010 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2012 return impl_convertToARGB( deviceColor );
2014 virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2016 const rendering::RGBColor* pIn( rgbColor.getConstArray() );
2017 const sal_Size nLen( rgbColor.getLength() );
2019 uno::Sequence< double > aRes(nLen*4);
2020 double* pColors=aRes.getArray();
2021 for( sal_Size i=0; i<nLen; ++i )
2023 *pColors++ = pIn->Blue;
2024 *pColors++ = pIn->Green;
2025 *pColors++ = pIn->Red;
2026 *pColors++ = 1.0; // the value does not matter
2027 ++pIn;
2029 return aRes;
2031 uno::Sequence< double > impl_convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
2033 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
2034 const sal_Size nLen( rgbColor.getLength() );
2036 uno::Sequence< double > aRes(nLen*4);
2037 double* pColors=aRes.getArray();
2038 for( sal_Size i=0; i<nLen; ++i )
2040 *pColors++ = pIn->Blue;
2041 *pColors++ = pIn->Green;
2042 *pColors++ = pIn->Red;
2043 *pColors++ = 1.0; // the value does not matter
2044 ++pIn;
2046 return aRes;
2048 virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2050 return impl_convertFromARGB( rgbColor );
2052 virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2054 return impl_convertFromARGB( rgbColor );
2057 // XIntegerBitmapColorSpace
2058 virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2060 return 32;
2062 virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2064 return maBitCounts;
2066 virtual ::sal_Int8 SAL_CALL getEndianness( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
2068 return util::Endianness::LITTLE;
2070 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
2074 if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
2076 const sal_Int8* pIn( deviceColor.getConstArray() );
2077 const sal_Size nLen( deviceColor.getLength() );
2078 ENSURE_ARG_OR_THROW2(nLen%4==0,
2079 "number of channels no multiple of 4",
2080 static_cast<rendering::XColorSpace*>(this), 0);
2082 uno::Sequence<double> aRes(nLen);
2083 double* pOut( aRes.getArray() );
2084 for( sal_Size i=0; i<nLen; i+=4 )
2086 *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
2087 *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
2088 *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
2089 *pOut++ = 1.0; // the value does not matter
2091 return aRes;
2093 else
2095 // TODO(P3): if we know anything about target
2096 // colorspace, this can be greatly sped up
2097 uno::Sequence<rendering::ARGBColor> aIntermediate(
2098 convertIntegerToARGB(deviceColor));
2099 return targetColorSpace->convertFromARGB(aIntermediate);
2102 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
2106 if( dynamic_cast<CairoNoAlphaColorSpace*>(targetColorSpace.get()) )
2108 // it's us, so simply pass-through the data
2109 return deviceColor;
2111 else
2113 // TODO(P3): if we know anything about target
2114 // colorspace, this can be greatly sped up
2115 uno::Sequence<rendering::ARGBColor> aIntermediate(
2116 convertIntegerToARGB(deviceColor));
2117 return targetColorSpace->convertIntegerFromARGB(aIntermediate);
2120 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
2121 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2123 const sal_Int8* pIn( deviceColor.getConstArray() );
2124 const sal_Size nLen( deviceColor.getLength() );
2125 ENSURE_ARG_OR_THROW2(nLen%4==0,
2126 "number of channels no multiple of 4",
2127 static_cast<rendering::XColorSpace*>(this), 0);
2129 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
2130 rendering::RGBColor* pOut( aRes.getArray() );
2131 for( sal_Size i=0; i<nLen; i+=4 )
2133 *pOut++ = rendering::RGBColor( pIn[2], pIn[1], pIn[0] );
2134 pIn += 4;
2136 return aRes;
2139 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
2140 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2142 return impl_convertIntegerToARGB( deviceColor );
2144 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
2145 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2147 return impl_convertIntegerToARGB( deviceColor );
2149 uno::Sequence< rendering::ARGBColor > impl_convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
2151 const sal_Int8* pIn( deviceColor.getConstArray() );
2152 const sal_Size nLen( deviceColor.getLength() );
2153 ENSURE_ARG_OR_THROW2(nLen%4==0,
2154 "number of channels no multiple of 4",
2155 static_cast<rendering::XColorSpace*>(this), 0);
2157 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
2158 rendering::ARGBColor* pOut( aRes.getArray() );
2159 for( sal_Size i=0; i<nLen; i+=4 )
2161 *pOut++ = rendering::ARGBColor(
2162 1.0,
2163 vcl::unotools::toDoubleColor(pIn[2]),
2164 vcl::unotools::toDoubleColor(pIn[1]),
2165 vcl::unotools::toDoubleColor(pIn[0]));
2166 pIn += 4;
2168 return aRes;
2171 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor )
2172 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2174 const rendering::RGBColor* pIn( rgbColor.getConstArray() );
2175 const sal_Size nLen( rgbColor.getLength() );
2177 uno::Sequence< sal_Int8 > aRes(nLen*4);
2178 sal_Int8* pColors=aRes.getArray();
2179 for( sal_Size i=0; i<nLen; ++i )
2181 *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
2182 *pColors++ = vcl::unotools::toByteColor(pIn->Green);
2183 *pColors++ = vcl::unotools::toByteColor(pIn->Red);
2184 *pColors++ = -1; // the value does not matter
2185 ++pIn;
2187 return aRes;
2190 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
2191 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2193 return impl_convertIntegerFromARGB( rgbColor );
2195 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
2196 throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) SAL_OVERRIDE
2198 return impl_convertIntegerFromARGB( rgbColor );
2200 uno::Sequence< ::sal_Int8 > impl_convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
2202 const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
2203 const sal_Size nLen( rgbColor.getLength() );
2205 uno::Sequence< sal_Int8 > aRes(nLen*4);
2206 sal_Int8* pColors=aRes.getArray();
2207 for( sal_Size i=0; i<nLen; ++i )
2209 *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
2210 *pColors++ = vcl::unotools::toByteColor(pIn->Green);
2211 *pColors++ = vcl::unotools::toByteColor(pIn->Red);
2212 *pColors++ = -1; // the value does not matter
2213 ++pIn;
2215 return aRes;
2218 public:
2219 CairoNoAlphaColorSpace() :
2220 maComponentTags(3),
2221 maBitCounts(3)
2223 sal_Int8* pTags = maComponentTags.getArray();
2224 sal_Int32* pBitCounts = maBitCounts.getArray();
2225 pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
2226 pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
2227 pTags[2] = rendering::ColorComponentTag::RGB_RED;
2229 pBitCounts[0] =
2230 pBitCounts[1] =
2231 pBitCounts[2] = 8;
2235 struct CairoNoAlphaColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
2236 CairoNoAlphaColorSpaceHolder>
2238 uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
2240 return new CairoNoAlphaColorSpace();
2244 struct CairoColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
2245 CairoColorSpaceHolder>
2247 uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
2249 return new CairoColorSpace();
2255 rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout()
2257 if( !mpCairo )
2258 return rendering::IntegerBitmapLayout(); // we're disposed
2260 const geometry::IntegerSize2D aSize(getSize());
2262 return impl_getMemoryLayout( aSize.Width, aSize.Height );
2265 rendering::IntegerBitmapLayout
2266 CanvasHelper::impl_getMemoryLayout( const sal_Int32 nWidth, const sal_Int32 nHeight )
2268 rendering::IntegerBitmapLayout aLayout;
2270 aLayout.ScanLines = nHeight;
2271 aLayout.ScanLineBytes = nWidth*4;
2272 aLayout.ScanLineStride = aLayout.ScanLineBytes;
2273 aLayout.PlaneStride = 0;
2274 aLayout.ColorSpace = mbHaveAlpha ? CairoColorSpaceHolder::get() : CairoNoAlphaColorSpaceHolder::get();
2275 aLayout.Palette.clear();
2276 aLayout.IsMsbFirst = sal_False;
2278 return aLayout;
2282 bool CanvasHelper::repaint( const SurfaceSharedPtr& pSurface,
2283 const rendering::ViewState& viewState,
2284 const rendering::RenderState& renderState )
2286 SAL_INFO( "canvas.cairo", "CanvasHelper::repaint");
2288 if( mpCairo )
2290 cairo_save( mpCairo.get() );
2292 cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
2293 cairo_clip( mpCairo.get() );
2295 useStates( viewState, renderState, true );
2297 cairo_matrix_t aMatrix;
2299 cairo_get_matrix( mpCairo.get(), &aMatrix );
2300 aMatrix.xx = aMatrix.yy = 1;
2301 cairo_set_matrix( mpCairo.get(), &aMatrix );
2303 cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
2304 cairo_paint( mpCairo.get() );
2305 cairo_restore( mpCairo.get() );
2308 return true;
2312 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */