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

Generated by: LCOV version 1.11