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