1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/logfile.hxx>
24 #include <rtl/math.hxx>
25 #include <rtl/instance.hxx>
27 #include <com/sun/star/util/Endianness.hpp>
28 #include <com/sun/star/rendering/TexturingMode.hpp>
29 #include <com/sun/star/rendering/CompositeOperation.hpp>
30 #include <com/sun/star/rendering/RepaintResult.hpp>
31 #include <com/sun/star/rendering/PathCapType.hpp>
32 #include <com/sun/star/rendering/PathJoinType.hpp>
33 #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
34 #include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
35 #include <com/sun/star/rendering/ColorSpaceType.hpp>
36 #include <com/sun/star/rendering/ColorComponentTag.hpp>
37 #include <com/sun/star/rendering/RenderingIntent.hpp>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <basegfx/point/b2dpoint.hxx>
41 #include <basegfx/polygon/b2dpolygon.hxx>
42 #include <basegfx/polygon/b2dpolypolygon.hxx>
43 #include <basegfx/polygon/b2dpolygontools.hxx>
44 #include <basegfx/tools/canvastools.hxx>
45 #include <basegfx/tools/keystoplerp.hxx>
46 #include <basegfx/tools/lerp.hxx>
48 #include <comphelper/sequence.hxx>
49 #include <cppuhelper/compbase1.hxx>
51 #include <canvas/canvastools.hxx>
52 #include <canvas/parametricpolypolygon.hxx>
54 #include <vcl/canvastools.hxx>
55 #include <vcl/bitmapex.hxx>
56 #include <vcl/bmpacc.hxx>
57 #include <vcl/virdev.hxx>
59 #include "cairo_spritecanvas.hxx"
60 #include "cairo_cachedbitmap.hxx"
61 #include "cairo_canvashelper.hxx"
62 #include "cairo_canvasbitmap.hxx"
64 #include <boost/tuple/tuple.hpp>
67 using namespace ::cairo
;
68 using namespace ::com::sun::star
;
72 CanvasHelper::CanvasHelper() :
73 mpSurfaceProvider(NULL
),
83 void CanvasHelper::disposing()
87 mpVirtualDevice
.reset();
89 mpSurfaceProvider
= NULL
;
92 void CanvasHelper::init( const ::basegfx::B2ISize
& rSizePixel
,
93 SurfaceProvider
& rSurfaceProvider
,
94 rendering::XGraphicDevice
* pDevice
)
97 mpSurfaceProvider
= &rSurfaceProvider
;
101 void CanvasHelper::setSize( const ::basegfx::B2ISize
& rSize
)
106 void CanvasHelper::setSurface( const SurfaceSharedPtr
& pSurface
, bool bHasAlpha
)
108 mbHaveAlpha
= bHasAlpha
;
109 mpVirtualDevice
.reset();
110 mpSurface
= pSurface
;
111 mpCairo
= pSurface
->getCairo();
114 static void setColor( Cairo
* pCairo
,
115 const uno::Sequence
<double>& rColor
)
117 if( rColor
.getLength() > 3 )
119 cairo_set_source_rgba( pCairo
,
125 else if( rColor
.getLength() == 3 )
126 cairo_set_source_rgb( pCairo
,
132 void CanvasHelper::useStates( const rendering::ViewState
& viewState
,
133 const rendering::RenderState
& renderState
,
137 Matrix aRenderMatrix
;
138 Matrix aCombinedMatrix
;
140 cairo_matrix_init( &aViewMatrix
,
141 viewState
.AffineTransform
.m00
, viewState
.AffineTransform
.m10
, viewState
.AffineTransform
.m01
,
142 viewState
.AffineTransform
.m11
, viewState
.AffineTransform
.m02
, viewState
.AffineTransform
.m12
);
143 cairo_matrix_init( &aRenderMatrix
,
144 renderState
.AffineTransform
.m00
, renderState
.AffineTransform
.m10
, renderState
.AffineTransform
.m01
,
145 renderState
.AffineTransform
.m11
, renderState
.AffineTransform
.m02
, renderState
.AffineTransform
.m12
);
146 cairo_matrix_multiply( &aCombinedMatrix
, &aRenderMatrix
, &aViewMatrix
);
148 if( viewState
.Clip
.is() )
150 OSL_TRACE ("view clip");
152 aViewMatrix
.x0
= basegfx::fround( aViewMatrix
.x0
);
153 aViewMatrix
.y0
= basegfx::fround( aViewMatrix
.y0
);
154 cairo_set_matrix( mpCairo
.get(), &aViewMatrix
);
155 doPolyPolygonPath( viewState
.Clip
, Clip
);
158 aCombinedMatrix
.x0
= basegfx::fround( aCombinedMatrix
.x0
);
159 aCombinedMatrix
.y0
= basegfx::fround( aCombinedMatrix
.y0
);
160 cairo_set_matrix( mpCairo
.get(), &aCombinedMatrix
);
162 if( renderState
.Clip
.is() )
164 OSL_TRACE ("render clip BEGIN");
166 doPolyPolygonPath( renderState
.Clip
, Clip
);
167 OSL_TRACE ("render clip END");
171 setColor(mpCairo
.get(),renderState
.DeviceColor
);
173 cairo_operator_t
compositingMode( CAIRO_OPERATOR_OVER
);
174 switch( renderState
.CompositeOperation
)
176 case rendering::CompositeOperation::CLEAR
:
177 compositingMode
= CAIRO_OPERATOR_CLEAR
;
179 case rendering::CompositeOperation::SOURCE
:
180 compositingMode
= CAIRO_OPERATOR_SOURCE
;
182 case rendering::CompositeOperation::DESTINATION
:
183 compositingMode
= CAIRO_OPERATOR_DEST
;
185 case rendering::CompositeOperation::OVER
:
186 compositingMode
= CAIRO_OPERATOR_OVER
;
188 case rendering::CompositeOperation::UNDER
:
189 compositingMode
= CAIRO_OPERATOR_DEST
;
191 case rendering::CompositeOperation::INSIDE
:
192 compositingMode
= CAIRO_OPERATOR_IN
;
194 case rendering::CompositeOperation::INSIDE_REVERSE
:
195 compositingMode
= CAIRO_OPERATOR_OUT
;
197 case rendering::CompositeOperation::OUTSIDE
:
198 compositingMode
= CAIRO_OPERATOR_DEST_OVER
;
200 case rendering::CompositeOperation::OUTSIDE_REVERSE
:
201 compositingMode
= CAIRO_OPERATOR_DEST_OUT
;
203 case rendering::CompositeOperation::ATOP
:
204 compositingMode
= CAIRO_OPERATOR_ATOP
;
206 case rendering::CompositeOperation::ATOP_REVERSE
:
207 compositingMode
= CAIRO_OPERATOR_DEST_ATOP
;
209 case rendering::CompositeOperation::XOR
:
210 compositingMode
= CAIRO_OPERATOR_XOR
;
212 case rendering::CompositeOperation::ADD
:
213 compositingMode
= CAIRO_OPERATOR_ADD
;
215 case rendering::CompositeOperation::SATURATE
:
216 compositingMode
= CAIRO_OPERATOR_SATURATE
;
219 cairo_set_operator( mpCairo
.get(), compositingMode
);
222 void CanvasHelper::clear()
224 OSL_TRACE ("clear whole area: %d x %d", maSize
.getX(), maSize
.getY() );
228 cairo_save( mpCairo
.get() );
230 cairo_identity_matrix( mpCairo
.get() );
231 // this does not really differ from all-zero, as cairo
232 // internally converts to premultiplied alpha. but anyway,
233 // this keeps it consistent with the other canvas impls
235 cairo_set_source_rgba( mpCairo
.get(), 1.0, 1.0, 1.0, 0.0 );
237 cairo_set_source_rgb( mpCairo
.get(), 1.0, 1.0, 1.0 );
238 cairo_set_operator( mpCairo
.get(), CAIRO_OPERATOR_SOURCE
);
240 cairo_rectangle( mpCairo
.get(), 0, 0, maSize
.getX(), maSize
.getY() );
241 cairo_fill( mpCairo
.get() );
243 cairo_restore( mpCairo
.get() );
247 void CanvasHelper::drawPoint( const rendering::XCanvas
* ,
248 const geometry::RealPoint2D
& ,
249 const rendering::ViewState
& ,
250 const rendering::RenderState
& )
254 void CanvasHelper::drawLine( const rendering::XCanvas
* /*pCanvas*/,
255 const geometry::RealPoint2D
& aStartPoint
,
256 const geometry::RealPoint2D
& aEndPoint
,
257 const rendering::ViewState
& viewState
,
258 const rendering::RenderState
& renderState
)
262 cairo_save( mpCairo
.get() );
264 cairo_set_line_width( mpCairo
.get(), 1 );
266 useStates( viewState
, renderState
, true );
268 cairo_move_to( mpCairo
.get(), aStartPoint
.X
+ 0.5, aStartPoint
.Y
+ 0.5 );
269 cairo_line_to( mpCairo
.get(), aEndPoint
.X
+ 0.5, aEndPoint
.Y
+ 0.5 );
270 cairo_stroke( mpCairo
.get() );
272 cairo_restore( mpCairo
.get() );
276 void CanvasHelper::drawBezier( const rendering::XCanvas
* ,
277 const geometry::RealBezierSegment2D
& aBezierSegment
,
278 const geometry::RealPoint2D
& aEndPoint
,
279 const rendering::ViewState
& viewState
,
280 const rendering::RenderState
& renderState
)
284 cairo_save( mpCairo
.get() );
286 cairo_set_line_width( mpCairo
.get(), 1 );
288 useStates( viewState
, renderState
, true );
290 cairo_move_to( mpCairo
.get(), aBezierSegment
.Px
+ 0.5, aBezierSegment
.Py
+ 0.5 );
291 cairo_curve_to( mpCairo
.get(),
292 aBezierSegment
.C1x
+ 0.5, aBezierSegment
.C1y
+ 0.5,
293 aBezierSegment
.C2x
+ 0.5, aBezierSegment
.C2y
+ 0.5,
294 aEndPoint
.X
+ 0.5, aEndPoint
.Y
+ 0.5 );
295 cairo_stroke( mpCairo
.get() );
297 cairo_restore( mpCairo
.get() );
301 #define PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME "Canvas::ParametricPolyPolygon"
303 /** surfaceFromXBitmap Create a surface from XBitmap
304 * @param xBitmap bitmap image that will be used for the surface
305 * @param bHasAlpha will be set to true if resulting surface has alpha
307 * This is a helper function for the other surfaceFromXBitmap().
308 * This function tries to create surface from xBitmap by checking if xBitmap is CanvasBitmap or SpriteCanvas.
310 * @return created surface or NULL
312 static SurfaceSharedPtr
surfaceFromXBitmap( const uno::Reference
< rendering::XBitmap
>& xBitmap
)
314 CanvasBitmap
* pBitmapImpl
= dynamic_cast< CanvasBitmap
* >( xBitmap
.get() );
316 return pBitmapImpl
->getSurface();
318 SurfaceProvider
* pSurfaceProvider
= dynamic_cast<SurfaceProvider
*>( xBitmap
.get() );
319 if( pSurfaceProvider
)
320 return pSurfaceProvider
->getSurface();
322 return SurfaceSharedPtr();
325 static ::BitmapEx
bitmapExFromXBitmap( const uno::Reference
< rendering::XBitmap
>& xBitmap
)
327 // TODO(F1): Add support for floating point bitmap formats
328 uno::Reference
<rendering::XIntegerReadOnlyBitmap
> xIntBmp(xBitmap
,
329 uno::UNO_QUERY_THROW
);
330 ::BitmapEx aBmpEx
= ::vcl::unotools::bitmapExFromXBitmap(xIntBmp
);
334 // TODO(F1): extract pixel from XBitmap interface
335 ENSURE_OR_THROW( false,
336 "bitmapExFromXBitmap(): could not extract BitmapEx" );
341 static sal_uInt8
lcl_GetColor(BitmapColor
const& rColor
)
344 if (rColor
.IsIndex())
346 nTemp
= rColor
.GetIndex();
350 nTemp
= rColor
.GetBlue();
351 // greyscale expected here, or what would non-grey colors mean?
352 assert(rColor
.GetRed() == nTemp
&& rColor
.GetGreen() == nTemp
);
357 static bool readAlpha( BitmapReadAccess
* pAlphaReadAcc
, long nY
, const long nWidth
, unsigned char* data
, long nOff
)
359 bool bIsAlpha
= false;
366 switch( pAlphaReadAcc
->GetScanlineFormat() )
368 case BMP_FORMAT_8BIT_TC_MASK
:
369 pReadScan
= pAlphaReadAcc
->GetScanline( nY
);
370 for( nX
= 0; nX
< nWidth
; nX
++ )
372 nAlpha
= data
[ nOff
] = 255 - ( *pReadScan
++ );
378 case BMP_FORMAT_8BIT_PAL
:
379 pReadScan
= pAlphaReadAcc
->GetScanline( nY
);
380 for( nX
= 0; nX
< nWidth
; nX
++ )
382 BitmapColor
const& rColor(
383 pAlphaReadAcc
->GetPaletteColor(*pReadScan
));
385 nAlpha
= data
[ nOff
] = 255 - lcl_GetColor(rColor
);
392 OSL_TRACE( "fallback to GetColor for alpha - slow, format: %d", pAlphaReadAcc
->GetScanlineFormat() );
393 for( nX
= 0; nX
< nWidth
; nX
++ )
395 nAlpha
= data
[ nOff
] = 255 - pAlphaReadAcc
->GetColor( nY
, nX
).GetIndex();
406 /** surfaceFromXBitmap Create a surface from XBitmap
407 * @param xBitmap bitmap image that will be used for the surface
408 * @param rDevice reference to the device into which we want to draw
409 * @param data will be filled with alpha data, if xBitmap is alpha/transparent image
410 * @param bHasAlpha will be set to true if resulting surface has alpha
412 * This function tries various methods for creating a surface from xBitmap. It also uses
413 * the helper function surfaceFromXBitmap( xBitmap, bHasAlpha )
415 * @return created surface or NULL
417 static SurfaceSharedPtr
surfaceFromXBitmap( const uno::Reference
< rendering::XBitmap
>& xBitmap
, const SurfaceProviderRef
& rSurfaceProvider
, unsigned char*& data
, bool& bHasAlpha
)
419 bHasAlpha
= xBitmap
->hasAlpha();
420 SurfaceSharedPtr pSurface
= surfaceFromXBitmap( xBitmap
);
425 ::BitmapEx aBmpEx
= bitmapExFromXBitmap(xBitmap
);
426 ::Bitmap aBitmap
= aBmpEx
.GetBitmap();
428 // there's no pixmap for alpha bitmap. we might still
429 // use rgb pixmap and only access alpha pixels the
430 // slow way. now we just speedup rgb bitmaps
431 if( !aBmpEx
.IsTransparent() && !aBmpEx
.IsAlpha() )
433 pSurface
= rSurfaceProvider
->createSurface( aBitmap
);
440 AlphaMask aAlpha
= aBmpEx
.GetAlpha();
442 ::BitmapReadAccess
* pBitmapReadAcc
= aBitmap
.AcquireReadAccess();
443 ::BitmapReadAccess
* pAlphaReadAcc
= NULL
;
444 const long nWidth
= pBitmapReadAcc
->Width();
445 const long nHeight
= pBitmapReadAcc
->Height();
447 bool bIsAlpha
= false;
449 if( aBmpEx
.IsTransparent() || aBmpEx
.IsAlpha() )
450 pAlphaReadAcc
= aAlpha
.AcquireReadAccess();
452 data
= (unsigned char*) malloc( nWidth
*nHeight
*4 );
456 unsigned int nAlpha
= 255;
458 for( nY
= 0; nY
< nHeight
; nY
++ )
460 ::Scanline pReadScan
;
462 switch( pBitmapReadAcc
->GetScanlineFormat() )
464 case BMP_FORMAT_8BIT_PAL
:
465 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
467 if( readAlpha( pAlphaReadAcc
, nY
, nWidth
, data
, nOff
) )
470 for( nX
= 0; nX
< nWidth
; nX
++ )
474 nAlpha
= data
[ nOff
++ ];
476 nAlpha
= data
[ nOff
++ ] = 255;
479 nAlpha
= data
[ nOff
+ 3 ];
481 nAlpha
= data
[ nOff
+ 3 ] = 255;
483 aColor
= pBitmapReadAcc
->GetPaletteColor( *pReadScan
++ );
486 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( aColor
.GetRed() ) )/255 );
487 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( aColor
.GetGreen() ) )/255 );
488 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( aColor
.GetBlue() ) )/255 );
490 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( aColor
.GetBlue() ) )/255 );
491 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( aColor
.GetGreen() ) )/255 );
492 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( aColor
.GetRed() ) )/255 );
497 case BMP_FORMAT_24BIT_TC_BGR
:
498 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
500 if( readAlpha( pAlphaReadAcc
, nY
, nWidth
, data
, nOff
) )
503 for( nX
= 0; nX
< nWidth
; nX
++ )
507 nAlpha
= data
[ nOff
];
509 nAlpha
= data
[ nOff
] = 255;
510 data
[ nOff
+ 3 ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
511 data
[ nOff
+ 2 ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
512 data
[ nOff
+ 1 ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
516 nAlpha
= data
[ nOff
+ 3 ];
518 nAlpha
= data
[ nOff
+ 3 ] = 255;
519 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
520 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
521 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
526 case BMP_FORMAT_24BIT_TC_RGB
:
527 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
529 if( readAlpha( pAlphaReadAcc
, nY
, nWidth
, data
, nOff
) )
532 for( nX
= 0; nX
< nWidth
; nX
++ )
536 nAlpha
= data
[ nOff
++ ];
538 nAlpha
= data
[ nOff
++ ] = 255;
539 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
540 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
541 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
544 nAlpha
= data
[ nOff
+ 3 ];
546 nAlpha
= data
[ nOff
+ 3 ] = 255;
547 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 2 ] ) )/255 );
548 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 1 ] ) )/255 );
549 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 0 ] ) )/255 );
555 case BMP_FORMAT_32BIT_TC_BGRA
:
556 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
558 if( readAlpha( pAlphaReadAcc
, nY
, nWidth
, data
, nOff
) )
561 for( nX
= 0; nX
< nWidth
; nX
++ )
565 nAlpha
= data
[ nOff
++ ];
567 nAlpha
= data
[ nOff
++ ] = 255;
568 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 2 ] ) )/255 );
569 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 1 ] ) )/255 );
570 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 0 ] ) )/255 );
574 nAlpha
= data
[ nOff
+ 3 ];
576 nAlpha
= data
[ nOff
+ 3 ] = 255;
577 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
578 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
579 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
585 case BMP_FORMAT_32BIT_TC_RGBA
:
586 pReadScan
= pBitmapReadAcc
->GetScanline( nY
);
588 if( readAlpha( pAlphaReadAcc
, nY
, nWidth
, data
, nOff
) )
591 for( nX
= 0; nX
< nWidth
; nX
++ )
595 nAlpha
= data
[ nOff
++ ];
597 nAlpha
= data
[ nOff
++ ] = 255;
598 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
599 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
600 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( *pReadScan
++ ) )/255 );
604 nAlpha
= data
[ nOff
+ 3 ];
606 nAlpha
= data
[ nOff
+ 3 ] = 255;
607 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 2 ] ) )/255 );
608 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 1 ] ) )/255 );
609 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*( pReadScan
[ 0 ] ) )/255 );
616 OSL_TRACE( "fallback to GetColor - slow, format: %d", pBitmapReadAcc
->GetScanlineFormat() );
619 if( readAlpha( pAlphaReadAcc
, nY
, nWidth
, data
, nOff
) )
622 for( nX
= 0; nX
< nWidth
; nX
++ )
624 aColor
= pBitmapReadAcc
->GetColor( nY
, nX
);
626 // cairo need premultiplied color values
627 // TODO(rodo) handle endianess
630 nAlpha
= data
[ nOff
++ ];
632 nAlpha
= data
[ nOff
++ ] = 255;
633 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*aColor
.GetRed() )/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
.GetBlue() )/255 );
638 nAlpha
= data
[ nOff
+ 3 ];
640 nAlpha
= data
[ nOff
+ 3 ] = 255;
641 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*aColor
.GetBlue() )/255 );
642 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*aColor
.GetGreen() )/255 );
643 data
[ nOff
++ ] = sal::static_int_cast
<unsigned char>(( nAlpha
*aColor
.GetRed() )/255 );
650 aBitmap
.ReleaseAccess( pBitmapReadAcc
);
652 aAlpha
.ReleaseAccess( pAlphaReadAcc
);
654 SurfaceSharedPtr pImageSurface
= createSurface(
655 CairoSurfaceSharedPtr(
656 cairo_image_surface_create_for_data(
658 bIsAlpha
? CAIRO_FORMAT_ARGB32
: CAIRO_FORMAT_RGB24
,
659 nWidth
, nHeight
, nWidth
*4 ),
660 &cairo_surface_destroy
) );
661 pSurface
= pImageSurface
;
663 bHasAlpha
= bIsAlpha
;
665 OSL_TRACE("image: %d x %d alpha: %d alphaRead %p", nWidth
, nHeight
, bIsAlpha
, pAlphaReadAcc
);
672 static void addColorStops( Pattern
* pPattern
, const uno::Sequence
< uno::Sequence
< double > >& rColors
, const uno::Sequence
< double >& rStops
, bool bReverseStops
= false )
677 OSL_ASSERT( rColors
.getLength() == rStops
.getLength() );
679 for( i
= 0; i
< rColors
.getLength(); i
++ )
681 const uno::Sequence
< double >& rColor( rColors
[i
] );
682 stop
= bReverseStops
? 1 - rStops
[i
] : rStops
[i
];
683 if( rColor
.getLength() == 3 )
684 cairo_pattern_add_color_stop_rgb( pPattern
, stop
, rColor
[0], rColor
[1], rColor
[2] );
685 else if( rColor
.getLength() == 4 )
687 double alpha
= rColor
[3];
688 // cairo expects premultiplied alpha
689 cairo_pattern_add_color_stop_rgba( pPattern
, stop
, rColor
[0]*alpha
, rColor
[1]*alpha
, rColor
[2]*alpha
, alpha
);
694 static uno::Sequence
<double> lerp(const uno::Sequence
<double>& rLeft
, const uno::Sequence
<double>& rRight
, double fAlpha
)
696 if( rLeft
.getLength() == 3 )
698 uno::Sequence
<double> aRes(3);
699 aRes
[0] = basegfx::tools::lerp(rLeft
[0],rRight
[0],fAlpha
);
700 aRes
[1] = basegfx::tools::lerp(rLeft
[1],rRight
[1],fAlpha
);
701 aRes
[2] = basegfx::tools::lerp(rLeft
[2],rRight
[2],fAlpha
);
704 else if( rLeft
.getLength() == 4 )
706 uno::Sequence
<double> aRes(4);
707 aRes
[0] = basegfx::tools::lerp(rLeft
[0],rRight
[0],fAlpha
);
708 aRes
[1] = basegfx::tools::lerp(rLeft
[1],rRight
[1],fAlpha
);
709 aRes
[2] = basegfx::tools::lerp(rLeft
[2],rRight
[2],fAlpha
);
710 aRes
[3] = basegfx::tools::lerp(rLeft
[3],rRight
[3],fAlpha
);
714 return uno::Sequence
<double>();
717 static Pattern
* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon
& rPolygon
)
719 Pattern
* pPattern
= NULL
;
720 const ::canvas::ParametricPolyPolygon::Values aValues
= rPolygon
.getValues();
721 double x0
, x1
, y0
, y1
, cx
, cy
, r0
, r1
;
723 switch( aValues
.meType
)
725 case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR
:
730 pPattern
= cairo_pattern_create_linear( x0
, y0
, x1
, y1
);
731 addColorStops( pPattern
, aValues
.maColors
, aValues
.maStops
);
734 case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL
:
740 pPattern
= cairo_pattern_create_radial( cx
, cy
, r0
, cy
, cy
, r1
);
741 addColorStops( pPattern
, aValues
.maColors
, aValues
.maStops
, true );
750 static void doOperation( Operation aOperation
,
752 const uno::Sequence
< rendering::Texture
>* pTextures
,
753 const SurfaceProviderRef
& pDevice
,
754 const basegfx::B2DRange
& rBounds
)
759 /* TODO: multitexturing */
762 const ::com::sun::star::rendering::Texture
& aTexture ( (*pTextures
)[0] );
763 if( aTexture
.Bitmap
.is() )
765 unsigned char* data
= NULL
;
766 bool bHasAlpha
= false;
767 SurfaceSharedPtr pSurface
= surfaceFromXBitmap( (*pTextures
)[0].Bitmap
, pDevice
, data
, bHasAlpha
);
771 cairo_pattern_t
* pPattern
;
773 cairo_save( pCairo
);
775 ::com::sun::star::geometry::AffineMatrix2D
aTransform( aTexture
.AffineTransform
);
776 Matrix aScaleMatrix
, aTextureMatrix
, aScaledTextureMatrix
;
778 cairo_matrix_init( &aTextureMatrix
,
779 aTransform
.m00
, aTransform
.m10
, aTransform
.m01
,
780 aTransform
.m11
, aTransform
.m02
, aTransform
.m12
);
782 geometry::IntegerSize2D aSize
= aTexture
.Bitmap
->getSize();
784 cairo_matrix_init_scale( &aScaleMatrix
, 1.0/aSize
.Width
, 1.0/aSize
.Height
);
785 cairo_matrix_multiply( &aScaledTextureMatrix
, &aTextureMatrix
, &aScaleMatrix
);
786 cairo_matrix_invert( &aScaledTextureMatrix
);
788 // we don't care about repeat mode yet, so the workaround is disabled for now
789 pPattern
= cairo_pattern_create_for_surface( pSurface
->getCairoSurface().get() );
791 if( aTexture
.RepeatModeX
== rendering::TexturingMode::REPEAT
&&
792 aTexture
.RepeatModeY
== rendering::TexturingMode::REPEAT
)
794 cairo_pattern_set_extend( pPattern
, CAIRO_EXTEND_REPEAT
);
796 else if ( aTexture
.RepeatModeX
== rendering::TexturingMode::NONE
&&
797 aTexture
.RepeatModeY
== rendering::TexturingMode::NONE
)
799 cairo_pattern_set_extend( pPattern
, CAIRO_EXTEND_NONE
);
801 else if ( aTexture
.RepeatModeX
== rendering::TexturingMode::CLAMP
&&
802 aTexture
.RepeatModeY
== rendering::TexturingMode::CLAMP
)
804 #if CAIRO_VERSION >= 10200
805 cairo_pattern_set_extend( pPattern
, CAIRO_EXTEND_PAD
);
807 #warning "fallback for cairo before version 1.2"
808 cairo_pattern_set_extend( pPattern
, CAIRO_EXTEND_NONE
);
812 aScaledTextureMatrix
.x0
= basegfx::fround( aScaledTextureMatrix
.x0
);
813 aScaledTextureMatrix
.y0
= basegfx::fround( aScaledTextureMatrix
.y0
);
814 cairo_pattern_set_matrix( pPattern
, &aScaledTextureMatrix
);
816 cairo_set_source( pCairo
, pPattern
);
818 cairo_set_operator( pCairo
, CAIRO_OPERATOR_SOURCE
);
819 cairo_fill( pCairo
);
821 cairo_restore( pCairo
);
823 cairo_pattern_destroy( pPattern
);
829 else if( aTexture
.Gradient
.is() )
831 uno::Reference
< lang::XServiceInfo
> xRef( aTexture
.Gradient
, uno::UNO_QUERY
);
833 OSL_TRACE( "gradient fill" );
834 if( xRef
.is() && xRef
->getImplementationName() == PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME
)
836 // TODO(Q1): Maybe use dynamic_cast here
838 // TODO(E1): Return value
839 // TODO(F1): FillRule
840 OSL_TRACE( "known implementation" );
842 ::canvas::ParametricPolyPolygon
* pPolyImpl
= static_cast< ::canvas::ParametricPolyPolygon
* >( aTexture
.Gradient
.get() );
843 ::com::sun::star::geometry::AffineMatrix2D
aTransform( aTexture
.AffineTransform
);
844 Matrix aTextureMatrix
;
846 cairo_matrix_init( &aTextureMatrix
,
847 aTransform
.m00
, aTransform
.m10
, aTransform
.m01
,
848 aTransform
.m11
, aTransform
.m02
, aTransform
.m12
);
849 if( pPolyImpl
->getValues().meType
== canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR
)
851 // no general path gradient yet in cairo; emulate then
852 cairo_save( pCairo
);
853 cairo_clip( pCairo
);
855 // fill bound rect with start color
856 cairo_rectangle( pCairo
, rBounds
.getMinX(), rBounds
.getMinY(),
857 rBounds
.getWidth(), rBounds
.getHeight() );
858 setColor(pCairo
,pPolyImpl
->getValues().maColors
[0]);
861 cairo_transform( pCairo
, &aTextureMatrix
);
863 // longest line in gradient bound rect
864 const unsigned int nGradientSize(
865 static_cast<unsigned int>(
866 ::basegfx::B2DVector(rBounds
.getMinimum() - rBounds
.getMaximum()).getLength() + 1.0 ) );
868 // typical number for pixel of the same color (strip size)
869 const unsigned int nStripSize( nGradientSize
< 50 ? 2 : 4 );
871 // use at least three steps, and at utmost the number of color
873 const unsigned int nStepCount(
877 nGradientSize
/ nStripSize
,
880 const uno::Sequence
<double>* pColors
=&pPolyImpl
->getValues().maColors
[0];
881 basegfx::tools::KeyStopLerp
aLerper(pPolyImpl
->getValues().maStops
);
882 for( unsigned int i
=1; i
<nStepCount
; ++i
)
884 const double fT( i
/double(nStepCount
) );
886 std::ptrdiff_t nIndex
;
888 boost::tuples::tie(nIndex
,fAlpha
)=aLerper
.lerp(fT
);
890 setColor(pCairo
, lerp(pColors
[nIndex
], pColors
[nIndex
+1], fAlpha
));
891 cairo_rectangle( pCairo
, -1+fT
, -1+fT
, 2-2*fT
, 2-2*fT
);
895 cairo_restore( pCairo
);
899 Pattern
* pPattern
= patternFromParametricPolyPolygon( *pPolyImpl
);
903 OSL_TRACE( "filling with pattern" );
905 cairo_save( pCairo
);
907 cairo_transform( pCairo
, &aTextureMatrix
);
908 cairo_set_source( pCairo
, pPattern
);
909 cairo_fill( pCairo
);
910 cairo_restore( pCairo
);
912 cairo_pattern_destroy( pPattern
);
919 cairo_fill( pCairo
);
923 cairo_stroke( pCairo
);
927 cairo_clip( pCairo
);
933 static void clipNULL( Cairo
*pCairo
)
935 OSL_TRACE("clipNULL");
936 Matrix aOrigMatrix
, aIdentityMatrix
;
938 /* we set identity matrix here to overcome bug in cairo 0.9.2
939 where XCreatePixmap is called with zero width and height.
941 it also reaches faster path in cairo clipping code.
943 cairo_matrix_init_identity( &aIdentityMatrix
);
944 cairo_get_matrix( pCairo
, &aOrigMatrix
);
945 cairo_set_matrix( pCairo
, &aIdentityMatrix
);
947 cairo_reset_clip( pCairo
);
948 cairo_rectangle( pCairo
, 0, 0, 1, 1 );
949 cairo_clip( pCairo
);
950 cairo_rectangle( pCairo
, 2, 0, 1, 1 );
951 cairo_clip( pCairo
);
953 /* restore the original matrix */
954 cairo_set_matrix( pCairo
, &aOrigMatrix
);
957 void doPolyPolygonImplementation( ::basegfx::B2DPolyPolygon aPolyPolygon
,
958 Operation aOperation
,
960 const uno::Sequence
< rendering::Texture
>* pTextures
,
961 const SurfaceProviderRef
& pDevice
,
962 rendering::FillRule eFillrule
)
965 ENSURE_ARG_OR_THROW( pTextures
->getLength(),
966 "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence");
968 bool bOpToDo
= false;
969 Matrix aOrigMatrix
, aIdentityMatrix
;
970 double nX
, nY
, nBX
, nBY
, nAX
, nAY
;
972 cairo_get_matrix( pCairo
, &aOrigMatrix
);
973 cairo_matrix_init_identity( &aIdentityMatrix
);
974 cairo_set_matrix( pCairo
, &aIdentityMatrix
);
976 cairo_set_fill_rule( pCairo
,
977 eFillrule
== rendering::FillRule_EVEN_ODD
?
978 CAIRO_FILL_RULE_EVEN_ODD
: CAIRO_FILL_RULE_WINDING
);
980 for( sal_uInt32 nPolygonIndex
= 0; nPolygonIndex
< aPolyPolygon
.count(); nPolygonIndex
++ )
982 ::basegfx::B2DPolygon
aPolygon( aPolyPolygon
.getB2DPolygon( nPolygonIndex
) );
983 const sal_uInt32
nPointCount( aPolygon
.count() );
984 // to correctly render closed curves, need to output first
985 // point twice (so output one additional point)
986 const sal_uInt32
nExtendedPointCount( nPointCount
+
987 aPolygon
.isClosed()*aPolygon
.areControlPointsUsed() );
991 bool bIsBezier
= aPolygon
.areControlPointsUsed();
992 bool bIsRectangle
= ::basegfx::tools::isRectangle( aPolygon
);
993 ::basegfx::B2DPoint aA
, aB
, aP
;
995 for( sal_uInt32 j
=0; j
< nExtendedPointCount
; j
++ )
997 aP
= aPolygon
.getB2DPoint( j
% nPointCount
);
1001 cairo_matrix_transform_point( &aOrigMatrix
, &nX
, &nY
);
1003 if( ! bIsBezier
&& (bIsRectangle
|| aOperation
== Clip
) )
1005 nX
= basegfx::fround( nX
);
1006 nY
= basegfx::fround( nY
);
1009 if( aOperation
== Stroke
)
1017 cairo_move_to( pCairo
, nX
, nY
);
1018 OSL_TRACE( "move to %f,%f", nX
, nY
);
1024 aA
= aPolygon
.getNextControlPoint( (j
-1) % nPointCount
);
1025 aB
= aPolygon
.getPrevControlPoint( j
% nPointCount
);
1032 cairo_matrix_transform_point( &aOrigMatrix
, &nAX
, &nAY
);
1033 cairo_matrix_transform_point( &aOrigMatrix
, &nBX
, &nBY
);
1035 if( aOperation
== Stroke
)
1043 cairo_curve_to( pCairo
, nAX
, nAY
, nBX
, nBY
, nX
, nY
);
1047 cairo_line_to( pCairo
, nX
, nY
);
1048 OSL_TRACE( "line to %f,%f", nX
, nY
);
1054 if( aPolygon
.isClosed() )
1055 cairo_close_path( pCairo
);
1060 OSL_TRACE( "empty polygon for op: %d", aOperation
);
1061 if( aOperation
== Clip
)
1070 if( aOperation
== Fill
&& pTextures
)
1072 cairo_set_matrix( pCairo
, &aOrigMatrix
);
1073 doOperation( aOperation
, pCairo
, pTextures
, pDevice
, aPolyPolygon
.getB2DRange() );
1074 cairo_set_matrix( pCairo
, &aIdentityMatrix
);
1077 if( bOpToDo
&& ( aOperation
!= Fill
|| !pTextures
) )
1078 doOperation( aOperation
, pCairo
, pTextures
, pDevice
, aPolyPolygon
.getB2DRange() );
1080 cairo_set_matrix( pCairo
, &aOrigMatrix
);
1082 if( aPolyPolygon
.count() == 0 && aOperation
== Clip
)
1086 void CanvasHelper::doPolyPolygonPath( const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
1087 Operation aOperation
,
1089 const uno::Sequence
< rendering::Texture
>* pTextures
,
1090 Cairo
* pCairo
) const
1092 const ::basegfx::B2DPolyPolygon
& rPolyPoly(
1093 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon
) );
1096 pCairo
= mpCairo
.get();
1098 if(bNoLineJoin
&& Stroke
== aOperation
)
1100 // emulate rendering::PathJoinType::NONE by painting single edges
1101 for(sal_uInt32
a(0); a
< rPolyPoly
.count(); a
++)
1103 const basegfx::B2DPolygon
aCandidate(rPolyPoly
.getB2DPolygon(a
));
1104 const sal_uInt32
nPointCount(aCandidate
.count());
1108 const sal_uInt32
nEdgeCount(aCandidate
.isClosed() ? nPointCount
: nPointCount
- 1);
1109 basegfx::B2DPolygon aEdge
;
1110 aEdge
.append(aCandidate
.getB2DPoint(0));
1111 aEdge
.append(basegfx::B2DPoint(0.0, 0.0));
1113 for(sal_uInt32
b(0); b
< nEdgeCount
; b
++)
1115 const sal_uInt32
nNextIndex((b
+ 1) % nPointCount
);
1116 aEdge
.setB2DPoint(1, aCandidate
.getB2DPoint(nNextIndex
));
1117 aEdge
.setNextControlPoint(0, aCandidate
.getNextControlPoint(b
% nPointCount
));
1118 aEdge
.setPrevControlPoint(1, aCandidate
.getPrevControlPoint(nNextIndex
));
1120 doPolyPolygonImplementation( basegfx::B2DPolyPolygon(aEdge
),
1124 xPolyPolygon
->getFillRule() );
1126 // prepare next step
1127 aEdge
.setB2DPoint(0, aEdge
.getB2DPoint(1));
1134 doPolyPolygonImplementation( rPolyPoly
, aOperation
,
1137 xPolyPolygon
->getFillRule() );
1141 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawPolyPolygon( const rendering::XCanvas
* ,
1142 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
1143 const rendering::ViewState
& viewState
,
1144 const rendering::RenderState
& renderState
)
1146 #ifdef CAIRO_CANVAS_PERF_TRACE
1147 struct timespec aTimer
;
1148 mxDevice
->startPerfTrace( &aTimer
);
1153 cairo_save( mpCairo
.get() );
1155 cairo_set_line_width( mpCairo
.get(), 1 );
1157 useStates( viewState
, renderState
, true );
1158 doPolyPolygonPath( xPolyPolygon
, Stroke
);
1160 cairo_restore( mpCairo
.get() );
1163 OSL_TRACE ("CanvasHelper called after it was disposed");
1165 #ifdef CAIRO_CANVAS_PERF_TRACE
1166 mxDevice
->stopPerfTrace( &aTimer
, "drawPolyPolygon" );
1169 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1172 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokePolyPolygon( const rendering::XCanvas
* ,
1173 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
1174 const rendering::ViewState
& viewState
,
1175 const rendering::RenderState
& renderState
,
1176 const rendering::StrokeAttributes
& strokeAttributes
)
1178 #ifdef CAIRO_CANVAS_PERF_TRACE
1179 struct timespec aTimer
;
1180 mxDevice
->startPerfTrace( &aTimer
);
1185 cairo_save( mpCairo
.get() );
1187 useStates( viewState
, renderState
, true );
1190 double w
= strokeAttributes
.StrokeWidth
, h
= 0;
1191 cairo_get_matrix( mpCairo
.get(), &aMatrix
);
1192 cairo_matrix_transform_distance( &aMatrix
, &w
, &h
);
1193 cairo_set_line_width( mpCairo
.get(), w
);
1195 cairo_set_miter_limit( mpCairo
.get(), strokeAttributes
.MiterLimit
);
1197 // FIXME: cairo doesn't handle end cap so far (rodo)
1198 switch( strokeAttributes
.StartCapType
)
1200 case rendering::PathCapType::BUTT
:
1201 cairo_set_line_cap( mpCairo
.get(), CAIRO_LINE_CAP_BUTT
);
1203 case rendering::PathCapType::ROUND
:
1204 cairo_set_line_cap( mpCairo
.get(), CAIRO_LINE_CAP_ROUND
);
1206 case rendering::PathCapType::SQUARE
:
1207 cairo_set_line_cap( mpCairo
.get(), CAIRO_LINE_CAP_SQUARE
);
1211 bool bNoLineJoin(false);
1213 switch( strokeAttributes
.JoinType
)
1215 // cairo doesn't have join type NONE so we use MITER as it's pretty close
1216 case rendering::PathJoinType::NONE
:
1218 case rendering::PathJoinType::MITER
:
1219 cairo_set_line_join( mpCairo
.get(), CAIRO_LINE_JOIN_MITER
);
1221 case rendering::PathJoinType::ROUND
:
1222 cairo_set_line_join( mpCairo
.get(), CAIRO_LINE_JOIN_ROUND
);
1224 case rendering::PathJoinType::BEVEL
:
1225 cairo_set_line_join( mpCairo
.get(), CAIRO_LINE_JOIN_BEVEL
);
1229 if( strokeAttributes
.DashArray
.getLength() > 0 )
1231 double* pDashArray
= new double[ strokeAttributes
.DashArray
.getLength() ];
1232 for( sal_Int32 i
=0; i
<strokeAttributes
.DashArray
.getLength(); i
++ )
1233 pDashArray
[i
] = strokeAttributes
.DashArray
[i
] * w
;
1234 cairo_set_dash( mpCairo
.get(), pDashArray
, strokeAttributes
.DashArray
.getLength(), 0 );
1235 delete[] pDashArray
;
1238 // TODO(rodo) use LineArray of strokeAttributes
1240 doPolyPolygonPath( xPolyPolygon
, Stroke
, bNoLineJoin
);
1242 cairo_restore( mpCairo
.get() );
1245 OSL_TRACE ("CanvasHelper called after it was disposed");
1247 #ifdef CAIRO_CANVAS_PERF_TRACE
1248 mxDevice
->stopPerfTrace( &aTimer
, "strokePolyPolygon" );
1251 // TODO(P1): Provide caching here.
1252 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1255 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas
* ,
1256 const uno::Reference
< rendering::XPolyPolygon2D
>& /*xPolyPolygon*/,
1257 const rendering::ViewState
& /*viewState*/,
1258 const rendering::RenderState
& /*renderState*/,
1259 const uno::Sequence
< rendering::Texture
>& /*textures*/,
1260 const rendering::StrokeAttributes
& /*strokeAttributes*/ )
1263 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1266 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas
* ,
1267 const uno::Reference
< rendering::XPolyPolygon2D
>& /*xPolyPolygon*/,
1268 const rendering::ViewState
& /*viewState*/,
1269 const rendering::RenderState
& /*renderState*/,
1270 const uno::Sequence
< rendering::Texture
>& /*textures*/,
1271 const uno::Reference
< geometry::XMapping2D
>& /*xMapping*/,
1272 const rendering::StrokeAttributes
& /*strokeAttributes*/ )
1275 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1278 uno::Reference
< rendering::XPolyPolygon2D
> CanvasHelper::queryStrokeShapes( const rendering::XCanvas
* ,
1279 const uno::Reference
< rendering::XPolyPolygon2D
>& /*xPolyPolygon*/,
1280 const rendering::ViewState
& /*viewState*/,
1281 const rendering::RenderState
& /*renderState*/,
1282 const rendering::StrokeAttributes
& /*strokeAttributes*/ )
1285 return uno::Reference
< rendering::XPolyPolygon2D
>(NULL
);
1288 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::fillPolyPolygon( const rendering::XCanvas
* ,
1289 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
1290 const rendering::ViewState
& viewState
,
1291 const rendering::RenderState
& renderState
)
1293 #ifdef CAIRO_CANVAS_PERF_TRACE
1294 struct timespec aTimer
;
1295 mxDevice
->startPerfTrace( &aTimer
);
1300 cairo_save( mpCairo
.get() );
1302 useStates( viewState
, renderState
, true );
1303 doPolyPolygonPath( xPolyPolygon
, Fill
);
1305 cairo_restore( mpCairo
.get() );
1308 OSL_TRACE ("CanvasHelper called after it was disposed");
1310 #ifdef CAIRO_CANVAS_PERF_TRACE
1311 mxDevice
->stopPerfTrace( &aTimer
, "fillPolyPolygon" );
1314 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1317 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas
* ,
1318 const uno::Reference
< rendering::XPolyPolygon2D
>& xPolyPolygon
,
1319 const rendering::ViewState
& viewState
,
1320 const rendering::RenderState
& renderState
,
1321 const uno::Sequence
< rendering::Texture
>& textures
)
1325 cairo_save( mpCairo
.get() );
1327 useStates( viewState
, renderState
, true );
1328 doPolyPolygonPath( xPolyPolygon
, Fill
, false, &textures
);
1330 cairo_restore( mpCairo
.get() );
1333 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1336 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas
* ,
1337 const uno::Reference
< rendering::XPolyPolygon2D
>& /*xPolyPolygon*/,
1338 const rendering::ViewState
& /*viewState*/,
1339 const rendering::RenderState
& /*renderState*/,
1340 const uno::Sequence
< rendering::Texture
>& /*textures*/,
1341 const uno::Reference
< geometry::XMapping2D
>& /*xMapping*/ )
1344 return uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1347 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::implDrawBitmapSurface( const rendering::XCanvas
* pCanvas
,
1348 const SurfaceSharedPtr
& pInputSurface
,
1349 const rendering::ViewState
& viewState
,
1350 const rendering::RenderState
& renderState
,
1351 const geometry::IntegerSize2D
& rSize
,
1352 bool bModulateColors
,
1355 SurfaceSharedPtr pSurface
=pInputSurface
;
1356 uno::Reference
< rendering::XCachedPrimitive
> rv
= uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1357 geometry::IntegerSize2D aBitmapSize
= rSize
;
1361 cairo_save( mpCairo
.get() );
1363 cairo_rectangle( mpCairo
.get(), 0, 0, maSize
.getX(), maSize
.getY() );
1364 cairo_clip( mpCairo
.get() );
1366 useStates( viewState
, renderState
, true );
1370 cairo_get_matrix( mpCairo
.get(), &aMatrix
);
1371 if( ! ::rtl::math::approxEqual( aMatrix
.xx
, 1 ) &&
1372 ! ::rtl::math::approxEqual( aMatrix
.yy
, 1 ) &&
1373 ::rtl::math::approxEqual( aMatrix
.x0
, 0 ) &&
1374 ::rtl::math::approxEqual( aMatrix
.y0
, 0 ) &&
1375 basegfx::fround( rSize
.Width
* aMatrix
.xx
) > 8 &&
1376 basegfx::fround( rSize
.Height
* aMatrix
.yy
) > 8 )
1378 double dWidth
, dHeight
;
1380 dWidth
= basegfx::fround( rSize
.Width
* aMatrix
.xx
);
1381 dHeight
= basegfx::fround( rSize
.Height
* aMatrix
.yy
);
1382 aBitmapSize
.Width
= static_cast<sal_Int32
>( dWidth
);
1383 aBitmapSize
.Height
= static_cast<sal_Int32
>( dHeight
);
1385 SurfaceSharedPtr pScaledSurface
= mpSurfaceProvider
->createSurface(
1386 ::basegfx::B2ISize( aBitmapSize
.Width
, aBitmapSize
.Height
),
1387 bHasAlpha
? CAIRO_CONTENT_COLOR_ALPHA
: CAIRO_CONTENT_COLOR
);
1388 CairoSharedPtr pCairo
= pScaledSurface
->getCairo();
1390 cairo_set_operator( pCairo
.get(), CAIRO_OPERATOR_SOURCE
);
1391 // add 0.5px to size to avoid rounding errors in cairo, leading sometimes to random data on the image right/bottom borders
1392 cairo_scale( pCairo
.get(), (dWidth
+0.5)/rSize
.Width
, (dHeight
+0.5)/rSize
.Height
);
1393 cairo_set_source_surface( pCairo
.get(), pSurface
->getCairoSurface().get(), 0, 0 );
1394 cairo_paint( pCairo
.get() );
1396 pSurface
= pScaledSurface
;
1398 aMatrix
.xx
= aMatrix
.yy
= 1;
1399 cairo_set_matrix( mpCairo
.get(), &aMatrix
);
1401 rv
= uno::Reference
< rendering::XCachedPrimitive
>(
1402 new CachedBitmap( pSurface
, viewState
, renderState
,
1403 // cast away const, need to
1404 // change refcount (as this is
1405 // ~invisible to client code,
1406 // still logically const)
1407 const_cast< rendering::XCanvas
* >(pCanvas
)) );
1410 if( !bHasAlpha
&& mbHaveAlpha
)
1412 double x
, y
, width
, height
;
1415 width
= aBitmapSize
.Width
;
1416 height
= aBitmapSize
.Height
;
1417 cairo_matrix_transform_point( &aMatrix
, &x
, &y
);
1418 cairo_matrix_transform_distance( &aMatrix
, &width
, &height
);
1420 // in case the bitmap doesn't have alpha and covers whole area
1421 // we try to change surface to plain rgb
1422 OSL_TRACE ("chance to change surface to rgb, %f, %f, %f x %f (%d x %d)", x
, y
, width
, height
, maSize
.getX(), maSize
.getY() );
1423 if( x
<= 0 && y
<= 0 && x
+ width
>= maSize
.getX() && y
+ height
>= maSize
.getY() )
1425 OSL_TRACE ("trying to change surface to rgb");
1426 if( mpSurfaceProvider
) {
1427 SurfaceSharedPtr pNewSurface
= mpSurfaceProvider
->changeSurface( false, false );
1430 setSurface( pNewSurface
, false );
1432 // set state to new mpCairo.get()
1433 useStates( viewState
, renderState
, true );
1434 // use the possibly modified matrix
1435 cairo_set_matrix( mpCairo
.get(), &aMatrix
);
1440 cairo_set_source_surface( mpCairo
.get(), pSurface
->getCairoSurface().get(), 0, 0 );
1442 ::rtl::math::approxEqual( aMatrix
.xx
, 1 ) &&
1443 ::rtl::math::approxEqual( aMatrix
.yy
, 1 ) &&
1444 ::rtl::math::approxEqual( aMatrix
.x0
, 0 ) &&
1445 ::rtl::math::approxEqual( aMatrix
.y0
, 0 ) )
1446 cairo_set_operator( mpCairo
.get(), CAIRO_OPERATOR_SOURCE
);
1447 #if CAIRO_VERSION >= 10200
1448 cairo_pattern_set_extend( cairo_get_source(mpCairo
.get()), CAIRO_EXTEND_PAD
);
1450 cairo_rectangle( mpCairo
.get(), 0, 0, aBitmapSize
.Width
, aBitmapSize
.Height
);
1451 cairo_clip( mpCairo
.get() );
1453 if( bModulateColors
)
1454 cairo_paint_with_alpha( mpCairo
.get(), renderState
.DeviceColor
[3] );
1456 cairo_paint( mpCairo
.get() );
1457 cairo_restore( mpCairo
.get() );
1460 OSL_TRACE ("CanvasHelper called after it was disposed");
1462 return rv
; // uno::Reference< rendering::XCachedPrimitive >(NULL);
1465 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawBitmap( const rendering::XCanvas
* pCanvas
,
1466 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
1467 const rendering::ViewState
& viewState
,
1468 const rendering::RenderState
& renderState
)
1470 #ifdef CAIRO_CANVAS_PERF_TRACE
1471 struct timespec aTimer
;
1472 mxDevice
->startPerfTrace( &aTimer
);
1475 uno::Reference
< rendering::XCachedPrimitive
> rv
;
1476 unsigned char* data
= NULL
;
1477 bool bHasAlpha
= false;
1478 SurfaceSharedPtr pSurface
= surfaceFromXBitmap( xBitmap
, mpSurfaceProvider
, data
, bHasAlpha
);
1479 geometry::IntegerSize2D aSize
= xBitmap
->getSize();
1483 rv
= implDrawBitmapSurface( pCanvas
, pSurface
, viewState
, renderState
, aSize
, false, bHasAlpha
);
1489 rv
= uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1491 #ifdef CAIRO_CANVAS_PERF_TRACE
1492 mxDevice
->stopPerfTrace( &aTimer
, "drawBitmap" );
1498 uno::Reference
< rendering::XCachedPrimitive
> CanvasHelper::drawBitmapModulated( const rendering::XCanvas
* pCanvas
,
1499 const uno::Reference
< rendering::XBitmap
>& xBitmap
,
1500 const rendering::ViewState
& viewState
,
1501 const rendering::RenderState
& renderState
)
1503 #ifdef CAIRO_CANVAS_PERF_TRACE
1504 struct timespec aTimer
;
1505 mxDevice
->startPerfTrace( &aTimer
);
1508 uno::Reference
< rendering::XCachedPrimitive
> rv
;
1509 unsigned char* data
= NULL
;
1510 bool bHasAlpha
= false;
1511 SurfaceSharedPtr pSurface
= surfaceFromXBitmap( xBitmap
, mpSurfaceProvider
, data
, bHasAlpha
);
1512 geometry::IntegerSize2D aSize
= xBitmap
->getSize();
1516 rv
= implDrawBitmapSurface( pCanvas
, pSurface
, viewState
, renderState
, aSize
, true, bHasAlpha
);
1522 rv
= uno::Reference
< rendering::XCachedPrimitive
>(NULL
);
1524 #ifdef CAIRO_CANVAS_PERF_TRACE
1525 mxDevice
->stopPerfTrace( &aTimer
, "drawBitmap" );
1531 uno::Reference
< rendering::XGraphicDevice
> CanvasHelper::getDevice()
1533 return uno::Reference
< rendering::XGraphicDevice
>(mpDevice
);
1536 void CanvasHelper::copyRect( const rendering::XCanvas
* ,
1537 const uno::Reference
< rendering::XBitmapCanvas
>& /*sourceCanvas*/,
1538 const geometry::RealRectangle2D
& /*sourceRect*/,
1539 const rendering::ViewState
& /*sourceViewState*/,
1540 const rendering::RenderState
& /*sourceRenderState*/,
1541 const geometry::RealRectangle2D
& /*destRect*/,
1542 const rendering::ViewState
& /*destViewState*/,
1543 const rendering::RenderState
& /*destRenderState*/ )
1545 // TODO(F2): copyRect NYI
1548 geometry::IntegerSize2D
CanvasHelper::getSize()
1550 if( !mpSurfaceProvider
)
1551 geometry::IntegerSize2D(1, 1); // we're disposed
1553 return ::basegfx::unotools::integerSize2DFromB2ISize( maSize
);
1556 uno::Reference
< rendering::XBitmap
> CanvasHelper::getScaledBitmap( const geometry::RealSize2D
& newSize
,
1557 sal_Bool
/*beFast*/ )
1559 #ifdef CAIRO_CANVAS_PERF_TRACE
1560 struct timespec aTimer
;
1561 mxDevice
->startPerfTrace( &aTimer
);
1566 return uno::Reference
< rendering::XBitmap
>( new CanvasBitmap( ::basegfx::B2ISize( ::canvas::tools::roundUp( newSize
.Width
),
1567 ::canvas::tools::roundUp( newSize
.Height
) ),
1568 mpSurfaceProvider
, mpDevice
, false ) );
1571 OSL_TRACE ("CanvasHelper called after it was disposed");
1573 #ifdef CAIRO_CANVAS_PERF_TRACE
1574 mxDevice
->stopPerfTrace( &aTimer
, "getScaledBitmap" );
1577 return uno::Reference
< rendering::XBitmap
>();
1580 uno::Sequence
< sal_Int8
> CanvasHelper::getData( rendering::IntegerBitmapLayout
& aLayout
,
1581 const geometry::IntegerRectangle2D
& rect
)
1585 const sal_Int32
nWidth( rect
.X2
- rect
.X1
);
1586 const sal_Int32
nHeight( rect
.Y2
- rect
.Y1
);
1587 const Format
eFormat( mbHaveAlpha
? CAIRO_FORMAT_ARGB32
: CAIRO_FORMAT_RGB24
);
1588 uno::Sequence
< sal_Int8
> aRes( 4*nWidth
*nHeight
);
1589 sal_Int8
* pData
= aRes
.getArray();
1590 cairo_surface_t
* pImageSurface
= cairo_image_surface_create_for_data( (unsigned char *) pData
,
1592 nWidth
, nHeight
, 4*nWidth
);
1593 cairo_t
* pCairo
= cairo_create( pImageSurface
);
1594 cairo_set_source_surface( pCairo
, mpSurface
->getCairoSurface().get(), -rect
.X1
, -rect
.Y1
);
1595 cairo_paint( pCairo
);
1596 cairo_destroy( pCairo
);
1597 cairo_surface_destroy( pImageSurface
);
1599 aLayout
= impl_getMemoryLayout( nWidth
, nHeight
);
1604 return uno::Sequence
< sal_Int8
>();
1607 void CanvasHelper::setData( const uno::Sequence
< sal_Int8
>& /*data*/,
1608 const rendering::IntegerBitmapLayout
& /*bitmapLayout*/,
1609 const geometry::IntegerRectangle2D
& /*rect*/ )
1613 void CanvasHelper::setPixel( const uno::Sequence
< sal_Int8
>& /*color*/,
1614 const rendering::IntegerBitmapLayout
& /*bitmapLayout*/,
1615 const geometry::IntegerPoint2D
& /*pos*/ )
1619 uno::Sequence
< sal_Int8
> CanvasHelper::getPixel( rendering::IntegerBitmapLayout
& /*bitmapLayout*/,
1620 const geometry::IntegerPoint2D
& /*pos*/ )
1622 return uno::Sequence
< sal_Int8
>();
1627 class CairoColorSpace
: public cppu::WeakImplHelper1
< com::sun::star::rendering::XIntegerBitmapColorSpace
>
1630 uno::Sequence
< sal_Int8
> maComponentTags
;
1631 uno::Sequence
< sal_Int32
> maBitCounts
;
1633 virtual ::sal_Int8 SAL_CALL
getType( ) throw (uno::RuntimeException
)
1635 return rendering::ColorSpaceType::RGB
;
1637 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
getComponentTags( ) throw (uno::RuntimeException
)
1639 return maComponentTags
;
1641 virtual ::sal_Int8 SAL_CALL
getRenderingIntent( ) throw (uno::RuntimeException
)
1643 return rendering::RenderingIntent::PERCEPTUAL
;
1645 virtual uno::Sequence
< beans::PropertyValue
> SAL_CALL
getProperties( ) throw (uno::RuntimeException
)
1647 return uno::Sequence
< beans::PropertyValue
>();
1649 virtual uno::Sequence
< double > SAL_CALL
convertColorSpace( const uno::Sequence
< double >& deviceColor
,
1650 const uno::Reference
< rendering::XColorSpace
>& targetColorSpace
) throw (lang::IllegalArgumentException
,
1651 uno::RuntimeException
)
1653 // TODO(P3): if we know anything about target
1654 // colorspace, this can be greatly sped up
1655 uno::Sequence
<rendering::ARGBColor
> aIntermediate(
1656 convertToARGB(deviceColor
));
1657 return targetColorSpace
->convertFromARGB(aIntermediate
);
1659 virtual uno::Sequence
< rendering::RGBColor
> SAL_CALL
convertToRGB( const uno::Sequence
< double >& deviceColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1661 const double* pIn( deviceColor
.getConstArray() );
1662 const sal_Size
nLen( deviceColor
.getLength() );
1663 ENSURE_ARG_OR_THROW2(nLen
%4==0,
1664 "number of channels no multiple of 4",
1665 static_cast<rendering::XColorSpace
*>(this), 0);
1667 uno::Sequence
< rendering::RGBColor
> aRes(nLen
/4);
1668 rendering::RGBColor
* pOut( aRes
.getArray() );
1669 for( sal_Size i
=0; i
<nLen
; i
+=4 )
1671 const double fAlpha(pIn
[3]);
1673 *pOut
++ = rendering::RGBColor(0.0, 0.0, 0.0);
1675 *pOut
++ = rendering::RGBColor(pIn
[2]/fAlpha
,pIn
[1]/fAlpha
,pIn
[0]/fAlpha
);
1680 virtual uno::Sequence
< rendering::ARGBColor
> SAL_CALL
convertToARGB( const uno::Sequence
< double >& deviceColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1682 const double* pIn( deviceColor
.getConstArray() );
1683 const sal_Size
nLen( deviceColor
.getLength() );
1684 ENSURE_ARG_OR_THROW2(nLen
%4==0,
1685 "number of channels no multiple of 4",
1686 static_cast<rendering::XColorSpace
*>(this), 0);
1688 uno::Sequence
< rendering::ARGBColor
> aRes(nLen
/4);
1689 rendering::ARGBColor
* pOut( aRes
.getArray() );
1690 for( sal_Size i
=0; i
<nLen
; i
+=4 )
1692 const double fAlpha(pIn
[3]);
1694 *pOut
++ = rendering::ARGBColor(0.0, 0.0, 0.0, 0.0);
1696 *pOut
++ = rendering::ARGBColor(fAlpha
,pIn
[2]/fAlpha
,pIn
[1]/fAlpha
,pIn
[0]/fAlpha
);
1701 virtual uno::Sequence
< rendering::ARGBColor
> SAL_CALL
convertToPARGB( const uno::Sequence
< double >& deviceColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1703 const double* pIn( deviceColor
.getConstArray() );
1704 const sal_Size
nLen( deviceColor
.getLength() );
1705 ENSURE_ARG_OR_THROW2(nLen
%4==0,
1706 "number of channels no multiple of 4",
1707 static_cast<rendering::XColorSpace
*>(this), 0);
1709 uno::Sequence
< rendering::ARGBColor
> aRes(nLen
/4);
1710 rendering::ARGBColor
* pOut( aRes
.getArray() );
1711 for( sal_Size i
=0; i
<nLen
; i
+=4 )
1713 *pOut
++ = rendering::ARGBColor(pIn
[3],pIn
[2],pIn
[1],pIn
[1]);
1718 virtual uno::Sequence
< double > SAL_CALL
convertFromRGB( const uno::Sequence
< rendering::RGBColor
>& rgbColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1720 const rendering::RGBColor
* pIn( rgbColor
.getConstArray() );
1721 const sal_Size
nLen( rgbColor
.getLength() );
1723 uno::Sequence
< double > aRes(nLen
*4);
1724 double* pColors
=aRes
.getArray();
1725 for( sal_Size i
=0; i
<nLen
; ++i
)
1727 *pColors
++ = pIn
->Blue
;
1728 *pColors
++ = pIn
->Green
;
1729 *pColors
++ = pIn
->Red
;
1735 virtual uno::Sequence
< double > SAL_CALL
convertFromARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1737 const rendering::ARGBColor
* pIn( rgbColor
.getConstArray() );
1738 const sal_Size
nLen( rgbColor
.getLength() );
1740 uno::Sequence
< double > aRes(nLen
*4);
1741 double* pColors
=aRes
.getArray();
1742 for( sal_Size i
=0; i
<nLen
; ++i
)
1744 *pColors
++ = pIn
->Alpha
*pIn
->Blue
;
1745 *pColors
++ = pIn
->Alpha
*pIn
->Green
;
1746 *pColors
++ = pIn
->Alpha
*pIn
->Red
;
1747 *pColors
++ = pIn
->Alpha
;
1752 virtual uno::Sequence
< double > SAL_CALL
convertFromPARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1754 const rendering::ARGBColor
* pIn( rgbColor
.getConstArray() );
1755 const sal_Size
nLen( rgbColor
.getLength() );
1757 uno::Sequence
< double > aRes(nLen
*4);
1758 double* pColors
=aRes
.getArray();
1759 for( sal_Size i
=0; i
<nLen
; ++i
)
1761 *pColors
++ = pIn
->Blue
;
1762 *pColors
++ = pIn
->Green
;
1763 *pColors
++ = pIn
->Red
;
1764 *pColors
++ = pIn
->Alpha
;
1770 // XIntegerBitmapColorSpace
1771 virtual ::sal_Int32 SAL_CALL
getBitsPerPixel( ) throw (uno::RuntimeException
)
1775 virtual uno::Sequence
< ::sal_Int32
> SAL_CALL
getComponentBitCounts( ) throw (uno::RuntimeException
)
1779 virtual ::sal_Int8 SAL_CALL
getEndianness( ) throw (uno::RuntimeException
)
1781 return util::Endianness::LITTLE
;
1783 virtual uno::Sequence
<double> SAL_CALL
convertFromIntegerColorSpace( const uno::Sequence
< ::sal_Int8
>& deviceColor
,
1784 const uno::Reference
< rendering::XColorSpace
>& targetColorSpace
)
1785 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1787 if( dynamic_cast<CairoColorSpace
*>(targetColorSpace
.get()) )
1789 const sal_Int8
* pIn( deviceColor
.getConstArray() );
1790 const sal_Size
nLen( deviceColor
.getLength() );
1791 ENSURE_ARG_OR_THROW2(nLen
%4==0,
1792 "number of channels no multiple of 4",
1793 static_cast<rendering::XColorSpace
*>(this), 0);
1795 uno::Sequence
<double> aRes(nLen
);
1796 double* pOut( aRes
.getArray() );
1797 for( sal_Size i
=0; i
<nLen
; i
+=4 )
1799 *pOut
++ = vcl::unotools::toDoubleColor(*pIn
++);
1800 *pOut
++ = vcl::unotools::toDoubleColor(*pIn
++);
1801 *pOut
++ = vcl::unotools::toDoubleColor(*pIn
++);
1802 *pOut
++ = vcl::unotools::toDoubleColor(*pIn
++);
1808 // TODO(P3): if we know anything about target
1809 // colorspace, this can be greatly sped up
1810 uno::Sequence
<rendering::ARGBColor
> aIntermediate(
1811 convertIntegerToARGB(deviceColor
));
1812 return targetColorSpace
->convertFromARGB(aIntermediate
);
1815 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
convertToIntegerColorSpace( const uno::Sequence
< ::sal_Int8
>& deviceColor
,
1816 const uno::Reference
< rendering::XIntegerBitmapColorSpace
>& targetColorSpace
)
1817 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1819 if( dynamic_cast<CairoColorSpace
*>(targetColorSpace
.get()) )
1821 // it's us, so simply pass-through the data
1826 // TODO(P3): if we know anything about target
1827 // colorspace, this can be greatly sped up
1828 uno::Sequence
<rendering::ARGBColor
> aIntermediate(
1829 convertIntegerToARGB(deviceColor
));
1830 return targetColorSpace
->convertIntegerFromARGB(aIntermediate
);
1833 virtual uno::Sequence
< rendering::RGBColor
> SAL_CALL
convertIntegerToRGB( const uno::Sequence
< ::sal_Int8
>& deviceColor
)
1834 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1836 const sal_Int8
* pIn( deviceColor
.getConstArray() );
1837 const sal_Size
nLen( deviceColor
.getLength() );
1838 ENSURE_ARG_OR_THROW2(nLen
%4==0,
1839 "number of channels no multiple of 4",
1840 static_cast<rendering::XColorSpace
*>(this), 0);
1842 uno::Sequence
< rendering::RGBColor
> aRes(nLen
/4);
1843 rendering::RGBColor
* pOut( aRes
.getArray() );
1844 for( sal_Size i
=0; i
<nLen
; i
+=4 )
1846 const double fAlpha((sal_uInt8
)pIn
[3]);
1848 *pOut
++ = rendering::RGBColor(
1853 *pOut
++ = rendering::RGBColor(0,0,0);
1859 virtual uno::Sequence
< rendering::ARGBColor
> SAL_CALL
convertIntegerToARGB( const uno::Sequence
< ::sal_Int8
>& deviceColor
)
1860 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1862 const sal_Int8
* pIn( deviceColor
.getConstArray() );
1863 const sal_Size
nLen( deviceColor
.getLength() );
1864 ENSURE_ARG_OR_THROW2(nLen
%4==0,
1865 "number of channels no multiple of 4",
1866 static_cast<rendering::XColorSpace
*>(this), 0);
1868 uno::Sequence
< rendering::ARGBColor
> aRes(nLen
/4);
1869 rendering::ARGBColor
* pOut( aRes
.getArray() );
1870 for( sal_Size i
=0; i
<nLen
; i
+=4 )
1872 const double fAlpha((sal_uInt8
)pIn
[3]);
1874 *pOut
++ = rendering::ARGBColor(
1880 *pOut
++ = rendering::ARGBColor(0,0,0,0);
1885 virtual uno::Sequence
< rendering::ARGBColor
> SAL_CALL
convertIntegerToPARGB( const uno::Sequence
< ::sal_Int8
>& deviceColor
)
1886 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1888 const sal_Int8
* pIn( deviceColor
.getConstArray() );
1889 const sal_Size
nLen( deviceColor
.getLength() );
1890 ENSURE_ARG_OR_THROW2(nLen
%4==0,
1891 "number of channels no multiple of 4",
1892 static_cast<rendering::XColorSpace
*>(this), 0);
1894 uno::Sequence
< rendering::ARGBColor
> aRes(nLen
/4);
1895 rendering::ARGBColor
* pOut( aRes
.getArray() );
1896 for( sal_Size i
=0; i
<nLen
; i
+=4 )
1898 *pOut
++ = rendering::ARGBColor(
1899 vcl::unotools::toDoubleColor(pIn
[3]),
1900 vcl::unotools::toDoubleColor(pIn
[2]),
1901 vcl::unotools::toDoubleColor(pIn
[1]),
1902 vcl::unotools::toDoubleColor(pIn
[0]));
1908 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
convertIntegerFromRGB( const uno::Sequence
< rendering::RGBColor
>& rgbColor
)
1909 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1911 const rendering::RGBColor
* pIn( rgbColor
.getConstArray() );
1912 const sal_Size
nLen( rgbColor
.getLength() );
1914 uno::Sequence
< sal_Int8
> aRes(nLen
*4);
1915 sal_Int8
* pColors
=aRes
.getArray();
1916 for( sal_Size i
=0; i
<nLen
; ++i
)
1918 *pColors
++ = vcl::unotools::toByteColor(pIn
->Blue
);
1919 *pColors
++ = vcl::unotools::toByteColor(pIn
->Green
);
1920 *pColors
++ = vcl::unotools::toByteColor(pIn
->Red
);
1927 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
convertIntegerFromARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
)
1928 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1930 const rendering::ARGBColor
* pIn( rgbColor
.getConstArray() );
1931 const sal_Size
nLen( rgbColor
.getLength() );
1933 uno::Sequence
< sal_Int8
> aRes(nLen
*4);
1934 sal_Int8
* pColors
=aRes
.getArray();
1935 for( sal_Size i
=0; i
<nLen
; ++i
)
1937 const double fAlpha(pIn
->Alpha
);
1938 *pColors
++ = vcl::unotools::toByteColor(fAlpha
*pIn
->Blue
);
1939 *pColors
++ = vcl::unotools::toByteColor(fAlpha
*pIn
->Green
);
1940 *pColors
++ = vcl::unotools::toByteColor(fAlpha
*pIn
->Red
);
1941 *pColors
++ = vcl::unotools::toByteColor(fAlpha
);
1946 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
convertIntegerFromPARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
)
1947 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
1949 const rendering::ARGBColor
* pIn( rgbColor
.getConstArray() );
1950 const sal_Size
nLen( rgbColor
.getLength() );
1952 uno::Sequence
< sal_Int8
> aRes(nLen
*4);
1953 sal_Int8
* pColors
=aRes
.getArray();
1954 for( sal_Size i
=0; i
<nLen
; ++i
)
1956 *pColors
++ = vcl::unotools::toByteColor(pIn
->Blue
);
1957 *pColors
++ = vcl::unotools::toByteColor(pIn
->Green
);
1958 *pColors
++ = vcl::unotools::toByteColor(pIn
->Red
);
1959 *pColors
++ = vcl::unotools::toByteColor(pIn
->Alpha
);
1970 sal_Int8
* pTags
= maComponentTags
.getArray();
1971 sal_Int32
* pBitCounts
= maBitCounts
.getArray();
1972 pTags
[0] = rendering::ColorComponentTag::RGB_BLUE
;
1973 pTags
[1] = rendering::ColorComponentTag::RGB_GREEN
;
1974 pTags
[2] = rendering::ColorComponentTag::RGB_RED
;
1975 pTags
[3] = rendering::ColorComponentTag::PREMULTIPLIED_ALPHA
;
1984 class CairoNoAlphaColorSpace
: public cppu::WeakImplHelper1
< com::sun::star::rendering::XIntegerBitmapColorSpace
>
1987 uno::Sequence
< sal_Int8
> maComponentTags
;
1988 uno::Sequence
< sal_Int32
> maBitCounts
;
1990 virtual ::sal_Int8 SAL_CALL
getType( ) throw (uno::RuntimeException
)
1992 return rendering::ColorSpaceType::RGB
;
1994 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
getComponentTags( ) throw (uno::RuntimeException
)
1996 return maComponentTags
;
1998 virtual ::sal_Int8 SAL_CALL
getRenderingIntent( ) throw (uno::RuntimeException
)
2000 return rendering::RenderingIntent::PERCEPTUAL
;
2002 virtual uno::Sequence
< beans::PropertyValue
> SAL_CALL
getProperties( ) throw (uno::RuntimeException
)
2004 return uno::Sequence
< beans::PropertyValue
>();
2006 virtual uno::Sequence
< double > SAL_CALL
convertColorSpace( const uno::Sequence
< double >& deviceColor
,
2007 const uno::Reference
< rendering::XColorSpace
>& targetColorSpace
) throw (lang::IllegalArgumentException
,
2008 uno::RuntimeException
)
2010 // TODO(P3): if we know anything about target
2011 // colorspace, this can be greatly sped up
2012 uno::Sequence
<rendering::ARGBColor
> aIntermediate(
2013 convertToARGB(deviceColor
));
2014 return targetColorSpace
->convertFromARGB(aIntermediate
);
2016 virtual uno::Sequence
< rendering::RGBColor
> SAL_CALL
convertToRGB( const uno::Sequence
< double >& deviceColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2018 const double* pIn( deviceColor
.getConstArray() );
2019 const sal_Size
nLen( deviceColor
.getLength() );
2020 ENSURE_ARG_OR_THROW2(nLen
%4==0,
2021 "number of channels no multiple of 4",
2022 static_cast<rendering::XColorSpace
*>(this), 0);
2024 uno::Sequence
< rendering::RGBColor
> aRes(nLen
/4);
2025 rendering::RGBColor
* pOut( aRes
.getArray() );
2026 for( sal_Size i
=0; i
<nLen
; i
+=4 )
2028 *pOut
++ = rendering::RGBColor(pIn
[2], pIn
[1], pIn
[0]);
2033 uno::Sequence
< rendering::ARGBColor
> impl_convertToARGB( const uno::Sequence
< double >& deviceColor
)
2035 const double* pIn( deviceColor
.getConstArray() );
2036 const sal_Size
nLen( deviceColor
.getLength() );
2037 ENSURE_ARG_OR_THROW2(nLen
%4==0,
2038 "number of channels no multiple of 4",
2039 static_cast<rendering::XColorSpace
*>(this), 0);
2041 uno::Sequence
< rendering::ARGBColor
> aRes(nLen
/4);
2042 rendering::ARGBColor
* pOut( aRes
.getArray() );
2043 for( sal_Size i
=0; i
<nLen
; i
+=4 )
2045 *pOut
++ = rendering::ARGBColor(1.0, pIn
[2], pIn
[1], pIn
[0]);
2050 virtual uno::Sequence
< rendering::ARGBColor
> SAL_CALL
convertToARGB( const uno::Sequence
< double >& deviceColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2052 return impl_convertToARGB( deviceColor
);
2054 virtual uno::Sequence
< rendering::ARGBColor
> SAL_CALL
convertToPARGB( const uno::Sequence
< double >& deviceColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2056 return impl_convertToARGB( deviceColor
);
2058 virtual uno::Sequence
< double > SAL_CALL
convertFromRGB( const uno::Sequence
< rendering::RGBColor
>& rgbColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2060 const rendering::RGBColor
* pIn( rgbColor
.getConstArray() );
2061 const sal_Size
nLen( rgbColor
.getLength() );
2063 uno::Sequence
< double > aRes(nLen
*4);
2064 double* pColors
=aRes
.getArray();
2065 for( sal_Size i
=0; i
<nLen
; ++i
)
2067 *pColors
++ = pIn
->Blue
;
2068 *pColors
++ = pIn
->Green
;
2069 *pColors
++ = pIn
->Red
;
2070 *pColors
++ = 1.0; // the value does not matter
2075 uno::Sequence
< double > impl_convertFromARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
)
2077 const rendering::ARGBColor
* pIn( rgbColor
.getConstArray() );
2078 const sal_Size
nLen( rgbColor
.getLength() );
2080 uno::Sequence
< double > aRes(nLen
*4);
2081 double* pColors
=aRes
.getArray();
2082 for( sal_Size i
=0; i
<nLen
; ++i
)
2084 *pColors
++ = pIn
->Blue
;
2085 *pColors
++ = pIn
->Green
;
2086 *pColors
++ = pIn
->Red
;
2087 *pColors
++ = 1.0; // the value does not matter
2092 virtual uno::Sequence
< double > SAL_CALL
convertFromARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2094 return impl_convertFromARGB( rgbColor
);
2096 virtual uno::Sequence
< double > SAL_CALL
convertFromPARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
) throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2098 return impl_convertFromARGB( rgbColor
);
2101 // XIntegerBitmapColorSpace
2102 virtual ::sal_Int32 SAL_CALL
getBitsPerPixel( ) throw (uno::RuntimeException
)
2106 virtual uno::Sequence
< ::sal_Int32
> SAL_CALL
getComponentBitCounts( ) throw (uno::RuntimeException
)
2110 virtual ::sal_Int8 SAL_CALL
getEndianness( ) throw (uno::RuntimeException
)
2112 return util::Endianness::LITTLE
;
2114 virtual uno::Sequence
<double> SAL_CALL
convertFromIntegerColorSpace( const uno::Sequence
< ::sal_Int8
>& deviceColor
,
2115 const uno::Reference
< rendering::XColorSpace
>& targetColorSpace
)
2116 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2118 if( dynamic_cast<CairoColorSpace
*>(targetColorSpace
.get()) )
2120 const sal_Int8
* pIn( deviceColor
.getConstArray() );
2121 const sal_Size
nLen( deviceColor
.getLength() );
2122 ENSURE_ARG_OR_THROW2(nLen
%4==0,
2123 "number of channels no multiple of 4",
2124 static_cast<rendering::XColorSpace
*>(this), 0);
2126 uno::Sequence
<double> aRes(nLen
);
2127 double* pOut( aRes
.getArray() );
2128 for( sal_Size i
=0; i
<nLen
; i
+=4 )
2130 *pOut
++ = vcl::unotools::toDoubleColor(*pIn
++);
2131 *pOut
++ = vcl::unotools::toDoubleColor(*pIn
++);
2132 *pOut
++ = vcl::unotools::toDoubleColor(*pIn
++);
2133 *pOut
++ = 1.0; // the value does not matter
2139 // TODO(P3): if we know anything about target
2140 // colorspace, this can be greatly sped up
2141 uno::Sequence
<rendering::ARGBColor
> aIntermediate(
2142 convertIntegerToARGB(deviceColor
));
2143 return targetColorSpace
->convertFromARGB(aIntermediate
);
2146 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
convertToIntegerColorSpace( const uno::Sequence
< ::sal_Int8
>& deviceColor
,
2147 const uno::Reference
< rendering::XIntegerBitmapColorSpace
>& targetColorSpace
)
2148 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2150 if( dynamic_cast<CairoNoAlphaColorSpace
*>(targetColorSpace
.get()) )
2152 // it's us, so simply pass-through the data
2157 // TODO(P3): if we know anything about target
2158 // colorspace, this can be greatly sped up
2159 uno::Sequence
<rendering::ARGBColor
> aIntermediate(
2160 convertIntegerToARGB(deviceColor
));
2161 return targetColorSpace
->convertIntegerFromARGB(aIntermediate
);
2164 virtual uno::Sequence
< rendering::RGBColor
> SAL_CALL
convertIntegerToRGB( const uno::Sequence
< ::sal_Int8
>& deviceColor
)
2165 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2167 const sal_Int8
* pIn( deviceColor
.getConstArray() );
2168 const sal_Size
nLen( deviceColor
.getLength() );
2169 ENSURE_ARG_OR_THROW2(nLen
%4==0,
2170 "number of channels no multiple of 4",
2171 static_cast<rendering::XColorSpace
*>(this), 0);
2173 uno::Sequence
< rendering::RGBColor
> aRes(nLen
/4);
2174 rendering::RGBColor
* pOut( aRes
.getArray() );
2175 for( sal_Size i
=0; i
<nLen
; i
+=4 )
2177 *pOut
++ = rendering::RGBColor( pIn
[2], pIn
[1], pIn
[0] );
2183 virtual uno::Sequence
< rendering::ARGBColor
> SAL_CALL
convertIntegerToARGB( const uno::Sequence
< ::sal_Int8
>& deviceColor
)
2184 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2186 return impl_convertIntegerToARGB( deviceColor
);
2188 virtual uno::Sequence
< rendering::ARGBColor
> SAL_CALL
convertIntegerToPARGB( const uno::Sequence
< ::sal_Int8
>& deviceColor
)
2189 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2191 return impl_convertIntegerToARGB( deviceColor
);
2193 uno::Sequence
< rendering::ARGBColor
> impl_convertIntegerToARGB( const uno::Sequence
< ::sal_Int8
>& deviceColor
)
2195 const sal_Int8
* pIn( deviceColor
.getConstArray() );
2196 const sal_Size
nLen( deviceColor
.getLength() );
2197 ENSURE_ARG_OR_THROW2(nLen
%4==0,
2198 "number of channels no multiple of 4",
2199 static_cast<rendering::XColorSpace
*>(this), 0);
2201 uno::Sequence
< rendering::ARGBColor
> aRes(nLen
/4);
2202 rendering::ARGBColor
* pOut( aRes
.getArray() );
2203 for( sal_Size i
=0; i
<nLen
; i
+=4 )
2205 *pOut
++ = rendering::ARGBColor(
2207 vcl::unotools::toDoubleColor(pIn
[2]),
2208 vcl::unotools::toDoubleColor(pIn
[1]),
2209 vcl::unotools::toDoubleColor(pIn
[0]));
2215 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
convertIntegerFromRGB( const uno::Sequence
< rendering::RGBColor
>& rgbColor
)
2216 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2218 const rendering::RGBColor
* pIn( rgbColor
.getConstArray() );
2219 const sal_Size
nLen( rgbColor
.getLength() );
2221 uno::Sequence
< sal_Int8
> aRes(nLen
*4);
2222 sal_Int8
* pColors
=aRes
.getArray();
2223 for( sal_Size i
=0; i
<nLen
; ++i
)
2225 *pColors
++ = vcl::unotools::toByteColor(pIn
->Blue
);
2226 *pColors
++ = vcl::unotools::toByteColor(pIn
->Green
);
2227 *pColors
++ = vcl::unotools::toByteColor(pIn
->Red
);
2228 *pColors
++ = -1; // the value does not matter
2234 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
convertIntegerFromARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
)
2235 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2237 return impl_convertIntegerFromARGB( rgbColor
);
2239 virtual uno::Sequence
< ::sal_Int8
> SAL_CALL
convertIntegerFromPARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
)
2240 throw (lang::IllegalArgumentException
, uno::RuntimeException
)
2242 return impl_convertIntegerFromARGB( rgbColor
);
2244 uno::Sequence
< ::sal_Int8
> impl_convertIntegerFromARGB( const uno::Sequence
< rendering::ARGBColor
>& rgbColor
)
2246 const rendering::ARGBColor
* pIn( rgbColor
.getConstArray() );
2247 const sal_Size
nLen( rgbColor
.getLength() );
2249 uno::Sequence
< sal_Int8
> aRes(nLen
*4);
2250 sal_Int8
* pColors
=aRes
.getArray();
2251 for( sal_Size i
=0; i
<nLen
; ++i
)
2253 *pColors
++ = vcl::unotools::toByteColor(pIn
->Blue
);
2254 *pColors
++ = vcl::unotools::toByteColor(pIn
->Green
);
2255 *pColors
++ = vcl::unotools::toByteColor(pIn
->Red
);
2256 *pColors
++ = -1; // the value does not matter
2263 CairoNoAlphaColorSpace() :
2267 sal_Int8
* pTags
= maComponentTags
.getArray();
2268 sal_Int32
* pBitCounts
= maBitCounts
.getArray();
2269 pTags
[0] = rendering::ColorComponentTag::RGB_BLUE
;
2270 pTags
[1] = rendering::ColorComponentTag::RGB_GREEN
;
2271 pTags
[2] = rendering::ColorComponentTag::RGB_RED
;
2279 struct CairoNoAlphaColorSpaceHolder
: public rtl::StaticWithInit
<uno::Reference
<rendering::XIntegerBitmapColorSpace
>,
2280 CairoNoAlphaColorSpaceHolder
>
2282 uno::Reference
<rendering::XIntegerBitmapColorSpace
> operator()()
2284 return new CairoNoAlphaColorSpace();
2288 struct CairoColorSpaceHolder
: public rtl::StaticWithInit
<uno::Reference
<rendering::XIntegerBitmapColorSpace
>,
2289 CairoColorSpaceHolder
>
2291 uno::Reference
<rendering::XIntegerBitmapColorSpace
> operator()()
2293 return new CairoColorSpace();
2299 rendering::IntegerBitmapLayout
CanvasHelper::getMemoryLayout()
2302 return rendering::IntegerBitmapLayout(); // we're disposed
2304 const geometry::IntegerSize2D
aSize(getSize());
2306 return impl_getMemoryLayout( aSize
.Width
, aSize
.Height
);
2309 rendering::IntegerBitmapLayout
2310 CanvasHelper::impl_getMemoryLayout( const sal_Int32 nWidth
, const sal_Int32 nHeight
)
2312 rendering::IntegerBitmapLayout aLayout
;
2314 aLayout
.ScanLines
= nHeight
;
2315 aLayout
.ScanLineBytes
= nWidth
*4;
2316 aLayout
.ScanLineStride
= aLayout
.ScanLineBytes
;
2317 aLayout
.PlaneStride
= 0;
2318 aLayout
.ColorSpace
= mbHaveAlpha
? CairoColorSpaceHolder::get() : CairoNoAlphaColorSpaceHolder::get();
2319 aLayout
.Palette
.clear();
2320 aLayout
.IsMsbFirst
= sal_False
;
2325 bool CanvasHelper::hasAlpha() const
2330 bool CanvasHelper::repaint( const SurfaceSharedPtr
& pSurface
,
2331 const rendering::ViewState
& viewState
,
2332 const rendering::RenderState
& renderState
)
2334 OSL_TRACE("CanvasHelper::repaint");
2338 cairo_save( mpCairo
.get() );
2340 cairo_rectangle( mpCairo
.get(), 0, 0, maSize
.getX(), maSize
.getY() );
2341 cairo_clip( mpCairo
.get() );
2343 useStates( viewState
, renderState
, true );
2347 cairo_get_matrix( mpCairo
.get(), &aMatrix
);
2348 aMatrix
.xx
= aMatrix
.yy
= 1;
2349 cairo_set_matrix( mpCairo
.get(), &aMatrix
);
2351 cairo_set_source_surface( mpCairo
.get(), pSurface
->getCairoSurface().get(), 0, 0 );
2352 cairo_paint( mpCairo
.get() );
2353 cairo_restore( mpCairo
.get() );
2360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */