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