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

Generated by: LCOV version 1.10