LCOV - code coverage report
Current view: top level - canvas/source/cairo - cairo_canvashelper.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 11 1071 1.0 %
Date: 2014-11-03 Functions: 4 102 3.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10