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  return;
221 
222  cairo_save( mpCairo.get() );
223 
224  cairo_identity_matrix( mpCairo.get() );
225  // this does not really differ from all-zero, as cairo
226  // internally converts to premultiplied alpha. but anyway,
227  // this keeps it consistent with the other canvas impls
228  if( mbHaveAlpha )
229  cairo_set_source_rgba( mpCairo.get(), 1.0, 1.0, 1.0, 0.0 );
230  else
231  cairo_set_source_rgb( mpCairo.get(), 1.0, 1.0, 1.0 );
232  cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
233 
234  cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
235  cairo_fill( mpCairo.get() );
236 
237  cairo_restore( mpCairo.get() );
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  return;
248 
249  cairo_save( mpCairo.get() );
250 
251  cairo_set_line_width( mpCairo.get(), 1 );
252 
253  useStates( viewState, renderState, true );
254 
255  cairo_move_to( mpCairo.get(), aStartPoint.X + 0.5, aStartPoint.Y + 0.5 );
256  cairo_line_to( mpCairo.get(), aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
257  cairo_stroke( mpCairo.get() );
258 
259  cairo_restore( mpCairo.get() );
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  return;
270 
271  cairo_save( mpCairo.get() );
272 
273  cairo_set_line_width( mpCairo.get(), 1 );
274 
275  useStates( viewState, renderState, true );
276 
277  cairo_move_to( mpCairo.get(), aBezierSegment.Px + 0.5, aBezierSegment.Py + 0.5 );
278  // tdf#99165 correction of control points not needed here, only hairlines drawn
279  // (see cairo_set_line_width above)
280  cairo_curve_to( mpCairo.get(),
281  aBezierSegment.C1x + 0.5, aBezierSegment.C1y + 0.5,
282  aBezierSegment.C2x + 0.5, aBezierSegment.C2y + 0.5,
283  aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
284  cairo_stroke( mpCairo.get() );
285 
286  cairo_restore( mpCairo.get() );
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  tools::Long nWidth;
364  tools::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  int nPixelWidth = std::round(rSize.Width * aMatrix.xx);
1181  int nPixelHeight = std::round(rSize.Height * aMatrix.yy);
1182  if (std::abs(nPixelWidth) > 0 && std::abs(nPixelHeight) > 0)
1183  {
1184  // Only render the image if it's at least 1x1 px sized.
1185  if (bModulateColors)
1186  cairo_paint_with_alpha(mpCairo.get(), renderState.DeviceColor[3]);
1187  else
1188  {
1189  cairo_paint(mpCairo.get());
1190  if (cairo_status(mpCairo.get()) != CAIRO_STATUS_SUCCESS)
1191  {
1192  SAL_WARN("canvas.cairo", "cairo_paint() failed: " << cairo_status_to_string(
1193  cairo_status(mpCairo.get())));
1194  }
1195  }
1196  }
1197  cairo_restore( mpCairo.get() );
1198  }
1199  else
1200  SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1201 
1202  return rv; // uno::Reference< rendering::XCachedPrimitive >(NULL);
1203  }
1204 
1205  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* pCanvas,
1206  const uno::Reference< rendering::XBitmap >& xBitmap,
1207  const rendering::ViewState& viewState,
1208  const rendering::RenderState& renderState )
1209  {
1210 #ifdef CAIRO_CANVAS_PERF_TRACE
1211  struct timespec aTimer;
1212  mxDevice->startPerfTrace( &aTimer );
1213 #endif
1214 
1215  uno::Reference< rendering::XCachedPrimitive > rv;
1216  unsigned char* data = nullptr;
1217  bool bHasAlpha = false;
1218  SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
1219  geometry::IntegerSize2D aSize = xBitmap->getSize();
1220 
1221  if( pSurface )
1222  {
1223  rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, false, bHasAlpha );
1224 
1225  if( data )
1226  free( data );
1227  }
1228  else
1229  rv.set(nullptr);
1230 
1231 #ifdef CAIRO_CANVAS_PERF_TRACE
1232  mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1233 #endif
1234 
1235  return rv;
1236  }
1237 
1238  uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas,
1239  const uno::Reference< rendering::XBitmap >& xBitmap,
1240  const rendering::ViewState& viewState,
1241  const rendering::RenderState& renderState )
1242  {
1243 #ifdef CAIRO_CANVAS_PERF_TRACE
1244  struct timespec aTimer;
1245  mxDevice->startPerfTrace( &aTimer );
1246 #endif
1247 
1248  uno::Reference< rendering::XCachedPrimitive > rv;
1249  unsigned char* data = nullptr;
1250  bool bHasAlpha = false;
1251  SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
1252  geometry::IntegerSize2D aSize = xBitmap->getSize();
1253 
1254  if( pSurface )
1255  {
1256  rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, true, bHasAlpha );
1257 
1258  if( data )
1259  free( data );
1260  }
1261  else
1262  rv.set(nullptr);
1263 
1264 #ifdef CAIRO_CANVAS_PERF_TRACE
1265  mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
1266 #endif
1267 
1268  return rv;
1269  }
1270 
1271 
1272  geometry::IntegerSize2D CanvasHelper::getSize() const
1273  {
1274  if( !mpSurfaceProvider )
1275  return geometry::IntegerSize2D(1, 1); // we're disposed
1276 
1277  return ::basegfx::unotools::integerSize2DFromB2ISize( maSize );
1278  }
1279 
1280  uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D& newSize,
1281  bool /*beFast*/ )
1282  {
1283 #ifdef CAIRO_CANVAS_PERF_TRACE
1284  struct timespec aTimer;
1285  mxDevice->startPerfTrace( &aTimer );
1286 #endif
1287 
1288  if( mpCairo )
1289  {
1290  return uno::Reference< rendering::XBitmap >( new CanvasBitmap( ::basegfx::B2ISize( ::canvas::tools::roundUp( newSize.Width ),
1291  ::canvas::tools::roundUp( newSize.Height ) ),
1292  mpSurfaceProvider, mpDevice, false ) );
1293  }
1294  else
1295  SAL_INFO( "canvas.cairo", "CanvasHelper called after it was disposed");
1296 
1297 #ifdef CAIRO_CANVAS_PERF_TRACE
1298  mxDevice->stopPerfTrace( &aTimer, "getScaledBitmap" );
1299 #endif
1300 
1301  return uno::Reference< rendering::XBitmap >();
1302  }
1303 
1304  uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& aLayout,
1305  const geometry::IntegerRectangle2D& rect )
1306  {
1307  if( mpCairo )
1308  {
1309  const sal_Int32 nWidth( rect.X2 - rect.X1 );
1310  const sal_Int32 nHeight( rect.Y2 - rect.Y1 );
1311  const cairo_format_t eFormat( mbHaveAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24 );
1312  uno::Sequence< sal_Int8 > aRes( 4*nWidth*nHeight );
1313  sal_Int8* pData = aRes.getArray();
1314  cairo_surface_t* pImageSurface = cairo_image_surface_create_for_data( reinterpret_cast<unsigned char *>(pData),
1315  eFormat,
1316  nWidth, nHeight, 4*nWidth );
1317  cairo_t* pCairo = cairo_create( pImageSurface );
1318  cairo_set_source_surface( pCairo, mpSurface->getCairoSurface().get(), -rect.X1, -rect.Y1);
1319  cairo_paint( pCairo );
1320  cairo_destroy( pCairo );
1321  cairo_surface_destroy( pImageSurface );
1322 
1323  aLayout = impl_getMemoryLayout( nWidth, nHeight );
1324 
1325  return aRes;
1326  }
1327 
1328  return uno::Sequence< sal_Int8 >();
1329  }
1330 
1331  uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/,
1332  const geometry::IntegerPoint2D& /*pos*/ )
1333  {
1334  return uno::Sequence< sal_Int8 >();
1335  }
1336 
1337  namespace
1338  {
1339  class CairoColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace >
1340  {
1341  private:
1342  uno::Sequence< sal_Int8 > maComponentTags;
1343  uno::Sequence< sal_Int32 > maBitCounts;
1344 
1345  virtual ::sal_Int8 SAL_CALL getType( ) override
1346  {
1347  return rendering::ColorSpaceType::RGB;
1348  }
1349  virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override
1350  {
1351  return maComponentTags;
1352  }
1353  virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override
1354  {
1355  return rendering::RenderingIntent::PERCEPTUAL;
1356  }
1357  virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override
1358  {
1359  return uno::Sequence< beans::PropertyValue >();
1360  }
1361  virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
1362  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
1363  {
1364  // TODO(P3): if we know anything about target
1365  // colorspace, this can be greatly sped up
1366  uno::Sequence<rendering::ARGBColor> aIntermediate(
1367  convertToARGB(deviceColor));
1368  return targetColorSpace->convertFromARGB(aIntermediate);
1369  }
1370  virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override
1371  {
1372  const double* pIn( deviceColor.getConstArray() );
1373  const std::size_t nLen( deviceColor.getLength() );
1374  ENSURE_ARG_OR_THROW2(nLen%4==0,
1375  "number of channels no multiple of 4",
1376  static_cast<rendering::XColorSpace*>(this), 0);
1377 
1378  uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1379  rendering::RGBColor* pOut( aRes.getArray() );
1380  for( std::size_t i=0; i<nLen; i+=4 )
1381  {
1382  const double fAlpha(pIn[3]);
1383  if( fAlpha == 0.0 )
1384  *pOut++ = rendering::RGBColor(0.0, 0.0, 0.0);
1385  else
1386  *pOut++ = rendering::RGBColor(pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1387  pIn += 4;
1388  }
1389  return aRes;
1390  }
1391  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
1392  {
1393  const double* pIn( deviceColor.getConstArray() );
1394  const std::size_t nLen( deviceColor.getLength() );
1395  ENSURE_ARG_OR_THROW2(nLen%4==0,
1396  "number of channels no multiple of 4",
1397  static_cast<rendering::XColorSpace*>(this), 0);
1398 
1399  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1400  rendering::ARGBColor* pOut( aRes.getArray() );
1401  for( std::size_t i=0; i<nLen; i+=4 )
1402  {
1403  const double fAlpha(pIn[3]);
1404  if( fAlpha == 0.0 )
1405  *pOut++ = rendering::ARGBColor(0.0, 0.0, 0.0, 0.0);
1406  else
1407  *pOut++ = rendering::ARGBColor(fAlpha,pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha);
1408  pIn += 4;
1409  }
1410  return aRes;
1411  }
1412  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
1413  {
1414  const double* pIn( deviceColor.getConstArray() );
1415  const std::size_t nLen( deviceColor.getLength() );
1416  ENSURE_ARG_OR_THROW2(nLen%4==0,
1417  "number of channels no multiple of 4",
1418  static_cast<rendering::XColorSpace*>(this), 0);
1419 
1420  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1421  rendering::ARGBColor* pOut( aRes.getArray() );
1422  for( std::size_t i=0; i<nLen; i+=4 )
1423  {
1424  *pOut++ = rendering::ARGBColor(pIn[3],pIn[2],pIn[1],pIn[1]);
1425  pIn += 4;
1426  }
1427  return aRes;
1428  }
1429  virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
1430  {
1431  const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1432  const std::size_t nLen( rgbColor.getLength() );
1433 
1434  uno::Sequence< double > aRes(nLen*4);
1435  double* pColors=aRes.getArray();
1436  for( std::size_t i=0; i<nLen; ++i )
1437  {
1438  *pColors++ = pIn->Blue;
1439  *pColors++ = pIn->Green;
1440  *pColors++ = pIn->Red;
1441  *pColors++ = 1.0;
1442  ++pIn;
1443  }
1444  return aRes;
1445  }
1446  virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1447  {
1448  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1449  const std::size_t nLen( rgbColor.getLength() );
1450 
1451  uno::Sequence< double > aRes(nLen*4);
1452  double* pColors=aRes.getArray();
1453  for( std::size_t i=0; i<nLen; ++i )
1454  {
1455  *pColors++ = pIn->Alpha*pIn->Blue;
1456  *pColors++ = pIn->Alpha*pIn->Green;
1457  *pColors++ = pIn->Alpha*pIn->Red;
1458  *pColors++ = pIn->Alpha;
1459  ++pIn;
1460  }
1461  return aRes;
1462  }
1463  virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1464  {
1465  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1466  const std::size_t nLen( rgbColor.getLength() );
1467 
1468  uno::Sequence< double > aRes(nLen*4);
1469  double* pColors=aRes.getArray();
1470  for( std::size_t i=0; i<nLen; ++i )
1471  {
1472  *pColors++ = pIn->Blue;
1473  *pColors++ = pIn->Green;
1474  *pColors++ = pIn->Red;
1475  *pColors++ = pIn->Alpha;
1476  ++pIn;
1477  }
1478  return aRes;
1479  }
1480 
1481  // XIntegerBitmapColorSpace
1482  virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override
1483  {
1484  return 32;
1485  }
1486  virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override
1487  {
1488  return maBitCounts;
1489  }
1490  virtual ::sal_Int8 SAL_CALL getEndianness( ) override
1491  {
1492  return util::Endianness::LITTLE;
1493  }
1494  virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1495  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
1496  {
1497  if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1498  {
1499  const sal_Int8* pIn( deviceColor.getConstArray() );
1500  const std::size_t nLen( deviceColor.getLength() );
1501  ENSURE_ARG_OR_THROW2(nLen%4==0,
1502  "number of channels no multiple of 4",
1503  static_cast<rendering::XColorSpace*>(this), 0);
1504 
1505  uno::Sequence<double> aRes(nLen);
1506  double* pOut( aRes.getArray() );
1507  for( std::size_t i=0; i<nLen; i+=4 )
1508  {
1509  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1510  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1511  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1512  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1513  }
1514  return aRes;
1515  }
1516  else
1517  {
1518  // TODO(P3): if we know anything about target
1519  // colorspace, this can be greatly sped up
1520  uno::Sequence<rendering::ARGBColor> aIntermediate(
1521  convertIntegerToARGB(deviceColor));
1522  return targetColorSpace->convertFromARGB(aIntermediate);
1523  }
1524  }
1525  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1526  const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override
1527  {
1528  if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1529  {
1530  // it's us, so simply pass-through the data
1531  return deviceColor;
1532  }
1533  else
1534  {
1535  // TODO(P3): if we know anything about target
1536  // colorspace, this can be greatly sped up
1537  uno::Sequence<rendering::ARGBColor> aIntermediate(
1538  convertIntegerToARGB(deviceColor));
1539  return targetColorSpace->convertIntegerFromARGB(aIntermediate);
1540  }
1541  }
1542  virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1543  {
1544  const sal_Int8* pIn( deviceColor.getConstArray() );
1545  const std::size_t nLen( deviceColor.getLength() );
1546  ENSURE_ARG_OR_THROW2(nLen%4==0,
1547  "number of channels no multiple of 4",
1548  static_cast<rendering::XColorSpace*>(this), 0);
1549 
1550  uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1551  rendering::RGBColor* pOut( aRes.getArray() );
1552  for( std::size_t i=0; i<nLen; i+=4 )
1553  {
1554  const double fAlpha(static_cast<sal_uInt8>(pIn[3]));
1555  if( fAlpha )
1556  *pOut++ = rendering::RGBColor(
1557  pIn[2]/fAlpha,
1558  pIn[1]/fAlpha,
1559  pIn[0]/fAlpha);
1560  else
1561  *pOut++ = rendering::RGBColor(0,0,0);
1562  pIn += 4;
1563  }
1564  return aRes;
1565  }
1566 
1567  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1568  {
1569  const sal_Int8* pIn( deviceColor.getConstArray() );
1570  const std::size_t nLen( deviceColor.getLength() );
1571  ENSURE_ARG_OR_THROW2(nLen%4==0,
1572  "number of channels no multiple of 4",
1573  static_cast<rendering::XColorSpace*>(this), 0);
1574 
1575  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1576  rendering::ARGBColor* pOut( aRes.getArray() );
1577  for( std::size_t i=0; i<nLen; i+=4 )
1578  {
1579  const double fAlpha(static_cast<sal_uInt8>(pIn[3]));
1580  if( fAlpha )
1581  *pOut++ = rendering::ARGBColor(
1582  fAlpha/255.0,
1583  pIn[2]/fAlpha,
1584  pIn[1]/fAlpha,
1585  pIn[0]/fAlpha);
1586  else
1587  *pOut++ = rendering::ARGBColor(0,0,0,0);
1588  pIn += 4;
1589  }
1590  return aRes;
1591  }
1592  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1593  {
1594  const sal_Int8* pIn( deviceColor.getConstArray() );
1595  const std::size_t nLen( deviceColor.getLength() );
1596  ENSURE_ARG_OR_THROW2(nLen%4==0,
1597  "number of channels no multiple of 4",
1598  static_cast<rendering::XColorSpace*>(this), 0);
1599 
1600  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1601  rendering::ARGBColor* pOut( aRes.getArray() );
1602  for( std::size_t i=0; i<nLen; i+=4 )
1603  {
1604  *pOut++ = rendering::ARGBColor(
1609  pIn += 4;
1610  }
1611  return aRes;
1612  }
1613 
1614  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
1615  {
1616  const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1617  const std::size_t nLen( rgbColor.getLength() );
1618 
1619  uno::Sequence< sal_Int8 > aRes(nLen*4);
1620  sal_Int8* pColors=aRes.getArray();
1621  for( std::size_t i=0; i<nLen; ++i )
1622  {
1623  *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1624  *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1625  *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1626  *pColors++ = -1;
1627  ++pIn;
1628  }
1629  return aRes;
1630  }
1631 
1632  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1633  {
1634  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1635  const std::size_t nLen( rgbColor.getLength() );
1636 
1637  uno::Sequence< sal_Int8 > aRes(nLen*4);
1638  sal_Int8* pColors=aRes.getArray();
1639  for( std::size_t i=0; i<nLen; ++i )
1640  {
1641  const double fAlpha(pIn->Alpha);
1642  *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Blue);
1643  *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Green);
1644  *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Red);
1645  *pColors++ = vcl::unotools::toByteColor(fAlpha);
1646  ++pIn;
1647  }
1648  return aRes;
1649  }
1650  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1651  {
1652  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1653  const std::size_t nLen( rgbColor.getLength() );
1654 
1655  uno::Sequence< sal_Int8 > aRes(nLen*4);
1656  sal_Int8* pColors=aRes.getArray();
1657  for( std::size_t i=0; i<nLen; ++i )
1658  {
1659  *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1660  *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1661  *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1662  *pColors++ = vcl::unotools::toByteColor(pIn->Alpha);
1663  ++pIn;
1664  }
1665  return aRes;
1666  }
1667 
1668  public:
1669  CairoColorSpace() :
1670  maComponentTags(4),
1671  maBitCounts(4)
1672  {
1673  sal_Int8* pTags = maComponentTags.getArray();
1674  sal_Int32* pBitCounts = maBitCounts.getArray();
1675  pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
1676  pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
1677  pTags[2] = rendering::ColorComponentTag::RGB_RED;
1678  pTags[3] = rendering::ColorComponentTag::PREMULTIPLIED_ALPHA;
1679 
1680  pBitCounts[0] =
1681  pBitCounts[1] =
1682  pBitCounts[2] =
1683  pBitCounts[3] = 8;
1684  }
1685  };
1686 
1687  class CairoNoAlphaColorSpace : public cppu::WeakImplHelper< css::rendering::XIntegerBitmapColorSpace >
1688  {
1689  private:
1690  uno::Sequence< sal_Int8 > maComponentTags;
1691  uno::Sequence< sal_Int32 > maBitCounts;
1692 
1693  virtual ::sal_Int8 SAL_CALL getType( ) override
1694  {
1695  return rendering::ColorSpaceType::RGB;
1696  }
1697  virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override
1698  {
1699  return maComponentTags;
1700  }
1701  virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override
1702  {
1703  return rendering::RenderingIntent::PERCEPTUAL;
1704  }
1705  virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override
1706  {
1707  return uno::Sequence< beans::PropertyValue >();
1708  }
1709  virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
1710  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
1711  {
1712  // TODO(P3): if we know anything about target
1713  // colorspace, this can be greatly sped up
1714  uno::Sequence<rendering::ARGBColor> aIntermediate(
1715  convertToARGB(deviceColor));
1716  return targetColorSpace->convertFromARGB(aIntermediate);
1717  }
1718  virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override
1719  {
1720  const double* pIn( deviceColor.getConstArray() );
1721  const std::size_t nLen( deviceColor.getLength() );
1722  ENSURE_ARG_OR_THROW2(nLen%4==0,
1723  "number of channels no multiple of 4",
1724  static_cast<rendering::XColorSpace*>(this), 0);
1725 
1726  uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1727  rendering::RGBColor* pOut( aRes.getArray() );
1728  for( std::size_t i=0; i<nLen; i+=4 )
1729  {
1730  *pOut++ = rendering::RGBColor(pIn[2], pIn[1], pIn[0]);
1731  pIn += 4;
1732  }
1733  return aRes;
1734  }
1735  uno::Sequence< rendering::ARGBColor > impl_convertToARGB( const uno::Sequence< double >& deviceColor )
1736  {
1737  const double* pIn( deviceColor.getConstArray() );
1738  const std::size_t nLen( deviceColor.getLength() );
1739  ENSURE_ARG_OR_THROW2(nLen%4==0,
1740  "number of channels no multiple of 4",
1741  static_cast<rendering::XColorSpace*>(this), 0);
1742 
1743  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1744  rendering::ARGBColor* pOut( aRes.getArray() );
1745  for( std::size_t i=0; i<nLen; i+=4 )
1746  {
1747  *pOut++ = rendering::ARGBColor(1.0, pIn[2], pIn[1], pIn[0]);
1748  pIn += 4;
1749  }
1750  return aRes;
1751  }
1752  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override
1753  {
1754  return impl_convertToARGB( deviceColor );
1755  }
1756  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override
1757  {
1758  return impl_convertToARGB( deviceColor );
1759  }
1760  virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
1761  {
1762  const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1763  const std::size_t nLen( rgbColor.getLength() );
1764 
1765  uno::Sequence< double > aRes(nLen*4);
1766  double* pColors=aRes.getArray();
1767  for( std::size_t i=0; i<nLen; ++i )
1768  {
1769  *pColors++ = pIn->Blue;
1770  *pColors++ = pIn->Green;
1771  *pColors++ = pIn->Red;
1772  *pColors++ = 1.0; // the value does not matter
1773  ++pIn;
1774  }
1775  return aRes;
1776  }
1777  uno::Sequence< double > impl_convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
1778  {
1779  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1780  const std::size_t nLen( rgbColor.getLength() );
1781 
1782  uno::Sequence< double > aRes(nLen*4);
1783  double* pColors=aRes.getArray();
1784  for( std::size_t i=0; i<nLen; ++i )
1785  {
1786  *pColors++ = pIn->Blue;
1787  *pColors++ = pIn->Green;
1788  *pColors++ = pIn->Red;
1789  *pColors++ = 1.0; // the value does not matter
1790  ++pIn;
1791  }
1792  return aRes;
1793  }
1794  virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1795  {
1796  return impl_convertFromARGB( rgbColor );
1797  }
1798  virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1799  {
1800  return impl_convertFromARGB( rgbColor );
1801  }
1802 
1803  // XIntegerBitmapColorSpace
1804  virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override
1805  {
1806  return 32;
1807  }
1808  virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override
1809  {
1810  return maBitCounts;
1811  }
1812  virtual ::sal_Int8 SAL_CALL getEndianness( ) override
1813  {
1814  return util::Endianness::LITTLE;
1815  }
1816  virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1817  const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override
1818  {
1819  if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) )
1820  {
1821  const sal_Int8* pIn( deviceColor.getConstArray() );
1822  const std::size_t nLen( deviceColor.getLength() );
1823  ENSURE_ARG_OR_THROW2(nLen%4==0,
1824  "number of channels no multiple of 4",
1825  static_cast<rendering::XColorSpace*>(this), 0);
1826 
1827  uno::Sequence<double> aRes(nLen);
1828  double* pOut( aRes.getArray() );
1829  for( std::size_t i=0; i<nLen; i+=4 )
1830  {
1831  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1832  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1833  *pOut++ = vcl::unotools::toDoubleColor(*pIn++);
1834  *pOut++ = 1.0; pIn++; // the value does not matter
1835  }
1836  return aRes;
1837  }
1838  else
1839  {
1840  // TODO(P3): if we know anything about target
1841  // colorspace, this can be greatly sped up
1842  uno::Sequence<rendering::ARGBColor> aIntermediate(
1843  convertIntegerToARGB(deviceColor));
1844  return targetColorSpace->convertFromARGB(aIntermediate);
1845  }
1846  }
1847  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor,
1848  const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override
1849  {
1850  if( dynamic_cast<CairoNoAlphaColorSpace*>(targetColorSpace.get()) )
1851  {
1852  // it's us, so simply pass-through the data
1853  return deviceColor;
1854  }
1855  else
1856  {
1857  // TODO(P3): if we know anything about target
1858  // colorspace, this can be greatly sped up
1859  uno::Sequence<rendering::ARGBColor> aIntermediate(
1860  convertIntegerToARGB(deviceColor));
1861  return targetColorSpace->convertIntegerFromARGB(aIntermediate);
1862  }
1863  }
1864  virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1865  {
1866  const sal_Int8* pIn( deviceColor.getConstArray() );
1867  const std::size_t nLen( deviceColor.getLength() );
1868  ENSURE_ARG_OR_THROW2(nLen%4==0,
1869  "number of channels no multiple of 4",
1870  static_cast<rendering::XColorSpace*>(this), 0);
1871 
1872  uno::Sequence< rendering::RGBColor > aRes(nLen/4);
1873  rendering::RGBColor* pOut( aRes.getArray() );
1874  for( std::size_t i=0; i<nLen; i+=4 )
1875  {
1876  *pOut++ = rendering::RGBColor( pIn[2], pIn[1], pIn[0] );
1877  pIn += 4;
1878  }
1879  return aRes;
1880  }
1881 
1882  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1883  {
1884  return impl_convertIntegerToARGB( deviceColor );
1885  }
1886  virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override
1887  {
1888  return impl_convertIntegerToARGB( deviceColor );
1889  }
1890  uno::Sequence< rendering::ARGBColor > impl_convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor )
1891  {
1892  const sal_Int8* pIn( deviceColor.getConstArray() );
1893  const std::size_t nLen( deviceColor.getLength() );
1894  ENSURE_ARG_OR_THROW2(nLen%4==0,
1895  "number of channels no multiple of 4",
1896  static_cast<rendering::XColorSpace*>(this), 0);
1897 
1898  uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
1899  rendering::ARGBColor* pOut( aRes.getArray() );
1900  for( std::size_t i=0; i<nLen; i+=4 )
1901  {
1902  *pOut++ = rendering::ARGBColor(
1903  1.0,
1907  pIn += 4;
1908  }
1909  return aRes;
1910  }
1911 
1912  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override
1913  {
1914  const rendering::RGBColor* pIn( rgbColor.getConstArray() );
1915  const std::size_t nLen( rgbColor.getLength() );
1916 
1917  uno::Sequence< sal_Int8 > aRes(nLen*4);
1918  sal_Int8* pColors=aRes.getArray();
1919  for( std::size_t i=0; i<nLen; ++i )
1920  {
1921  *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1922  *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1923  *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1924  *pColors++ = -1; // the value does not matter
1925  ++pIn;
1926  }
1927  return aRes;
1928  }
1929 
1930  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1931  {
1932  return impl_convertIntegerFromARGB( rgbColor );
1933  }
1934  virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override
1935  {
1936  return impl_convertIntegerFromARGB( rgbColor );
1937  }
1938  uno::Sequence< ::sal_Int8 > impl_convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor )
1939  {
1940  const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
1941  const std::size_t nLen( rgbColor.getLength() );
1942 
1943  uno::Sequence< sal_Int8 > aRes(nLen*4);
1944  sal_Int8* pColors=aRes.getArray();
1945  for( std::size_t i=0; i<nLen; ++i )
1946  {
1947  *pColors++ = vcl::unotools::toByteColor(pIn->Blue);
1948  *pColors++ = vcl::unotools::toByteColor(pIn->Green);
1949  *pColors++ = vcl::unotools::toByteColor(pIn->Red);
1950  *pColors++ = -1; // the value does not matter
1951  ++pIn;
1952  }
1953  return aRes;
1954  }
1955 
1956  public:
1957  CairoNoAlphaColorSpace() :
1958  maComponentTags(3),
1959  maBitCounts(3)
1960  {
1961  sal_Int8* pTags = maComponentTags.getArray();
1962  sal_Int32* pBitCounts = maBitCounts.getArray();
1963  pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
1964  pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
1965  pTags[2] = rendering::ColorComponentTag::RGB_RED;
1966 
1967  pBitCounts[0] =
1968  pBitCounts[1] =
1969  pBitCounts[2] = 8;
1970  }
1971  };
1972 
1973  struct CairoNoAlphaColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
1974  CairoNoAlphaColorSpaceHolder>
1975  {
1976  uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
1977  {
1978  return new CairoNoAlphaColorSpace();
1979  }
1980  };
1981 
1982  struct CairoColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>,
1983  CairoColorSpaceHolder>
1984  {
1985  uno::Reference<rendering::XIntegerBitmapColorSpace> operator()()
1986  {
1987  return new CairoColorSpace();
1988  }
1989  };
1990 
1991  }
1992 
1993  rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout()
1994  {
1995  if( !mpCairo )
1996  return rendering::IntegerBitmapLayout(); // we're disposed
1997 
1998  const geometry::IntegerSize2D aSize(getSize());
1999 
2000  return impl_getMemoryLayout( aSize.Width, aSize.Height );
2001  }
2002 
2003  rendering::IntegerBitmapLayout
2004  CanvasHelper::impl_getMemoryLayout( const sal_Int32 nWidth, const sal_Int32 nHeight )
2005  {
2006  rendering::IntegerBitmapLayout aLayout;
2007 
2008  aLayout.ScanLines = nHeight;
2009  aLayout.ScanLineBytes = nWidth*4;
2010  aLayout.ScanLineStride = aLayout.ScanLineBytes;
2011  aLayout.PlaneStride = 0;
2012  aLayout.ColorSpace = mbHaveAlpha ? CairoColorSpaceHolder::get() : CairoNoAlphaColorSpaceHolder::get();
2013  aLayout.Palette.clear();
2014  aLayout.IsMsbFirst = false;
2015 
2016  return aLayout;
2017  }
2018 
2019 
2020  bool CanvasHelper::repaint( const SurfaceSharedPtr& pSurface,
2021  const rendering::ViewState& viewState,
2022  const rendering::RenderState& renderState )
2023  {
2024  SAL_INFO( "canvas.cairo", "CanvasHelper::repaint");
2025 
2026  if( mpCairo )
2027  {
2028  cairo_save( mpCairo.get() );
2029 
2030  cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() );
2031  cairo_clip( mpCairo.get() );
2032 
2033  useStates( viewState, renderState, true );
2034 
2035  cairo_matrix_t aMatrix;
2036 
2037  cairo_get_matrix( mpCairo.get(), &aMatrix );
2038  aMatrix.xx = aMatrix.yy = 1;
2039  cairo_set_matrix( mpCairo.get(), &aMatrix );
2040 
2041  cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
2042  cairo_paint( mpCairo.get() );
2043  cairo_restore( mpCairo.get() );
2044  }
2045 
2046  return true;
2047  }
2048 }
2049 
2050 /* 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)
long Long
double getX() const
void setSize(const ::basegfx::B2ISize &rSize)
#define max(a, b)
Definition: dx_winstuff.hxx:45
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 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:48
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)
void CanvasCairoExtractBitmapData(BitmapEx const &rBmpEx, Bitmap &rBitmap, unsigned char *&data, bool &bHasAlpha, tools::Long &rnWidth, tools::Long &rnHeight)
#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()
exports com.sun.star.chart2. data
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)
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
#define SAL_WARN(area, stream)
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