fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / canvas / source / cairo / cairo_canvashelper.cxx
blob5953495f63eaed0a493c33f0ab740606c722521b
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/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>
65 #include <algorithm>
67 using namespace ::cairo;
68 using namespace ::com::sun::star;
70 namespace cairocanvas
72 CanvasHelper::CanvasHelper() :
73 mpSurfaceProvider(NULL),
74 mpDevice(NULL),
75 mpVirtualDevice(),
76 mbHaveAlpha(),
77 mpCairo(),
78 mpSurface(),
79 maSize()
83 void CanvasHelper::disposing()
85 mpSurface.reset();
86 mpCairo.reset();
87 mpVirtualDevice.reset();
88 mpDevice = NULL;
89 mpSurfaceProvider = NULL;
92 void CanvasHelper::init( const ::basegfx::B2ISize& rSizePixel,
93 SurfaceProvider& rSurfaceProvider,
94 rendering::XGraphicDevice* pDevice )
96 maSize = rSizePixel;
97 mpSurfaceProvider = &rSurfaceProvider;
98 mpDevice = pDevice;
101 void CanvasHelper::setSize( const ::basegfx::B2ISize& rSize )
103 maSize = 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,
120 rColor[0],
121 rColor[1],
122 rColor[2],
123 rColor[3] );
125 else if( rColor.getLength() == 3 )
126 cairo_set_source_rgb( pCairo,
127 rColor[0],
128 rColor[1],
129 rColor[2] );
132 void CanvasHelper::useStates( const rendering::ViewState& viewState,
133 const rendering::RenderState& renderState,
134 bool bSetColor )
136 Matrix aViewMatrix;
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");
170 if( bSetColor )
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;
178 break;
179 case rendering::CompositeOperation::SOURCE:
180 compositingMode = CAIRO_OPERATOR_SOURCE;
181 break;
182 case rendering::CompositeOperation::DESTINATION:
183 compositingMode = CAIRO_OPERATOR_DEST;
184 break;
185 case rendering::CompositeOperation::OVER:
186 compositingMode = CAIRO_OPERATOR_OVER;
187 break;
188 case rendering::CompositeOperation::UNDER:
189 compositingMode = CAIRO_OPERATOR_DEST;
190 break;
191 case rendering::CompositeOperation::INSIDE:
192 compositingMode = CAIRO_OPERATOR_IN;
193 break;
194 case rendering::CompositeOperation::INSIDE_REVERSE:
195 compositingMode = CAIRO_OPERATOR_OUT;
196 break;
197 case rendering::CompositeOperation::OUTSIDE:
198 compositingMode = CAIRO_OPERATOR_DEST_OVER;
199 break;
200 case rendering::CompositeOperation::OUTSIDE_REVERSE:
201 compositingMode = CAIRO_OPERATOR_DEST_OUT;
202 break;
203 case rendering::CompositeOperation::ATOP:
204 compositingMode = CAIRO_OPERATOR_ATOP;
205 break;
206 case rendering::CompositeOperation::ATOP_REVERSE:
207 compositingMode = CAIRO_OPERATOR_DEST_ATOP;
208 break;
209 case rendering::CompositeOperation::XOR:
210 compositingMode = CAIRO_OPERATOR_XOR;
211 break;
212 case rendering::CompositeOperation::ADD:
213 compositingMode = CAIRO_OPERATOR_ADD;
214 break;
215 case rendering::CompositeOperation::SATURATE:
216 compositingMode = CAIRO_OPERATOR_SATURATE;
217 break;
219 cairo_set_operator( mpCairo.get(), compositingMode );
222 void CanvasHelper::clear()
224 OSL_TRACE ("clear whole area: %d x %d", maSize.getX(), maSize.getY() );
226 if( mpCairo )
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
234 if( mbHaveAlpha )
235 cairo_set_source_rgba( mpCairo.get(), 1.0, 1.0, 1.0, 0.0 );
236 else
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 )
260 if( mpCairo )
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 )
282 if( mpCairo )
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() );
315 if( pBitmapImpl )
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);
331 if( !!aBmpEx )
332 return aBmpEx;
334 // TODO(F1): extract pixel from XBitmap interface
335 ENSURE_OR_THROW( false,
336 "bitmapExFromXBitmap(): could not extract BitmapEx" );
338 return ::BitmapEx();
341 static sal_uInt8 lcl_GetColor(BitmapColor const& rColor)
343 sal_uInt8 nTemp(0);
344 if (rColor.IsIndex())
346 nTemp = rColor.GetIndex();
348 else
350 nTemp = rColor.GetBlue();
351 // greyscale expected here, or what would non-grey colors mean?
352 assert(rColor.GetRed() == nTemp && rColor.GetGreen() == nTemp);
354 return nTemp;
357 static bool readAlpha( BitmapReadAccess* pAlphaReadAcc, long nY, const long nWidth, unsigned char* data, long nOff )
359 bool bIsAlpha = false;
360 long nX;
361 int nAlpha;
362 Scanline pReadScan;
364 nOff += 3;
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++ );
373 if( nAlpha != 255 )
374 bIsAlpha = true;
375 nOff += 4;
377 break;
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));
384 pReadScan++;
385 nAlpha = data[ nOff ] = 255 - lcl_GetColor(rColor);
386 if( nAlpha != 255 )
387 bIsAlpha = true;
388 nOff += 4;
390 break;
391 default:
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();
396 if( nAlpha != 255 )
397 bIsAlpha = true;
398 nOff += 4;
402 return bIsAlpha;
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 );
421 if( pSurface )
422 data = NULL;
423 else
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 );
434 data = NULL;
435 bHasAlpha = false;
438 if( !pSurface )
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();
446 long nX, nY;
447 bool bIsAlpha = false;
449 if( aBmpEx.IsTransparent() || aBmpEx.IsAlpha() )
450 pAlphaReadAcc = aAlpha.AcquireReadAccess();
452 data = (unsigned char*) malloc( nWidth*nHeight*4 );
454 long nOff = 0;
455 ::Color aColor;
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 );
466 if( pAlphaReadAcc )
467 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
468 bIsAlpha = true;
470 for( nX = 0; nX < nWidth; nX++ )
472 #ifdef OSL_BIGENDIAN
473 if( pAlphaReadAcc )
474 nAlpha = data[ nOff++ ];
475 else
476 nAlpha = data[ nOff++ ] = 255;
477 #else
478 if( pAlphaReadAcc )
479 nAlpha = data[ nOff + 3 ];
480 else
481 nAlpha = data[ nOff + 3 ] = 255;
482 #endif
483 aColor = pBitmapReadAcc->GetPaletteColor( *pReadScan++ );
485 #ifdef OSL_BIGENDIAN
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 );
489 #else
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 );
493 nOff++;
494 #endif
496 break;
497 case BMP_FORMAT_24BIT_TC_BGR:
498 pReadScan = pBitmapReadAcc->GetScanline( nY );
499 if( pAlphaReadAcc )
500 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
501 bIsAlpha = true;
503 for( nX = 0; nX < nWidth; nX++ )
505 #ifdef OSL_BIGENDIAN
506 if( pAlphaReadAcc )
507 nAlpha = data[ nOff ];
508 else
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 );
513 nOff += 4;
514 #else
515 if( pAlphaReadAcc )
516 nAlpha = data[ nOff + 3 ];
517 else
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 );
522 nOff++;
523 #endif
525 break;
526 case BMP_FORMAT_24BIT_TC_RGB:
527 pReadScan = pBitmapReadAcc->GetScanline( nY );
528 if( pAlphaReadAcc )
529 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
530 bIsAlpha = true;
532 for( nX = 0; nX < nWidth; nX++ )
534 #ifdef OSL_BIGENDIAN
535 if( pAlphaReadAcc )
536 nAlpha = data[ nOff++ ];
537 else
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 );
542 #else
543 if( pAlphaReadAcc )
544 nAlpha = data[ nOff + 3 ];
545 else
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 );
550 pReadScan += 3;
551 nOff++;
552 #endif
554 break;
555 case BMP_FORMAT_32BIT_TC_BGRA:
556 pReadScan = pBitmapReadAcc->GetScanline( nY );
557 if( pAlphaReadAcc )
558 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
559 bIsAlpha = true;
561 for( nX = 0; nX < nWidth; nX++ )
563 #ifdef OSL_BIGENDIAN
564 if( pAlphaReadAcc )
565 nAlpha = data[ nOff++ ];
566 else
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 );
571 pReadScan += 4;
572 #else
573 if( pAlphaReadAcc )
574 nAlpha = data[ nOff + 3 ];
575 else
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 );
580 pReadScan++;
581 nOff++;
582 #endif
584 break;
585 case BMP_FORMAT_32BIT_TC_RGBA:
586 pReadScan = pBitmapReadAcc->GetScanline( nY );
587 if( pAlphaReadAcc )
588 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
589 bIsAlpha = true;
591 for( nX = 0; nX < nWidth; nX++ )
593 #ifdef OSL_BIGENDIAN
594 if( pAlphaReadAcc )
595 nAlpha = data[ nOff ++ ];
596 else
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 );
601 pReadScan++;
602 #else
603 if( pAlphaReadAcc )
604 nAlpha = data[ nOff + 3 ];
605 else
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 );
610 pReadScan += 4;
611 nOff++;
612 #endif
614 break;
615 default:
616 OSL_TRACE( "fallback to GetColor - slow, format: %d", pBitmapReadAcc->GetScanlineFormat() );
618 if( pAlphaReadAcc )
619 if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
620 bIsAlpha = true;
622 for( nX = 0; nX < nWidth; nX++ )
624 aColor = pBitmapReadAcc->GetColor( nY, nX );
626 // cairo need premultiplied color values
627 // TODO(rodo) handle endianess
628 #ifdef OSL_BIGENDIAN
629 if( pAlphaReadAcc )
630 nAlpha = data[ nOff++ ];
631 else
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 );
636 #else
637 if( pAlphaReadAcc )
638 nAlpha = data[ nOff + 3 ];
639 else
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 );
644 nOff ++;
645 #endif
650 aBitmap.ReleaseAccess( pBitmapReadAcc );
651 if( pAlphaReadAcc )
652 aAlpha.ReleaseAccess( pAlphaReadAcc );
654 SurfaceSharedPtr pImageSurface = createSurface(
655 CairoSurfaceSharedPtr(
656 cairo_image_surface_create_for_data(
657 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);
669 return pSurface;
672 static void addColorStops( Pattern* pPattern, const uno::Sequence< uno::Sequence< double > >& rColors, const uno::Sequence< double >& rStops, bool bReverseStops = false )
674 float stop;
675 int i;
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);
702 return aRes;
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);
711 return aRes;
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:
726 x0 = 0;
727 y0 = 0;
728 x1 = 1;
729 y1 = 0;
730 pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
731 addColorStops( pPattern, aValues.maColors, aValues.maStops );
732 break;
734 case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
735 cx = 0;
736 cy = 0;
737 r0 = 0;
738 r1 = 1;
740 pPattern = cairo_pattern_create_radial( cx, cy, r0, cy, cy, r1 );
741 addColorStops( pPattern, aValues.maColors, aValues.maStops, true );
742 break;
743 default:
744 break;
747 return pPattern;
750 static void doOperation( Operation aOperation,
751 Cairo* pCairo,
752 const uno::Sequence< rendering::Texture >* pTextures,
753 const SurfaceProviderRef& pDevice,
754 const basegfx::B2DRange& rBounds )
756 switch( aOperation )
758 case Fill:
759 /* TODO: multitexturing */
760 if( pTextures )
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 );
769 if( pSurface )
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 );
806 #else
807 #warning "fallback for cairo before version 1.2"
808 cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_NONE );
809 #endif
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 );
817 if( !bHasAlpha )
818 cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
819 cairo_fill( pCairo );
821 cairo_restore( pCairo );
823 cairo_pattern_destroy( pPattern );
826 if( data )
827 free( data );
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]);
859 cairo_fill(pCairo);
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
872 // steps
873 const unsigned int nStepCount(
874 ::std::max(
876 ::std::min(
877 nGradientSize / nStripSize,
878 128U )) + 1 );
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;
887 double fAlpha;
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 );
892 cairo_fill(pCairo);
895 cairo_restore( pCairo );
897 else
899 Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl );
901 if( pPattern )
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 );
918 else
919 cairo_fill( pCairo );
920 OSL_TRACE("fill");
921 break;
922 case Stroke:
923 cairo_stroke( pCairo );
924 OSL_TRACE("stroke");
925 break;
926 case Clip:
927 cairo_clip( pCairo );
928 OSL_TRACE("clip");
929 break;
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,
959 Cairo* pCairo,
960 const uno::Sequence< rendering::Texture >* pTextures,
961 const SurfaceProviderRef& pDevice,
962 rendering::FillRule eFillrule )
964 if( pTextures )
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() );
989 if( nPointCount > 1)
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 );
999 nX = aP.getX();
1000 nY = aP.getY();
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 )
1011 nX += 0.5;
1012 nY += 0.5;
1015 if( j==0 )
1017 cairo_move_to( pCairo, nX, nY );
1018 OSL_TRACE( "move to %f,%f", nX, nY );
1020 else
1022 if( bIsBezier )
1024 aA = aPolygon.getNextControlPoint( (j-1) % nPointCount );
1025 aB = aPolygon.getPrevControlPoint( j % nPointCount );
1027 nAX = aA.getX();
1028 nAY = aA.getY();
1029 nBX = aB.getX();
1030 nBY = aB.getY();
1032 cairo_matrix_transform_point( &aOrigMatrix, &nAX, &nAY );
1033 cairo_matrix_transform_point( &aOrigMatrix, &nBX, &nBY );
1035 if( aOperation == Stroke )
1037 nAX += 0.5;
1038 nAY += 0.5;
1039 nBX += 0.5;
1040 nBY += 0.5;
1043 cairo_curve_to( pCairo, nAX, nAY, nBX, nBY, nX, nY );
1045 else
1047 cairo_line_to( pCairo, nX, nY );
1048 OSL_TRACE( "line to %f,%f", nX, nY );
1050 bOpToDo = true;
1054 if( aPolygon.isClosed() )
1055 cairo_close_path( pCairo );
1058 else
1060 OSL_TRACE( "empty polygon for op: %d", aOperation );
1061 if( aOperation == Clip )
1063 clipNULL( pCairo );
1065 return;
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 )
1083 clipNULL( pCairo );
1086 void CanvasHelper::doPolyPolygonPath( const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1087 Operation aOperation,
1088 bool bNoLineJoin,
1089 const uno::Sequence< rendering::Texture >* pTextures,
1090 Cairo* pCairo ) const
1092 const ::basegfx::B2DPolyPolygon& rPolyPoly(
1093 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) );
1095 if( !pCairo )
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());
1106 if(nPointCount)
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),
1121 aOperation,
1122 pCairo, pTextures,
1123 mpSurfaceProvider,
1124 xPolyPolygon->getFillRule() );
1126 // prepare next step
1127 aEdge.setB2DPoint(0, aEdge.getB2DPoint(1));
1132 else
1134 doPolyPolygonImplementation( rPolyPoly, aOperation,
1135 pCairo, pTextures,
1136 mpSurfaceProvider,
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 );
1149 #endif
1151 if( mpCairo )
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() );
1162 else
1163 OSL_TRACE ("CanvasHelper called after it was disposed");
1165 #ifdef CAIRO_CANVAS_PERF_TRACE
1166 mxDevice->stopPerfTrace( &aTimer, "drawPolyPolygon" );
1167 #endif
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 );
1181 #endif
1183 if( mpCairo )
1185 cairo_save( mpCairo.get() );
1187 useStates( viewState, renderState, true );
1189 Matrix aMatrix;
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 );
1202 break;
1203 case rendering::PathCapType::ROUND:
1204 cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_ROUND );
1205 break;
1206 case rendering::PathCapType::SQUARE:
1207 cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_SQUARE );
1208 break;
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:
1217 bNoLineJoin = true;
1218 case rendering::PathJoinType::MITER:
1219 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_MITER );
1220 break;
1221 case rendering::PathJoinType::ROUND:
1222 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_ROUND );
1223 break;
1224 case rendering::PathJoinType::BEVEL:
1225 cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_BEVEL );
1226 break;
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() );
1244 else
1245 OSL_TRACE ("CanvasHelper called after it was disposed");
1247 #ifdef CAIRO_CANVAS_PERF_TRACE
1248 mxDevice->stopPerfTrace( &aTimer, "strokePolyPolygon" );
1249 #endif
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*/ )
1262 // TODO
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*/ )
1274 // TODO
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*/ )
1284 // TODO
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 );
1296 #endif
1298 if( mpCairo )
1300 cairo_save( mpCairo.get() );
1302 useStates( viewState, renderState, true );
1303 doPolyPolygonPath( xPolyPolygon, Fill );
1305 cairo_restore( mpCairo.get() );
1307 else
1308 OSL_TRACE ("CanvasHelper called after it was disposed");
1310 #ifdef CAIRO_CANVAS_PERF_TRACE
1311 mxDevice->stopPerfTrace( &aTimer, "fillPolyPolygon" );
1312 #endif
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 )
1323 if( mpCairo )
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*/ )
1343 // TODO
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,
1353 bool bHasAlpha )
1355 SurfaceSharedPtr pSurface=pInputSurface;
1356 uno::Reference< rendering::XCachedPrimitive > rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1357 geometry::IntegerSize2D aBitmapSize = rSize;
1359 if( mpCairo )
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 );
1368 Matrix aMatrix;
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;
1414 x = y = 0;
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 );
1429 if( pNewSurface )
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 );
1441 if( !bHasAlpha &&
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 );
1449 #endif
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] );
1455 else
1456 cairo_paint( mpCairo.get() );
1457 cairo_restore( mpCairo.get() );
1459 else
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 );
1473 #endif
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();
1481 if( pSurface )
1483 rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, false, bHasAlpha );
1485 if( data )
1486 free( data );
1488 else
1489 rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1491 #ifdef CAIRO_CANVAS_PERF_TRACE
1492 mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1493 #endif
1495 return rv;
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 );
1506 #endif
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();
1514 if( pSurface )
1516 rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, true, bHasAlpha );
1518 if( data )
1519 free( data );
1521 else
1522 rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
1524 #ifdef CAIRO_CANVAS_PERF_TRACE
1525 mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1526 #endif
1528 return rv;
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 );
1562 #endif
1564 if( mpCairo )
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 ) );
1570 else
1571 OSL_TRACE ("CanvasHelper called after it was disposed");
1573 #ifdef CAIRO_CANVAS_PERF_TRACE
1574 mxDevice->stopPerfTrace( &aTimer, "getScaledBitmap" );
1575 #endif
1577 return uno::Reference< rendering::XBitmap >();
1580 uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& aLayout,
1581 const geometry::IntegerRectangle2D& rect )
1583 if( mpCairo )
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,
1591 eFormat,
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 );
1601 return aRes;
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 >();
1625 namespace
1627 class CairoColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace >
1629 private:
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]);
1672 if( fAlpha == 0.0 )
1673 *pOut++ = rendering::RGBColor(0.0, 0.0, 0.0);
1674 else
1675 *pOut++ = rendering::RGBColor(pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1676 pIn += 4;
1678 return aRes;
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]);
1693 if( fAlpha == 0.0 )
1694 *pOut++ = rendering::ARGBColor(0.0, 0.0, 0.0, 0.0);
1695 else
1696 *pOut++ = rendering::ARGBColor(fAlpha,pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1697 pIn += 4;
1699 return aRes;
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]);
1714 pIn += 4;
1716 return aRes;
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;
1730 *pColors++ = 1.0;
1731 ++pIn;
1733 return aRes;
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;
1748 ++pIn;
1750 return aRes;
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;
1765 ++pIn;
1767 return aRes;
1770 // XIntegerBitmapColorSpace
1771 virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) throw (uno::RuntimeException)
1773 return 32;
1775 virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (uno::RuntimeException)
1777 return maBitCounts;
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++);
1804 return aRes;
1806 else
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
1822 return deviceColor;
1824 else
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]);
1847 if( fAlpha )
1848 *pOut++ = rendering::RGBColor(
1849 pIn[2]/fAlpha,
1850 pIn[1]/fAlpha,
1851 pIn[0]/fAlpha);
1852 else
1853 *pOut++ = rendering::RGBColor(0,0,0);
1854 pIn += 4;
1856 return aRes;
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]);
1873 if( fAlpha )
1874 *pOut++ = rendering::ARGBColor(
1875 fAlpha/255.0,
1876 pIn[2]/fAlpha,
1877 pIn[1]/fAlpha,
1878 pIn[0]/fAlpha);
1879 else
1880 *pOut++ = rendering::ARGBColor(0,0,0,0);
1881 pIn += 4;
1883 return aRes;
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]));
1903 pIn += 4;
1905 return aRes;
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);
1921 *pColors++ = -1;
1922 ++pIn;
1924 return aRes;
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);
1942 ++pIn;
1944 return aRes;
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);
1960 ++pIn;
1962 return aRes;
1965 public:
1966 CairoColorSpace() :
1967 maComponentTags(4),
1968 maBitCounts(4)
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;
1977 pBitCounts[0] =
1978 pBitCounts[1] =
1979 pBitCounts[2] =
1980 pBitCounts[3] = 8;
1984 class CairoNoAlphaColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace >
1986 private:
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]);
2029 pIn += 4;
2031 return aRes;
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]);
2046 pIn += 4;
2048 return aRes;
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
2071 ++pIn;
2073 return aRes;
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
2088 ++pIn;
2090 return aRes;
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)
2104 return 32;
2106 virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (uno::RuntimeException)
2108 return maBitCounts;
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
2135 return aRes;
2137 else
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
2153 return deviceColor;
2155 else
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] );
2178 pIn += 4;
2180 return aRes;
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(
2206 1.0,
2207 vcl::unotools::toDoubleColor(pIn[2]),
2208 vcl::unotools::toDoubleColor(pIn[1]),
2209 vcl::unotools::toDoubleColor(pIn[0]));
2210 pIn += 4;
2212 return aRes;
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
2229 ++pIn;
2231 return aRes;
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
2257 ++pIn;
2259 return aRes;
2262 public:
2263 CairoNoAlphaColorSpace() :
2264 maComponentTags(3),
2265 maBitCounts(3)
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;
2273 pBitCounts[0] =
2274 pBitCounts[1] =
2275 pBitCounts[2] = 8;
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()
2301 if( !mpCairo )
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;
2322 return aLayout;
2325 bool CanvasHelper::hasAlpha() const
2327 return mbHaveAlpha;
2330 bool CanvasHelper::repaint( const SurfaceSharedPtr& pSurface,
2331 const rendering::ViewState& viewState,
2332 const rendering::RenderState& renderState )
2334 OSL_TRACE("CanvasHelper::repaint");
2336 if( mpCairo )
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 );
2345 Matrix aMatrix;
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() );
2356 return true;
2360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */