LibreOffice Module canvas (master)  1
cairo_canvashelper.cxx
Go to the documentation of this file.
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 <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <algorithm>
24 #include <tuple>
25 
31 #include <basegfx/utils/lerp.hxx>
32 #include <com/sun/star/rendering/ColorComponentTag.hpp>
33 #include <com/sun/star/rendering/ColorSpaceType.hpp>
34 #include <com/sun/star/rendering/CompositeOperation.hpp>
35 #include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
36 #include <com/sun/star/rendering/PathCapType.hpp>
37 #include <com/sun/star/rendering/PathJoinType.hpp>
38 #include <com/sun/star/rendering/RenderingIntent.hpp>
39 #include <com/sun/star/rendering/TexturingMode.hpp>
40 #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
41 #include <com/sun/star/util/Endianness.hpp>
42 #include <comphelper/sequence.hxx>
43 #include <cppuhelper/implbase.hxx>
44 #include <rtl/instance.hxx>
45 #include <rtl/math.hxx>
46 #include <tools/diagnose_ex.h>
47 #include <vcl/bitmapex.hxx>
48 #include <vcl/BitmapTools.hxx>
49 #include <vcl/canvastools.hxx>
50 #include <vcl/virdev.hxx>
51 
52 #include <canvas/canvastools.hxx>
53 #include <parametricpolypolygon.hxx>
54 #include <cairo.h>
55 
56 #include "cairo_cachedbitmap.hxx"
57 #include "cairo_canvasbitmap.hxx"
58 #include "cairo_canvashelper.hxx"
59 
60 using namespace ::cairo;
61 using namespace ::com::sun::star;
62 
63 namespace cairocanvas
64 {
66  mpSurfaceProvider(nullptr),
67  mpDevice(nullptr),
69  mbHaveAlpha(),
70  mpCairo(),
71  mpSurface(),
72  maSize()
73  {
74  }
75 
77  {
78  mpSurface.reset();
79  mpCairo.reset();
81  mpDevice = nullptr;
82  mpSurfaceProvider = nullptr;
83  }
84 
85  void CanvasHelper::init( const ::basegfx::B2ISize& rSizePixel,
86  SurfaceProvider& rSurfaceProvider,
87  rendering::XGraphicDevice* pDevice )
88  {
89  maSize = rSizePixel;
90  mpSurfaceProvider = &rSurfaceProvider;
91  mpDevice = pDevice;
92  }
93 
94  void CanvasHelper::setSize( const ::basegfx::B2ISize& rSize )
95  {
96  maSize = rSize;
97  }
98 
99  void CanvasHelper::setSurface( const SurfaceSharedPtr& pSurface, bool bHasAlpha )
100  {
101  mbHaveAlpha = bHasAlpha;
103  mpSurface = pSurface;
104  mpCairo = pSurface->getCairo();
105  }
106 
107  static void setColor( cairo_t* pCairo,
108  const uno::Sequence<double>& rColor )
109  {
110  if( rColor.getLength() > 3 )
111  {
112  cairo_set_source_rgba( pCairo,
113  rColor[0],
114  rColor[1],
115  rColor[2],
116  rColor[3] );
117  }
118  else if( rColor.getLength() == 3 )
119  cairo_set_source_rgb( pCairo,
120  rColor[0],
121  rColor[1],
122  rColor[2] );
123  }
124 
125  void CanvasHelper::useStates( const rendering::ViewState& viewState,
126  const rendering::RenderState& renderState,
127  bool bSetColor )
128  {
129  cairo_matrix_t aViewMatrix;
130  cairo_matrix_t aRenderMatrix;
131  cairo_matrix_t aCombinedMatrix;
132 
133  cairo_matrix_init( &aViewMatrix,
134  viewState.AffineTransform.m00, viewState.AffineTransform.m10, viewState.AffineTransform.m01,
135  viewState.AffineTransform.m11, viewState.AffineTransform.m02, viewState.AffineTransform.m12);
136  cairo_matrix_init( &aRenderMatrix,
137  renderState.AffineTransform.m00, renderState.AffineTransform.m10, renderState.AffineTransform.m01,
138  renderState.AffineTransform.m11, renderState.AffineTransform.m02, renderState.AffineTransform.m12);
139  cairo_matrix_multiply( &aCombinedMatrix, &aRenderMatrix, &aViewMatrix);
140 
141  if( viewState.Clip.is() )
142  {
143  SAL_INFO( "canvas.cairo", "view clip");
144 
145  aViewMatrix.x0 = basegfx::fround( aViewMatrix.x0 );
146  aViewMatrix.y0 = basegfx::fround( aViewMatrix.y0 );
147  cairo_set_matrix( mpCairo.get(), &aViewMatrix );
148  doPolyPolygonPath( viewState.Clip, Clip );
149  }
150 
151  aCombinedMatrix.x0 = basegfx::fround( aCombinedMatrix.x0 );
152  aCombinedMatrix.y0 = basegfx::fround( aCombinedMatrix.y0 );
153  cairo_set_matrix( mpCairo.get(), &aCombinedMatrix );
154 
155  if( renderState.Clip.is() )
156  {
157  SAL_INFO( "canvas.cairo", "render clip BEGIN");
158 
159  doPolyPolygonPath( renderState.Clip, Clip );
160  SAL_INFO( "canvas.cairo", "render clip END");
161  }
162 
163  if( bSetColor )
164  setColor(mpCairo.get(),renderState.DeviceColor);
165 
166  cairo_operator_t compositingMode( CAIRO_OPERATOR_OVER );
167  switch( renderState.CompositeOperation )
168  {
169  case rendering::CompositeOperation::CLEAR:
170  compositingMode = CAIRO_OPERATOR_CLEAR;
171  break;
172  case rendering::CompositeOperation::SOURCE:
173  compositingMode = CAIRO_OPERATOR_SOURCE;
174  break;
175  case rendering::CompositeOperation::DESTINATION:
176  compositingMode = CAIRO_OPERATOR_DEST;
177  break;
178  case rendering::CompositeOperation::OVER:
179  compositingMode = CAIRO_OPERATOR_OVER;
180  break;
181  case rendering::CompositeOperation::UNDER:
182  compositingMode = CAIRO_OPERATOR_DEST;
183  break;
184  case rendering::CompositeOperation::INSIDE:
185  compositingMode = CAIRO_OPERATOR_IN;
186  break;
187  case rendering::CompositeOperation::INSIDE_REVERSE:
188  compositingMode = CAIRO_OPERATOR_OUT;
189  break;
190  case rendering::CompositeOperation::OUTSIDE:
191  compositingMode = CAIRO_OPERATOR_DEST_OVER;
192  break;
193  case rendering::CompositeOperation::OUTSIDE_REVERSE:
194  compositingMode = CAIRO_OPERATOR_DEST_OUT;
195  break;
196  case rendering::CompositeOperation::ATOP:
197  compositingMode = CAIRO_OPERATOR_ATOP;
198  break;
199  case rendering::CompositeOperation::ATOP_REVERSE:
200  compositingMode = CAIRO_OPERATOR_DEST_ATOP;
201  break;
202  case rendering::CompositeOperation::XOR:
203  compositingMode = CAIRO_OPERATOR_XOR;
204  break;
205  case rendering::CompositeOperation::ADD:
206  compositingMode = CAIRO_OPERATOR_ADD;
207  break;
208  case rendering::CompositeOperation::SATURATE:
209  compositingMode = CAIRO_OPERATOR_SATURATE;
210  break;
211  }
212  cairo_set_operator( mpCairo.get(), compositingMode );
213  }
214 
216  {
217  SAL_INFO( "canvas.cairo", "clear whole area: " << maSize.getX() << " x " << maSize.getY() );
218 
219  if( mpCairo )
220  {
221  cairo_save( mpCairo.get() );
222 
223  cairo_identity_matrix( mpCairo.get() );
224  // this does not really differ from all-zero, as cairo
225  // internally converts to premultiplied alpha. but anyway,
226  // this keeps it consistent with the other canvas impls
227  if( mbHaveAlpha )
228  cairo_set_source_rgba( mpCairo.get(), 1.0, 1.0, 1.0, 0.0 );
229  else
230  cairo_set_source_rgb( mpCairo.get(), 1.0, 1.0, 1.0 );
231  cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
232 
233  cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
234  cairo_fill( mpCairo.get() );
235 
236  cairo_restore( mpCairo.get() );
237  }
238  }
239 
240  void CanvasHelper::drawLine( const rendering::XCanvas* /*pCanvas*/,
241  const geometry::RealPoint2D& aStartPoint,
242  const geometry::RealPoint2D& aEndPoint,
243  const rendering::ViewState& viewState,
244  const rendering::RenderState& renderState )
245  {
246  if( mpCairo )
247  {
248  cairo_save( mpCairo.get() );
249 
250  cairo_set_line_width( mpCairo.get(), 1 );
251 
252  useStates( viewState, renderState, true );
253 
254  cairo_move_to( mpCairo.get(), aStartPoint.X + 0.5, aStartPoint.Y + 0.5 );
255  cairo_line_to( mpCairo.get(), aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
256  cairo_stroke( mpCairo.get() );
257 
258  cairo_restore( mpCairo.get() );
259  }
260  }
261 
262  void CanvasHelper::drawBezier( const rendering::XCanvas* ,
263  const geometry::RealBezierSegment2D& aBezierSegment,
264  const geometry::RealPoint2D& aEndPoint,
265  const rendering::ViewState& viewState,
266  const rendering::RenderState& renderState )
267  {
268  if( mpCairo )
269  {
270  cairo_save( mpCairo.get() );
271 
272  cairo_set_line_width( mpCairo.get(), 1 );
273 
274  useStates( viewState, renderState, true );
275 
276  cairo_move_to( mpCairo.get(), aBezierSegment.Px + 0.5, aBezierSegment.Py + 0.5 );
277  // tdf#99165 correction of control points not needed here, only hairlines drawn
278  // (see cairo_set_line_width above)
279  cairo_curve_to( mpCairo.get(),
280  aBezierSegment.C1x + 0.5, aBezierSegment.C1y + 0.5,
281  aBezierSegment.C2x + 0.5, aBezierSegment.C2y + 0.5,
282  aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
283  cairo_stroke( mpCairo.get() );
284 
285  cairo_restore( mpCairo.get() );
286  }
287  }
288 
289 #define PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME "Canvas::ParametricPolyPolygon"
290 
300  static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap )
301  {
302  CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() );
303  if( pBitmapImpl )
304  return pBitmapImpl->getSurface();
305 
306  SurfaceProvider* pSurfaceProvider = dynamic_cast<SurfaceProvider*>( xBitmap.get() );
307  if( pSurfaceProvider )
308  return pSurfaceProvider->getSurface();
309 
310  return SurfaceSharedPtr();
311  }
312 
313  static ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap )
314  {
315  // TODO(F1): Add support for floating point bitmap formats
316  uno::Reference<rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap,
317  uno::UNO_QUERY_THROW);
319  if( !!aBmpEx )
320  return aBmpEx;
321 
322  // TODO(F1): extract pixel from XBitmap interface
323  ENSURE_OR_THROW( false,
324  "bitmapExFromXBitmap(): could not extract BitmapEx" );
325 
326  return ::BitmapEx();
327  }
328 
340  static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, const SurfaceProviderRef& rSurfaceProvider, unsigned char*& data, bool& bHasAlpha )
341  {
342  bHasAlpha = xBitmap->hasAlpha();
343  SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap );
344  if( pSurface )
345  data = nullptr;
346  else
347  {
348  ::BitmapEx aBmpEx = bitmapExFromXBitmap(xBitmap);
349  ::Bitmap aBitmap = aBmpEx.GetBitmap();
350 
351  // there's no pixmap for alpha bitmap. we might still
352  // use rgb pixmap and only access alpha pixels the
353  // slow way. now we just speedup rgb bitmaps
354  if( !aBmpEx.IsTransparent() && !aBmpEx.IsAlpha() )
355  {
356  pSurface = rSurfaceProvider->createSurface( aBitmap );
357  data = nullptr;
358  bHasAlpha = false;
359  }
360 
361  if( !pSurface )
362  {
363  long nWidth;
364  long nHeight;
365  vcl::bitmap::CanvasCairoExtractBitmapData(aBmpEx, aBitmap, data, bHasAlpha, nWidth, nHeight);
366 
367  SurfaceSharedPtr pImageSurface = rSurfaceProvider->getOutputDevice()->CreateSurface(
369  cairo_image_surface_create_for_data(
370  data,
371  bHasAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
372  nWidth, nHeight, nWidth*4 ),
373  &cairo_surface_destroy) );
374  pSurface = pImageSurface;
375 
376  SAL_INFO( "canvas.cairo","image: " << nWidth << " x " << nHeight << " alpha: " << bHasAlpha);
377  }
378  }
379 
380  return pSurface;
381  }
382 
383  static void addColorStops( cairo_pattern_t* pPattern, const uno::Sequence< uno::Sequence< double > >& rColors, const uno::Sequence< double >& rStops, bool bReverseStops )
384  {
385  int i;
386 
387  OSL_ASSERT( rColors.getLength() == rStops.getLength() );
388 
389  for( i = 0; i < rColors.getLength(); i++ )
390  {
391  const uno::Sequence< double >& rColor( rColors[i] );
392  float stop = bReverseStops ? 1 - rStops[i] : rStops[i];
393  if( rColor.getLength() == 3 )
394  cairo_pattern_add_color_stop_rgb( pPattern, stop, rColor[0], rColor[1], rColor[2] );
395  else if( rColor.getLength() == 4 )
396  {
397  double alpha = rColor[3];
398  // cairo expects premultiplied alpha
399  cairo_pattern_add_color_stop_rgba( pPattern, stop, rColor[0]*alpha, rColor[1]*alpha, rColor[2]*alpha, alpha );
400  }
401  }
402  }
403 
404  static uno::Sequence<double> lerp(const uno::Sequence<double>& rLeft, const uno::Sequence<double>& rRight, double fAlpha)
405  {
406  if( rLeft.getLength() == 3 )
407  {
408  uno::Sequence<double> aRes(3);
409  aRes[0] = basegfx::utils::lerp(rLeft[0],rRight[0],fAlpha);
410  aRes[1] = basegfx::utils::lerp(rLeft[1],rRight[1],fAlpha);
411  aRes[2] = basegfx::utils::lerp(rLeft[2],rRight[2],fAlpha);
412  return aRes;
413  }
414  else if( rLeft.getLength() == 4 )
415  {
416  uno::Sequence<double> aRes(4);
417  aRes[0] = basegfx::utils::lerp(rLeft[0],rRight[0],fAlpha);
418  aRes[1] = basegfx::utils::lerp(rLeft[1],rRight[1],fAlpha);
419  aRes[2] = basegfx::utils::lerp(rLeft[2],rRight[2],fAlpha);
420  aRes[3] = basegfx::utils::lerp(rLeft[3],rRight[3],fAlpha);
421  return aRes;
422  }
423 
424  return uno::Sequence<double>();
425  }
426 
427  static cairo_pattern_t* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon const & rPolygon )
428  {
429  cairo_pattern_t* pPattern = nullptr;
430  const ::canvas::ParametricPolyPolygon::Values aValues = rPolygon.getValues();
431  double x0, x1, y0, y1, cx, cy, r0, r1;
432 
433  switch( aValues.meType )
434  {
435  case ::canvas::ParametricPolyPolygon::GradientType::Linear:
436  x0 = 0;
437  y0 = 0;
438  x1 = 1;
439  y1 = 0;
440  pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
441  addColorStops( pPattern, aValues.maColors, aValues.maStops, false );
442  break;
443 
444  case ::canvas::ParametricPolyPolygon::GradientType::Elliptical:
445  cx = 0;
446  cy = 0;
447  r0 = 0;
448  r1 = 1;
449 
450  pPattern = cairo_pattern_create_radial( cx, cy, r0, cy, cy, r1 );
451  addColorStops( pPattern, aValues.maColors, aValues.maStops, true );
452  break;
453  default:
454  break;
455  }
456 
457  return pPattern;
458  }
459 
460  static void doOperation( Operation aOperation,
461  cairo_t* pCairo,
462  const uno::Sequence< rendering::Texture >* pTextures,
463  const SurfaceProviderRef& pDevice,
464  const basegfx::B2DRange& rBounds )
465  {
466  switch( aOperation )
467  {
468  case Fill:
469  /* TODO: multitexturing */
470  if( pTextures )
471  {
472  const css::rendering::Texture& aTexture ( (*pTextures)[0] );
473  if( aTexture.Bitmap.is() )
474  {
475  unsigned char* data = nullptr;
476  bool bHasAlpha = false;
477  SurfaceSharedPtr pSurface = surfaceFromXBitmap( (*pTextures)[0].Bitmap, pDevice, data, bHasAlpha );
478 
479  if( pSurface )
480  {
481  cairo_pattern_t* pPattern;
482 
483  cairo_save( pCairo );
484 
485  css::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform );
486  cairo_matrix_t aScaleMatrix, aTextureMatrix, aScaledTextureMatrix;
487 
488  cairo_matrix_init( &aTextureMatrix,
489  aTransform.m00, aTransform.m10, aTransform.m01,
490  aTransform.m11, aTransform.m02, aTransform.m12);
491 
492  geometry::IntegerSize2D aSize = aTexture.Bitmap->getSize();
493 
494  cairo_matrix_init_scale( &aScaleMatrix, 1.0/aSize.Width, 1.0/aSize.Height );
495  cairo_matrix_multiply( &aScaledTextureMatrix, &aTextureMatrix, &aScaleMatrix );
496  cairo_matrix_invert( &aScaledTextureMatrix );
497 
498  // we don't care about repeat mode yet, so the workaround is disabled for now
499  pPattern = cairo_pattern_create_for_surface( pSurface->getCairoSurface().get() );
500 
501  if( aTexture.RepeatModeX == rendering::TexturingMode::REPEAT &&
502  aTexture.RepeatModeY == rendering::TexturingMode::REPEAT )
503  {
504  cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_REPEAT );
505  }
506  else if ( aTexture.RepeatModeX == rendering::TexturingMode::NONE &&
507  aTexture.RepeatModeY == rendering::TexturingMode::NONE )
508  {
509  cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_NONE );
510  }
511  else if ( aTexture.RepeatModeX == rendering::TexturingMode::CLAMP &&
512  aTexture.RepeatModeY == rendering::TexturingMode::CLAMP )
513  {
514  cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_PAD );
515  }
516 
517  aScaledTextureMatrix.x0 = basegfx::fround( aScaledTextureMatrix.x0 );
518  aScaledTextureMatrix.y0 = basegfx::fround( aScaledTextureMatrix.y0 );
519 
520  double x1, y1, x2, y2;
521  cairo_path_extents(pCairo, &x1, &y1, &x2, &y2);
522  aScaledTextureMatrix.x0 -= (x1 * aScaledTextureMatrix.xx);
523  aScaledTextureMatrix.y0 -= (y1 * aScaledTextureMatrix.yy);
524 
525  cairo_pattern_set_matrix( pPattern, &aScaledTextureMatrix );
526 
527  cairo_set_source( pCairo, pPattern );
528  if( !bHasAlpha )
529  cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
530  cairo_fill( pCairo );
531 
532  cairo_restore( pCairo );
533 
534  cairo_pattern_destroy( pPattern );
535  }
536 
537  if( data )
538  free( data );
539  }
540  else if( aTexture.Gradient.is() )
541  {
542  uno::Reference< lang::XServiceInfo > xRef( aTexture.Gradient, uno::UNO_QUERY );
543 
544  SAL_INFO( "canvas.cairo", "gradient fill" );
545  if( xRef.is() && xRef->getImplementationName() == PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME )
546  {
547  // TODO(Q1): Maybe use dynamic_cast here
548 
549  // TODO(E1): Return value
550  // TODO(F1): FillRule
551  SAL_INFO( "canvas.cairo", "known implementation" );
552 
553  ::canvas::ParametricPolyPolygon* pPolyImpl = static_cast< ::canvas::ParametricPolyPolygon* >( aTexture.Gradient.get() );
554  css::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform );
555  cairo_matrix_t aTextureMatrix;
556 
557  cairo_matrix_init( &aTextureMatrix,
558  aTransform.m00, aTransform.m10, aTransform.m01,
559  aTransform.m11, aTransform.m02, aTransform.m12);
561  {
562  // no general path gradient yet in cairo; emulate then
563  cairo_save( pCairo );
564  cairo_clip( pCairo );
565 
566  // fill bound rect with start color
567  cairo_rectangle( pCairo, rBounds.getMinX(), rBounds.getMinY(),
568  rBounds.getWidth(), rBounds.getHeight() );
569  setColor(pCairo,pPolyImpl->getValues().maColors[0]);
570  cairo_fill(pCairo);
571 
572  cairo_transform( pCairo, &aTextureMatrix );
573 
574  // longest line in gradient bound rect
575  const unsigned int nGradientSize(
576  static_cast<unsigned int>(
577  ::basegfx::B2DVector(rBounds.getMinimum() - rBounds.getMaximum()).getLength() + 1.0 ) );
578 
579  // typical number for pixel of the same color (strip size)
580  const unsigned int nStripSize( nGradientSize < 50 ? 2 : 4 );
581 
582  // use at least three steps, and at utmost the number of color
583  // steps
584  const unsigned int nStepCount(
585  std::max(
586  3U,
587  std::min(
588  nGradientSize / nStripSize,
589  128U )) + 1 );
590 
591  const uno::Sequence<double>* pColors=&pPolyImpl->getValues().maColors[0];
592  basegfx::utils::KeyStopLerp aLerper(pPolyImpl->getValues().maStops);
593  for( unsigned int i=1; i<nStepCount; ++i )
594  {
595  const double fT( i/double(nStepCount) );
596 
597  std::ptrdiff_t nIndex;
598  double fAlpha;
599  std::tie(nIndex,fAlpha)=aLerper.lerp(fT);
600 
601  setColor(pCairo, lerp(pColors[nIndex], pColors[nIndex+1], fAlpha));
602  cairo_rectangle( pCairo, -1+fT, -1+fT, 2-2*fT, 2-2*fT );
603  cairo_fill(pCairo);
604  }
605 
606  cairo_restore( pCairo );
607  }
608  else
609  {
610  cairo_pattern_t* pPattern = patternFromParametricPolyPolygon( *pPolyImpl );
611 
612  if( pPattern )
613  {
614  SAL_INFO( "canvas.cairo", "filling with pattern" );
615 
616  cairo_save( pCairo );
617 
618  cairo_transform( pCairo, &aTextureMatrix );
619  cairo_set_source( pCairo, pPattern );
620  cairo_fill( pCairo );
621  cairo_restore( pCairo );
622 
623  cairo_pattern_destroy( pPattern );
624  }
625  }
626  }
627  }
628  }
629  else
630  cairo_fill( pCairo );
631  SAL_INFO( "canvas.cairo", "fill");
632  break;
633  case Stroke:
634  cairo_stroke( pCairo );
635  SAL_INFO( "canvas.cairo", "stroke");
636  break;
637  case Clip:
638  cairo_clip( pCairo );
639  SAL_INFO( "canvas.cairo", "clip");
640  break;
641  }
642  }
643 
644  static void clipNULL( cairo_t *pCairo )
645  {
646  SAL_INFO( "canvas.cairo", "clipNULL");
647  cairo_matrix_t aOrigMatrix, aIdentityMatrix;
648 
649  /* we set identity matrix here to overcome bug in cairo 0.9.2
650  where XCreatePixmap is called with zero width and height.
651 
652  it also reaches faster path in cairo clipping code.
653  */
654  cairo_matrix_init_identity( &aIdentityMatrix );
655  cairo_get_matrix( pCairo, &aOrigMatrix );
656  cairo_set_matrix( pCairo, &aIdentityMatrix );
657 
658  cairo_reset_clip( pCairo );
659  cairo_rectangle( pCairo, 0, 0, 1, 1 );
660  cairo_clip( pCairo );
661  cairo_rectangle( pCairo, 2, 0, 1, 1 );
662  cairo_clip( pCairo );
663 
664  /* restore the original matrix */
665  cairo_set_matrix( pCairo, &aOrigMatrix );
666  }
667 
668  void doPolyPolygonImplementation( const ::basegfx::B2DPolyPolygon& aPolyPolygon,
669  Operation aOperation,
670  cairo_t* pCairo,
671  const uno::Sequence< rendering::Texture >* pTextures,
672  const SurfaceProviderRef& pDevice,
673  rendering::FillRule eFillrule )
674  {
675  if( pTextures )
676  ENSURE_ARG_OR_THROW( pTextures->hasElements(),
677  "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence");
678 
679  bool bOpToDo = false;
680  cairo_matrix_t aOrigMatrix, aIdentityMatrix;
681  double nX, nY, nBX, nBY, nAX, nAY, nLastX(0.0), nLastY(0.0);
682 
683  cairo_get_matrix( pCairo, &aOrigMatrix );
684  cairo_matrix_init_identity( &aIdentityMatrix );
685  cairo_set_matrix( pCairo, &aIdentityMatrix );
686 
687  cairo_set_fill_rule( pCairo,
688  eFillrule == rendering::FillRule_EVEN_ODD ?
689  CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING );
690 
691  for( sal_uInt32 nPolygonIndex = 0; nPolygonIndex < aPolyPolygon.count(); nPolygonIndex++ )
692  {
693  const ::basegfx::B2DPolygon& aPolygon( aPolyPolygon.getB2DPolygon( nPolygonIndex ) );
694  const sal_uInt32 nPointCount( aPolygon.count() );
695  // to correctly render closed curves, need to output first
696  // point twice (so output one additional point)
697  const sal_uInt32 nExtendedPointCount( nPointCount +
698  int(aPolygon.isClosed() && aPolygon.areControlPointsUsed()) );
699 
700  if( nPointCount > 1)
701  {
702  bool bIsBezier = aPolygon.areControlPointsUsed();
703  ::basegfx::B2DPoint aA, aB, aP;
704 
705  for( sal_uInt32 j=0; j < nExtendedPointCount; j++ )
706  {
707  aP = aPolygon.getB2DPoint( j % nPointCount );
708 
709  nX = aP.getX();
710  nY = aP.getY();
711  cairo_matrix_transform_point( &aOrigMatrix, &nX, &nY );
712 
713  if (!bIsBezier && aOperation == Clip)
714  {
715  nX = basegfx::fround( nX );
716  nY = basegfx::fround( nY );
717  }
718 
719  if( aOperation == Stroke )
720  {
721  nX += 0.5;
722  nY += 0.5;
723  }
724 
725  if( j==0 )
726  {
727  cairo_move_to( pCairo, nX, nY );
728  SAL_INFO( "canvas.cairo", "move to " << nX << "," << nY );
729  }
730  else
731  {
732  if( bIsBezier )
733  {
734  aA = aPolygon.getNextControlPoint( (j-1) % nPointCount );
735  aB = aPolygon.getPrevControlPoint( j % nPointCount );
736 
737  nAX = aA.getX();
738  nAY = aA.getY();
739  nBX = aB.getX();
740  nBY = aB.getY();
741 
742  cairo_matrix_transform_point( &aOrigMatrix, &nAX, &nAY );
743  cairo_matrix_transform_point( &aOrigMatrix, &nBX, &nBY );
744 
745  if( aOperation == Stroke )
746  {
747  nAX += 0.5;
748  nAY += 0.5;
749  nBX += 0.5;
750  nBY += 0.5;
751  }
752 
753  // tdf#99165 if the control points are 'empty', create the mathematical
754  // correct replacement ones to avoid problems with the graphical sub-system
755  // tdf#101026 The 1st attempt to create a mathematically correct replacement control
756  // vector was wrong. Best alternative is one as close as possible which means short.
757  if (basegfx::fTools::equal(nAX, nLastX) && basegfx::fTools::equal(nAY, nLastY))
758  {
759  nAX = nLastX + ((nBX - nLastX) * 0.0005);
760  nAY = nLastY + ((nBY - nLastY) * 0.0005);
761  }
762 
763  if(basegfx::fTools::equal(nBX, nX) && basegfx::fTools::equal(nBY, nY))
764  {
765  nBX = nX + ((nAX - nX) * 0.0005);
766  nBY = nY + ((nAY - nY) * 0.0005);
767  }
768 
769  cairo_curve_to( pCairo, nAX, nAY, nBX, nBY, nX, nY );
770  }
771  else
772  {
773  cairo_line_to( pCairo, nX, nY );
774  SAL_INFO( "canvas.cairo", "line to " << nX << "," << nY );
775  }
776  bOpToDo = true;
777  }
778 
779  nLastX = nX;
780  nLastY = nY;
781  }
782 
783  if( aPolygon.isClosed() )
784  cairo_close_path( pCairo );
785 
786  }
787  else
788  {
789  SAL_INFO( "canvas.cairo", "empty polygon for op: " << aOperation );
790  if( aOperation == Clip )
791  {
792  clipNULL( pCairo );
793 
794  return;
795  }
796  }
797  }
798 
799  if( aOperation == Fill && pTextures )
800  {
801  cairo_set_matrix( pCairo, &aOrigMatrix );
802  doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
803  cairo_set_matrix( pCairo, &aIdentityMatrix );
804  }
805 
806  if( bOpToDo && ( aOperation != Fill || !pTextures ) )
807  doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
808 
809  cairo_set_matrix( pCairo, &aOrigMatrix );
810 
811  if( aPolyPolygon.count() == 0 && aOperation == Clip )
812  clipNULL( pCairo );
813  }
814 
815  void CanvasHelper::doPolyPolygonPath( const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
816  Operation aOperation,
817  bool bNoLineJoin,
818  const uno::Sequence< rendering::Texture >* pTextures ) const
819  {
820  const ::basegfx::B2DPolyPolygon& rPolyPoly(
822 
823  cairo_t* pCairo = mpCairo.get();
824 
825  if(bNoLineJoin && aOperation == Stroke)
826  {
827  // emulate rendering::PathJoinType::NONE by painting single edges
828  for(sal_uInt32 a(0); a < rPolyPoly.count(); a++)
829  {
830  const basegfx::B2DPolygon& aCandidate(rPolyPoly.getB2DPolygon(a));
831  const sal_uInt32 nPointCount(aCandidate.count());
832 
833  if(nPointCount)
834  {
835  const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount: nPointCount - 1);
836  basegfx::B2DPolygon aEdge;
837  aEdge.append(aCandidate.getB2DPoint(0));
838  aEdge.append(basegfx::B2DPoint(0.0, 0.0));
839 
840  for(sal_uInt32 b(0); b < nEdgeCount; b++)
841  {
842  const sal_uInt32 nNextIndex((b + 1) % nPointCount);
843  aEdge.setB2DPoint(1, aCandidate.getB2DPoint(nNextIndex));
844  aEdge.setNextControlPoint(0, aCandidate.getNextControlPoint(b % nPointCount));
845  aEdge.setPrevControlPoint(1, aCandidate.getPrevControlPoint(nNextIndex));
846 
848  aOperation,
849  pCairo, pTextures,
851  xPolyPolygon->getFillRule() );
852 
853  // prepare next step
854  aEdge.setB2DPoint(0, aEdge.getB2DPoint(1));
855  }
856  }
857  }
858  }
859  else
860  {
861  doPolyPolygonImplementation( rPolyPoly, aOperation,
862  pCairo, pTextures,
864  xPolyPolygon->getFillRule() );
865  }
866  }
867 
868  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* ,
869  const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
870  const rendering::ViewState& viewState,
871  const rendering::RenderState& renderState )
872  {
873 #ifdef CAIRO_CANVAS_PERF_TRACE
874  struct timespec aTimer;
875  mxDevice->startPerfTrace( &aTimer );
876 #endif
877 
878  if( mpCairo )
879  {
880  cairo_save( mpCairo.get() );
881 
882  cairo_set_line_width( mpCairo.get(), 1 );
883 
884  useStates( viewState, renderState, true );
885  doPolyPolygonPath( xPolyPolygon, Stroke );
886 
887  cairo_restore( mpCairo.get() );
888  }
889  else
890  SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
891 
892 #ifdef CAIRO_CANVAS_PERF_TRACE
893  mxDevice->stopPerfTrace( &aTimer, "drawPolyPolygon" );
894 #endif
895 
896  return uno::Reference< rendering::XCachedPrimitive >(nullptr);
897  }
898 
899  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* ,
900  const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
901  const rendering::ViewState& viewState,
902  const rendering::RenderState& renderState,
903  const rendering::StrokeAttributes& strokeAttributes )
904  {
905 #ifdef CAIRO_CANVAS_PERF_TRACE
906  struct timespec aTimer;
907  mxDevice->startPerfTrace( &aTimer );
908 #endif
909 
910  if( mpCairo )
911  {
912  cairo_save( mpCairo.get() );
913 
914  useStates( viewState, renderState, true );
915 
916  cairo_matrix_t aMatrix;
917  double w = strokeAttributes.StrokeWidth, h = 0;
918  cairo_get_matrix( mpCairo.get(), &aMatrix );
919  cairo_matrix_transform_distance( &aMatrix, &w, &h );
920  cairo_set_line_width( mpCairo.get(), w );
921 
922  cairo_set_miter_limit( mpCairo.get(), strokeAttributes.MiterLimit );
923 
924  // FIXME: cairo doesn't handle end cap so far (rodo)
925  switch( strokeAttributes.StartCapType )
926  {
927  case rendering::PathCapType::BUTT:
928  cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_BUTT );
929  break;
930  case rendering::PathCapType::ROUND:
931  cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_ROUND );
932  break;
933  case rendering::PathCapType::SQUARE:
934  cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_SQUARE );
935  break;
936  }
937 
938  bool bNoLineJoin(false);
939 
940  switch( strokeAttributes.JoinType )
941  {
942  case rendering::PathJoinType::NONE:
943  bNoLineJoin = true;
944  [[fallthrough]]; // cairo doesn't have join type NONE so we use MITER as it's pretty close
945  case rendering::PathJoinType::MITER:
946  cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_MITER );
947  break;
948  case rendering::PathJoinType::ROUND:
949  cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_ROUND );
950  break;
951  case rendering::PathJoinType::BEVEL:
952  cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_BEVEL );
953  break;
954  }
955 
956  //tdf#103026 If the w scaling is 0, then all dashes become zero so
957  //cairo will set the cairo_t status to CAIRO_STATUS_INVALID_DASH
958  //and no further drawing will occur
959  if (strokeAttributes.DashArray.hasElements() && w > 0.0)
960  {
961  auto aDashArray(comphelper::sequenceToContainer<std::vector<double>>(strokeAttributes.DashArray));
962  for (auto& rDash : aDashArray)
963  rDash *= w;
964  cairo_set_dash(mpCairo.get(), aDashArray.data(), aDashArray.size(), 0);
965  }
966 
967  // TODO(rodo) use LineArray of strokeAttributes
968 
969  doPolyPolygonPath( xPolyPolygon, Stroke, bNoLineJoin );
970 
971  cairo_restore( mpCairo.get() );
972  }
973  else
974  SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
975 
976 #ifdef CAIRO_CANVAS_PERF_TRACE
977  mxDevice->stopPerfTrace( &aTimer, "strokePolyPolygon" );
978 #endif
979 
980  // TODO(P1): Provide caching here.
981  return uno::Reference< rendering::XCachedPrimitive >(nullptr);
982  }
983 
984  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* ,
985  const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
986  const rendering::ViewState& /*viewState*/,
987  const rendering::RenderState& /*renderState*/,
988  const uno::Sequence< rendering::Texture >& /*textures*/,
989  const rendering::StrokeAttributes& /*strokeAttributes*/ )
990  {
991  // TODO
992  return uno::Reference< rendering::XCachedPrimitive >(nullptr);
993  }
994 
995  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* ,
996  const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
997  const rendering::ViewState& /*viewState*/,
998  const rendering::RenderState& /*renderState*/,
999  const uno::Sequence< rendering::Texture >& /*textures*/,
1000  const uno::Reference< geometry::XMapping2D >& /*xMapping*/,
1001  const rendering::StrokeAttributes& /*strokeAttributes*/ )
1002  {
1003  // TODO
1004  return uno::Reference< rendering::XCachedPrimitive >(nullptr);
1005  }
1006 
1007  uno::Reference< rendering::XPolyPolygon2D > CanvasHelper::queryStrokeShapes( const rendering::XCanvas* ,
1008  const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
1009  const rendering::ViewState& /*viewState*/,
1010  const rendering::RenderState& /*renderState*/,
1011  const rendering::StrokeAttributes& /*strokeAttributes*/ )
1012  {
1013  // TODO
1014  return uno::Reference< rendering::XPolyPolygon2D >(nullptr);
1015  }
1016 
1017  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* ,
1018  const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1019  const rendering::ViewState& viewState,
1020  const rendering::RenderState& renderState )
1021  {
1022 #ifdef CAIRO_CANVAS_PERF_TRACE
1023  struct timespec aTimer;
1024  mxDevice->startPerfTrace( &aTimer );
1025 #endif
1026 
1027  if( mpCairo )
1028  {
1029  cairo_save( mpCairo.get() );
1030 
1031  useStates( viewState, renderState, true );
1032  doPolyPolygonPath( xPolyPolygon, Fill );
1033 
1034  cairo_restore( mpCairo.get() );
1035  }
1036  else
1037  SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1038 
1039 #ifdef CAIRO_CANVAS_PERF_TRACE
1040  mxDevice->stopPerfTrace( &aTimer, "fillPolyPolygon" );
1041 #endif
1042 
1043  return uno::Reference< rendering::XCachedPrimitive >(nullptr);
1044  }
1045 
1046  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* ,
1047  const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
1048  const rendering::ViewState& viewState,
1049  const rendering::RenderState& renderState,
1050  const uno::Sequence< rendering::Texture >& textures )
1051  {
1052  if( mpCairo )
1053  {
1054  cairo_save( mpCairo.get() );
1055 
1056  useStates( viewState, renderState, true );
1057  doPolyPolygonPath( xPolyPolygon, Fill, false, &textures );
1058 
1059  cairo_restore( mpCairo.get() );
1060  }
1061 
1062  return uno::Reference< rendering::XCachedPrimitive >(nullptr);
1063  }
1064 
1065  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* ,
1066  const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
1067  const rendering::ViewState& /*viewState*/,
1068  const rendering::RenderState& /*renderState*/,
1069  const uno::Sequence< rendering::Texture >& /*textures*/,
1070  const uno::Reference< geometry::XMapping2D >& /*xMapping*/ )
1071  {
1072  // TODO
1073  return uno::Reference< rendering::XCachedPrimitive >(nullptr);
1074  }
1075 
1076  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::implDrawBitmapSurface( const rendering::XCanvas* pCanvas,
1077  const SurfaceSharedPtr& pInputSurface,
1078  const rendering::ViewState& viewState,
1079  const rendering::RenderState& renderState,
1080  const geometry::IntegerSize2D& rSize,
1081  bool bModulateColors,
1082  bool bHasAlpha )
1083  {
1084  SurfaceSharedPtr pSurface=pInputSurface;
1085  uno::Reference< rendering::XCachedPrimitive > rv;
1086  geometry::IntegerSize2D aBitmapSize = rSize;
1087 
1088  if( mpCairo )
1089  {
1090  cairo_save( mpCairo.get() );
1091 
1092  cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
1093  cairo_clip( mpCairo.get() );
1094 
1095  useStates( viewState, renderState, true );
1096 
1097  cairo_matrix_t aMatrix;
1098 
1099  cairo_get_matrix( mpCairo.get(), &aMatrix );
1100  if( ! ::rtl::math::approxEqual( aMatrix.xx, 1 ) &&
1101  ! ::rtl::math::approxEqual( aMatrix.yy, 1 ) &&
1102  ::rtl::math::approxEqual( aMatrix.x0, 0 ) &&
1103  ::rtl::math::approxEqual( aMatrix.y0, 0 ) &&
1104  basegfx::fround( rSize.Width * aMatrix.xx ) > 8 &&
1105  basegfx::fround( rSize.Height* aMatrix.yy ) > 8 )
1106  {
1107  double dWidth, dHeight;
1108 
1109  dWidth = basegfx::fround( rSize.Width * aMatrix.xx );
1110  dHeight = basegfx::fround( rSize.Height* aMatrix.yy );
1111  aBitmapSize.Width = static_cast<sal_Int32>( dWidth );
1112  aBitmapSize.Height = static_cast<sal_Int32>( dHeight );
1113 
1115  ::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ),
1116  bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
1117  CairoSharedPtr pCairo = pScaledSurface->getCairo();
1118 
1119  cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE );
1120  // add 0.5px to size to avoid rounding errors in cairo, leading sometimes to random data on the image right/bottom borders
1121  cairo_scale( pCairo.get(), (dWidth+0.5)/rSize.Width, (dHeight+0.5)/rSize.Height );
1122  cairo_set_source_surface( pCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
1123  cairo_paint( pCairo.get() );
1124 
1125  pSurface = pScaledSurface;
1126 
1127  aMatrix.xx = aMatrix.yy = 1;
1128  cairo_set_matrix( mpCairo.get(), &aMatrix );
1129 
1130  rv.set(
1131  new CachedBitmap( pSurface, viewState, renderState,
1132  // cast away const, need to
1133  // change refcount (as this is
1134  // ~invisible to client code,
1135  // still logically const)
1136  const_cast< rendering::XCanvas* >(pCanvas)) );
1137  }
1138 
1139  if( !bHasAlpha && mbHaveAlpha )
1140  {
1141  double x, y, width, height;
1142 
1143  x = y = 0;
1144  width = aBitmapSize.Width;
1145  height = aBitmapSize.Height;
1146  cairo_matrix_transform_point( &aMatrix, &x, &y );
1147  cairo_matrix_transform_distance( &aMatrix, &width, &height );
1148 
1149  // in case the bitmap doesn't have alpha and covers whole area
1150  // we try to change surface to plain rgb
1151  SAL_INFO( "canvas.cairo","chance to change surface to rgb, " << x << ", " << y << ", " << width << " x " << height << " (" << maSize.getX() << " x " << maSize.getY() << ")" );
1152  if( x <= 0 && y <= 0 && x + width >= maSize.getX() && y + height >= maSize.getY() )
1153  {
1154  SAL_INFO( "canvas.cairo","trying to change surface to rgb");
1155  if( mpSurfaceProvider ) {
1157 
1158  if( pNewSurface )
1159  setSurface( pNewSurface, false );
1160 
1161  // set state to new mpCairo.get()
1162  useStates( viewState, renderState, true );
1163  // use the possibly modified matrix
1164  cairo_set_matrix( mpCairo.get(), &aMatrix );
1165  }
1166  }
1167  }
1168 
1169  cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
1170  if( !bHasAlpha &&
1171  ::rtl::math::approxEqual( aMatrix.xx, 1 ) &&
1172  ::rtl::math::approxEqual( aMatrix.yy, 1 ) &&
1173  ::rtl::math::approxEqual( aMatrix.x0, 0 ) &&
1174  ::rtl::math::approxEqual( aMatrix.y0, 0 ) )
1175  cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
1176  cairo_pattern_set_extend( cairo_get_source(mpCairo.get()), CAIRO_EXTEND_PAD );
1177  cairo_rectangle( mpCairo.get(), 0, 0, aBitmapSize.Width, aBitmapSize.Height );
1178  cairo_clip( mpCairo.get() );
1179 
1180  if( bModulateColors )
1181  cairo_paint_with_alpha( mpCairo.get(), renderState.DeviceColor[3] );
1182  else
1183  cairo_paint( mpCairo.get() );
1184  cairo_restore( mpCairo.get() );
1185  }
1186  else
1187  SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1188 
1189  return rv; // uno::Reference< rendering::XCachedPrimitive >(NULL);
1190  }
1191 
1192  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* pCanvas,
1193  const uno::Reference< rendering::XBitmap >& xBitmap,
1194  const rendering::ViewState& viewState,
1195  const rendering::RenderState& renderState )
1196  {
1197 #ifdef CAIRO_CANVAS_PERF_TRACE
1198  struct timespec aTimer;
1199  mxDevice->startPerfTrace( &aTimer );
1200 #endif
1201 
1202  uno::Reference< rendering::XCachedPrimitive > rv;
1203  unsigned char* data = nullptr;
1204  bool bHasAlpha = false;
1205  SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
1206  geometry::IntegerSize2D aSize = xBitmap->getSize();
1207 
1208  if( pSurface )
1209  {
1210  rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, false, bHasAlpha );
1211 
1212  if( data )
1213  free( data );
1214  }
1215  else
1216  rv.set(nullptr);
1217 
1218 #ifdef CAIRO_CANVAS_PERF_TRACE
1219  mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1220 #endif
1221 
1222  return rv;
1223  }
1224 
1225  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas,
1226  const uno::Reference< rendering::XBitmap >& xBitmap,
1227  const rendering::ViewState& viewState,
1228  const rendering::RenderState& renderState )
1229  {
1230 #ifdef CAIRO_CANVAS_PERF_TRACE
1231  struct timespec aTimer;
1232  mxDevice->startPerfTrace( &aTimer );
1233 #endif
1234 
1235  uno::Reference< rendering::XCachedPrimitive > rv;
1236  unsigned char* data = nullptr;
1237  bool bHasAlpha = false;
1238  SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
1239  geometry::IntegerSize2D aSize = xBitmap->getSize();
1240 
1241  if( pSurface )
1242  {
1243  rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, true, bHasAlpha );
1244 
1245  if( data )
1246  free( data );
1247  }
1248  else
1249  rv.set(nullptr);
1250 
1251 #ifdef CAIRO_CANVAS_PERF_TRACE
1252  mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1253 #endif
1254 
1255  return rv;
1256  }
1257 
1258 
1259  geometry::IntegerSize2D CanvasHelper::getSize() const
1260  {
1261  if( !mpSurfaceProvider )
1262  return geometry::IntegerSize2D(1, 1); // we're disposed
1263 
1264  return ::basegfx::unotools::integerSize2DFromB2ISize( maSize );
1265  }
1266 
1267  uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D& newSize,
1268  bool /*beFast*/ )
1269  {
1270 #ifdef CAIRO_CANVAS_PERF_TRACE
1271  struct timespec aTimer;
1272  mxDevice->startPerfTrace( &aTimer );
1273 #endif
1274 
1275  if( mpCairo )
1276  {
1277  return uno::Reference< rendering::XBitmap >( new CanvasBitmap( ::basegfx::B2ISize( ::canvas::tools::roundUp( newSize.Width ),
1278  ::canvas::tools::roundUp( newSize.Height ) ),
1279  mpSurfaceProvider, mpDevice, false ) );
1280  }
1281  else
1282  SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1283 
1284 #ifdef CAIRO_CANVAS_PERF_TRACE
1285  mxDevice->stopPerfTrace( &aTimer, "getScaledBitmap" );
1286 #endif
1287 
1288  return uno::Reference< rendering::XBitmap >();
1289  }
1290 
1291  uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& aLayout,
1292  const geometry::IntegerRectangle2D& rect )
1293  {
1294  if( mpCairo )
1295  {
1296  const sal_Int32 nWidth( rect.X2 - rect.X1 );
1297  const sal_Int32 nHeight( rect.Y2 - rect.Y1 );
1298  const cairo_format_t eFormat( mbHaveAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24 );
1299  uno::Sequence< sal_Int8 > aRes( 4*nWidth*nHeight );
1300  sal_Int8* pData = aRes.getArray();
1301  cairo_surface_t* pImageSurface = cairo_image_surface_create_for_data( reinterpret_cast<unsigned char *>(pData),
1302  eFormat,
1303  nWidth, nHeight, 4*nWidth );
1304  cairo_t* pCairo = cairo_create( pImageSurface );
1305  cairo_set_source_surface( pCairo, mpSurface->getCairoSurface().get(), -rect.X1, -rect.Y1);
1306  cairo_paint( pCairo );
1307  cairo_destroy( pCairo );
1308  cairo_surface_destroy( pImageSurface );
1309 
1310  aLayout = impl_getMemoryLayout( nWidth, nHeight );
1311 
1312  return aRes;
1313  }
1314 
1315  return uno::Sequence< sal_Int8 >();
1316  }
1317 
1318  uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/,
1319  const geometry::IntegerPoint2D& /*pos*/ )
1320  {
1321  return uno::Sequence< sal_Int8 >();
1322  }
1323 
1324  namespace
1325  {
1326  class CairoColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace >
1327  {
1328  private:
1329  uno::Sequence< sal_Int8 > maComponentTags;
1330  uno::Sequence< sal_Int32 > maBitCounts;
1331 
1332  virtual ::sal_Int8 SAL_CALL getType( ) override
1333  {
1334  return rendering::ColorSpaceType::RGB;
1335  }
1336  virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override
1337  {
1338  return maComponentTags;
1339  }
1340  virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override
1341  {
1342  return rendering::RenderingIntent::PERCEPTUAL;
1343  }
1344  virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override
1345  {
1346  return uno::Sequence< beans::PropertyValue >();
1347  }
1348  virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
1349  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
1350  {
1351  // TODO(P3): if we know anything about target
1352  // colorspace, this can be greatly sped up
1353  uno::Sequence<rendering::ARGBColor> aIntermediate(
1354  convertToARGB(deviceColor));
1355  return targetColorSpace->convertFromARGB(aIntermediate);
1356  }
1357  virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override
1358  {
1359  const double* pIn( deviceColor.getConstArray() );
1360  const std::size_t nLen( deviceColor.getLength() );
1361  ENSURE_ARG_OR_THROW2(nLen%4==0,
1362  "number of channels no multiple of 4",
1363  static_cast<rendering::XColorSpace*>(this), 0);
1364 
1365  uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1366  rendering::RGBColor* pOut( aRes.getArray() );
1367  for( std::size_t i=0; i<nLen; i+=4 )
1368  {
1369  const double fAlpha(pIn[3]);
1370  if( fAlpha == 0.0 )
1371  *pOut++ = rendering::RGBColor(0.0, 0.0, 0.0);
1372  else
1373  *pOut++ = rendering::RGBColor(pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1374  pIn += 4;
1375  }
1376  return aRes;
1377  }
1378  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
1379  {
1380  const double* pIn( deviceColor.getConstArray() );
1381  const std::size_t nLen( deviceColor.getLength() );
1382  ENSURE_ARG_OR_THROW2(nLen%4==0,
1383  "number of channels no multiple of 4",
1384  static_cast<rendering::XColorSpace*>(this), 0);
1385 
1386  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1387  rendering::ARGBColor* pOut( aRes.getArray() );
1388  for( std::size_t i=0; i<nLen; i+=4 )
1389  {
1390  const double fAlpha(pIn[3]);
1391  if( fAlpha == 0.0 )
1392  *pOut++ = rendering::ARGBColor(0.0, 0.0, 0.0, 0.0);
1393  else
1394  *pOut++ = rendering::ARGBColor(fAlpha,pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1395  pIn += 4;
1396  }
1397  return aRes;
1398  }
1399  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
1400  {
1401  const double* pIn( deviceColor.getConstArray() );
1402  const std::size_t nLen( deviceColor.getLength() );
1403  ENSURE_ARG_OR_THROW2(nLen%4==0,
1404  "number of channels no multiple of 4",
1405  static_cast<rendering::XColorSpace*>(this), 0);
1406 
1407  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1408  rendering::ARGBColor* pOut( aRes.getArray() );
1409  for( std::size_t i=0; i<nLen; i+=4 )
1410  {
1411  *pOut++ = rendering::ARGBColor(pIn[3],pIn[2],pIn[1],pIn[1]);
1412  pIn += 4;
1413  }
1414  return aRes;
1415  }
1416  virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
1417  {
1418  const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1419  const std::size_t nLen( rgbColor.getLength() );
1420 
1421  uno::Sequence< double > aRes(nLen*4);
1422  double* pColors=aRes.getArray();
1423  for( std::size_t i=0; i<nLen; ++i )
1424  {
1425  *pColors++ = pIn->Blue;
1426  *pColors++ = pIn->Green;
1427  *pColors++ = pIn->Red;
1428  *pColors++ = 1.0;
1429  ++pIn;
1430  }
1431  return aRes;
1432  }
1433  virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1434  {
1435  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1436  const std::size_t nLen( rgbColor.getLength() );
1437 
1438  uno::Sequence< double > aRes(nLen*4);
1439  double* pColors=aRes.getArray();
1440  for( std::size_t i=0; i<nLen; ++i )
1441  {
1442  *pColors++ = pIn->Alpha*pIn->Blue;
1443  *pColors++ = pIn->Alpha*pIn->Green;
1444  *pColors++ = pIn->Alpha*pIn->Red;
1445  *pColors++ = pIn->Alpha;
1446  ++pIn;
1447  }
1448  return aRes;
1449  }
1450  virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1451  {
1452  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1453  const std::size_t nLen( rgbColor.getLength() );
1454 
1455  uno::Sequence< double > aRes(nLen*4);
1456  double* pColors=aRes.getArray();
1457  for( std::size_t i=0; i<nLen; ++i )
1458  {
1459  *pColors++ = pIn->Blue;
1460  *pColors++ = pIn->Green;
1461  *pColors++ = pIn->Red;
1462  *pColors++ = pIn->Alpha;
1463  ++pIn;
1464  }
1465  return aRes;
1466  }
1467 
1468  // XIntegerBitmapColorSpace
1469  virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override
1470  {
1471  return 32;
1472  }
1473  virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override
1474  {
1475  return maBitCounts;
1476  }
1477  virtual ::sal_Int8 SAL_CALL getEndianness( ) override
1478  {
1479  return util::Endianness::LITTLE;
1480  }
1481  virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1482  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
1483  {
1484  if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1485  {
1486  const sal_Int8* pIn( deviceColor.getConstArray() );
1487  const std::size_t nLen( deviceColor.getLength() );
1488  ENSURE_ARG_OR_THROW2(nLen%4==0,
1489  "number of channels no multiple of 4",
1490  static_cast<rendering::XColorSpace*>(this), 0);
1491 
1492  uno::Sequence<double> aRes(nLen);
1493  double* pOut( aRes.getArray() );
1494  for( std::size_t i=0; i<nLen; i+=4 )
1495  {
1496  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1497  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1498  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1499  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1500  }
1501  return aRes;
1502  }
1503  else
1504  {
1505  // TODO(P3): if we know anything about target
1506  // colorspace, this can be greatly sped up
1507  uno::Sequence<rendering::ARGBColor> aIntermediate(
1508  convertIntegerToARGB(deviceColor));
1509  return targetColorSpace->convertFromARGB(aIntermediate);
1510  }
1511  }
1512  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1513  const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override
1514  {
1515  if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1516  {
1517  // it's us, so simply pass-through the data
1518  return deviceColor;
1519  }
1520  else
1521  {
1522  // TODO(P3): if we know anything about target
1523  // colorspace, this can be greatly sped up
1524  uno::Sequence<rendering::ARGBColor> aIntermediate(
1525  convertIntegerToARGB(deviceColor));
1526  return targetColorSpace->convertIntegerFromARGB(aIntermediate);
1527  }
1528  }
1529  virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1530  {
1531  const sal_Int8* pIn( deviceColor.getConstArray() );
1532  const std::size_t nLen( deviceColor.getLength() );
1533  ENSURE_ARG_OR_THROW2(nLen%4==0,
1534  "number of channels no multiple of 4",
1535  static_cast<rendering::XColorSpace*>(this), 0);
1536 
1537  uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1538  rendering::RGBColor* pOut( aRes.getArray() );
1539  for( std::size_t i=0; i<nLen; i+=4 )
1540  {
1541  const double fAlpha(static_cast<sal_uInt8>(pIn[3]));
1542  if( fAlpha )
1543  *pOut++ = rendering::RGBColor(
1544  pIn[2]/fAlpha,
1545  pIn[1]/fAlpha,
1546  pIn[0]/fAlpha);
1547  else
1548  *pOut++ = rendering::RGBColor(0,0,0);
1549  pIn += 4;
1550  }
1551  return aRes;
1552  }
1553 
1554  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1555  {
1556  const sal_Int8* pIn( deviceColor.getConstArray() );
1557  const std::size_t nLen( deviceColor.getLength() );
1558  ENSURE_ARG_OR_THROW2(nLen%4==0,
1559  "number of channels no multiple of 4",
1560  static_cast<rendering::XColorSpace*>(this), 0);
1561 
1562  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1563  rendering::ARGBColor* pOut( aRes.getArray() );
1564  for( std::size_t i=0; i<nLen; i+=4 )
1565  {
1566  const double fAlpha(static_cast<sal_uInt8>(pIn[3]));
1567  if( fAlpha )
1568  *pOut++ = rendering::ARGBColor(
1569  fAlpha/255.0,
1570  pIn[2]/fAlpha,
1571  pIn[1]/fAlpha,
1572  pIn[0]/fAlpha);
1573  else
1574  *pOut++ = rendering::ARGBColor(0,0,0,0);
1575  pIn += 4;
1576  }
1577  return aRes;
1578  }
1579  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1580  {
1581  const sal_Int8* pIn( deviceColor.getConstArray() );
1582  const std::size_t nLen( deviceColor.getLength() );
1583  ENSURE_ARG_OR_THROW2(nLen%4==0,
1584  "number of channels no multiple of 4",
1585  static_cast<rendering::XColorSpace*>(this), 0);
1586 
1587  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1588  rendering::ARGBColor* pOut( aRes.getArray() );
1589  for( std::size_t i=0; i<nLen; i+=4 )
1590  {
1591  *pOut++ = rendering::ARGBColor(
1596  pIn += 4;
1597  }
1598  return aRes;
1599  }
1600 
1601  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
1602  {
1603  const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1604  const std::size_t nLen( rgbColor.getLength() );
1605 
1606  uno::Sequence< sal_Int8 > aRes(nLen*4);
1607  sal_Int8* pColors=aRes.getArray();
1608  for( std::size_t i=0; i<nLen; ++i )
1609  {
1610  *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1611  *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1612  *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1613  *pColors++ = -1;
1614  ++pIn;
1615  }
1616  return aRes;
1617  }
1618 
1619  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1620  {
1621  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1622  const std::size_t nLen( rgbColor.getLength() );
1623 
1624  uno::Sequence< sal_Int8 > aRes(nLen*4);
1625  sal_Int8* pColors=aRes.getArray();
1626  for( std::size_t i=0; i<nLen; ++i )
1627  {
1628  const double fAlpha(pIn->Alpha);
1629  *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Blue);
1630  *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Green);
1631  *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Red);
1632  *pColors++ = vcl::unotools::toByteColor(fAlpha);
1633  ++pIn;
1634  }
1635  return aRes;
1636  }
1637  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1638  {
1639  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1640  const std::size_t nLen( rgbColor.getLength() );
1641 
1642  uno::Sequence< sal_Int8 > aRes(nLen*4);
1643  sal_Int8* pColors=aRes.getArray();
1644  for( std::size_t i=0; i<nLen; ++i )
1645  {
1646  *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1647  *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1648  *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1649  *pColors++ = vcl::unotools::toByteColor(pIn->Alpha);
1650  ++pIn;
1651  }
1652  return aRes;
1653  }
1654 
1655  public:
1656  CairoColorSpace() :
1657  maComponentTags(4),
1658  maBitCounts(4)
1659  {
1660  sal_Int8* pTags = maComponentTags.getArray();
1661  sal_Int32* pBitCounts = maBitCounts.getArray();
1662  pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
1663  pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
1664  pTags[2] = rendering::ColorComponentTag::RGB_RED;
1665  pTags[3] = rendering::ColorComponentTag::PREMULTIPLIED_ALPHA;
1666 
1667  pBitCounts[0] =
1668  pBitCounts[1] =
1669  pBitCounts[2] =
1670  pBitCounts[3] = 8;
1671  }
1672  };
1673 
1674  class CairoNoAlphaColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace >
1675  {
1676  private:
1677  uno::Sequence< sal_Int8 > maComponentTags;
1678  uno::Sequence< sal_Int32 > maBitCounts;
1679 
1680  virtual ::sal_Int8 SAL_CALL getType( ) override
1681  {
1682  return rendering::ColorSpaceType::RGB;
1683  }
1684  virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override
1685  {
1686  return maComponentTags;
1687  }
1688  virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override
1689  {
1690  return rendering::RenderingIntent::PERCEPTUAL;
1691  }
1692  virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override
1693  {
1694  return uno::Sequence< beans::PropertyValue >();
1695  }
1696  virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
1697  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
1698  {
1699  // TODO(P3): if we know anything about target
1700  // colorspace, this can be greatly sped up
1701  uno::Sequence<rendering::ARGBColor> aIntermediate(
1702  convertToARGB(deviceColor));
1703  return targetColorSpace->convertFromARGB(aIntermediate);
1704  }
1705  virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override
1706  {
1707  const double* pIn( deviceColor.getConstArray() );
1708  const std::size_t nLen( deviceColor.getLength() );
1709  ENSURE_ARG_OR_THROW2(nLen%4==0,
1710  "number of channels no multiple of 4",
1711  static_cast<rendering::XColorSpace*>(this), 0);
1712 
1713  uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1714  rendering::RGBColor* pOut( aRes.getArray() );
1715  for( std::size_t i=0; i<nLen; i+=4 )
1716  {
1717  *pOut++ = rendering::RGBColor(pIn[2], pIn[1], pIn[0]);
1718  pIn += 4;
1719  }
1720  return aRes;
1721  }
1722  uno::Sequence< rendering::ARGBColor > impl_convertToARGB( const uno::Sequence< double >& deviceColor )
1723  {
1724  const double* pIn( deviceColor.getConstArray() );
1725  const std::size_t nLen( deviceColor.getLength() );
1726  ENSURE_ARG_OR_THROW2(nLen%4==0,
1727  "number of channels no multiple of 4",
1728  static_cast<rendering::XColorSpace*>(this), 0);
1729 
1730  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1731  rendering::ARGBColor* pOut( aRes.getArray() );
1732  for( std::size_t i=0; i<nLen; i+=4 )
1733  {
1734  *pOut++ = rendering::ARGBColor(1.0, pIn[2], pIn[1], pIn[0]);
1735  pIn += 4;
1736  }
1737  return aRes;
1738  }
1739  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
1740  {
1741  return impl_convertToARGB( deviceColor );
1742  }
1743  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
1744  {
1745  return impl_convertToARGB( deviceColor );
1746  }
1747  virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
1748  {
1749  const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1750  const std::size_t nLen( rgbColor.getLength() );
1751 
1752  uno::Sequence< double > aRes(nLen*4);
1753  double* pColors=aRes.getArray();
1754  for( std::size_t i=0; i<nLen; ++i )
1755  {
1756  *pColors++ = pIn->Blue;
1757  *pColors++ = pIn->Green;
1758  *pColors++ = pIn->Red;
1759  *pColors++ = 1.0; // the value does not matter
1760  ++pIn;
1761  }
1762  return aRes;
1763  }
1764  uno::Sequence< double > impl_convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
1765  {
1766  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1767  const std::size_t nLen( rgbColor.getLength() );
1768 
1769  uno::Sequence< double > aRes(nLen*4);
1770  double* pColors=aRes.getArray();
1771  for( std::size_t i=0; i<nLen; ++i )
1772  {
1773  *pColors++ = pIn->Blue;
1774  *pColors++ = pIn->Green;
1775  *pColors++ = pIn->Red;
1776  *pColors++ = 1.0; // the value does not matter
1777  ++pIn;
1778  }
1779  return aRes;
1780  }
1781  virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1782  {
1783  return impl_convertFromARGB( rgbColor );
1784  }
1785  virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1786  {
1787  return impl_convertFromARGB( rgbColor );
1788  }
1789 
1790  // XIntegerBitmapColorSpace
1791  virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override
1792  {
1793  return 32;
1794  }
1795  virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override
1796  {
1797  return maBitCounts;
1798  }
1799  virtual ::sal_Int8 SAL_CALL getEndianness( ) override
1800  {
1801  return util::Endianness::LITTLE;
1802  }
1803  virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1804  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
1805  {
1806  if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1807  {
1808  const sal_Int8* pIn( deviceColor.getConstArray() );
1809  const std::size_t nLen( deviceColor.getLength() );
1810  ENSURE_ARG_OR_THROW2(nLen%4==0,
1811  "number of channels no multiple of 4",
1812  static_cast<rendering::XColorSpace*>(this), 0);
1813 
1814  uno::Sequence<double> aRes(nLen);
1815  double* pOut( aRes.getArray() );
1816  for( std::size_t i=0; i<nLen; i+=4 )
1817  {
1818  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1819  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1820  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1821  *pOut++ = 1.0; pIn++; // the value does not matter
1822  }
1823  return aRes;
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  convertIntegerToARGB(deviceColor));
1831  return targetColorSpace->convertFromARGB(aIntermediate);
1832  }
1833  }
1834  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1835  const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override
1836  {
1837  if( dynamic_cast<CairoNoAlphaColorSpace*>(targetColorSpace.get()) )
1838  {
1839  // it's us, so simply pass-through the data
1840  return deviceColor;
1841  }
1842  else
1843  {
1844  // TODO(P3): if we know anything about target
1845  // colorspace, this can be greatly sped up
1846  uno::Sequence<rendering::ARGBColor> aIntermediate(
1847  convertIntegerToARGB(deviceColor));
1848  return targetColorSpace->convertIntegerFromARGB(aIntermediate);
1849  }
1850  }
1851  virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1852  {
1853  const sal_Int8* pIn( deviceColor.getConstArray() );
1854  const std::size_t nLen( deviceColor.getLength() );
1855  ENSURE_ARG_OR_THROW2(nLen%4==0,
1856  "number of channels no multiple of 4",
1857  static_cast<rendering::XColorSpace*>(this), 0);
1858 
1859  uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1860  rendering::RGBColor* pOut( aRes.getArray() );
1861  for( std::size_t i=0; i<nLen; i+=4 )
1862  {
1863  *pOut++ = rendering::RGBColor( pIn[2], pIn[1], pIn[0] );
1864  pIn += 4;
1865  }
1866  return aRes;
1867  }
1868 
1869  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1870  {
1871  return impl_convertIntegerToARGB( deviceColor );
1872  }
1873  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1874  {
1875  return impl_convertIntegerToARGB( deviceColor );
1876  }
1877  uno::Sequence< rendering::ARGBColor > impl_convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1878  {
1879  const sal_Int8* pIn( deviceColor.getConstArray() );
1880  const std::size_t nLen( deviceColor.getLength() );
1881  ENSURE_ARG_OR_THROW2(nLen%4==0,
1882  "number of channels no multiple of 4",
1883  static_cast<rendering::XColorSpace*>(this), 0);
1884 
1885  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1886  rendering::ARGBColor* pOut( aRes.getArray() );
1887  for( std::size_t i=0; i<nLen; i+=4 )
1888  {
1889  *pOut++ = rendering::ARGBColor(
1890  1.0,
1894  pIn += 4;
1895  }
1896  return aRes;
1897  }
1898 
1899  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
1900  {
1901  const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1902  const std::size_t nLen( rgbColor.getLength() );
1903 
1904  uno::Sequence< sal_Int8 > aRes(nLen*4);
1905  sal_Int8* pColors=aRes.getArray();
1906  for( std::size_t i=0; i<nLen; ++i )
1907  {
1908  *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1909  *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1910  *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1911  *pColors++ = -1; // the value does not matter
1912  ++pIn;
1913  }
1914  return aRes;
1915  }
1916 
1917  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1918  {
1919  return impl_convertIntegerFromARGB( rgbColor );
1920  }
1921  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1922  {
1923  return impl_convertIntegerFromARGB( rgbColor );
1924  }
1925  uno::Sequence< ::sal_Int8 > impl_convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
1926  {
1927  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1928  const std::size_t nLen( rgbColor.getLength() );
1929 
1930  uno::Sequence< sal_Int8 > aRes(nLen*4);
1931  sal_Int8* pColors=aRes.getArray();
1932  for( std::size_t i=0; i<nLen; ++i )
1933  {
1934  *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1935  *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1936  *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1937  *pColors++ = -1; // the value does not matter
1938  ++pIn;
1939  }
1940  return aRes;
1941  }
1942 
1943  public:
1944  CairoNoAlphaColorSpace() :
1945  maComponentTags(3),
1946  maBitCounts(3)
1947  {
1948  sal_Int8* pTags = maComponentTags.getArray();
1949  sal_Int32* pBitCounts = maBitCounts.getArray();
1950  pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
1951  pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
1952  pTags[2] = rendering::ColorComponentTag::RGB_RED;
1953 
1954  pBitCounts[0] =
1955  pBitCounts[1] =
1956  pBitCounts[2] = 8;
1957  }
1958  };
1959 
1960  struct CairoNoAlphaColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
1961  CairoNoAlphaColorSpaceHolder>
1962  {
1963  uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
1964  {
1965  return new CairoNoAlphaColorSpace();
1966  }
1967  };
1968 
1969  struct CairoColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
1970  CairoColorSpaceHolder>
1971  {
1972  uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
1973  {
1974  return new CairoColorSpace();
1975  }
1976  };
1977 
1978  }
1979 
1980  rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout()
1981  {
1982  if( !mpCairo )
1983  return rendering::IntegerBitmapLayout(); // we're disposed
1984 
1985  const geometry::IntegerSize2D aSize(getSize());
1986 
1987  return impl_getMemoryLayout( aSize.Width, aSize.Height );
1988  }
1989 
1990  rendering::IntegerBitmapLayout
1991  CanvasHelper::impl_getMemoryLayout( const sal_Int32 nWidth, const sal_Int32 nHeight )
1992  {
1993  rendering::IntegerBitmapLayout aLayout;
1994 
1995  aLayout.ScanLines = nHeight;
1996  aLayout.ScanLineBytes = nWidth*4;
1997  aLayout.ScanLineStride = aLayout.ScanLineBytes;
1998  aLayout.PlaneStride = 0;
1999  aLayout.ColorSpace = mbHaveAlpha ? CairoColorSpaceHolder::get() : CairoNoAlphaColorSpaceHolder::get();
2000  aLayout.Palette.clear();
2001  aLayout.IsMsbFirst = false;
2002 
2003  return aLayout;
2004  }
2005 
2006 
2007  bool CanvasHelper::repaint( const SurfaceSharedPtr& pSurface,
2008  const rendering::ViewState& viewState,
2009  const rendering::RenderState& renderState )
2010  {
2011  SAL_INFO( "canvas.cairo", "CanvasHelper::repaint");
2012 
2013  if( mpCairo )
2014  {
2015  cairo_save( mpCairo.get() );
2016 
2017  cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
2018  cairo_clip( mpCairo.get() );
2019 
2020  useStates( viewState, renderState, true );
2021 
2022  cairo_matrix_t aMatrix;
2023 
2024  cairo_get_matrix( mpCairo.get(), &aMatrix );
2025  aMatrix.xx = aMatrix.yy = 1;
2026  cairo_set_matrix( mpCairo.get(), &aMatrix );
2027 
2028  cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
2029  cairo_paint( mpCairo.get() );
2030  cairo_restore( mpCairo.get() );
2031  }
2032 
2033  return true;
2034  }
2035 }
2036 
2037 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::rendering::IntegerBitmapLayout impl_getMemoryLayout(sal_Int32 nWidth, sal_Int32 nHeight)
css::uno::Reference< css::rendering::XCachedPrimitive > implDrawBitmapSurface(const css::rendering::XCanvas *pCanvas, const ::cairo::SurfaceSharedPtr &pSurface, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, const css::geometry::IntegerSize2D &rSize, bool bModulateColors, bool bHasAlpha)
sal_Int32 nIndex
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
Target interface for XCachedPrimitive implementations.
css::uno::Reference< css::rendering::XCachedPrimitive > strokeTexturedPolyPolygon(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, const css::uno::Sequence< css::rendering::Texture > &textures, const css::rendering::StrokeAttributes &strokeAttributes)
double getHeight() const
::cairo::CairoSharedPtr mpCairo
bool getType(BSTR name, Type &type)
std::unique_ptr< ContentProperties > pData
static bool equal(const double &rfValA, const double &rfValB)
const GradientType meType
Type of gradient to render (as e.g. linear grads are not represented by maGradientPoly) ...
virtual ::cairo::SurfaceSharedPtr createSurface(const ::basegfx::B2ISize &rSize, int aContent)=0
create new surface in given size
signed char sal_Int8
const css::uno::Sequence< css::uno::Sequence< double > > maColors
Gradient colors.
static uno::Sequence< double > lerp(const uno::Sequence< double > &rLeft, const uno::Sequence< double > &rRight, double fAlpha)
double getX() const
void setSize(const ::basegfx::B2ISize &rSize)
#define max(a, b)
Definition: dx_winstuff.hxx:46
static void addColorStops(cairo_pattern_t *pPattern, const uno::Sequence< uno::Sequence< double > > &rColors, const uno::Sequence< double > &rStops, bool bReverseStops)
::BitmapEx bitmapExFromXBitmap(const uno::Reference< rendering::XBitmap > &xBitmap)
css::uno::Sequence< sal_Int8 > getPixel(css::rendering::IntegerBitmapLayout &bitmapLayout, const css::geometry::IntegerPoint2D &pos)
double getY() const
B2DPoint getMaximum() const
::BitmapEx bitmapExFromXBitmap(const uno::Reference< rendering::XIntegerReadOnlyBitmap > &xInputBitmap)
float x
Definition: dx_9rm.cxx:190
void CanvasCairoExtractBitmapData(BitmapEx const &rBmpEx, Bitmap &rBitmap, unsigned char *&data, bool &bHasAlpha, long &rnWidth, long &rnHeight)
void disposing()
Release all references.
std::shared_ptr< cairo_t > CairoSharedPtr
DstType sequenceToContainer(const css::uno::Sequence< SrcType > &i_Sequence)
bool IsAlpha() const
#define min(a, b)
Definition: dx_winstuff.hxx:49
double getWidth() const
COMReference< IDirect3DDevice9 > mpDevice
Definition: dx_9rm.cxx:169
struct _cairo_surface cairo_surface_t
virtual ::cairo::SurfaceSharedPtr getSurface() override
oslFileHandle & pOut
VclPtr< OutputDevice > mpVirtualDevice
css::uno::Reference< css::rendering::XCachedPrimitive > fillPolyPolygon(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
static cairo_pattern_t * patternFromParametricPolyPolygon(::canvas::ParametricPolyPolygon const &rPolygon)
B2IRange fround(const B2DRange &rRange)
sal_Int8 toByteColor(double val)
float y
Definition: dx_9rm.cxx:190
void drawBezier(const css::rendering::XCanvas *pCanvas, const css::geometry::RealBezierSegment2D &aBezierSegment, const css::geometry::RealPoint2D &aEndPoint, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
std::shared_ptr< Surface > SurfaceSharedPtr
const css::uno::Sequence< double > maStops
Gradient color stops.
uno::Sequence< sal_Int8 > maComponentTags
static void clipNULL(cairo_t *pCairo)
int i
uno_Any a
css::uno::Reference< css::rendering::XCachedPrimitive > strokePolyPolygon(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, const css::rendering::StrokeAttributes &strokeAttributes)
css::uno::Reference< css::rendering::XCachedPrimitive > drawBitmap(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XBitmap > &xBitmap, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
sal_Int32 getX() const
void doPolyPolygonImplementation(const ::basegfx::B2DPolyPolygon &aPolyPolygon, Operation aOperation, cairo_t *pCairo, const uno::Sequence< rendering::Texture > *pTextures, const SurfaceProviderRef &pDevice, rendering::FillRule eFillrule)
css::uno::Reference< css::rendering::XPolyPolygon2D > queryStrokeShapes(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, const css::rendering::StrokeAttributes &strokeAttributes)
css::uno::Reference< css::rendering::XCachedPrimitive > fillTextureMappedPolyPolygon(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, const css::uno::Sequence< css::rendering::Texture > &textures, const css::uno::Reference< css::geometry::XMapping2D > &xMapping)
#define ENSURE_ARG_OR_THROW2(c, m, ifc, arg)
::basegfx::B2DPolyPolygon b2DPolyPolygonFromXPolyPolygon2D(const uno::Reference< rendering::XPolyPolygon2D > &xPoly)
sal_Int32 w
def stop
std::shared_ptr< cairo_surface_t > CairoSurfaceSharedPtr
css::uno::Sequence< sal_Int8 > getData(css::rendering::IntegerBitmapLayout &bitmapLayout, const css::geometry::IntegerRectangle2D &rect)
css::uno::Reference< css::rendering::XCachedPrimitive > drawPolyPolygon(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
void useStates(const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, bool setColor)
struct _cairo cairo_t
bool IsTransparent() const
#define ENSURE_ARG_OR_THROW(c, m)
bool mbHaveAlpha
When true, content is able to represent alpha.
css::rendering::IntegerBitmapLayout getMemoryLayout()
static void doOperation(Operation aOperation, cairo_t *pCairo, const uno::Sequence< rendering::Texture > *pTextures, const SurfaceProviderRef &pDevice, const basegfx::B2DRange &rBounds)
::cairo::SurfaceSharedPtr mpSurface
Bitmap GetBitmap(Color aTransparentReplaceColor) const
virtual ::cairo::SurfaceSharedPtr changeSurface()=0
convert surface from alpha to non-alpha, does not copy content channel.
css::geometry::IntegerSize2D getSize() const
SurfaceProvider * mpSurfaceProvider
Surface provider.
#define ENSURE_OR_THROW(c, m)
sal_Int32 roundUp(const double &rVal)
Round given floating point value up to next integer.
virtual ::cairo::SurfaceSharedPtr getSurface()=0
Query surface from this provider.
void setSurface(const ::cairo::SurfaceSharedPtr &pSurface, bool bHasAlpha)
void init(const ::basegfx::B2ISize &rSizePixel, SurfaceProvider &rSurfaceProvider, css::rendering::XGraphicDevice *pDevice)
Initialize canvas helper.
double getMinY() const
double toDoubleColor(sal_uInt8 val)
cairo_t * mpCairo
css::uno::Reference< css::rendering::XCachedPrimitive > drawBitmapModulated(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XBitmap > &xBitmap, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
void doPolyPolygonPath(const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, Operation aOperation, bool bNoLineJoin=false, const css::uno::Sequence< css::rendering::Texture > *pTextures=nullptr) const
#define SAL_INFO(area, stream)
static SurfaceSharedPtr surfaceFromXBitmap(const uno::Reference< rendering::XBitmap > &xBitmap)
surfaceFromXBitmap Create a surface from XBitmap
#define PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME
sal_Int32 getY() const
B2DPoint getMinimum() const
ValueType lerp(const ValueType &rFrom, const ValueType &rTo, double t)
css::rendering::XGraphicDevice * mpDevice
Phyical output device.
double getLength(const B2DPolygon &rCandidate)
void drawLine(const css::rendering::XCanvas *pCanvas, const css::geometry::RealPoint2D &aStartPoint, const css::geometry::RealPoint2D &aEndPoint, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
static void setColor(cairo_t *pCairo, const uno::Sequence< double > &rColor)
uno::Sequence< sal_Int32 > maBitCounts
double getMinX() const
css::uno::Reference< css::rendering::XCachedPrimitive > fillTexturedPolyPolygon(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, const css::uno::Sequence< css::rendering::Texture > &textures)
Values getValues() const
Query all defining values of this object atomically.
bool repaint(const ::cairo::SurfaceSharedPtr &pSurface, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
css::uno::Reference< css::rendering::XBitmap > getScaledBitmap(const css::geometry::RealSize2D &newSize, bool beFast)
sal_Int32 h
COMReference< surface_type > mpSurface
css::uno::Reference< css::rendering::XCachedPrimitive > strokeTextureMappedPolyPolygon(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, const css::uno::Sequence< css::rendering::Texture > &textures, const css::uno::Reference< css::geometry::XMapping2D > &xMapping, const css::rendering::StrokeAttributes &strokeAttributes)
VclPtr< VirtualDevice > mpVirtualDevice
::basegfx::B2IVector maSize
Definition: dx_9rm.cxx:116