2006-02-28 09:34:46 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
|
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
|
|
*
|
|
|
|
* $RCSfile: cairo_canvashelper.cxx,v $
|
|
|
|
*
|
2007-11-01 13:39:47 +00:00
|
|
|
* $Revision: 1.10 $
|
2006-02-28 09:34:46 +00:00
|
|
|
*
|
2007-11-01 13:39:47 +00:00
|
|
|
* last change: $Author: hr $ $Date: 2007-11-01 14:39:47 $
|
2006-02-28 09:34:46 +00:00
|
|
|
*
|
|
|
|
* The Contents of this file are made available subject to
|
|
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* GNU Lesser General Public License Version 2.1
|
|
|
|
* =============================================
|
|
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
|
* MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2006-09-17 02:19:05 +00:00
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
|
|
#include "precompiled_canvas.hxx"
|
|
|
|
|
2006-02-28 09:34:46 +00:00
|
|
|
#include <canvas/debug.hxx>
|
|
|
|
|
|
|
|
#include <rtl/logfile.hxx>
|
|
|
|
#include <rtl/math.hxx>
|
|
|
|
|
|
|
|
#include <com/sun/star/lang/XUnoTunnel.hpp>
|
|
|
|
|
|
|
|
#include <com/sun/star/rendering/IntegerBitmapFormat.hpp>
|
|
|
|
#include <com/sun/star/rendering/Endianness.hpp>
|
|
|
|
#include <com/sun/star/rendering/TexturingMode.hpp>
|
|
|
|
#include <com/sun/star/rendering/CompositeOperation.hpp>
|
|
|
|
#include <com/sun/star/rendering/RepaintResult.hpp>
|
|
|
|
#include <com/sun/star/rendering/PathCapType.hpp>
|
|
|
|
#include <com/sun/star/rendering/PathJoinType.hpp>
|
|
|
|
|
|
|
|
#include <basegfx/matrix/b2dhommatrix.hxx>
|
|
|
|
#include <basegfx/point/b2dpoint.hxx>
|
|
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
|
|
#include <basegfx/polygon/b2dpolypolygon.hxx>
|
|
|
|
#include <basegfx/tools/canvastools.hxx>
|
|
|
|
|
|
|
|
#include <comphelper/sequence.hxx>
|
|
|
|
|
|
|
|
#include <canvas/canvastools.hxx>
|
|
|
|
#include <canvas/parametricpolypolygon.hxx>
|
|
|
|
|
|
|
|
#include <vcl/canvastools.hxx>
|
|
|
|
#include <vcl/bitmapex.hxx>
|
|
|
|
#include <vcl/bmpacc.hxx>
|
|
|
|
#include <vcl/virdev.hxx>
|
|
|
|
|
|
|
|
#include "cairo_spritecanvas.hxx"
|
|
|
|
#include "cairo_cachedbitmap.hxx"
|
|
|
|
#include "cairo_canvashelper.hxx"
|
|
|
|
#include "cairo_canvasbitmap.hxx"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
using namespace ::cairo;
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
|
|
|
|
namespace cairocanvas
|
|
|
|
{
|
|
|
|
CanvasHelper::CanvasHelper() :
|
|
|
|
mpDevice( NULL ),
|
2007-07-17 13:20:31 +00:00
|
|
|
mpVirtualDevice( NULL ),
|
2006-02-28 09:34:46 +00:00
|
|
|
mbHaveAlpha(),
|
|
|
|
mpCairo( NULL ),
|
|
|
|
mpSurface( NULL ),
|
2007-07-17 13:20:31 +00:00
|
|
|
mpSurfaceProvider( NULL )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CanvasHelper::disposing()
|
|
|
|
{
|
|
|
|
mpDevice = NULL;
|
|
|
|
|
|
|
|
if( mpVirtualDevice ) {
|
|
|
|
delete mpVirtualDevice;
|
|
|
|
mpVirtualDevice = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( mpCairo )
|
|
|
|
{
|
|
|
|
cairo_destroy( mpCairo );
|
|
|
|
mpCairo = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( mpSurface ) {
|
|
|
|
mpSurface->Unref();
|
|
|
|
mpSurface = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
void CanvasHelper::init( const ::basegfx::B2ISize& /*rSize*/,
|
2006-02-28 09:34:46 +00:00
|
|
|
SpriteCanvas& rDevice )
|
|
|
|
{
|
|
|
|
mpDevice = &rDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CanvasHelper::setSurface( Surface* pSurface, bool bHasAlpha, SurfaceProvider* pSurfaceProvider )
|
|
|
|
{
|
|
|
|
mbHaveAlpha = bHasAlpha;
|
|
|
|
mpSurfaceProvider = pSurfaceProvider;
|
|
|
|
|
|
|
|
if( mpSurface ) {
|
|
|
|
mpSurface->Unref();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( mpVirtualDevice ) {
|
|
|
|
delete mpVirtualDevice;
|
|
|
|
mpVirtualDevice = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
mpSurface = pSurface;
|
|
|
|
mpSurface->Ref();
|
|
|
|
|
|
|
|
if( mpCairo )
|
|
|
|
{
|
|
|
|
cairo_destroy( mpCairo );
|
|
|
|
}
|
|
|
|
|
|
|
|
mpCairo = pSurface->getCairo();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CanvasHelper::useStates( const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState,
|
|
|
|
bool setColor )
|
|
|
|
{
|
|
|
|
Matrix aViewMatrix;
|
|
|
|
Matrix aRenderMatrix;
|
|
|
|
Matrix aCombinedMatrix;
|
|
|
|
|
|
|
|
cairo_matrix_init( &aViewMatrix,
|
|
|
|
viewState.AffineTransform.m00, viewState.AffineTransform.m10, viewState.AffineTransform.m01,
|
|
|
|
viewState.AffineTransform.m11, viewState.AffineTransform.m02, viewState.AffineTransform.m12);
|
|
|
|
cairo_matrix_init( &aRenderMatrix,
|
|
|
|
renderState.AffineTransform.m00, renderState.AffineTransform.m10, renderState.AffineTransform.m01,
|
|
|
|
renderState.AffineTransform.m11, renderState.AffineTransform.m02, renderState.AffineTransform.m12);
|
|
|
|
cairo_matrix_multiply( &aCombinedMatrix, &aRenderMatrix, &aViewMatrix);
|
|
|
|
|
|
|
|
if( viewState.Clip.is() ) {
|
|
|
|
OSL_TRACE ("view clip\n");
|
|
|
|
|
|
|
|
aViewMatrix.x0 = round( aViewMatrix.x0 );
|
|
|
|
aViewMatrix.y0 = round( aViewMatrix.y0 );
|
|
|
|
cairo_set_matrix( mpCairo, &aViewMatrix );
|
2006-11-01 13:45:42 +00:00
|
|
|
doPolyPolygonPath( viewState.Clip, Clip );
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
aCombinedMatrix.x0 = round( aCombinedMatrix.x0 );
|
|
|
|
aCombinedMatrix.y0 = round( aCombinedMatrix.y0 );
|
|
|
|
cairo_set_matrix( mpCairo, &aCombinedMatrix );
|
|
|
|
|
|
|
|
if( renderState.Clip.is() ) {
|
|
|
|
OSL_TRACE ("render clip BEGIN\n");
|
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
doPolyPolygonPath( renderState.Clip, Clip );
|
2006-02-28 09:34:46 +00:00
|
|
|
OSL_TRACE ("render clip END\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if( setColor ) {
|
|
|
|
if( renderState.DeviceColor.getLength() > 3 )
|
|
|
|
cairo_set_source_rgba( mpCairo,
|
|
|
|
renderState.DeviceColor [0],
|
|
|
|
renderState.DeviceColor [1],
|
|
|
|
renderState.DeviceColor [2],
|
|
|
|
renderState.DeviceColor [3] );
|
|
|
|
else if (renderState.DeviceColor.getLength() == 3)
|
|
|
|
cairo_set_source_rgb( mpCairo,
|
|
|
|
renderState.DeviceColor [0],
|
|
|
|
renderState.DeviceColor [1],
|
|
|
|
renderState.DeviceColor [2] );
|
|
|
|
}
|
2007-07-17 13:20:31 +00:00
|
|
|
|
|
|
|
cairo_operator_t compositingMode( CAIRO_OPERATOR_OVER );
|
|
|
|
switch( renderState.CompositeOperation )
|
|
|
|
{
|
|
|
|
case rendering::CompositeOperation::CLEAR:
|
|
|
|
compositingMode = CAIRO_OPERATOR_CLEAR;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::SOURCE:
|
|
|
|
compositingMode = CAIRO_OPERATOR_SOURCE;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::DESTINATION:
|
|
|
|
compositingMode = CAIRO_OPERATOR_DEST;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::OVER:
|
|
|
|
compositingMode = CAIRO_OPERATOR_OVER;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::UNDER:
|
|
|
|
compositingMode = CAIRO_OPERATOR_DEST;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::INSIDE:
|
|
|
|
compositingMode = CAIRO_OPERATOR_IN;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::INSIDE_REVERSE:
|
|
|
|
compositingMode = CAIRO_OPERATOR_OUT;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::OUTSIDE:
|
|
|
|
compositingMode = CAIRO_OPERATOR_DEST_OVER;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::OUTSIDE_REVERSE:
|
|
|
|
compositingMode = CAIRO_OPERATOR_DEST_OUT;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::ATOP:
|
|
|
|
compositingMode = CAIRO_OPERATOR_ATOP;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::ATOP_REVERSE:
|
|
|
|
compositingMode = CAIRO_OPERATOR_DEST_ATOP;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::XOR:
|
|
|
|
compositingMode = CAIRO_OPERATOR_XOR;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::ADD:
|
|
|
|
compositingMode = CAIRO_OPERATOR_ADD;
|
|
|
|
break;
|
|
|
|
case rendering::CompositeOperation::SATURATE:
|
|
|
|
compositingMode = CAIRO_OPERATOR_SATURATE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cairo_set_operator( mpCairo, compositingMode );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void CanvasHelper::clear()
|
|
|
|
{
|
|
|
|
if( mpCairo )
|
|
|
|
{
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
cairo_identity_matrix( mpCairo );
|
|
|
|
cairo_set_operator( mpCairo, CAIRO_OPERATOR_SOURCE );
|
|
|
|
cairo_set_source_rgba( mpCairo, 0, 0, 0, 0 );
|
|
|
|
|
|
|
|
const ::basegfx::B2ISize& rSize( mpDevice->getSizePixel() );
|
|
|
|
cairo_rectangle( mpCairo, 0, 0, rSize.getX(), rSize.getY() );
|
|
|
|
cairo_fill( mpCairo );
|
|
|
|
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
}
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
void CanvasHelper::drawPoint( const rendering::XCanvas* ,
|
|
|
|
const geometry::RealPoint2D& ,
|
|
|
|
const rendering::ViewState& ,
|
|
|
|
const rendering::RenderState& )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
void CanvasHelper::drawLine( const rendering::XCanvas* /*pCanvas*/,
|
2006-02-28 09:34:46 +00:00
|
|
|
const geometry::RealPoint2D& aStartPoint,
|
|
|
|
const geometry::RealPoint2D& aEndPoint,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState )
|
|
|
|
{
|
|
|
|
if( mpCairo ) {
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
cairo_set_line_width( mpCairo, 1 );
|
|
|
|
|
|
|
|
useStates( viewState, renderState, true );
|
|
|
|
|
|
|
|
cairo_move_to( mpCairo, aStartPoint.X + 0.5, aStartPoint.Y + 0.5 );
|
|
|
|
cairo_line_to( mpCairo, aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
|
|
|
|
cairo_stroke( mpCairo );
|
|
|
|
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
void CanvasHelper::drawBezier( const rendering::XCanvas* ,
|
2006-02-28 09:34:46 +00:00
|
|
|
const geometry::RealBezierSegment2D& aBezierSegment,
|
|
|
|
const geometry::RealPoint2D& aEndPoint,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState )
|
|
|
|
{
|
2007-07-17 13:20:31 +00:00
|
|
|
if( mpCairo ) {
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
cairo_set_line_width( mpCairo, 1 );
|
|
|
|
|
|
|
|
useStates( viewState, renderState, true );
|
|
|
|
|
|
|
|
cairo_move_to( mpCairo, aBezierSegment.Px + 0.5, aBezierSegment.Py + 0.5 );
|
|
|
|
cairo_curve_to( mpCairo,
|
|
|
|
aBezierSegment.C1x + 0.5, aBezierSegment.C1y + 0.5,
|
|
|
|
aBezierSegment.C2x + 0.5, aBezierSegment.C2y + 0.5,
|
|
|
|
aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
|
|
|
|
cairo_stroke( mpCairo );
|
|
|
|
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
}
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define CANVASBITMAP_IMPLEMENTATION_NAME "CairoCanvas::CanvasBitmap"
|
|
|
|
#define PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME "Canvas::ParametricPolyPolygon"
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
|
|
|
|
/** surfaceFromXBitmap Create a surface from XBitmap
|
|
|
|
* @param xBitmap bitmap image that will be used for the surface
|
|
|
|
* @param bHasAlpha will be set to true if resulting surface has alpha
|
|
|
|
*
|
|
|
|
* This is a helper function for the other surfaceFromXBitmap().
|
|
|
|
* This function tries to create surface from xBitmap by checking if xBitmap is CanvasBitmap or SpriteCanvas.
|
|
|
|
*
|
|
|
|
* @return created surface or NULL
|
|
|
|
**/
|
2006-02-28 09:34:46 +00:00
|
|
|
static Surface* surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, bool &bHasAlpha )
|
|
|
|
{
|
|
|
|
CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() );
|
|
|
|
|
|
|
|
if( pBitmapImpl ) {
|
|
|
|
// TODO(Q1): Maybe use dynamic_cast here
|
|
|
|
bHasAlpha = pBitmapImpl->hasAlpha();
|
|
|
|
|
|
|
|
return pBitmapImpl->getSurface();
|
|
|
|
}
|
|
|
|
|
2006-12-13 13:39:19 +00:00
|
|
|
|
|
|
|
SpriteCanvas* pCanvasImpl = dynamic_cast< SpriteCanvas* >( xBitmap.get() );
|
|
|
|
if( pCanvasImpl && pCanvasImpl->getBufferSurface () )
|
|
|
|
{
|
|
|
|
bHasAlpha = false;
|
|
|
|
|
|
|
|
return pCanvasImpl->getBackgroundSurface();
|
|
|
|
}
|
|
|
|
|
2006-02-28 09:34:46 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap )
|
|
|
|
{
|
|
|
|
uno::Reference< lang::XUnoTunnel > xTunnel( xBitmap, uno::UNO_QUERY );
|
|
|
|
if( xTunnel.is() )
|
|
|
|
{
|
|
|
|
sal_Int64 nPtr = xTunnel->getSomething( vcl::unotools::getTunnelIdentifier( vcl::unotools::Id_BitmapEx ) );
|
|
|
|
if( nPtr )
|
|
|
|
return BitmapEx( *(BitmapEx*)nPtr );
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(F1): extract pixel from XBitmap interface
|
|
|
|
ENSURE_AND_THROW( false,
|
|
|
|
"bitmapExFromXBitmap(): could not extract BitmapEx" );
|
|
|
|
|
|
|
|
return ::BitmapEx();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool readAlpha( BitmapReadAccess* pAlphaReadAcc, long nY, const long nWidth, unsigned char* data, long nOff )
|
|
|
|
{
|
|
|
|
bool bIsAlpha = false;
|
|
|
|
long nX;
|
|
|
|
int nAlpha;
|
|
|
|
Scanline pReadScan;
|
|
|
|
|
|
|
|
nOff += 3;
|
|
|
|
|
|
|
|
switch( pAlphaReadAcc->GetScanlineFormat() ) {
|
|
|
|
case BMP_FORMAT_8BIT_TC_MASK:
|
|
|
|
pReadScan = pAlphaReadAcc->GetScanline( nY );
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
|
|
|
nAlpha = data[ nOff ] = 255 - ( *pReadScan++ );
|
|
|
|
if( nAlpha != 255 )
|
|
|
|
bIsAlpha = true;
|
|
|
|
nOff += 4;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BMP_FORMAT_8BIT_PAL:
|
|
|
|
pReadScan = pAlphaReadAcc->GetScanline( nY );
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
|
|
|
nAlpha = data[ nOff ] = 255 - ( pAlphaReadAcc->GetPaletteColor( *pReadScan++ ).GetBlue() );
|
|
|
|
if( nAlpha != 255 )
|
|
|
|
bIsAlpha = true;
|
|
|
|
nOff += 4;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
OSL_TRACE( "fallback to GetColor for alpha - slow, format: %d\n", pAlphaReadAcc->GetScanlineFormat() );
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
|
|
|
nAlpha = data[ nOff ] = 255 - pAlphaReadAcc->GetColor( nY, nX ).GetBlue();
|
|
|
|
if( nAlpha != 255 )
|
|
|
|
bIsAlpha = true;
|
|
|
|
nOff += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return bIsAlpha;
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
|
|
|
|
/** surfaceFromXBitmap Create a surface from XBitmap
|
|
|
|
* @param xBitmap bitmap image that will be used for the surface
|
|
|
|
* @param rDevice reference to the device into which we want to draw
|
|
|
|
* @param data will be filled with alpha data, if xBitmap is alpha/transparent image
|
|
|
|
* @param bHasAlpha will be set to true if resulting surface has alpha
|
|
|
|
*
|
|
|
|
* This function tries various methods for creating a surface from xBitmap. It also uses
|
|
|
|
* the helper function surfaceFromXBitmap( xBitmap, bHasAlpha )
|
|
|
|
*
|
|
|
|
* @return created surface or NULL
|
|
|
|
**/
|
2006-02-28 09:34:46 +00:00
|
|
|
static Surface* surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, const DeviceRef& rDevice, unsigned char*& data, bool& bHasAlpha )
|
|
|
|
{
|
|
|
|
Surface* pSurface = surfaceFromXBitmap( xBitmap, bHasAlpha );
|
|
|
|
if( pSurface ) {
|
|
|
|
pSurface->Ref();
|
|
|
|
data = NULL;
|
|
|
|
} else {
|
|
|
|
BitmapEx aBmpEx = bitmapExFromXBitmap(xBitmap);
|
|
|
|
Bitmap aBitmap = aBmpEx.GetBitmap();
|
|
|
|
|
|
|
|
// there's no pixmap for alpha bitmap. we might still
|
|
|
|
// use rgb pixmap and only access alpha pixels the
|
|
|
|
// slow way. now we just speedup rgb bitmaps
|
|
|
|
if( !aBmpEx.IsTransparent() && !aBmpEx.IsAlpha() ) {
|
|
|
|
pSurface = rDevice->getSurface( aBitmap );
|
|
|
|
data = NULL;
|
|
|
|
bHasAlpha = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !pSurface ) {
|
2007-02-05 11:49:49 +00:00
|
|
|
AlphaMask aAlpha = aBmpEx.GetAlpha();
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
BitmapReadAccess* pBitmapReadAcc = aBitmap.AcquireReadAccess();
|
|
|
|
BitmapReadAccess* pAlphaReadAcc = NULL;
|
|
|
|
const long nWidth = pBitmapReadAcc->Width();
|
|
|
|
const long nHeight = pBitmapReadAcc->Height();
|
|
|
|
long nX, nY;
|
|
|
|
bool bIsAlpha = false;
|
|
|
|
|
|
|
|
if( aBmpEx.IsTransparent() || aBmpEx.IsAlpha() )
|
|
|
|
pAlphaReadAcc = aAlpha.AcquireReadAccess();
|
|
|
|
|
|
|
|
data = (unsigned char*) malloc( nWidth*nHeight*4 );
|
|
|
|
|
|
|
|
long nOff = 0;
|
|
|
|
Color aColor;
|
|
|
|
unsigned int nAlpha = 255;
|
|
|
|
|
|
|
|
for( nY = 0; nY < nHeight; nY++ ) {
|
|
|
|
Scanline pReadScan;
|
|
|
|
|
|
|
|
switch( pBitmapReadAcc->GetScanlineFormat() ) {
|
|
|
|
case BMP_FORMAT_8BIT_PAL:
|
|
|
|
pReadScan = pBitmapReadAcc->GetScanline( nY );
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
|
|
|
|
bIsAlpha = true;
|
|
|
|
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
2007-11-01 13:39:47 +00:00
|
|
|
#ifdef OSL_BIGENDIAN
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff++ ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff++ ] = 255;
|
|
|
|
#else
|
2006-02-28 09:34:46 +00:00
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff + 3 ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff + 3 ] = 255;
|
2007-11-01 13:39:47 +00:00
|
|
|
#endif
|
2006-02-28 09:34:46 +00:00
|
|
|
aColor = pBitmapReadAcc->GetPaletteColor( *pReadScan++ );
|
|
|
|
|
2007-11-01 13:39:47 +00:00
|
|
|
#ifdef OSL_BIGENDIAN
|
|
|
|
data[ nOff++ ] = ( nAlpha*( aColor.GetRed() ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( aColor.GetGreen() ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( aColor.GetBlue() ) )/255;
|
|
|
|
#else
|
2006-02-28 09:34:46 +00:00
|
|
|
data[ nOff++ ] = ( nAlpha*( aColor.GetBlue() ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( aColor.GetGreen() ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( aColor.GetRed() ) )/255;
|
|
|
|
nOff++;
|
2007-11-01 13:39:47 +00:00
|
|
|
#endif
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BMP_FORMAT_24BIT_TC_BGR:
|
|
|
|
pReadScan = pBitmapReadAcc->GetScanline( nY );
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
|
|
|
|
bIsAlpha = true;
|
|
|
|
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
2007-11-01 13:39:47 +00:00
|
|
|
#ifdef OSL_BIGENDIAN
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff ] = 255;
|
|
|
|
data[ nOff + 3 ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff + 2 ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff + 1 ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
nOff += 4;
|
|
|
|
#else
|
2006-02-28 09:34:46 +00:00
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff + 3 ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff + 3 ] = 255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
nOff++;
|
2007-11-01 13:39:47 +00:00
|
|
|
#endif
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BMP_FORMAT_24BIT_TC_RGB:
|
|
|
|
pReadScan = pBitmapReadAcc->GetScanline( nY );
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
|
|
|
|
bIsAlpha = true;
|
|
|
|
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
2007-11-01 13:39:47 +00:00
|
|
|
#ifdef OSL_BIGENDIAN
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff++ ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff++ ] = 255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
#else
|
2006-02-28 09:34:46 +00:00
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff + 3 ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff + 3 ] = 255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 2 ] ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 1 ] ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 0 ] ) )/255;
|
|
|
|
pReadScan += 3;
|
2007-11-01 13:39:47 +00:00
|
|
|
nOff++;
|
|
|
|
#endif
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BMP_FORMAT_32BIT_TC_BGRA:
|
|
|
|
pReadScan = pBitmapReadAcc->GetScanline( nY );
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
|
|
|
|
bIsAlpha = true;
|
|
|
|
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
2007-11-01 13:39:47 +00:00
|
|
|
#ifdef OSL_BIGENDIAN
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff++ ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff++ ] = pReadScan[ 3 ];
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 2 ] ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 1 ] ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 0 ] ) )/255;
|
|
|
|
pReadScan += 4;
|
|
|
|
#else
|
2006-02-28 09:34:46 +00:00
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff + 3 ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff + 3 ] = pReadScan[ 3 ];
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
pReadScan++;
|
2007-11-01 13:39:47 +00:00
|
|
|
nOff++;
|
|
|
|
#endif
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BMP_FORMAT_32BIT_TC_RGBA:
|
|
|
|
pReadScan = pBitmapReadAcc->GetScanline( nY );
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
|
|
|
|
bIsAlpha = true;
|
|
|
|
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
2007-11-01 13:39:47 +00:00
|
|
|
#ifdef OSL_BIGENDIAN
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff ++ ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff ++ ] = 255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( *pReadScan++ ) )/255;
|
|
|
|
pReadScan++;
|
|
|
|
#else
|
2006-02-28 09:34:46 +00:00
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff + 3 ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff + 3 ] = 255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 2 ] ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 1 ] ) )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*( pReadScan[ 0 ] ) )/255;
|
|
|
|
pReadScan += 4;
|
2007-11-01 13:39:47 +00:00
|
|
|
nOff++;
|
|
|
|
#endif
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
OSL_TRACE( "fallback to GetColor - slow, format: %d\n", pBitmapReadAcc->GetScanlineFormat() );
|
|
|
|
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
|
|
|
|
bIsAlpha = true;
|
|
|
|
|
|
|
|
for( nX = 0; nX < nWidth; nX++ ) {
|
|
|
|
aColor = pBitmapReadAcc->GetColor( nY, nX );
|
|
|
|
|
|
|
|
// cairo need premultiplied color values
|
|
|
|
// TODO(rodo) handle endianess
|
2007-11-01 13:39:47 +00:00
|
|
|
#ifdef OSL_BIGENDIAN
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff++ ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff++ ] = 255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*aColor.GetRed() )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*aColor.GetGreen() )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*aColor.GetBlue() )/255;
|
|
|
|
#else
|
2006-02-28 09:34:46 +00:00
|
|
|
if( pAlphaReadAcc )
|
|
|
|
nAlpha = data[ nOff + 3 ];
|
|
|
|
else
|
|
|
|
nAlpha = data[ nOff + 3 ] = 255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*aColor.GetBlue() )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*aColor.GetGreen() )/255;
|
|
|
|
data[ nOff++ ] = ( nAlpha*aColor.GetRed() )/255;
|
|
|
|
nOff ++;
|
2007-11-01 13:39:47 +00:00
|
|
|
#endif
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aBitmap.ReleaseAccess( pBitmapReadAcc );
|
|
|
|
if( pAlphaReadAcc )
|
|
|
|
aAlpha.ReleaseAccess( pAlphaReadAcc );
|
|
|
|
|
|
|
|
Surface* pImageSurface = new Surface( cairo_image_surface_create_for_data( data,
|
|
|
|
bIsAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
|
|
|
|
nWidth, nHeight, nWidth*4 ) );
|
|
|
|
|
|
|
|
// pSurface = rDevice->getSurface( ::basegfx::B2ISize( nWidth, nHeight ), bIsAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
|
|
|
|
// Cairo* pTargetCairo = cairo_create( pSurface );
|
|
|
|
// cairo_set_source_surface( pTargetCairo, pImageSurface, 0, 0 );
|
|
|
|
|
|
|
|
// //if( !bIsAlpha )
|
|
|
|
// //cairo_set_operator( pTargetCairo, CAIRO_OPERATOR_SOURCE );
|
|
|
|
|
|
|
|
// cairo_paint( pTargetCairo );
|
|
|
|
// cairo_destroy( pTargetCairo );
|
|
|
|
// cairo_surface_destroy( pImageSurface );
|
|
|
|
pSurface = pImageSurface;
|
|
|
|
|
|
|
|
bHasAlpha = bIsAlpha;
|
|
|
|
|
|
|
|
OSL_TRACE("image: %d x %d alpha: %d alphaRead %p", nWidth, nHeight, bIsAlpha, pAlphaReadAcc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pSurface;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void addColorStop( Pattern* pPattern, double nOffset, const uno::Sequence< double >& rColor )
|
|
|
|
{
|
|
|
|
if( rColor.getLength() == 3 )
|
|
|
|
cairo_pattern_add_color_stop_rgb( pPattern, nOffset, rColor[0], rColor[1], rColor[2] );
|
|
|
|
else if( rColor.getLength() == 4 )
|
|
|
|
cairo_pattern_add_color_stop_rgba( pPattern, nOffset, rColor[0], rColor[1], rColor[2], rColor[3] );
|
|
|
|
}
|
|
|
|
|
|
|
|
static Pattern* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon& rPolygon, Matrix& rMatrix )
|
|
|
|
{
|
|
|
|
Pattern* pPattern = NULL;
|
|
|
|
const ::canvas::ParametricPolyPolygon::Values aValues = rPolygon.getValues();
|
|
|
|
double x0, x1, y0, y1, cx, cy, r0, r1;
|
|
|
|
|
|
|
|
// undef macros from vclenum.hxx which conflicts with GradientType enum values
|
|
|
|
#undef GRADIENT_LINEAR
|
|
|
|
#undef GRADIENT_AXIAL
|
|
|
|
#undef GRADIENT_ELLIPTICAL
|
|
|
|
|
|
|
|
switch( aValues.meType ) {
|
|
|
|
case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR:
|
|
|
|
x0 = 0;
|
|
|
|
y0 = 0;
|
|
|
|
x1 = 1;
|
|
|
|
y1 = 0;
|
|
|
|
cairo_matrix_transform_point( &rMatrix, &x0, &y0 );
|
|
|
|
cairo_matrix_transform_point( &rMatrix, &x1, &y1 );
|
|
|
|
pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
|
|
|
|
addColorStop( pPattern, 0, aValues.maColor1 );
|
|
|
|
addColorStop( pPattern, 1, aValues.maColor2 );
|
|
|
|
break;
|
|
|
|
|
|
|
|
// FIXME: NYI
|
|
|
|
case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR:
|
|
|
|
case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL:
|
|
|
|
x0 = 0;
|
|
|
|
y0 = 0;
|
|
|
|
x1 = 1;
|
|
|
|
y1 = 0;
|
|
|
|
cairo_matrix_transform_point( &rMatrix, &x0, &y0 );
|
|
|
|
cairo_matrix_transform_point( &rMatrix, &x1, &y1 );
|
|
|
|
pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
|
|
|
|
addColorStop( pPattern, 0, aValues.maColor1 );
|
|
|
|
addColorStop( pPattern, 0.5, aValues.maColor2 );
|
|
|
|
addColorStop( pPattern, 1, aValues.maColor1 );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
|
|
|
|
cx = 0.5;
|
|
|
|
cy = 0.5;
|
|
|
|
r0 = 0;
|
|
|
|
r1 = 0.5;
|
2007-07-17 13:20:31 +00:00
|
|
|
Matrix aScaleMatrix;
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
cairo_matrix_transform_point( &rMatrix, &cx, &cy );
|
|
|
|
cairo_matrix_transform_distance( &rMatrix, &r0, &r1 );
|
|
|
|
pPattern = cairo_pattern_create_radial( cx, cy, r0, cx, cy, r1 );
|
|
|
|
addColorStop( pPattern, 0, aValues.maColor1 );
|
|
|
|
addColorStop( pPattern, 1, aValues.maColor2 );
|
|
|
|
|
|
|
|
if( ! ::rtl::math::approxEqual( aValues.mnAspectRatio, 1 ) ) {
|
|
|
|
cairo_matrix_init_scale( &aScaleMatrix, 1, aValues.mnAspectRatio );
|
|
|
|
cairo_pattern_set_matrix( pPattern, &aScaleMatrix );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pPattern;
|
|
|
|
}
|
|
|
|
|
|
|
|
void doOperation( Operation aOperation,
|
2007-07-17 13:20:31 +00:00
|
|
|
Cairo* pCairo,
|
|
|
|
sal_uInt32 /*nPolygonIndex*/,
|
|
|
|
const uno::Sequence< rendering::Texture >* pTextures,
|
|
|
|
SpriteCanvas* pDevice )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
switch( aOperation ) {
|
|
|
|
case Fill:
|
2006-03-22 09:59:35 +00:00
|
|
|
/* TODO: multitexturing */
|
2006-02-28 09:34:46 +00:00
|
|
|
if( pTextures ) {
|
2006-03-22 09:59:35 +00:00
|
|
|
const ::com::sun::star::rendering::Texture& aTexture ( (*pTextures)[0] );
|
2006-02-28 09:34:46 +00:00
|
|
|
if( aTexture.Bitmap.is() ) {
|
|
|
|
unsigned char* data;
|
|
|
|
bool bHasAlpha;
|
2006-03-22 09:59:35 +00:00
|
|
|
Surface* pSurface = surfaceFromXBitmap( (*pTextures)[0].Bitmap, pDevice, data, bHasAlpha );
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
if( pSurface ) {
|
|
|
|
cairo_pattern_t* pPattern;
|
|
|
|
|
|
|
|
cairo_save( pCairo );
|
|
|
|
|
|
|
|
::com::sun::star::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform );
|
2007-07-17 13:20:31 +00:00
|
|
|
Matrix aScaleMatrix, aTextureMatrix, aScaledTextureMatrix;
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
cairo_matrix_init( &aTextureMatrix,
|
|
|
|
aTransform.m00, aTransform.m10, aTransform.m01,
|
|
|
|
aTransform.m11, aTransform.m02, aTransform.m12);
|
|
|
|
|
|
|
|
geometry::IntegerSize2D aSize = aTexture.Bitmap->getSize();
|
|
|
|
|
|
|
|
cairo_matrix_init_scale( &aScaleMatrix, 1.0/aSize.Width, 1.0/aSize.Height );
|
|
|
|
cairo_matrix_multiply( &aScaledTextureMatrix, &aTextureMatrix, &aScaleMatrix );
|
|
|
|
cairo_matrix_invert( &aScaledTextureMatrix );
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
OSL_TRACE("slow workaround");
|
|
|
|
// workaround for X/glitz and/or cairo bug
|
|
|
|
// we create big enough temporary surface, copy texture bitmap there and use it for the pattern
|
|
|
|
// it only happens on enlargening matrices with REPEAT mode enabled
|
|
|
|
Surface* pTmpSurface = pDevice->getSurface();
|
|
|
|
Cairo* pTmpCairo = cairo_create( pTmpSurface );
|
|
|
|
cairo_set_source_surface( pTmpCairo, pSurface, 0, 0 );
|
|
|
|
cairo_paint( pTmpCairo );
|
|
|
|
pPattern = cairo_pattern_create_for_surface( pTmpSurface );
|
|
|
|
#else
|
|
|
|
|
|
|
|
// we don't care about repeat mode yet, so the workaround is disabled for now
|
|
|
|
pPattern = cairo_pattern_create_for_surface( pSurface->mpSurface );
|
|
|
|
#endif
|
|
|
|
if( aTexture.RepeatModeX == rendering::TexturingMode::REPEAT &&
|
|
|
|
aTexture.RepeatModeY == rendering::TexturingMode::REPEAT )
|
|
|
|
cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_REPEAT );
|
|
|
|
aScaledTextureMatrix.x0 = round( aScaledTextureMatrix.x0 );
|
|
|
|
aScaledTextureMatrix.y0 = round( aScaledTextureMatrix.y0 );
|
|
|
|
cairo_pattern_set_matrix( pPattern, &aScaledTextureMatrix );
|
|
|
|
|
|
|
|
cairo_set_source( pCairo, pPattern );
|
|
|
|
if( !bHasAlpha )
|
|
|
|
cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
|
|
|
|
cairo_fill( pCairo );
|
|
|
|
|
|
|
|
cairo_restore( pCairo );
|
|
|
|
|
|
|
|
cairo_pattern_destroy( pPattern );
|
|
|
|
pSurface->Unref();
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
cairo_destroy( pTmpCairo );
|
|
|
|
cairo_surface_destroy( pTmpSurface );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if( data )
|
|
|
|
free( data );
|
|
|
|
} else if( aTexture.Gradient.is() ) {
|
|
|
|
uno::Reference< lang::XServiceInfo > xRef( aTexture.Gradient, uno::UNO_QUERY );
|
|
|
|
|
|
|
|
OSL_TRACE( "gradient fill\n" );
|
|
|
|
if( xRef.is() &&
|
|
|
|
xRef->getImplementationName().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME ) ) ) ) {
|
|
|
|
// TODO(Q1): Maybe use dynamic_cast here
|
|
|
|
|
|
|
|
// TODO(E1): Return value
|
|
|
|
// TODO(F1): FillRule
|
|
|
|
OSL_TRACE( "known implementation\n" );
|
|
|
|
|
|
|
|
::canvas::ParametricPolyPolygon* pPolyImpl = static_cast< ::canvas::ParametricPolyPolygon* >( aTexture.Gradient.get() );
|
|
|
|
::com::sun::star::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform );
|
|
|
|
Matrix aTextureMatrix;
|
|
|
|
|
|
|
|
cairo_matrix_init( &aTextureMatrix,
|
|
|
|
aTransform.m00, aTransform.m10, aTransform.m01,
|
|
|
|
aTransform.m11, aTransform.m02, aTransform.m12);
|
|
|
|
Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl, aTextureMatrix );
|
|
|
|
|
|
|
|
if( pPattern ) {
|
|
|
|
OSL_TRACE( "filling with pattern\n" );
|
|
|
|
|
|
|
|
cairo_save( pCairo );
|
|
|
|
|
|
|
|
cairo_set_source( pCairo, pPattern );
|
|
|
|
cairo_fill( pCairo );
|
|
|
|
cairo_restore( pCairo );
|
|
|
|
|
|
|
|
cairo_pattern_destroy( pPattern );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
cairo_fill( pCairo );
|
|
|
|
OSL_TRACE("fill\n");
|
|
|
|
break;
|
|
|
|
case Stroke:
|
|
|
|
cairo_stroke( pCairo );
|
|
|
|
OSL_TRACE("stroke\n");
|
|
|
|
break;
|
|
|
|
case Clip:
|
|
|
|
cairo_clip( pCairo );
|
|
|
|
OSL_TRACE("clip\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void clipNULL( Cairo *pCairo )
|
|
|
|
{
|
|
|
|
OSL_TRACE("clipNULL\n");
|
|
|
|
Matrix aOrigMatrix, aIdentityMatrix;
|
|
|
|
|
|
|
|
/* we set identity matrix here to overcome bug in cairo 0.9.2
|
|
|
|
where XCreatePixmap is called with zero width and height.
|
|
|
|
|
|
|
|
it also reaches faster path in cairo clipping code.
|
|
|
|
*/
|
|
|
|
cairo_matrix_init_identity( &aIdentityMatrix );
|
|
|
|
cairo_get_matrix( pCairo, &aOrigMatrix );
|
|
|
|
cairo_set_matrix( pCairo, &aIdentityMatrix );
|
|
|
|
|
|
|
|
cairo_reset_clip( pCairo );
|
|
|
|
cairo_rectangle( pCairo, 0, 0, 1, 1 );
|
|
|
|
cairo_clip( pCairo );
|
|
|
|
cairo_rectangle( pCairo, 2, 0, 1, 1 );
|
|
|
|
cairo_clip( pCairo );
|
|
|
|
|
|
|
|
/* restore the original matrix */
|
|
|
|
cairo_set_matrix( pCairo, &aOrigMatrix );
|
|
|
|
}
|
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
void doPolyPolygonImplementation( ::basegfx::B2DPolyPolygon aPolyPolygon,
|
2006-02-28 09:34:46 +00:00
|
|
|
Operation aOperation,
|
|
|
|
Cairo* pCairo,
|
|
|
|
const uno::Sequence< rendering::Texture >* pTextures,
|
|
|
|
SpriteCanvas* pDevice )
|
|
|
|
{
|
2006-03-22 09:59:35 +00:00
|
|
|
if( pTextures )
|
|
|
|
CHECK_AND_THROW( pTextures->getLength(),
|
|
|
|
"CanvasHelper::fillTexturedPolyPolygon: empty texture sequence");
|
|
|
|
|
2006-02-28 09:34:46 +00:00
|
|
|
bool bOpToDo = false;
|
|
|
|
Matrix aOrigMatrix, aIdentityMatrix;
|
2007-07-17 13:20:31 +00:00
|
|
|
double nX, nY, nBX, nBY, nAX, nAY;
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
cairo_get_matrix( pCairo, &aOrigMatrix );
|
|
|
|
cairo_matrix_init_identity( &aIdentityMatrix );
|
|
|
|
cairo_set_matrix( pCairo, &aIdentityMatrix );
|
|
|
|
|
|
|
|
for( sal_uInt32 nPolygonIndex = 0; nPolygonIndex < aPolyPolygon.count(); nPolygonIndex++ ) {
|
2007-08-02 15:32:02 +00:00
|
|
|
::basegfx::B2DPolygon aPolygon( aPolyPolygon.getB2DPolygon( nPolygonIndex ) );
|
|
|
|
const sal_uInt32 nPointCount( aPolygon.count() );
|
2006-02-28 09:34:46 +00:00
|
|
|
|
2007-08-02 15:32:02 +00:00
|
|
|
if( nPointCount > 1) {
|
2006-02-28 09:34:46 +00:00
|
|
|
bool bIsBezier = aPolygon.areControlPointsUsed();
|
|
|
|
::basegfx::B2DPoint aA, aB, aP;
|
|
|
|
|
|
|
|
aP = aPolygon.getB2DPoint( 0 );
|
|
|
|
nX = aP.getX();
|
|
|
|
nY = aP.getY();
|
|
|
|
|
|
|
|
cairo_matrix_transform_point( &aOrigMatrix, &nX, &nY );
|
|
|
|
|
|
|
|
if( ! bIsBezier ) {
|
|
|
|
nX = round( nX );
|
|
|
|
nY = round( nY );
|
|
|
|
}
|
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
if( aOperation == Stroke ) {
|
2006-02-28 09:34:46 +00:00
|
|
|
nX += 0.5;
|
|
|
|
nY += 0.5;
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_move_to( pCairo, nX, nY );
|
|
|
|
OSL_TRACE( "move to %f,%f\n", nX, nY );
|
|
|
|
|
|
|
|
if( bIsBezier ) {
|
2007-08-02 15:32:02 +00:00
|
|
|
aA = aPolygon.getNextControlPoint( 0 );
|
|
|
|
aB = aPolygon.getPrevControlPoint( 1 );
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
|
2007-08-02 15:32:02 +00:00
|
|
|
for( sal_uInt32 j = 1; j < nPointCount; j++ ) {
|
2006-02-28 09:34:46 +00:00
|
|
|
aP = aPolygon.getB2DPoint( j );
|
|
|
|
|
|
|
|
nX = aP.getX();
|
|
|
|
nY = aP.getY();
|
|
|
|
cairo_matrix_transform_point( &aOrigMatrix, &nX, &nY );
|
|
|
|
|
|
|
|
if( ! bIsBezier ) {
|
|
|
|
nX = round( nX );
|
|
|
|
nY = round( nY );
|
|
|
|
}
|
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
if( aOperation == Stroke ) {
|
2006-02-28 09:34:46 +00:00
|
|
|
nX += 0.5;
|
|
|
|
nY += 0.5;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( bIsBezier ) {
|
|
|
|
nAX = aA.getX();
|
|
|
|
nAY = aA.getY();
|
|
|
|
nBX = aB.getX();
|
|
|
|
nBY = aB.getY();
|
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
if( aOperation == Stroke ) {
|
2006-02-28 09:34:46 +00:00
|
|
|
nAX += 0.5;
|
|
|
|
nAY += 0.5;
|
|
|
|
nBX += 0.5;
|
|
|
|
nBY += 0.5;
|
|
|
|
}
|
|
|
|
cairo_matrix_transform_point( &aOrigMatrix, &nAX, &nAY );
|
|
|
|
cairo_matrix_transform_point( &aOrigMatrix, &nBX, &nBY );
|
|
|
|
cairo_curve_to( pCairo, nAX, nAY, nBX, nBY, nX, nY );
|
|
|
|
|
2007-08-02 15:32:02 +00:00
|
|
|
aA = aPolygon.getNextControlPoint( j );
|
|
|
|
aB = aPolygon.getPrevControlPoint( ( j + 1 ) % nPointCount );
|
2006-02-28 09:34:46 +00:00
|
|
|
} else {
|
|
|
|
cairo_line_to( pCairo, nX, nY );
|
|
|
|
OSL_TRACE( "line to %f,%f\n", nX, nY );
|
|
|
|
}
|
|
|
|
bOpToDo = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( aPolygon.isClosed() )
|
|
|
|
cairo_close_path( pCairo );
|
|
|
|
|
|
|
|
if( aOperation == Fill && pTextures ) {
|
|
|
|
cairo_set_matrix( pCairo, &aOrigMatrix );
|
|
|
|
doOperation( aOperation, pCairo, nPolygonIndex, pTextures, pDevice );
|
|
|
|
cairo_set_matrix( pCairo, &aIdentityMatrix );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
OSL_TRACE( "empty polygon for op: %d\n\n", aOperation );
|
|
|
|
if( aOperation == Clip ) {
|
|
|
|
clipNULL( pCairo );
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( bOpToDo && ( aOperation != Fill || !pTextures ) )
|
|
|
|
doOperation( aOperation, pCairo );
|
|
|
|
|
|
|
|
cairo_set_matrix( pCairo, &aOrigMatrix );
|
|
|
|
|
|
|
|
// fixme, spec says even clipping polypolygon with zero polygons means NULL clip, but it breaks animations with sprites
|
|
|
|
// if( aPolyPolygon.count() == 0 && aOperation == Clip )
|
|
|
|
// clipNULL( pCairo );
|
|
|
|
}
|
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
void CanvasHelper::doPolyPolygonPath( const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
|
2006-02-28 09:34:46 +00:00
|
|
|
Operation aOperation,
|
|
|
|
const uno::Sequence< rendering::Texture >* pTextures,
|
|
|
|
Cairo* pCairo ) const
|
|
|
|
{
|
|
|
|
::basegfx::B2DPolyPolygon aPoly = ::canvas::tools::polyPolygonFromXPolyPolygon2D( xPolyPolygon );
|
|
|
|
|
|
|
|
if( !pCairo )
|
|
|
|
pCairo = mpCairo;
|
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
doPolyPolygonImplementation( aPoly, aOperation, pCairo, pTextures, mpDevice );
|
2006-02-28 09:34:46 +00:00
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* ,
|
2006-02-28 09:34:46 +00:00
|
|
|
const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState )
|
|
|
|
{
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
struct timespec aTimer;
|
|
|
|
mxDevice->startPerfTrace( &aTimer );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if( mpCairo ) {
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
cairo_set_line_width( mpCairo, 1 );
|
|
|
|
|
|
|
|
useStates( viewState, renderState, true );
|
2006-11-01 13:45:42 +00:00
|
|
|
doPolyPolygonPath( xPolyPolygon, Stroke );
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
} else
|
|
|
|
OSL_TRACE ("CanvasHelper called after it was disposed");
|
|
|
|
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
mxDevice->stopPerfTrace( &aTimer, "drawPolyPolygon" );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* ,
|
2006-02-28 09:34:46 +00:00
|
|
|
const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState,
|
|
|
|
const rendering::StrokeAttributes& strokeAttributes )
|
|
|
|
{
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
struct timespec aTimer;
|
|
|
|
mxDevice->startPerfTrace( &aTimer );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if( mpCairo ) {
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
useStates( viewState, renderState, true );
|
|
|
|
|
|
|
|
cairo_set_line_width( mpCairo, strokeAttributes.StrokeWidth );
|
|
|
|
cairo_set_miter_limit( mpCairo, strokeAttributes.MiterLimit );
|
|
|
|
|
|
|
|
// FIXME: cairo doesn't handle end cap so far (rodo)
|
|
|
|
switch( strokeAttributes.StartCapType ) {
|
|
|
|
case rendering::PathCapType::BUTT:
|
|
|
|
cairo_set_line_cap( mpCairo, CAIRO_LINE_CAP_BUTT );
|
|
|
|
break;
|
|
|
|
case rendering::PathCapType::ROUND:
|
|
|
|
cairo_set_line_cap( mpCairo, CAIRO_LINE_CAP_ROUND );
|
|
|
|
break;
|
|
|
|
case rendering::PathCapType::SQUARE:
|
|
|
|
cairo_set_line_cap( mpCairo, CAIRO_LINE_CAP_SQUARE );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( strokeAttributes.JoinType ) {
|
|
|
|
// cairo doesn't have join type NONE so we use MITTER as it's pretty close
|
|
|
|
case rendering::PathJoinType::NONE:
|
|
|
|
case rendering::PathJoinType::MITER:
|
|
|
|
cairo_set_line_join( mpCairo, CAIRO_LINE_JOIN_MITER );
|
|
|
|
break;
|
|
|
|
case rendering::PathJoinType::ROUND:
|
|
|
|
cairo_set_line_join( mpCairo, CAIRO_LINE_JOIN_ROUND );
|
|
|
|
break;
|
|
|
|
case rendering::PathJoinType::BEVEL:
|
|
|
|
cairo_set_line_join( mpCairo, CAIRO_LINE_JOIN_BEVEL );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( strokeAttributes.DashArray.getLength() > 0 ) {
|
|
|
|
double* pDashArray = new double[ strokeAttributes.DashArray.getLength() ];
|
|
|
|
for( sal_Int32 i=0; i<strokeAttributes.DashArray.getLength(); i++ )
|
|
|
|
pDashArray[i]=strokeAttributes.DashArray[i];
|
|
|
|
cairo_set_dash( mpCairo, pDashArray, strokeAttributes.DashArray.getLength(), 0 );
|
|
|
|
delete[] pDashArray;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(rodo) use LineArray of strokeAttributes
|
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
doPolyPolygonPath( xPolyPolygon, Stroke );
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
} else
|
|
|
|
OSL_TRACE ("CanvasHelper called after it was disposed");
|
|
|
|
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
mxDevice->stopPerfTrace( &aTimer, "strokePolyPolygon" );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// TODO(P1): Provide caching here.
|
|
|
|
return uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* ,
|
|
|
|
const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
|
|
|
|
const rendering::ViewState& /*viewState*/,
|
|
|
|
const rendering::RenderState& /*renderState*/,
|
|
|
|
const uno::Sequence< rendering::Texture >& /*textures*/,
|
|
|
|
const rendering::StrokeAttributes& /*strokeAttributes*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* ,
|
|
|
|
const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
|
|
|
|
const rendering::ViewState& /*viewState*/,
|
|
|
|
const rendering::RenderState& /*renderState*/,
|
|
|
|
const uno::Sequence< rendering::Texture >& /*textures*/,
|
|
|
|
const uno::Reference< geometry::XMapping2D >& /*xMapping*/,
|
|
|
|
const rendering::StrokeAttributes& /*strokeAttributes*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XPolyPolygon2D > CanvasHelper::queryStrokeShapes( const rendering::XCanvas* ,
|
|
|
|
const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
|
|
|
|
const rendering::ViewState& /*viewState*/,
|
|
|
|
const rendering::RenderState& /*renderState*/,
|
|
|
|
const rendering::StrokeAttributes& /*strokeAttributes*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return uno::Reference< rendering::XPolyPolygon2D >(NULL);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* ,
|
2006-02-28 09:34:46 +00:00
|
|
|
const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState )
|
|
|
|
{
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
struct timespec aTimer;
|
|
|
|
mxDevice->startPerfTrace( &aTimer );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if( mpCairo ) {
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
useStates( viewState, renderState, true );
|
2006-11-01 13:45:42 +00:00
|
|
|
doPolyPolygonPath( xPolyPolygon, Fill );
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
} else
|
|
|
|
OSL_TRACE ("CanvasHelper called after it was disposed");
|
|
|
|
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
mxDevice->stopPerfTrace( &aTimer, "fillPolyPolygon" );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* ,
|
2006-02-28 09:34:46 +00:00
|
|
|
const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState,
|
|
|
|
const uno::Sequence< rendering::Texture >& textures )
|
|
|
|
{
|
|
|
|
if( mpCairo ) {
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
useStates( viewState, renderState, true );
|
2006-11-01 13:45:42 +00:00
|
|
|
doPolyPolygonPath( xPolyPolygon, Fill, &textures );
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
}
|
|
|
|
|
|
|
|
return uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* ,
|
|
|
|
const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/,
|
|
|
|
const rendering::ViewState& /*viewState*/,
|
|
|
|
const rendering::RenderState& /*renderState*/,
|
|
|
|
const uno::Sequence< rendering::Texture >& /*textures*/,
|
|
|
|
const uno::Reference< geometry::XMapping2D >& /*xMapping*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::implDrawBitmapSurface( Surface* pSurface,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState,
|
|
|
|
const geometry::IntegerSize2D& rSize,
|
2007-07-17 13:20:31 +00:00
|
|
|
bool /*bModulateColors*/,
|
2006-02-28 09:34:46 +00:00
|
|
|
bool bHasAlpha )
|
|
|
|
{
|
|
|
|
uno::Reference< rendering::XCachedPrimitive > rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
|
2006-11-01 13:45:42 +00:00
|
|
|
geometry::IntegerSize2D aBitmapSize = rSize;
|
2006-02-28 09:34:46 +00:00
|
|
|
|
|
|
|
if( mpCairo ) {
|
|
|
|
const ::basegfx::B2ISize& aSize = mpDevice->getSizePixel();
|
|
|
|
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
cairo_rectangle( mpCairo, 0, 0, aSize.getX(), aSize.getY() );
|
|
|
|
cairo_clip( mpCairo );
|
|
|
|
|
|
|
|
useStates( viewState, renderState, true );
|
|
|
|
|
|
|
|
// if( !bHasAlpha )
|
|
|
|
// cairo_set_operator( mpCairo, CAIRO_OPERATOR_SOURCE );
|
|
|
|
|
|
|
|
Matrix aMatrix;
|
|
|
|
|
|
|
|
cairo_get_matrix( mpCairo, &aMatrix );
|
|
|
|
if( ! ::rtl::math::approxEqual( aMatrix.xx, 1 ) &&
|
|
|
|
! ::rtl::math::approxEqual( aMatrix.yy, 1 ) &&
|
|
|
|
::rtl::math::approxEqual( aMatrix.x0, 0 ) &&
|
|
|
|
::rtl::math::approxEqual( aMatrix.y0, 0 ) &&
|
|
|
|
round( rSize.Width * aMatrix.xx ) > 8 &&
|
|
|
|
round( rSize.Height* aMatrix.yy ) > 8 )
|
|
|
|
{
|
|
|
|
double dWidth, dHeight;
|
|
|
|
|
|
|
|
dWidth = round( rSize.Width * aMatrix.xx );
|
|
|
|
dHeight = round( rSize.Height* aMatrix.yy );
|
2006-11-01 13:45:42 +00:00
|
|
|
aBitmapSize.Width = static_cast<sal_Int32>( dWidth );
|
|
|
|
aBitmapSize.Height = static_cast<sal_Int32>( dHeight );
|
2006-02-28 09:34:46 +00:00
|
|
|
|
2006-11-01 13:45:42 +00:00
|
|
|
Surface* pScaledSurface = mpDevice->getSurface( ::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ),
|
|
|
|
bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
|
2006-02-28 09:34:46 +00:00
|
|
|
Cairo* pCairo = pScaledSurface->getCairo();
|
|
|
|
|
2006-03-22 09:59:35 +00:00
|
|
|
// cairo_set_operator( pCairo, CAIRO_OPERATOR_SOURCE );
|
2006-02-28 09:34:46 +00:00
|
|
|
cairo_scale( pCairo, dWidth/rSize.Width, dHeight/rSize.Height );
|
2006-03-22 09:59:35 +00:00
|
|
|
cairo_set_source_surface( pCairo, pSurface->mpSurface, 0, 0 );
|
2006-02-28 09:34:46 +00:00
|
|
|
cairo_paint( pCairo );
|
|
|
|
|
|
|
|
cairo_destroy( pCairo );
|
|
|
|
|
|
|
|
pSurface = pScaledSurface;
|
|
|
|
|
|
|
|
aMatrix.xx = aMatrix.yy = 1;
|
|
|
|
cairo_set_matrix( mpCairo, &aMatrix );
|
|
|
|
|
|
|
|
rv = uno::Reference< rendering::XCachedPrimitive >( new CachedBitmap( pSurface, viewState, renderState, mpDevice ) );
|
|
|
|
|
|
|
|
pSurface->Unref();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !bHasAlpha && mbHaveAlpha /* && mpSurfaceProvider */ )
|
|
|
|
{
|
|
|
|
double x, y, width, height;
|
|
|
|
|
|
|
|
x = y = 0;
|
2006-11-01 13:45:42 +00:00
|
|
|
width = aBitmapSize.Width;
|
|
|
|
height = aBitmapSize.Height;
|
2006-02-28 09:34:46 +00:00
|
|
|
cairo_matrix_transform_point( &aMatrix, &x, &y );
|
|
|
|
cairo_matrix_transform_distance( &aMatrix, &width, &height );
|
|
|
|
|
|
|
|
// in case the bitmap doesn't have alpha and covers whole area
|
|
|
|
// we try to change surface to plain rgb
|
|
|
|
OSL_TRACE ("chance to change surface to rgb, %f, %f, %f x %f (%d x %d)", x, y, width, height, aSize.getX(), aSize.getY() );
|
|
|
|
if( x <= 0 && y <= 0 && x + width >= aSize.getX() && y + height >= aSize.getY() )
|
|
|
|
{
|
|
|
|
OSL_TRACE ("trying to change surface to rgb");
|
|
|
|
if( mpSurfaceProvider ) {
|
|
|
|
Surface* pNewSurface = mpSurfaceProvider->changeSurface( false, false );
|
|
|
|
|
|
|
|
if( pNewSurface )
|
|
|
|
setSurface( pNewSurface, false, mpSurfaceProvider );
|
|
|
|
|
|
|
|
// set state to new mpCairo
|
|
|
|
useStates( viewState, renderState, true );
|
|
|
|
// use the possibly modified matrix
|
|
|
|
cairo_set_matrix( mpCairo, &aMatrix );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_set_source_surface( mpCairo, pSurface->mpSurface, 0, 0 );
|
2006-11-01 13:45:42 +00:00
|
|
|
if( !bHasAlpha &&
|
|
|
|
::rtl::math::approxEqual( aMatrix.xx, 1 ) &&
|
|
|
|
::rtl::math::approxEqual( aMatrix.yy, 1 ) &&
|
|
|
|
::rtl::math::approxEqual( aMatrix.x0, 0 ) &&
|
|
|
|
::rtl::math::approxEqual( aMatrix.y0, 0 ) )
|
|
|
|
cairo_set_operator( mpCairo, CAIRO_OPERATOR_SOURCE );
|
|
|
|
cairo_rectangle( mpCairo, 0, 0, aBitmapSize.Width, aBitmapSize.Height );
|
|
|
|
cairo_clip( mpCairo );
|
2006-02-28 09:34:46 +00:00
|
|
|
cairo_paint( mpCairo );
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
} else
|
|
|
|
OSL_TRACE ("CanvasHelper called after it was disposed");
|
|
|
|
|
|
|
|
return rv; // uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* ,
|
2006-02-28 09:34:46 +00:00
|
|
|
const uno::Reference< rendering::XBitmap >& xBitmap,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState )
|
|
|
|
{
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
struct timespec aTimer;
|
|
|
|
mxDevice->startPerfTrace( &aTimer );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uno::Reference< rendering::XCachedPrimitive > rv;
|
|
|
|
unsigned char* data;
|
|
|
|
bool bHasAlpha;
|
|
|
|
Surface* pSurface = surfaceFromXBitmap( xBitmap, mpDevice, data, bHasAlpha );
|
|
|
|
geometry::IntegerSize2D aSize = xBitmap->getSize();
|
|
|
|
|
|
|
|
if( pSurface ) {
|
|
|
|
rv = implDrawBitmapSurface( pSurface, viewState, renderState, aSize, false, bHasAlpha );
|
|
|
|
|
|
|
|
pSurface->Unref();
|
|
|
|
|
|
|
|
if( data )
|
|
|
|
free( data );
|
|
|
|
} else
|
|
|
|
rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* ,
|
|
|
|
const uno::Reference< rendering::XBitmap >& /*xBitmap*/,
|
|
|
|
const rendering::ViewState& /*viewState*/,
|
|
|
|
const rendering::RenderState& /*renderState*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
// TODO(P1): Provide caching here.
|
|
|
|
return uno::Reference< rendering::XCachedPrimitive >(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice()
|
|
|
|
{
|
|
|
|
return uno::Reference< rendering::XGraphicDevice >(mpDevice);
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
void CanvasHelper::copyRect( const rendering::XCanvas* ,
|
|
|
|
const uno::Reference< rendering::XBitmapCanvas >& /*sourceCanvas*/,
|
|
|
|
const geometry::RealRectangle2D& /*sourceRect*/,
|
|
|
|
const rendering::ViewState& /*sourceViewState*/,
|
|
|
|
const rendering::RenderState& /*sourceRenderState*/,
|
|
|
|
const geometry::RealRectangle2D& /*destRect*/,
|
|
|
|
const rendering::ViewState& /*destViewState*/,
|
|
|
|
const rendering::RenderState& /*destRenderState*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
// TODO(F2): copyRect NYI
|
|
|
|
}
|
|
|
|
|
|
|
|
geometry::IntegerSize2D CanvasHelper::getSize()
|
|
|
|
{
|
|
|
|
if( !mpDevice )
|
|
|
|
geometry::IntegerSize2D(1, 1); // we're disposed
|
|
|
|
|
|
|
|
return ::basegfx::unotools::integerSize2DFromB2ISize( mpDevice->getSizePixel() );
|
|
|
|
}
|
|
|
|
|
|
|
|
uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D& newSize,
|
2007-07-17 13:20:31 +00:00
|
|
|
sal_Bool /*beFast*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
struct timespec aTimer;
|
|
|
|
mxDevice->startPerfTrace( &aTimer );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if( mpCairo ) {
|
|
|
|
return uno::Reference< rendering::XBitmap >( new CanvasBitmap( ::basegfx::B2ISize( ::canvas::tools::roundUp( newSize.Width ),
|
|
|
|
::canvas::tools::roundUp( newSize.Height ) ),
|
|
|
|
mpDevice, false ) );
|
|
|
|
} else
|
|
|
|
OSL_TRACE ("CanvasHelper called after it was disposed");
|
|
|
|
|
|
|
|
#ifdef CAIRO_CANVAS_PERF_TRACE
|
|
|
|
mxDevice->stopPerfTrace( &aTimer, "getScaledBitmap" );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return uno::Reference< rendering::XBitmap >();
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& /*bitmapLayout*/,
|
|
|
|
const geometry::IntegerRectangle2D& /*rect*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return uno::Sequence< sal_Int8 >();
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
void CanvasHelper::setData( const uno::Sequence< sal_Int8 >& /*data*/,
|
|
|
|
const rendering::IntegerBitmapLayout& /*bitmapLayout*/,
|
|
|
|
const geometry::IntegerRectangle2D& /*rect*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
void CanvasHelper::setPixel( const uno::Sequence< sal_Int8 >& /*color*/,
|
|
|
|
const rendering::IntegerBitmapLayout& /*bitmapLayout*/,
|
|
|
|
const geometry::IntegerPoint2D& /*pos*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:20:31 +00:00
|
|
|
uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/,
|
|
|
|
const geometry::IntegerPoint2D& /*pos*/ )
|
2006-02-28 09:34:46 +00:00
|
|
|
{
|
|
|
|
return uno::Sequence< sal_Int8 >();
|
|
|
|
}
|
|
|
|
|
|
|
|
uno::Reference< rendering::XBitmapPalette > CanvasHelper::getPalette()
|
|
|
|
{
|
|
|
|
// TODO(F1): Palette bitmaps NYI
|
|
|
|
return uno::Reference< rendering::XBitmapPalette >();
|
|
|
|
}
|
|
|
|
|
|
|
|
rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout()
|
|
|
|
{
|
|
|
|
// TODO(F1): finish memory layout initialization
|
|
|
|
rendering::IntegerBitmapLayout aLayout;
|
|
|
|
|
|
|
|
const geometry::IntegerSize2D& rBmpSize( getSize() );
|
|
|
|
|
|
|
|
aLayout.ScanLines = rBmpSize.Width;
|
|
|
|
aLayout.ScanLineBytes = rBmpSize.Height * 4;
|
|
|
|
aLayout.ScanLineStride = aLayout.ScanLineBytes;
|
|
|
|
aLayout.PlaneStride = 0;
|
|
|
|
aLayout.ColorSpace.set( mpDevice );
|
|
|
|
aLayout.NumComponents = 4;
|
|
|
|
aLayout.ComponentMasks.realloc(4);
|
|
|
|
aLayout.ComponentMasks[0] = 0x00FF0000;
|
|
|
|
aLayout.ComponentMasks[1] = 0x0000FF00;
|
|
|
|
aLayout.ComponentMasks[2] = 0x000000FF;
|
|
|
|
aLayout.ComponentMasks[3] = 0xFF000000;
|
|
|
|
aLayout.Palette.clear();
|
|
|
|
aLayout.Endianness = rendering::Endianness::LITTLE;
|
|
|
|
aLayout.Format = rendering::IntegerBitmapFormat::CHUNKY_32BIT;
|
|
|
|
aLayout.IsMsbFirst = sal_False;
|
|
|
|
|
|
|
|
return aLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CanvasHelper::flush() const
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CanvasHelper::hasAlpha() const
|
|
|
|
{
|
|
|
|
return mbHaveAlpha;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CanvasHelper::repaint( Surface* pSurface,
|
|
|
|
const rendering::ViewState& viewState,
|
|
|
|
const rendering::RenderState& renderState )
|
|
|
|
{
|
|
|
|
OSL_TRACE("CanvasHelper::repaint");
|
|
|
|
|
|
|
|
if( mpCairo ) {
|
|
|
|
const ::basegfx::B2ISize& aSize = mpDevice->getSizePixel();
|
|
|
|
|
|
|
|
cairo_save( mpCairo );
|
|
|
|
|
|
|
|
cairo_rectangle( mpCairo, 0, 0, aSize.getX(), aSize.getY() );
|
|
|
|
cairo_clip( mpCairo );
|
|
|
|
|
|
|
|
useStates( viewState, renderState, true );
|
|
|
|
|
|
|
|
Matrix aMatrix;
|
|
|
|
|
|
|
|
cairo_get_matrix( mpCairo, &aMatrix );
|
|
|
|
aMatrix.xx = aMatrix.yy = 1;
|
|
|
|
cairo_set_matrix( mpCairo, &aMatrix );
|
|
|
|
|
|
|
|
// if( !bHasAlpha )
|
|
|
|
// cairo_set_operator( mpCairo, CAIRO_OPERATOR_SOURCE );
|
|
|
|
|
|
|
|
cairo_set_source_surface( mpCairo, pSurface->mpSurface, 0, 0 );
|
|
|
|
cairo_paint( mpCairo );
|
|
|
|
cairo_restore( mpCairo );
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|