diff options
Diffstat (limited to 'canvas/source/cairo')
42 files changed, 9321 insertions, 0 deletions
diff --git a/canvas/source/cairo/cairo_cachedbitmap.cxx b/canvas/source/cairo/cairo_cachedbitmap.cxx new file mode 100644 index 000000000000..53b0bb02d76d --- /dev/null +++ b/canvas/source/cairo/cairo_cachedbitmap.cxx @@ -0,0 +1,90 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> + +#include "cairo_cachedbitmap.hxx" +#include "cairo_repainttarget.hxx" + +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tools/canvastools.hxx> + + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + CachedBitmap::CachedBitmap( const SurfaceSharedPtr& pSurface, + const rendering::ViewState& rUsedViewState, + const rendering::RenderState& rUsedRenderState, + const uno::Reference< rendering::XCanvas >& rTarget ) : + CachedPrimitiveBase( rUsedViewState, rTarget, true ), + mpSurface( pSurface ), + maRenderState( rUsedRenderState ) + {} + + void SAL_CALL CachedBitmap::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpSurface.reset(); + CachedPrimitiveBase::disposing(); + } + + ::sal_Int8 CachedBitmap::doRedraw( const rendering::ViewState& rNewState, + const rendering::ViewState& /*rOldState*/, + const uno::Reference< rendering::XCanvas >& rTargetCanvas, + bool bSameViewTransform ) + { + ENSURE_OR_THROW( bSameViewTransform, + "CachedBitmap::doRedraw(): base called with changed view transform " + "(told otherwise during construction)" ); + + RepaintTarget* pTarget = dynamic_cast< RepaintTarget* >(rTargetCanvas.get()); + + ENSURE_OR_THROW( pTarget, + "CachedBitmap::redraw(): cannot cast target to RepaintTarget" ); + + if( !pTarget->repaint( mpSurface, + rNewState, + maRenderState ) ) + { + // target failed to repaint + return rendering::RepaintResult::FAILED; + } + + return rendering::RepaintResult::REDRAWN; + } +} diff --git a/canvas/source/cairo/cairo_cachedbitmap.hxx b/canvas/source/cairo/cairo_cachedbitmap.hxx new file mode 100644 index 000000000000..a704a0d6c20f --- /dev/null +++ b/canvas/source/cairo/cairo_cachedbitmap.hxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_CACHEDBITMAP_HXX +#define _CAIROCANVAS_CACHEDBITMAP_HXX + +#include <canvas/base/cachedprimitivebase.hxx> + +#include "cairo_cairo.hxx" + +/* Definition of CachedBitmap class */ + +namespace cairocanvas +{ + class CachedBitmap : public ::canvas::CachedPrimitiveBase + { + public: + + /** Create an XCachedPrimitive for given GraphicObject + */ + CachedBitmap( const ::cairo::SurfaceSharedPtr& pSurface, + const ::com::sun::star::rendering::ViewState& rUsedViewState, + const ::com::sun::star::rendering::RenderState& rUsedRenderState, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas >& rTarget ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + private: + virtual ::sal_Int8 doRedraw( const ::com::sun::star::rendering::ViewState& rNewState, + const ::com::sun::star::rendering::ViewState& rOldState, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas >& rTargetCanvas, + bool bSameViewTransform ); + + + ::cairo::SurfaceSharedPtr mpSurface; + const ::com::sun::star::rendering::RenderState maRenderState; + }; +} + +#endif /* _CAIROCANVAS_CACHEDBITMAP_HXX */ diff --git a/canvas/source/cairo/cairo_cairo.cxx b/canvas/source/cairo/cairo_cairo.cxx new file mode 100644 index 000000000000..f855a4f1700c --- /dev/null +++ b/canvas/source/cairo/cairo_cairo.cxx @@ -0,0 +1,64 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include "cairo_cairo.hxx" + +#ifdef WNT +# include <tools/prewin.h> +# include <windows.h> +# include <tools/postwin.h> +#endif + +#include <vcl/sysdata.hxx> +#include <vcl/syschild.hxx> + +namespace cairo +{ +/**************************************************************************************** + * Platform independent part of surface backends for OpenOffice.org Cairo Canvas * + * For the rest of the functions (and the platform-specific derived * + * Surface classes), see platform specific cairo_<platform>_cairo.cxx * + ****************************************************************************************/ + + const SystemEnvData* GetSysData(const Window *pOutputWindow) + { + const SystemEnvData* pSysData = NULL; + // check whether we're a SysChild: have to fetch system data + // directly from SystemChildWindow, because the GetSystemData + // method is unfortunately not virtual + const SystemChildWindow* pSysChild = dynamic_cast< const SystemChildWindow* >( pOutputWindow ); + if( pSysChild ) + pSysData = pSysChild->GetSystemData(); + else + pSysData = pOutputWindow->GetSystemData(); + return pSysData; + } +} diff --git a/canvas/source/cairo/cairo_cairo.hxx b/canvas/source/cairo/cairo_cairo.hxx new file mode 100644 index 000000000000..10832ac27be6 --- /dev/null +++ b/canvas/source/cairo/cairo_cairo.hxx @@ -0,0 +1,97 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_CAIRO_HXX +#define _CAIROCANVAS_CAIRO_HXX + +#include <sal/config.h> +#include <boost/shared_ptr.hpp> + +struct SystemEnvData; +struct BitmapSystemData; +struct SystemGraphicsData; +class VirtualDevice; +class OutputDevice; +class Window; +class Size; + +#include <cairo.h> //cannot be inside a namespace, otherwise Quartz fails to compile. + +namespace cairo { + typedef cairo_t Cairo; + typedef cairo_matrix_t Matrix; + typedef cairo_format_t Format; + typedef cairo_content_t Content; + typedef cairo_pattern_t Pattern; + + typedef boost::shared_ptr<cairo_surface_t> CairoSurfaceSharedPtr; + typedef boost::shared_ptr<Cairo> CairoSharedPtr; + + const SystemEnvData* GetSysData(const Window *pOutputWindow); + + /** Cairo surface interface + + For each cairo-supported platform, there's an implementation of + this interface + */ + struct Surface + { + public: + virtual ~Surface() {} + + // Query methods + virtual CairoSharedPtr getCairo() const = 0; + virtual CairoSurfaceSharedPtr getCairoSurface() const = 0; + virtual boost::shared_ptr<Surface> getSimilar( Content aContent, int width, int height ) const = 0; + + /// factory for VirDev on this surface + virtual boost::shared_ptr<VirtualDevice> createVirtualDevice() const = 0; + + /// Resize the surface (possibly destroying content) + virtual void Resize( int width, int height ) = 0; + + /// Flush all pending output to surface + virtual void flush() const = 0; + }; + + typedef boost::shared_ptr<Surface> SurfaceSharedPtr; + + /// Create Surface from given cairo surface + SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface ); + /// Create surface with given dimensions + SurfaceSharedPtr createSurface( const OutputDevice& rRefDevice, + int x, int y, int width, int height ); + /// Create Surface for given bitmap data + SurfaceSharedPtr createBitmapSurface( const OutputDevice& rRefDevice, + const BitmapSystemData& rData, + const Size& rSize ); + + /// Check whether cairo will work on given window + bool IsCairoWorking( OutputDevice* ); +} + +#endif diff --git a/canvas/source/cairo/cairo_canvas.cxx b/canvas/source/cairo/cairo_canvas.cxx new file mode 100644 index 000000000000..54d04158c993 --- /dev/null +++ b/canvas/source/cairo/cairo_canvas.cxx @@ -0,0 +1,195 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <osl/mutex.hxx> + +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <toolkit/helper/vclunohelper.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#ifdef WNT +# include <tools/prewin.h> +# include <windows.h> +# include <tools/postwin.h> +#endif + +#include <vcl/sysdata.hxx> + +#include "cairo_canvas.hxx" + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + Canvas::Canvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ) + { + } + + void Canvas::initialize() + { + // #i64742# Only perform initialization when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + /* maArguments: + 0: ptr to creating instance (Window or VirtualDevice) + 1: SystemEnvData as a streamed Any (or empty for VirtualDevice) + 2: current bounds of creating instance + 3: bool, denoting always on top state for Window (always false for VirtualDevice) + 4: XWindow for creating Window (or empty for VirtualDevice) + 5: SystemGraphicsData as a streamed Any + */ + VERBOSE_TRACE("Canvas created %p\n", this); + + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 6 && + maArguments[0].getValueTypeClass() == uno::TypeClass_HYPER && + maArguments[5].getValueTypeClass() == uno::TypeClass_SEQUENCE, + "Canvas::initialize: wrong number of arguments, or wrong types" ); + + // We expect a single Any here, containing a pointer to a valid + // VCL output device, on which to output (mostly needed for text) + sal_Int64 nPtr = 0; + maArguments[0] >>= nPtr; + OutputDevice* pOutDev = reinterpret_cast<OutputDevice*>(nPtr); + + ENSURE_ARG_OR_THROW( pOutDev != NULL, + "Canvas::initialize: invalid OutDev pointer" ); + + awt::Rectangle aBounds; + maArguments[2] >>= aBounds; + + uno::Sequence<sal_Int8> aSeq; + maArguments[5] >>= aSeq; + + const SystemGraphicsData* pSysData=reinterpret_cast<const SystemGraphicsData*>(aSeq.getConstArray()); + if( !pSysData || !pSysData->nSize ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed SystemGraphicsData invalid!")), + NULL); + + bool bHasXRender = IsCairoWorking(pOutDev); + ENSURE_ARG_OR_THROW( bHasXRender == true, + "SpriteCanvas::SpriteCanvas: No RENDER extension" ); + + // setup helper + maDeviceHelper.init( *this, + *pOutDev ); + + maCanvasHelper.init( basegfx::B2ISize(aBounds.Width, aBounds.Height), + *this, this ); + + // forward surface to render on to canvashelper + maCanvasHelper.setSurface( + maDeviceHelper.getSurface(), + false ); + + maArguments.realloc(0); + } + + Canvas::~Canvas() + { + OSL_TRACE( "CairoCanvas destroyed" ); + } + + void SAL_CALL Canvas::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mxComponentContext.clear(); + + // forward to parent + CanvasBaseT::disposing(); + } + + ::rtl::OUString SAL_CALL Canvas::getServiceName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CANVAS_SERVICE_NAME ) ); + } + + bool Canvas::repaint( const SurfaceSharedPtr& pSurface, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return maCanvasHelper.repaint( pSurface, viewState, renderState ); + } + + SurfaceSharedPtr Canvas::getSurface() + { + return maDeviceHelper.getSurface(); + } + + SurfaceSharedPtr Canvas::createSurface( const ::basegfx::B2ISize& rSize, Content aContent ) + { + return maDeviceHelper.createSurface( rSize, aContent ); + } + + SurfaceSharedPtr Canvas::createSurface( ::Bitmap& rBitmap ) + { + SurfaceSharedPtr pSurface; + + BitmapSystemData aData; + if( rBitmap.GetSystemData( aData ) ) { + const Size& rSize = rBitmap.GetSizePixel(); + + pSurface = maDeviceHelper.createSurface( aData, rSize ); + } + + return pSurface; + } + + SurfaceSharedPtr Canvas::changeSurface( bool, bool ) + { + // non-modifiable surface here + return SurfaceSharedPtr(); + } + + OutputDevice* Canvas::getOutputDevice() + { + return maDeviceHelper.getOutputDevice(); + } +} diff --git a/canvas/source/cairo/cairo_canvas.hxx b/canvas/source/cairo/cairo_canvas.hxx new file mode 100644 index 000000000000..bbcb89c54c7d --- /dev/null +++ b/canvas/source/cairo/cairo_canvas.hxx @@ -0,0 +1,161 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_CANVAS_HXX_ +#define _CAIROCANVAS_CANVAS_HXX_ + +#include <rtl/ref.hxx> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/awt/XWindowListener.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include <cppuhelper/compbase7.hxx> +#include <comphelper/uno3.hxx> + +#include <canvas/base/spritecanvasbase.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/bufferedgraphicdevicebase.hxx> + +#include <basegfx/vector/b2isize.hxx> + +#include "cairo_devicehelper.hxx" +#include "cairo_repainttarget.hxx" +#include "cairo_surfaceprovider.hxx" +#include "cairo_spritecanvashelper.hxx" + +#define CANVAS_SERVICE_NAME "com.sun.star.rendering.Canvas.Cairo" +#define CANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.Canvas.Cairo" + +namespace cairocanvas +{ + typedef ::cppu::WeakComponentImplHelper7< ::com::sun::star::rendering::XBitmapCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::rendering::XGraphicDevice, + ::com::sun::star::lang::XMultiServiceFactory, + ::com::sun::star::util::XUpdatable, + ::com::sun::star::beans::XPropertySet, + ::com::sun::star::lang::XServiceName > GraphicDeviceBase_Base; + typedef ::canvas::GraphicDeviceBase< ::canvas::BaseMutexHelper< GraphicDeviceBase_Base >, + DeviceHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBase_Base; + + /** Mixin SurfaceProvider + + Have to mixin the SurfaceProvider before deriving from + ::canvas::CanvasBase, as this template should already + implement some of those interface methods. + + The reason why this appears kinda convoluted is the fact that + we cannot specify non-IDL types as WeakComponentImplHelperN + template args, and furthermore, don't want to derive + ::canvas::CanvasBase directly from + SurfaceProvider (because derivees of + ::canvas::CanvasBase have to explicitely forward the + XInterface methods (e.g. via DECLARE_UNO3_AGG_DEFAULTS) + anyway). + */ + class CanvasBaseSurfaceProvider_Base : public CanvasBase_Base, + public SurfaceProvider + { + }; + + typedef ::canvas::IntegerBitmapBase< CanvasBaseSurfaceProvider_Base, + CanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBaseT; + + /** Product of this component's factory. + + The Canvas object combines the actual Window canvas with + the XGraphicDevice interface. This is because there's a + one-to-one relation between them, anyway, since each window + can have exactly one canvas and one associated + XGraphicDevice. And to avoid messing around with circular + references, this is implemented as one single object. + */ + class Canvas : public CanvasBaseT, + public RepaintTarget + { + public: + Canvas( const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Any >& aArguments, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& rxContext ); + + void initialize(); + + /// For resource tracking + ~Canvas(); + +#if defined __SUNPRO_CC + using CanvasBaseT::disposing; +#endif + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // Forwarding the XComponent implementation to the + // cppu::ImplHelper templated base + // Classname Base doing refcounting Base implementing the XComponent interface + // | | | + // V V V + DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( Canvas, GraphicDeviceBase_Base, ::cppu::WeakComponentImplHelperBase ); + + // XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (::com::sun::star::uno::RuntimeException); + + // RepaintTarget + virtual bool repaint( const ::cairo::SurfaceSharedPtr& pSurface, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + // SurfaceProvider + virtual SurfaceSharedPtr getSurface(); + virtual SurfaceSharedPtr createSurface( const ::basegfx::B2ISize& rSize, Content aContent = CAIRO_CONTENT_COLOR_ALPHA ); + virtual SurfaceSharedPtr createSurface( ::Bitmap& rBitmap ); + virtual SurfaceSharedPtr changeSurface( bool bHasAlpha, bool bCopyContent ); + virtual OutputDevice* getOutputDevice(); + + private: + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > maArguments; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > mxComponentContext; + }; + + typedef ::rtl::Reference< Canvas > CanvasRef; +} + +#endif diff --git a/canvas/source/cairo/cairo_canvasbitmap.cxx b/canvas/source/cairo/cairo_canvasbitmap.cxx new file mode 100644 index 000000000000..445839ca0127 --- /dev/null +++ b/canvas/source/cairo/cairo_canvasbitmap.cxx @@ -0,0 +1,286 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include "cairo_canvasbitmap.hxx" + +#ifdef CAIRO_HAS_XLIB_SURFACE +# include "cairo_xlib_cairo.hxx" +#elif defined CAIRO_HAS_QUARTZ_SURFACE +# include "cairo_quartz_cairo.hxx" +#elif defined CAIRO_HAS_WIN32_SURFACE +# include "cairo_win32_cairo.hxx" +# include <cairo-win32.h> +#else +# error Native API needed. +#endif + +using namespace ::cairo; +using namespace ::com::sun::star; + +#ifdef CAIRO_HAS_WIN32_SURFACE +namespace +{ + HBITMAP surface2HBitmap( const SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize ) + { + // cant seem to retrieve HBITMAP from cairo. copy content then + HDC hScreenDC=GetDC(NULL); + HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, + rSize.getX(), + rSize.getY() ); + + HDC hBmpDC = CreateCompatibleDC( 0 ); + HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hBmpBitmap ); + + BitBlt( hBmpDC, 0, 0, rSize.getX(), rSize.getX(), + cairo_win32_surface_get_dc(rSurface->getCairoSurface().get()), + 0, 0, SRCCOPY ); + + SelectObject( hBmpDC, hBmpOld ); + DeleteDC( hBmpDC ); + + return hBmpBitmap; + } +} +#endif + +namespace cairocanvas +{ + CanvasBitmap::CanvasBitmap( const ::basegfx::B2ISize& rSize, + const SurfaceProviderRef& rSurfaceProvider, + rendering::XGraphicDevice* pDevice, + bool bHasAlpha ) : + mpSurfaceProvider( rSurfaceProvider ), + mpBufferSurface(), + mpBufferCairo(), + maSize(rSize), + mbHasAlpha(bHasAlpha) + { + ENSURE_OR_THROW( mpSurfaceProvider.is(), + "CanvasBitmap::CanvasBitmap(): Invalid surface or device" ); + + OSL_TRACE( "bitmap size: %dx%d", rSize.getX(), rSize.getY() ); + + mpBufferSurface = mpSurfaceProvider->createSurface( rSize, bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR ); + mpBufferCairo = mpBufferSurface->getCairo(); + + maCanvasHelper.init( rSize, *mpSurfaceProvider, pDevice ); + maCanvasHelper.setSurface( mpBufferSurface, bHasAlpha ); + + // clear bitmap to 100% transparent + maCanvasHelper.clear(); + } + + void SAL_CALL CanvasBitmap::disposing() + { + mpSurfaceProvider.clear(); + + mpBufferCairo.reset(); + mpBufferSurface.reset(); + + // forward to parent + CanvasBitmap_Base::disposing(); + } + + SurfaceSharedPtr CanvasBitmap::getSurface() + { + return mpBufferSurface; + } + + SurfaceSharedPtr CanvasBitmap::createSurface( const ::basegfx::B2ISize& rSize, Content aContent ) + { + return mpSurfaceProvider->createSurface(rSize,aContent); + } + + SurfaceSharedPtr CanvasBitmap::createSurface( ::Bitmap& rBitmap ) + { + return mpSurfaceProvider->createSurface(rBitmap); + } + + SurfaceSharedPtr CanvasBitmap::changeSurface( bool, bool ) + { + // non-modifiable surface here + return SurfaceSharedPtr(); + } + + OutputDevice* CanvasBitmap::getOutputDevice() + { + return mpSurfaceProvider->getOutputDevice(); + } + + bool CanvasBitmap::repaint( const SurfaceSharedPtr& pSurface, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return maCanvasHelper.repaint( pSurface, viewState, renderState ); + } + + uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle ) throw (uno::RuntimeException) + { + uno::Any aRV( sal_Int32(0) ); + // 0 ... get BitmapEx + // 1 ... get Pixbuf with bitmap RGB content + // 2 ... get Pixbuf with bitmap alpha mask + switch( nHandle ) + { + case 0: + { + aRV = uno::Any( reinterpret_cast<sal_Int64>( (BitmapEx*) NULL ) ); + break; + } + case 1: + { +#ifdef CAIRO_HAS_XLIB_SURFACE + X11Surface* pXlibSurface=dynamic_cast<X11Surface*>(mpBufferSurface.get()); + OSL_ASSERT(pXlibSurface); + uno::Sequence< uno::Any > args( 3 ); + args[0] = uno::Any( false ); // do not call XFreePixmap on it + args[1] = uno::Any( pXlibSurface->getPixmap()->mhDrawable ); + args[2] = uno::Any( sal_Int32( pXlibSurface->getDepth() ) ); + + aRV = uno::Any( args ); +#elif defined CAIRO_HAS_QUARTZ_SURFACE + QuartzSurface* pQuartzSurface = dynamic_cast<QuartzSurface*>(mpBufferSurface.get()); + OSL_ASSERT(pQuartzSurface); + uno::Sequence< uno::Any > args( 1 ); + args[0] = uno::Any( sal_IntPtr (pQuartzSurface->getCGContext()) ); + aRV = uno::Any( args ); +#elif defined CAIRO_HAS_WIN32_SURFACE + // TODO(F2): check whether under all circumstances, + // the alpha channel is ignored here. + uno::Sequence< uno::Any > args( 1 ); + args[1] = uno::Any( sal_Int64(surface2HBitmap(mpBufferSurface,maSize)) ); + + aRV = uno::Any( args ); + // caller frees the bitmap +#else +# error Please define fast prop retrieval for your platform! +#endif + break; + } + case 2: + { +#ifdef CAIRO_HAS_XLIB_SURFACE + uno::Sequence< uno::Any > args( 3 ); + SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR ); + CairoSharedPtr pAlphaCairo = pAlphaSurface->getCairo(); + X11Surface* pXlibSurface=dynamic_cast<X11Surface*>(pAlphaSurface.get()); + OSL_ASSERT(pXlibSurface); + + // create RGB image (levels of gray) of alpha channel of original picture + cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 ); + cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pAlphaCairo.get() ); + cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 ); + cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR ); + cairo_paint( pAlphaCairo.get() ); + pAlphaCairo.reset(); + + X11PixmapSharedPtr pPixmap = pXlibSurface->getPixmap(); + args[0] = uno::Any( true ); + args[1] = ::com::sun::star::uno::Any( pPixmap->mhDrawable ); + args[2] = ::com::sun::star::uno::Any( sal_Int32( pXlibSurface->getDepth () ) ); + pPixmap->clear(); // caller takes ownership of pixmap + + // return pixmap and alphachannel pixmap - it will be used in BitmapEx + aRV = uno::Any( args ); +#elif defined CAIRO_HAS_QUARTZ_SURFACE + SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR ); + CairoSharedPtr pAlphaCairo = pAlphaSurface->getCairo(); + QuartzSurface* pQuartzSurface=dynamic_cast<QuartzSurface*>(pAlphaSurface.get()); + OSL_ASSERT(pQuartzSurface); + + // create RGB image (levels of gray) of alpha channel of original picture + cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 ); + cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pAlphaCairo.get() ); + cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 ); + cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR ); + cairo_paint( pAlphaCairo.get() ); + pAlphaCairo.reset(); + + uno::Sequence< uno::Any > args( 1 ); + args[0] = uno::Any( sal_IntPtr (pQuartzSurface->getCGContext()) ); + // return ??? and alphachannel ??? - it will be used in BitmapEx + aRV = uno::Any( args ); +#elif defined CAIRO_HAS_WIN32_SURFACE + SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR ); + CairoSharedPtr pAlphaCairo = pAlphaSurface->getCairo(); + + // create RGB image (levels of gray) of alpha channel of original picture + cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 ); + cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pAlphaCairo.get() ); + cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 ); + cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR ); + cairo_paint( pAlphaCairo.get() ); + pAlphaCairo.reset(); + + // cant seem to retrieve HBITMAP from cairo. copy content then + uno::Sequence< uno::Any > args( 1 ); + args[1] = uno::Any( sal_Int64(surface2HBitmap(pAlphaSurface,maSize)) ); + + aRV = uno::Any( args ); + // caller frees the bitmap +#else +# error Please define fast prop retrieval for your platform! +#endif + break; + } + } + + return aRV; + } + +#define IMPLEMENTATION_NAME "CairoCanvas.CanvasBitmap" +#define SERVICE_NAME "com.sun.star.rendering.CanvasBitmap" + + ::rtl::OUString SAL_CALL CanvasBitmap::getImplementationName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL CanvasBitmap::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL CanvasBitmap::getSupportedServiceNames( ) throw (uno::RuntimeException) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } + +} diff --git a/canvas/source/cairo/cairo_canvasbitmap.hxx b/canvas/source/cairo/cairo_canvasbitmap.hxx new file mode 100644 index 000000000000..5597a5ade004 --- /dev/null +++ b/canvas/source/cairo/cairo_canvasbitmap.hxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_CANVASBITMAP_HXX +#define _CAIROCANVAS_CANVASBITMAP_HXX + +#include <cppuhelper/compbase4.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <comphelper/uno3.hxx> + +#include <basegfx/vector/b2isize.hxx> + +#include <boost/shared_ptr.hpp> + +#include <canvas/base/integerbitmapbase.hxx> + +#include "cairo_cairo.hxx" +#include "cairo_canvashelper.hxx" +#include "cairo_repainttarget.hxx" +#include "cairo_spritecanvas.hxx" + + +/* Definition of CanvasBitmap class */ + +namespace cairocanvas +{ + typedef ::cppu::WeakComponentImplHelper4< ::com::sun::star::rendering::XBitmapCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::lang::XServiceInfo, + ::com::sun::star::beans::XFastPropertySet > CanvasBitmapBase_Base; + class CanvasBitmapSpriteSurface_Base : + public ::canvas::BaseMutexHelper<CanvasBitmapBase_Base>, + public SurfaceProvider + { + }; + + typedef ::canvas::IntegerBitmapBase< + CanvasBitmapSpriteSurface_Base, + CanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBitmap_Base; + + class CanvasBitmap : public CanvasBitmap_Base, + public RepaintTarget + { + public: + /** Create a canvas bitmap for the given surface + + @param rSize + Size of the bitmap + + @param rDevice + Reference device, with which bitmap should be compatible + */ + CanvasBitmap( const ::basegfx::B2ISize& rSize, + const SurfaceProviderRef& rDevice, + ::com::sun::star::rendering::XGraphicDevice* pDevice, + bool bHasAlpha ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // Forwarding the XComponent implementation to the + // cppu::ImplHelper templated base + // Classname Base doing refcounting Base implementing the XComponent interface + // | | | + // V V V + DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( CanvasBitmap, CanvasBitmapBase_Base, ::cppu::WeakComponentImplHelperBase ); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException); + + // SurfaceProvider + virtual SurfaceSharedPtr getSurface(); + virtual SurfaceSharedPtr createSurface( const ::basegfx::B2ISize& rSize, Content aContent = CAIRO_CONTENT_COLOR_ALPHA ); + virtual SurfaceSharedPtr createSurface( ::Bitmap& rBitmap ); + virtual SurfaceSharedPtr changeSurface( bool bHasAlpha, bool bCopyContent ); + virtual OutputDevice* getOutputDevice(); + + // RepaintTarget + virtual bool repaint( const SurfaceSharedPtr& pSurface, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + // XFastPropertySet + // used to retrieve BitmapEx pointer or X Pixmap handles for this bitmap + // handle values have these meanings: + // 0 ... get pointer to BitmapEx + // 1 ... get X pixmap handle to rgb content + // 2 ... get X pitmap handle to alpha mask + // returned any contains either BitmapEx pointer or array of three Any value + // 1st a bool value: true - free the pixmap after used by XFreePixmap, false do nothing, the pixmap is used internally in the canvas + // 2nd the pixmap handle + // 3rd the pixmap depth + virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setFastPropertyValue(sal_Int32, const ::com::sun::star::uno::Any&) throw (::com::sun::star::uno::RuntimeException) {} + + private: + SurfaceProviderRef mpSurfaceProvider; + ::cairo::SurfaceSharedPtr mpBufferSurface; + ::cairo::CairoSharedPtr mpBufferCairo; + + const ::basegfx::B2ISize maSize; + const bool mbHasAlpha; + }; +} + +#endif /* _CAIROCANVAS_CANVASBITMAP_HXX */ diff --git a/canvas/source/cairo/cairo_canvascustomsprite.cxx b/canvas/source/cairo/cairo_canvascustomsprite.cxx new file mode 100644 index 000000000000..ad9a743da885 --- /dev/null +++ b/canvas/source/cairo/cairo_canvascustomsprite.cxx @@ -0,0 +1,175 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> + +#include <canvas/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> + +#include "cairo_canvascustomsprite.hxx" +#include "cairo_spritecanvas.hxx" + + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + CanvasCustomSprite::CanvasCustomSprite( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rRefDevice ) : + mpSpriteCanvas( rRefDevice ), + maSize( ::canvas::tools::roundUp( rSpriteSize.Width ), + ::canvas::tools::roundUp( rSpriteSize.Height ) ) + { + ENSURE_OR_THROW( rRefDevice.get(), + "CanvasCustomSprite::CanvasCustomSprite(): Invalid sprite canvas" ); + + OSL_TRACE("sprite size: %d, %d", + ::canvas::tools::roundUp( rSpriteSize.Width ), + ::canvas::tools::roundUp( rSpriteSize.Height )); + + mpBufferSurface = mpSpriteCanvas->createSurface( maSize ); + + maCanvasHelper.init( maSize, + *rRefDevice, + rRefDevice.get() ); + maCanvasHelper.setSurface( mpBufferSurface, true ); + + maSpriteHelper.init( rSpriteSize, + rRefDevice ); + maSpriteHelper.setSurface( mpBufferSurface ); + + // clear sprite to 100% transparent + maCanvasHelper.clear(); + } + + void SAL_CALL CanvasCustomSprite::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpSpriteCanvas.clear(); + mpBufferSurface.reset(); + + // forward to parent + CanvasCustomSpriteBaseT::disposing(); + } + + void CanvasCustomSprite::redraw( const CairoSharedPtr& pCairo, + bool bBufferedUpdate ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + redraw( pCairo, maSpriteHelper.getPosPixel(), bBufferedUpdate ); + } + + void CanvasCustomSprite::redraw( const CairoSharedPtr& pCairo, + const ::basegfx::B2DPoint& rOrigOutputPos, + bool bBufferedUpdate ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + maSpriteHelper.redraw( pCairo, + rOrigOutputPos, + mbSurfaceDirty, + bBufferedUpdate ); + + mbSurfaceDirty = false; + } + + bool CanvasCustomSprite::repaint( const SurfaceSharedPtr& pSurface, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return maCanvasHelper.repaint( pSurface, viewState, renderState ); + } + + SurfaceSharedPtr CanvasCustomSprite::getSurface() + { + return mpBufferSurface; + } + + SurfaceSharedPtr CanvasCustomSprite::createSurface( const ::basegfx::B2ISize& rSize, Content aContent ) + { + return mpSpriteCanvas->createSurface(rSize,aContent); + } + + SurfaceSharedPtr CanvasCustomSprite::createSurface( ::Bitmap& rBitmap ) + { + return mpSpriteCanvas->createSurface(rBitmap); + } + + SurfaceSharedPtr CanvasCustomSprite::changeSurface( bool bHasAlpha, bool bCopyContent ) + { + if( !bHasAlpha && !bCopyContent ) + { + OSL_TRACE("replacing sprite background surface"); + + mpBufferSurface = mpSpriteCanvas->createSurface( maSize, CAIRO_CONTENT_COLOR ); + maSpriteHelper.setSurface( mpBufferSurface ); + + return mpBufferSurface; + } + + return SurfaceSharedPtr(); + } + + OutputDevice* CanvasCustomSprite::getOutputDevice() + { + return mpSpriteCanvas->getOutputDevice(); + } + +#define IMPLEMENTATION_NAME "CairoCanvas.CanvasCustomSprite" +#define SERVICE_NAME "com.sun.star.rendering.CanvasCustomSprite" + + ::rtl::OUString SAL_CALL CanvasCustomSprite::getImplementationName() throw( uno::RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL CanvasCustomSprite::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException ) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL CanvasCustomSprite::getSupportedServiceNames() throw( uno::RuntimeException ) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } +} diff --git a/canvas/source/cairo/cairo_canvascustomsprite.hxx b/canvas/source/cairo/cairo_canvascustomsprite.hxx new file mode 100644 index 000000000000..abebdc85d917 --- /dev/null +++ b/canvas/source/cairo/cairo_canvascustomsprite.hxx @@ -0,0 +1,156 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_CANVASCUSTOMSPRITE_HXX +#define _CAIROCANVAS_CANVASCUSTOMSPRITE_HXX + +#include <cppuhelper/compbase4.hxx> +#include <comphelper/uno3.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/rendering/XCustomSprite.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/canvascustomspritebase.hxx> + +#include "cairo_sprite.hxx" +#include "cairo_cairo.hxx" +#include "cairo_canvashelper.hxx" +#include "cairo_repainttarget.hxx" +#include "cairo_spritehelper.hxx" +#include "cairo_spritecanvas.hxx" + + +namespace cairocanvas +{ + typedef ::cppu::WeakComponentImplHelper4< ::com::sun::star::rendering::XCustomSprite, + ::com::sun::star::rendering::XBitmapCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::lang::XServiceInfo > CanvasCustomSpriteBase_Base; + /** Mixin Sprite + + Have to mixin the Sprite interface before deriving from + ::canvas::CanvasCustomSpriteBase, as this template should + already implement some of those interface methods. + + The reason why this appears kinda convoluted is the fact that + we cannot specify non-IDL types as WeakComponentImplHelperN + template args, and furthermore, don't want to derive + ::canvas::CanvasCustomSpriteBase directly from + ::canvas::Sprite (because derivees of + ::canvas::CanvasCustomSpriteBase have to explicitely forward + the XInterface methods (e.g. via DECLARE_UNO3_AGG_DEFAULTS) + anyway). Basically, ::canvas::CanvasCustomSpriteBase should + remain a base class that provides implementation, not to + enforce any specific interface on its derivees. + */ + class CanvasCustomSpriteSpriteBase_Base : public ::canvas::BaseMutexHelper< CanvasCustomSpriteBase_Base >, + public Sprite, + public SurfaceProvider + { + }; + + typedef ::canvas::CanvasCustomSpriteBase< CanvasCustomSpriteSpriteBase_Base, + SpriteHelper, + CanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasCustomSpriteBaseT; + + /* Definition of CanvasCustomSprite class */ + + class CanvasCustomSprite : public CanvasCustomSpriteBaseT, + public RepaintTarget + { + public: + /** Create a custom sprite + + @param rSpriteSize + Size of the sprite in pixel + + @param rRefDevice + Associated output device + + @param rSpriteCanvas + Target canvas + + @param rDevice + Target DX device + */ + CanvasCustomSprite( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rRefDevice ); + + virtual void SAL_CALL disposing(); + + // Forwarding the XComponent implementation to the + // cppu::ImplHelper templated base + // Classname Base doing refcount Base implementing the XComponent interface + // | | | + // V V V + DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( CanvasCustomSprite, CanvasCustomSpriteBase_Base, ::cppu::WeakComponentImplHelperBase ); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ); + + // Sprite + virtual void redraw( const ::cairo::CairoSharedPtr& pCairo, + bool bBufferedUpdate ) const; + virtual void redraw( const ::cairo::CairoSharedPtr& pCairo, + const ::basegfx::B2DPoint& rOrigOutputPos, + bool bBufferedUpdate ) const; + + // RepaintTarget + virtual bool repaint( const ::cairo::SurfaceSharedPtr& pSurface, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + // SurfaceProvider + virtual SurfaceSharedPtr getSurface(); + virtual SurfaceSharedPtr createSurface( const ::basegfx::B2ISize& rSize, Content aContent = CAIRO_CONTENT_COLOR_ALPHA ); + virtual SurfaceSharedPtr createSurface( ::Bitmap& rBitmap ); + virtual SurfaceSharedPtr changeSurface( bool bHasAlpha, bool bCopyContent ); + virtual OutputDevice* getOutputDevice(); + + private: + /** MUST hold here, too, since CanvasHelper only contains a + raw pointer (without refcounting) + */ + SpriteCanvasRef mpSpriteCanvas; + ::cairo::SurfaceSharedPtr mpBufferSurface; + ::basegfx::B2ISize maSize; + }; +} + +#endif /* _CAIROCANVAS_CANVASCUSTOMSPRITE_HXX */ diff --git a/canvas/source/cairo/cairo_canvasfont.cxx b/canvas/source/cairo/cairo_canvasfont.cxx new file mode 100644 index 000000000000..452280728151 --- /dev/null +++ b/canvas/source/cairo/cairo_canvasfont.cxx @@ -0,0 +1,193 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> + +#include <rtl/math.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <vcl/metric.hxx> +#include <i18npool/mslangid.hxx> + +#include "cairo_canvasfont.hxx" +#include "cairo_textlayout.hxx" + +using namespace ::com::sun::star; + +namespace cairocanvas +{ + namespace + { + // Little helper to encapsulate locking into policy class + class LocalGuard + { + public: + LocalGuard() : + aGuard( Application::GetSolarMutex() ) + { + } + + /// To be compatible with CanvasBase mutex concept + LocalGuard( const ::osl::Mutex& ) : + aGuard( Application::GetSolarMutex() ) + { + } + + private: + ::vos::OGuard aGuard; + }; + } + + CanvasFont::CanvasFont( const rendering::FontRequest& rFontRequest, + const uno::Sequence< beans::PropertyValue >& /*rExtraFontProperties*/, + const geometry::Matrix2D& rFontMatrix, + const SurfaceProviderRef& rDevice ) : + CanvasFont_Base( m_aMutex ), + maFont( Font( rFontRequest.FontDescription.FamilyName, + rFontRequest.FontDescription.StyleName, + Size( 0, ::basegfx::fround(rFontRequest.CellSize) ) ) ), + maFontRequest( rFontRequest ), + mpRefDevice( rDevice ) + { + maFont->SetAlign( ALIGN_BASELINE ); + maFont->SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); + maFont->SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? TRUE : FALSE ); + + // TODO(F2): improve panose->vclenum conversion + maFont->SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) ); + maFont->SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL ); + + maFont->SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest.Locale)); + + // adjust to stretched/shrinked font + if( !::rtl::math::approxEqual( rFontMatrix.m00, rFontMatrix.m11) ) + { + OutputDevice* pOutDev( mpRefDevice->getOutputDevice() ); + + if( pOutDev ) + { + const bool bOldMapState( pOutDev->IsMapModeEnabled() ); + pOutDev->EnableMapMode(FALSE); + + const Size aSize = pOutDev->GetFontMetric( *maFont ).GetSize(); + + const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 ); + double fStretch = (rFontMatrix.m00 + rFontMatrix.m01); + + if( !::basegfx::fTools::equalZero( fDividend) ) + fStretch /= fDividend; + + const long nNewWidth = ::basegfx::fround( aSize.Width() * fStretch ); + + maFont->SetWidth( nNewWidth ); + + pOutDev->EnableMapMode(bOldMapState); + } + } + } + + void SAL_CALL CanvasFont::disposing() + { + LocalGuard aGuard; + + mpRefDevice.clear(); + } + + uno::Reference< rendering::XTextLayout > SAL_CALL CanvasFont::createTextLayout( const rendering::StringContext& aText, sal_Int8 nDirection, sal_Int64 nRandomSeed ) throw (uno::RuntimeException) + { + LocalGuard aGuard; + + if( !mpRefDevice.is() ) + return uno::Reference< rendering::XTextLayout >(); // we're disposed + + return new TextLayout( aText, + nDirection, + nRandomSeed, + Reference( this ), + mpRefDevice ); + } + + rendering::FontRequest SAL_CALL CanvasFont::getFontRequest( ) throw (uno::RuntimeException) + { + LocalGuard aGuard; + + return maFontRequest; + } + + rendering::FontMetrics SAL_CALL CanvasFont::getFontMetrics( ) throw (uno::RuntimeException) + { + LocalGuard aGuard; + + // TODO(F1) + return rendering::FontMetrics(); + } + + uno::Sequence< double > SAL_CALL CanvasFont::getAvailableSizes( ) throw (uno::RuntimeException) + { + LocalGuard aGuard; + + // TODO(F1) + return uno::Sequence< double >(); + } + + uno::Sequence< beans::PropertyValue > SAL_CALL CanvasFont::getExtraFontProperties( ) throw (uno::RuntimeException) + { + LocalGuard aGuard; + + // TODO(F1) + return uno::Sequence< beans::PropertyValue >(); + } + +#define IMPLEMENTATION_NAME "CairoCanvas::CanvasFont" +#define SERVICE_NAME "com.sun.star.rendering.CanvasFont" + + ::rtl::OUString SAL_CALL CanvasFont::getImplementationName() throw( uno::RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL CanvasFont::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException ) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL CanvasFont::getSupportedServiceNames() throw( uno::RuntimeException ) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } + + ::Font CanvasFont::getVCLFont() const + { + return *maFont; + } +} diff --git a/canvas/source/cairo/cairo_canvasfont.hxx b/canvas/source/cairo/cairo_canvasfont.hxx new file mode 100644 index 000000000000..9b59ca57fa52 --- /dev/null +++ b/canvas/source/cairo/cairo_canvasfont.hxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_CANVASFONT_HXX +#define _CAIROCANVAS_CANVASFONT_HXX + +#include <comphelper/implementationreference.hxx> + +#include <cppuhelper/compbase2.hxx> +#include <comphelper/broadcasthelper.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/geometry/Matrix2D.hpp> +#include <com/sun/star/rendering/FontRequest.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> + +#include <vcl/font.hxx> + +#include <canvas/vclwrapper.hxx> + +#include "cairo_spritecanvas.hxx" + +#include <boost/utility.hpp> + + +/* Definition of CanvasFont class */ + +namespace cairocanvas +{ + typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XCanvasFont, + ::com::sun::star::lang::XServiceInfo > CanvasFont_Base; + + class CanvasFont : public ::comphelper::OBaseMutex, + public CanvasFont_Base, + private ::boost::noncopyable + { + public: + typedef ::comphelper::ImplementationReference< + CanvasFont, + ::com::sun::star::rendering::XCanvasFont > Reference; + + CanvasFont( const ::com::sun::star::rendering::FontRequest& fontRequest, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& extraFontProperties, + const ::com::sun::star::geometry::Matrix2D& rFontMatrix, + const SurfaceProviderRef& rDevice ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // XCanvasFont + virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XTextLayout > SAL_CALL createTextLayout( const ::com::sun::star::rendering::StringContext& aText, sal_Int8 nDirection, sal_Int64 nRandomSeed ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::FontRequest SAL_CALL getFontRequest( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::FontMetrics SAL_CALL getFontMetrics( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< double > SAL_CALL getAvailableSizes( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getExtraFontProperties( ) throw (::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ); + + ::Font getVCLFont() const; + + private: + ::canvas::vcltools::VCLObject<Font> maFont; + ::com::sun::star::rendering::FontRequest maFontRequest; + SurfaceProviderRef mpRefDevice; + }; + +} + +#endif /* _CAIROCANVAS_CANVASFONT_HXX */ diff --git a/canvas/source/cairo/cairo_canvashelper.cxx b/canvas/source/cairo/cairo_canvashelper.cxx new file mode 100644 index 000000000000..60647d4f8224 --- /dev/null +++ b/canvas/source/cairo/cairo_canvashelper.cxx @@ -0,0 +1,1996 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> +#include <rtl/instance.hxx> + +#include <com/sun/star/util/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 <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp> +#include <com/sun/star/rendering/IntegerBitmapLayout.hpp> +#include <com/sun/star/rendering/ColorSpaceType.hpp> +#include <com/sun/star/rendering/ColorComponentTag.hpp> +#include <com/sun/star/rendering/RenderingIntent.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/tools/keystoplerp.hxx> +#include <basegfx/tools/lerp.hxx> + +#include <comphelper/sequence.hxx> +#include <cppuhelper/compbase1.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 <boost/tuple/tuple.hpp> +#include <algorithm> + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + CanvasHelper::CanvasHelper() : + mpSurfaceProvider(NULL), + mpDevice(NULL), + mpVirtualDevice(), + mbHaveAlpha(), + mpCairo(), + mpSurface(), + maSize() + { + } + + void CanvasHelper::disposing() + { + mpSurface.reset(); + mpCairo.reset(); + mpVirtualDevice.reset(); + mpDevice = NULL; + mpSurfaceProvider = NULL; + } + + void CanvasHelper::init( const ::basegfx::B2ISize& rSizePixel, + SurfaceProvider& rSurfaceProvider, + rendering::XGraphicDevice* pDevice ) + { + maSize = rSizePixel; + mpSurfaceProvider = &rSurfaceProvider; + mpDevice = pDevice; + } + + void CanvasHelper::setSize( const ::basegfx::B2ISize& rSize ) + { + maSize = rSize; + } + + void CanvasHelper::setSurface( const SurfaceSharedPtr& pSurface, bool bHasAlpha ) + { + mbHaveAlpha = bHasAlpha; + mpVirtualDevice.reset(); + mpSurface = pSurface; + mpCairo = pSurface->getCairo(); + } + + static void setColor( Cairo* pCairo, + const uno::Sequence<double>& rColor ) + { + if( rColor.getLength() > 3 ) + { + const double alpha = rColor[3]; + + cairo_set_source_rgba( pCairo, + alpha*rColor[0], + alpha*rColor[1], + alpha*rColor[2], + alpha ); + } + else if( rColor.getLength() == 3 ) + cairo_set_source_rgb( pCairo, + rColor[0], + rColor[1], + rColor[2] ); + } + + void CanvasHelper::useStates( const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + bool bSetColor ) + { + 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"); + + aViewMatrix.x0 = basegfx::fround( aViewMatrix.x0 ); + aViewMatrix.y0 = basegfx::fround( aViewMatrix.y0 ); + cairo_set_matrix( mpCairo.get(), &aViewMatrix ); + doPolyPolygonPath( viewState.Clip, Clip ); + } + + aCombinedMatrix.x0 = basegfx::fround( aCombinedMatrix.x0 ); + aCombinedMatrix.y0 = basegfx::fround( aCombinedMatrix.y0 ); + cairo_set_matrix( mpCairo.get(), &aCombinedMatrix ); + + if( renderState.Clip.is() ) { + OSL_TRACE ("render clip BEGIN"); + + doPolyPolygonPath( renderState.Clip, Clip ); + OSL_TRACE ("render clip END"); + } + + if( bSetColor ) + setColor(mpCairo.get(),renderState.DeviceColor); + + 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.get(), compositingMode ); + } + + void CanvasHelper::clear() + { + OSL_TRACE ("clear whole area: %d x %d", maSize.getX(), maSize.getY() ); + + if( mpCairo ) + { + cairo_save( mpCairo.get() ); + + cairo_identity_matrix( mpCairo.get() ); + // this does not really differ from all-zero, as cairo + // internally converts to premultiplied alpha. but anyway, + // this keeps it consistent with the other canvas impls + if( mbHaveAlpha ) + cairo_set_source_rgba( mpCairo.get(), 1.0, 1.0, 1.0, 0.0 ); + else + cairo_set_source_rgb( mpCairo.get(), 1.0, 1.0, 1.0 ); + cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE ); + + cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() ); + cairo_fill( mpCairo.get() ); + + cairo_restore( mpCairo.get() ); + } + } + + void CanvasHelper::drawPoint( const rendering::XCanvas* , + const geometry::RealPoint2D& , + const rendering::ViewState& , + const rendering::RenderState& ) + { + } + + void CanvasHelper::drawLine( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealPoint2D& aStartPoint, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( mpCairo ) { + cairo_save( mpCairo.get() ); + + cairo_set_line_width( mpCairo.get(), 1 ); + + useStates( viewState, renderState, true ); + + cairo_move_to( mpCairo.get(), aStartPoint.X + 0.5, aStartPoint.Y + 0.5 ); + cairo_line_to( mpCairo.get(), aEndPoint.X + 0.5, aEndPoint.Y + 0.5 ); + cairo_stroke( mpCairo.get() ); + + cairo_restore( mpCairo.get() ); + } + } + + void CanvasHelper::drawBezier( const rendering::XCanvas* , + const geometry::RealBezierSegment2D& aBezierSegment, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( mpCairo ) { + cairo_save( mpCairo.get() ); + + cairo_set_line_width( mpCairo.get(), 1 ); + + useStates( viewState, renderState, true ); + + cairo_move_to( mpCairo.get(), aBezierSegment.Px + 0.5, aBezierSegment.Py + 0.5 ); + cairo_curve_to( mpCairo.get(), + 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.get() ); + + cairo_restore( mpCairo.get() ); + } + } + +#define CANVASBITMAP_IMPLEMENTATION_NAME "CairoCanvas::CanvasBitmap" +#define PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME "Canvas::ParametricPolyPolygon" + + + /** 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 + **/ + static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) + { + CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() ); + if( pBitmapImpl ) + return pBitmapImpl->getSurface(); + + SurfaceProvider* pSurfaceProvider = dynamic_cast<SurfaceProvider*>( xBitmap.get() ); + if( pSurfaceProvider ) + return pSurfaceProvider->getSurface(); + + return SurfaceSharedPtr(); + } + + static ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) + { + // TODO(F1): Add support for floating point bitmap formats + uno::Reference<rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap, + uno::UNO_QUERY_THROW); + ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap(xIntBmp); + if( !!aBmpEx ) + return aBmpEx; + + // TODO(F1): extract pixel from XBitmap interface + ENSURE_OR_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", 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; + } + + + /** 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 + **/ + static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, const SurfaceProviderRef& rSurfaceProvider, unsigned char*& data, bool& bHasAlpha ) + { + bHasAlpha = xBitmap->hasAlpha(); + SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap ); + if( pSurface ) + 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 = rSurfaceProvider->createSurface( aBitmap ); + data = NULL; + bHasAlpha = false; + } + + if( !pSurface ) { + AlphaMask aAlpha = aBmpEx.GetAlpha(); + + ::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++ ) { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff++ ]; + else + nAlpha = data[ nOff++ ] = 255; +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; +#endif + aColor = pBitmapReadAcc->GetPaletteColor( *pReadScan++ ); + +#ifdef OSL_BIGENDIAN + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 ); +#else + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 ); + nOff++; +#endif + } + 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++ ) { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff ]; + else + nAlpha = data[ nOff ] = 255; + data[ nOff + 3 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff + 2 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff + 1 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + nOff += 4; +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + nOff++; +#endif + } + 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++ ) { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff++ ]; + else + nAlpha = data[ nOff++ ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 ); + pReadScan += 3; + nOff++; +#endif + } + 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++ ) { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff++ ]; + else + nAlpha = data[ nOff++ ] = pReadScan[ 3 ]; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 ); + pReadScan += 4; +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = pReadScan[ 3 ]; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + pReadScan++; + nOff++; +#endif + } + 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++ ) { +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff ++ ]; + else + nAlpha = data[ nOff ++ ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 ); + pReadScan++; +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 ); + pReadScan += 4; + nOff++; +#endif + } + break; + default: + OSL_TRACE( "fallback to GetColor - slow, format: %d", 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 +#ifdef OSL_BIGENDIAN + if( pAlphaReadAcc ) + nAlpha = data[ nOff++ ]; + else + nAlpha = data[ nOff++ ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 ); +#else + if( pAlphaReadAcc ) + nAlpha = data[ nOff + 3 ]; + else + nAlpha = data[ nOff + 3 ] = 255; + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 ); + data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 ); + nOff ++; +#endif + } + } + } + + aBitmap.ReleaseAccess( pBitmapReadAcc ); + if( pAlphaReadAcc ) + aAlpha.ReleaseAccess( pAlphaReadAcc ); + + SurfaceSharedPtr pImageSurface = createSurface( + CairoSurfaceSharedPtr( + cairo_image_surface_create_for_data( + data, + bIsAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, + nWidth, nHeight, nWidth*4 ), + &cairo_surface_destroy) ); + + // pSurface = rSurfaceProvider->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 addColorStops( Pattern* pPattern, const uno::Sequence< uno::Sequence< double > >& rColors, const uno::Sequence< double >& rStops, bool bReverseStops = false ) + { + float stop; + int i; + + OSL_ASSERT( rColors.getLength() == rStops.getLength() ); + + for( i = 0; i < rColors.getLength(); i++ ) { + const uno::Sequence< double >& rColor( rColors[i] ); + stop = bReverseStops ? 1 - rStops[i] : rStops[i]; + if( rColor.getLength() == 3 ) + cairo_pattern_add_color_stop_rgb( pPattern, stop, rColor[0], rColor[1], rColor[2] ); + else if( rColor.getLength() == 4 ) { + double alpha = rColor[3]; + // cairo expects premultiplied alpha + cairo_pattern_add_color_stop_rgba( pPattern, stop, rColor[0]*alpha, rColor[1]*alpha, rColor[2]*alpha, alpha ); + } + } + } + + static uno::Sequence<double> lerp(const uno::Sequence<double>& rLeft, const uno::Sequence<double>& rRight, double fAlpha) + { + if( rLeft.getLength() == 3 ) + { + uno::Sequence<double> aRes(3); + aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha); + aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha); + aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha); + return aRes; + } + else if( rLeft.getLength() == 4 ) + { + uno::Sequence<double> aRes(4); + aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha); + aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha); + aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha); + aRes[3] = basegfx::tools::lerp(rLeft[3],rRight[3],fAlpha); + return aRes; + } + + return uno::Sequence<double>(); + } + + static Pattern* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon& rPolygon ) + { + 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_ELLIPTICAL + + switch( aValues.meType ) { + case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR: + x0 = 0; + y0 = 0; + x1 = 1; + y1 = 0; + pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 ); + addColorStops( pPattern, aValues.maColors, aValues.maStops ); + break; + + case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL: + cx = 0; + cy = 0; + r0 = 0; + r1 = 1; + + pPattern = cairo_pattern_create_radial( cx, cy, r0, cy, cy, r1 ); + addColorStops( pPattern, aValues.maColors, aValues.maStops, true ); + break; + default: + break; + } + + return pPattern; + } + + static void doOperation( Operation aOperation, + Cairo* pCairo, + const uno::Sequence< rendering::Texture >* pTextures, + const SurfaceProviderRef& pDevice, + const basegfx::B2DRange& rBounds ) + { + switch( aOperation ) { + case Fill: + /* TODO: multitexturing */ + if( pTextures ) { + const ::com::sun::star::rendering::Texture& aTexture ( (*pTextures)[0] ); + if( aTexture.Bitmap.is() ) { + unsigned char* data = NULL; + bool bHasAlpha = false; + SurfaceSharedPtr pSurface = surfaceFromXBitmap( (*pTextures)[0].Bitmap, pDevice, data, bHasAlpha ); + + if( pSurface ) { + cairo_pattern_t* pPattern; + + cairo_save( pCairo ); + + ::com::sun::star::geometry::AffineMatrix2D aTransform( aTexture.AffineTransform ); + Matrix aScaleMatrix, aTextureMatrix, aScaledTextureMatrix; + + 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 ); + + // we don't care about repeat mode yet, so the workaround is disabled for now + pPattern = cairo_pattern_create_for_surface( pSurface->getCairoSurface().get() ); + + if( aTexture.RepeatModeX == rendering::TexturingMode::REPEAT && + aTexture.RepeatModeY == rendering::TexturingMode::REPEAT ) + { + cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_REPEAT ); + } + else if ( aTexture.RepeatModeX == rendering::TexturingMode::NONE && + aTexture.RepeatModeY == rendering::TexturingMode::NONE ) + { + cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_NONE ); + } + else if ( aTexture.RepeatModeX == rendering::TexturingMode::CLAMP && + aTexture.RepeatModeY == rendering::TexturingMode::CLAMP ) + { + cairo_pattern_set_extend( pPattern, CAIRO_EXTEND_PAD ); + } + + aScaledTextureMatrix.x0 = basegfx::fround( aScaledTextureMatrix.x0 ); + aScaledTextureMatrix.y0 = basegfx::fround( 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 ); + } + + if( data ) + free( data ); + } else if( aTexture.Gradient.is() ) { + uno::Reference< lang::XServiceInfo > xRef( aTexture.Gradient, uno::UNO_QUERY ); + + OSL_TRACE( "gradient fill" ); + 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" ); + + ::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); + if( pPolyImpl->getValues().meType == canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR ) + { + // no general path gradient yet in cairo; emulate then + cairo_save( pCairo ); + cairo_clip( pCairo ); + + // fill bound rect with start color + cairo_rectangle( pCairo, rBounds.getMinX(), rBounds.getMinY(), + rBounds.getWidth(), rBounds.getHeight() ); + setColor(pCairo,pPolyImpl->getValues().maColors[0]); + cairo_fill(pCairo); + + cairo_transform( pCairo, &aTextureMatrix ); + + // longest line in gradient bound rect + const unsigned int nGradientSize( + static_cast<unsigned int>( + ::basegfx::B2DVector(rBounds.getMinimum() - rBounds.getMaximum()).getLength() + 1.0 ) ); + + // typical number for pixel of the same color (strip size) + const unsigned int nStripSize( nGradientSize < 50 ? 2 : 4 ); + + // use at least three steps, and at utmost the number of color + // steps + const unsigned int nStepCount( + ::std::max( + 3U, + ::std::min( + nGradientSize / nStripSize, + 128U )) + 1 ); + + const uno::Sequence<double>* pColors=&pPolyImpl->getValues().maColors[0]; + basegfx::tools::KeyStopLerp aLerper(pPolyImpl->getValues().maStops); + for( unsigned int i=1; i<nStepCount; ++i ) + { + const double fT( i/double(nStepCount) ); + + std::ptrdiff_t nIndex; + double fAlpha; + boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT); + + setColor(pCairo, lerp(pColors[nIndex], pColors[nIndex+1], fAlpha)); + cairo_rectangle( pCairo, -1+fT, -1+fT, 2-2*fT, 2-2*fT ); + cairo_fill(pCairo); + } + + cairo_restore( pCairo ); + } + else + { + Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl ); + + if( pPattern ) { + OSL_TRACE( "filling with pattern" ); + + cairo_save( pCairo ); + + cairo_transform( pCairo, &aTextureMatrix ); + cairo_set_source( pCairo, pPattern ); + cairo_fill( pCairo ); + cairo_restore( pCairo ); + + cairo_pattern_destroy( pPattern ); + } + } + } + } + } else + cairo_fill( pCairo ); + OSL_TRACE("fill"); + break; + case Stroke: + cairo_stroke( pCairo ); + OSL_TRACE("stroke"); + break; + case Clip: + cairo_clip( pCairo ); + OSL_TRACE("clip"); + break; + } + } + + static void clipNULL( Cairo *pCairo ) + { + OSL_TRACE("clipNULL"); + 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 ); + } + + void doPolyPolygonImplementation( ::basegfx::B2DPolyPolygon aPolyPolygon, + Operation aOperation, + Cairo* pCairo, + const uno::Sequence< rendering::Texture >* pTextures, + const SurfaceProviderRef& pDevice, + rendering::FillRule eFillrule ) + { + if( pTextures ) + ENSURE_ARG_OR_THROW( pTextures->getLength(), + "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence"); + + bool bOpToDo = false; + Matrix aOrigMatrix, aIdentityMatrix; + double nX, nY, nBX, nBY, nAX, nAY; + + cairo_get_matrix( pCairo, &aOrigMatrix ); + cairo_matrix_init_identity( &aIdentityMatrix ); + cairo_set_matrix( pCairo, &aIdentityMatrix ); + + cairo_set_fill_rule( pCairo, + eFillrule == rendering::FillRule_EVEN_ODD ? + CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING ); + + for( sal_uInt32 nPolygonIndex = 0; nPolygonIndex < aPolyPolygon.count(); nPolygonIndex++ ) { + ::basegfx::B2DPolygon aPolygon( aPolyPolygon.getB2DPolygon( nPolygonIndex ) ); + const sal_uInt32 nPointCount( aPolygon.count() ); + // to correctly render closed curves, need to output first + // point twice (so output one additional point) + const sal_uInt32 nExtendedPointCount( nPointCount + + aPolygon.isClosed()*aPolygon.areControlPointsUsed() ); + + if( nPointCount > 1) { + bool bIsBezier = aPolygon.areControlPointsUsed(); + bool bIsRectangle = ::basegfx::tools::isRectangle( aPolygon ); + ::basegfx::B2DPoint aA, aB, aP; + + for( sal_uInt32 j=0; j < nExtendedPointCount; j++ ) { + aP = aPolygon.getB2DPoint( j % nPointCount ); + + nX = aP.getX(); + nY = aP.getY(); + cairo_matrix_transform_point( &aOrigMatrix, &nX, &nY ); + + if( ! bIsBezier && (bIsRectangle || aOperation == Clip) ) { + nX = basegfx::fround( nX ); + nY = basegfx::fround( nY ); + } + + if( aOperation == Stroke ) { + nX += 0.5; + nY += 0.5; + } + + if( j==0 ) + { + cairo_move_to( pCairo, nX, nY ); + OSL_TRACE( "move to %f,%f", nX, nY ); + } + else { + if( bIsBezier ) { + aA = aPolygon.getNextControlPoint( (j-1) % nPointCount ); + aB = aPolygon.getPrevControlPoint( j % nPointCount ); + + nAX = aA.getX(); + nAY = aA.getY(); + nBX = aB.getX(); + nBY = aB.getY(); + + if( aOperation == Stroke ) { + 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 ); + } else { + cairo_line_to( pCairo, nX, nY ); + OSL_TRACE( "line to %f,%f", nX, nY ); + } + bOpToDo = true; + } + } + + if( aPolygon.isClosed() ) + cairo_close_path( pCairo ); + + if( aOperation == Fill && pTextures ) { + cairo_set_matrix( pCairo, &aOrigMatrix ); + doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() ); + cairo_set_matrix( pCairo, &aIdentityMatrix ); + } + } else { + OSL_TRACE( "empty polygon for op: %d\n", aOperation ); + if( aOperation == Clip ) { + clipNULL( pCairo ); + + return; + } + } + } + if( bOpToDo && ( aOperation != Fill || !pTextures ) ) + doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() ); + + cairo_set_matrix( pCairo, &aOrigMatrix ); + + if( aPolyPolygon.count() == 0 && aOperation == Clip ) + clipNULL( pCairo ); + } + + void CanvasHelper::doPolyPolygonPath( const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + Operation aOperation, + bool bNoLineJoin, + const uno::Sequence< rendering::Texture >* pTextures, + Cairo* pCairo ) const + { + const ::basegfx::B2DPolyPolygon& rPolyPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) ); + + if( !pCairo ) + pCairo = mpCairo.get(); + + if(bNoLineJoin && Stroke == aOperation) + { + // emulate rendering::PathJoinType::NONE by painting single edges + for(sal_uInt32 a(0); a < rPolyPoly.count(); a++) + { + const basegfx::B2DPolygon aCandidate(rPolyPoly.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aCandidate.count()); + + if(nPointCount) + { + const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount + 1: nPointCount); + basegfx::B2DPolygon aEdge; + aEdge.append(aCandidate.getB2DPoint(0)); + aEdge.append(basegfx::B2DPoint(0.0, 0.0)); + + for(sal_uInt32 b(0); b < nEdgeCount; b++) + { + const sal_uInt32 nNextIndex((b + 1) % nPointCount); + aEdge.setB2DPoint(1, aCandidate.getB2DPoint(nNextIndex)); + aEdge.setNextControlPoint(0, aCandidate.getNextControlPoint(b)); + aEdge.setPrevControlPoint(1, aCandidate.getPrevControlPoint(nNextIndex)); + + doPolyPolygonImplementation( basegfx::B2DPolyPolygon(aEdge), + aOperation, + pCairo, pTextures, + mpSurfaceProvider, + xPolyPolygon->getFillRule() ); + + // prepare next step + aEdge.setB2DPoint(0, aEdge.getB2DPoint(1)); + } + } + } + } + else + { + doPolyPolygonImplementation( rPolyPoly, aOperation, + pCairo, pTextures, + mpSurfaceProvider, + xPolyPolygon->getFillRule() ); + } + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* , + 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.get() ); + + cairo_set_line_width( mpCairo.get(), 1 ); + + useStates( viewState, renderState, true ); + doPolyPolygonPath( xPolyPolygon, Stroke ); + + cairo_restore( mpCairo.get() ); + } 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); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* , + 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.get() ); + + useStates( viewState, renderState, true ); + + Matrix aMatrix; + double w = strokeAttributes.StrokeWidth, h = 0; + cairo_get_matrix( mpCairo.get(), &aMatrix ); + cairo_matrix_transform_distance( &aMatrix, &w, &h ); + cairo_set_line_width( mpCairo.get(), w ); + + cairo_set_miter_limit( mpCairo.get(), strokeAttributes.MiterLimit ); + + // FIXME: cairo doesn't handle end cap so far (rodo) + switch( strokeAttributes.StartCapType ) { + case rendering::PathCapType::BUTT: + cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_BUTT ); + break; + case rendering::PathCapType::ROUND: + cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_ROUND ); + break; + case rendering::PathCapType::SQUARE: + cairo_set_line_cap( mpCairo.get(), CAIRO_LINE_CAP_SQUARE ); + break; + } + + bool bNoLineJoin(false); + + switch( strokeAttributes.JoinType ) { + // cairo doesn't have join type NONE so we use MITER as it's pretty close + case rendering::PathJoinType::NONE: + bNoLineJoin = true; + case rendering::PathJoinType::MITER: + cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_MITER ); + break; + case rendering::PathJoinType::ROUND: + cairo_set_line_join( mpCairo.get(), CAIRO_LINE_JOIN_ROUND ); + break; + case rendering::PathJoinType::BEVEL: + cairo_set_line_join( mpCairo.get(), 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.get(), pDashArray, strokeAttributes.DashArray.getLength(), 0 ); + delete[] pDashArray; + } + + // TODO(rodo) use LineArray of strokeAttributes + + doPolyPolygonPath( xPolyPolygon, Stroke, bNoLineJoin ); + + cairo_restore( mpCairo.get() ); + } 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); + } + + 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*/ ) + { + // TODO + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + 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*/ ) + { + // TODO + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + 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*/ ) + { + // TODO + return uno::Reference< rendering::XPolyPolygon2D >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* , + 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.get() ); + + useStates( viewState, renderState, true ); + doPolyPolygonPath( xPolyPolygon, Fill ); + + cairo_restore( mpCairo.get() ); + } 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); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* , + 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.get() ); + + useStates( viewState, renderState, true ); + doPolyPolygonPath( xPolyPolygon, Fill, false, &textures ); + + cairo_restore( mpCairo.get() ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + 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*/ ) + { + // TODO + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::implDrawBitmapSurface( const rendering::XCanvas* pCanvas, + const SurfaceSharedPtr& pInputSurface, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const geometry::IntegerSize2D& rSize, + bool bModulateColors, + bool bHasAlpha ) + { + SurfaceSharedPtr pSurface=pInputSurface; + uno::Reference< rendering::XCachedPrimitive > rv = uno::Reference< rendering::XCachedPrimitive >(NULL); + geometry::IntegerSize2D aBitmapSize = rSize; + + if( mpCairo ) { + cairo_save( mpCairo.get() ); + + cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() ); + cairo_clip( mpCairo.get() ); + + useStates( viewState, renderState, true ); + + // if( !bHasAlpha ) + // cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE ); + + Matrix aMatrix; + + cairo_get_matrix( mpCairo.get(), &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 ) && + basegfx::fround( rSize.Width * aMatrix.xx ) > 8 && + basegfx::fround( rSize.Height* aMatrix.yy ) > 8 ) + { + double dWidth, dHeight; + + dWidth = basegfx::fround( rSize.Width * aMatrix.xx ); + dHeight = basegfx::fround( rSize.Height* aMatrix.yy ); + aBitmapSize.Width = static_cast<sal_Int32>( dWidth ); + aBitmapSize.Height = static_cast<sal_Int32>( dHeight ); + + SurfaceSharedPtr pScaledSurface = mpSurfaceProvider->createSurface( + ::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ), + bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR ); + CairoSharedPtr pCairo = pScaledSurface->getCairo(); + + cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE ); + // add 0.5px to size to avoid rounding errors in cairo, leading sometimes to random data on the image right/bottom borders + cairo_scale( pCairo.get(), (dWidth+0.5)/rSize.Width, (dHeight+0.5)/rSize.Height ); + cairo_set_source_surface( pCairo.get(), pSurface->getCairoSurface().get(), 0, 0 ); + cairo_paint( pCairo.get() ); + + pSurface = pScaledSurface; + + aMatrix.xx = aMatrix.yy = 1; + cairo_set_matrix( mpCairo.get(), &aMatrix ); + + rv = uno::Reference< rendering::XCachedPrimitive >( + new CachedBitmap( pSurface, viewState, renderState, + // cast away const, need to + // change refcount (as this is + // ~invisible to client code, + // still logically const) + const_cast< rendering::XCanvas* >(pCanvas)) ); + } + + if( !bHasAlpha && mbHaveAlpha ) + { + double x, y, width, height; + + x = y = 0; + width = aBitmapSize.Width; + height = aBitmapSize.Height; + 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, maSize.getX(), maSize.getY() ); + if( x <= 0 && y <= 0 && x + width >= maSize.getX() && y + height >= maSize.getY() ) + { + OSL_TRACE ("trying to change surface to rgb"); + if( mpSurfaceProvider ) { + SurfaceSharedPtr pNewSurface = mpSurfaceProvider->changeSurface( false, false ); + + if( pNewSurface ) + setSurface( pNewSurface, false ); + + // set state to new mpCairo.get() + useStates( viewState, renderState, true ); + // use the possibly modified matrix + cairo_set_matrix( mpCairo.get(), &aMatrix ); + } + } + } + + cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 ); + 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.get(), CAIRO_OPERATOR_SOURCE ); + cairo_pattern_set_extend( cairo_get_source(mpCairo.get()), CAIRO_EXTEND_PAD ); + cairo_rectangle( mpCairo.get(), 0, 0, aBitmapSize.Width, aBitmapSize.Height ); + cairo_clip( mpCairo.get() ); + + if( bModulateColors ) + cairo_paint_with_alpha( mpCairo.get(), renderState.DeviceColor[3] ); + else + cairo_paint( mpCairo.get() ); + cairo_restore( mpCairo.get() ); + } else + OSL_TRACE ("CanvasHelper called after it was disposed"); + + return rv; // uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* pCanvas, + 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 = NULL; + bool bHasAlpha = false; + SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha ); + geometry::IntegerSize2D aSize = xBitmap->getSize(); + + if( pSurface ) { + rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, false, bHasAlpha ); + + if( data ) + free( data ); + } else + rv = uno::Reference< rendering::XCachedPrimitive >(NULL); + + #ifdef CAIRO_CANVAS_PERF_TRACE + mxDevice->stopPerfTrace( &aTimer, "drawBitmap" ); + #endif + + return rv; + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas, + 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 = NULL; + bool bHasAlpha = false; + SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha ); + geometry::IntegerSize2D aSize = xBitmap->getSize(); + + if( pSurface ) { + rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, true, bHasAlpha ); + + if( data ) + free( data ); + } else + rv = uno::Reference< rendering::XCachedPrimitive >(NULL); + +#ifdef CAIRO_CANVAS_PERF_TRACE + mxDevice->stopPerfTrace( &aTimer, "drawBitmap" ); +#endif + + return rv; + } + + uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice() + { + return uno::Reference< rendering::XGraphicDevice >(mpDevice); + } + + 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*/ ) + { + // TODO(F2): copyRect NYI + } + + geometry::IntegerSize2D CanvasHelper::getSize() + { + if( !mpSurfaceProvider ) + geometry::IntegerSize2D(1, 1); // we're disposed + + return ::basegfx::unotools::integerSize2DFromB2ISize( maSize ); + } + + uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D& newSize, + sal_Bool /*beFast*/ ) + { +#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 ) ), + mpSurfaceProvider, 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 >(); + } + + uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& aLayout, + const geometry::IntegerRectangle2D& rect ) + { + if( mpCairo ) { + aLayout = getMemoryLayout(); + + const sal_Int32 nWidth( rect.X2 - rect.X1 ); + const sal_Int32 nHeight( rect.Y2 - rect.Y1 ); + uno::Sequence< sal_Int8 > aRes( 4*nWidth*nHeight ); + sal_Int8* pData = aRes.getArray(); + cairo_surface_t* pImageSurface = cairo_image_surface_create_for_data( (unsigned char *) pData, + CAIRO_FORMAT_ARGB32, + nWidth, nHeight, 4*nWidth ); + cairo_t* pCairo = cairo_create( pImageSurface ); + cairo_set_source_surface( pCairo, mpSurface->getCairoSurface().get(), -rect.X1, -rect.Y1); + cairo_paint( pCairo ); + cairo_destroy( pCairo ); + cairo_surface_destroy( pImageSurface ); + + aLayout.ScanLines = nHeight; + aLayout.ScanLineBytes = nWidth*4; + aLayout.ScanLineStride = aLayout.ScanLineBytes; + + return aRes; + } + + return uno::Sequence< sal_Int8 >(); + } + + void CanvasHelper::setData( const uno::Sequence< sal_Int8 >& /*data*/, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& /*rect*/ ) + { + } + + void CanvasHelper::setPixel( const uno::Sequence< sal_Int8 >& /*color*/, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& /*pos*/ ) + { + } + + uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& /*pos*/ ) + { + return uno::Sequence< sal_Int8 >(); + } + + uno::Reference< rendering::XBitmapPalette > CanvasHelper::getPalette() + { + // TODO(F1): Palette bitmaps NYI + return uno::Reference< rendering::XBitmapPalette >(); + } + + namespace + { + class CairoColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace > + { + private: + uno::Sequence< sal_Int8 > maComponentTags; + uno::Sequence< sal_Int32 > maBitCounts; + + virtual ::sal_Int8 SAL_CALL getType( ) throw (uno::RuntimeException) + { + return rendering::ColorSpaceType::RGB; + } + virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) throw (uno::RuntimeException) + { + return maComponentTags; + } + virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (uno::RuntimeException) + { + return rendering::RenderingIntent::PERCEPTUAL; + } + virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) throw (uno::RuntimeException) + { + return uno::Sequence< beans::PropertyValue >(); + } + virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor, + const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException, + uno::RuntimeException) + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertToARGB(deviceColor)); + return targetColorSpace->convertFromARGB(aIntermediate); + } + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const double* pIn( deviceColor.getConstArray() ); + const sal_Size nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::RGBColor > aRes(nLen/4); + rendering::RGBColor* pOut( aRes.getArray() ); + for( sal_Size i=0; i<nLen; i+=4 ) + { + const double fAlpha(pIn[3]); + if( fAlpha == 0.0 ) + *pOut++ = rendering::RGBColor(0.0, 0.0, 0.0); + else + *pOut++ = rendering::RGBColor(pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const double* pIn( deviceColor.getConstArray() ); + const sal_Size nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( sal_Size i=0; i<nLen; i+=4 ) + { + const double fAlpha(pIn[3]); + if( fAlpha == 0.0 ) + *pOut++ = rendering::ARGBColor(0.0, 0.0, 0.0, 0.0); + else + *pOut++ = rendering::ARGBColor(fAlpha,pIn[2]/fAlpha,pIn[1]/fAlpha,pIn[0]/fAlpha); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const double* pIn( deviceColor.getConstArray() ); + const sal_Size nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( sal_Size i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::ARGBColor(pIn[3],pIn[2],pIn[1],pIn[1]); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const rendering::RGBColor* pIn( rgbColor.getConstArray() ); + const sal_Size nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( sal_Size i=0; i<nLen; ++i ) + { + *pColors++ = pIn->Blue; + *pColors++ = pIn->Green; + *pColors++ = pIn->Red; + *pColors++ = 1.0; + ++pIn; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const rendering::ARGBColor* pIn( rgbColor.getConstArray() ); + const sal_Size nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( sal_Size i=0; i<nLen; ++i ) + { + *pColors++ = pIn->Alpha*pIn->Blue; + *pColors++ = pIn->Alpha*pIn->Green; + *pColors++ = pIn->Alpha*pIn->Red; + *pColors++ = pIn->Alpha; + ++pIn; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const rendering::ARGBColor* pIn( rgbColor.getConstArray() ); + const sal_Size nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( sal_Size i=0; i<nLen; ++i ) + { + *pColors++ = pIn->Blue; + *pColors++ = pIn->Green; + *pColors++ = pIn->Red; + *pColors++ = pIn->Alpha; + ++pIn; + } + return aRes; + } + + // XIntegerBitmapColorSpace + virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) throw (uno::RuntimeException) + { + return 32; + } + virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (uno::RuntimeException) + { + return maBitCounts; + } + virtual ::sal_Int8 SAL_CALL getEndianness( ) throw (uno::RuntimeException) + { + return util::Endianness::LITTLE; + } + virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, + const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException, + uno::RuntimeException) + { + if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) ) + { + const sal_Int8* pIn( deviceColor.getConstArray() ); + const sal_Size nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence<double> aRes(nLen); + double* pOut( aRes.getArray() ); + for( sal_Size i=0; i<nLen; i+=4 ) + { + *pOut++ = vcl::unotools::toDoubleColor(*pIn++); + *pOut++ = vcl::unotools::toDoubleColor(*pIn++); + *pOut++ = vcl::unotools::toDoubleColor(*pIn++); + *pOut++ = vcl::unotools::toDoubleColor(*pIn++); + } + return aRes; + } + else + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertIntegerToARGB(deviceColor)); + return targetColorSpace->convertFromARGB(aIntermediate); + } + } + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, + const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException, + uno::RuntimeException) + { + if( dynamic_cast<CairoColorSpace*>(targetColorSpace.get()) ) + { + // it's us, so simply pass-through the data + return deviceColor; + } + else + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertIntegerToARGB(deviceColor)); + return targetColorSpace->convertIntegerFromARGB(aIntermediate); + } + } + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const sal_Int8* pIn( deviceColor.getConstArray() ); + const sal_Size nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::RGBColor > aRes(nLen/4); + rendering::RGBColor* pOut( aRes.getArray() ); + for( sal_Size i=0; i<nLen; i+=4 ) + { + const double fAlpha((sal_uInt8)pIn[3]); + if( fAlpha ) + *pOut++ = rendering::RGBColor( + pIn[2]/fAlpha, + pIn[1]/fAlpha, + pIn[0]/fAlpha); + else + *pOut++ = rendering::RGBColor(0,0,0); + pIn += 4; + } + return aRes; + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const sal_Int8* pIn( deviceColor.getConstArray() ); + const sal_Size nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( sal_Size i=0; i<nLen; i+=4 ) + { + const double fAlpha((sal_uInt8)pIn[3]); + if( fAlpha ) + *pOut++ = rendering::ARGBColor( + fAlpha/255.0, + pIn[2]/fAlpha, + pIn[1]/fAlpha, + pIn[0]/fAlpha); + else + *pOut++ = rendering::ARGBColor(0,0,0,0); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const sal_Int8* pIn( deviceColor.getConstArray() ); + const sal_Size nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( sal_Size i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::ARGBColor( + vcl::unotools::toDoubleColor(pIn[3]), + vcl::unotools::toDoubleColor(pIn[2]), + vcl::unotools::toDoubleColor(pIn[1]), + vcl::unotools::toDoubleColor(pIn[0])); + pIn += 4; + } + return aRes; + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const rendering::RGBColor* pIn( rgbColor.getConstArray() ); + const sal_Size nLen( rgbColor.getLength() ); + + uno::Sequence< sal_Int8 > aRes(nLen*4); + sal_Int8* pColors=aRes.getArray(); + for( sal_Size i=0; i<nLen; ++i ) + { + *pColors++ = vcl::unotools::toByteColor(pIn->Blue); + *pColors++ = vcl::unotools::toByteColor(pIn->Green); + *pColors++ = vcl::unotools::toByteColor(pIn->Red); + *pColors++ = 255; + ++pIn; + } + return aRes; + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const rendering::ARGBColor* pIn( rgbColor.getConstArray() ); + const sal_Size nLen( rgbColor.getLength() ); + + uno::Sequence< sal_Int8 > aRes(nLen*4); + sal_Int8* pColors=aRes.getArray(); + for( sal_Size i=0; i<nLen; ++i ) + { + const double fAlpha(pIn->Alpha); + *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Blue); + *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Green); + *pColors++ = vcl::unotools::toByteColor(fAlpha*pIn->Red); + *pColors++ = vcl::unotools::toByteColor(fAlpha); + ++pIn; + } + return aRes; + } + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + const rendering::ARGBColor* pIn( rgbColor.getConstArray() ); + const sal_Size nLen( rgbColor.getLength() ); + + uno::Sequence< sal_Int8 > aRes(nLen*4); + sal_Int8* pColors=aRes.getArray(); + for( sal_Size i=0; i<nLen; ++i ) + { + *pColors++ = vcl::unotools::toByteColor(pIn->Blue); + *pColors++ = vcl::unotools::toByteColor(pIn->Green); + *pColors++ = vcl::unotools::toByteColor(pIn->Red); + *pColors++ = vcl::unotools::toByteColor(pIn->Alpha); + ++pIn; + } + return aRes; + } + + public: + CairoColorSpace() : + maComponentTags(4), + maBitCounts(4) + { + sal_Int8* pTags = maComponentTags.getArray(); + sal_Int32* pBitCounts = maBitCounts.getArray(); + pTags[0] = rendering::ColorComponentTag::RGB_BLUE; + pTags[1] = rendering::ColorComponentTag::RGB_GREEN; + pTags[2] = rendering::ColorComponentTag::RGB_RED; + pTags[3] = rendering::ColorComponentTag::PREMULTIPLIED_ALPHA; + + pBitCounts[0] = + pBitCounts[1] = + pBitCounts[2] = + pBitCounts[3] = 8; + } + }; + + struct CairoColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>, + CairoColorSpaceHolder> + { + uno::Reference<rendering::XIntegerBitmapColorSpace> operator()() + { + return new CairoColorSpace(); + } + }; + } + + rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout() + { + if( !mpCairo ) + return rendering::IntegerBitmapLayout(); // we're disposed + + const geometry::IntegerSize2D aSize(getSize()); + rendering::IntegerBitmapLayout aLayout; + + aLayout.ScanLines = aSize.Height; + aLayout.ScanLineBytes = aSize.Width*4; + aLayout.ScanLineStride = aLayout.ScanLineBytes; + aLayout.PlaneStride = 0; + aLayout.ColorSpace = CairoColorSpaceHolder::get(); + aLayout.Palette.clear(); + aLayout.IsMsbFirst = sal_False; + + return aLayout; + } + + void CanvasHelper::flush() const + { + } + + bool CanvasHelper::hasAlpha() const + { + return mbHaveAlpha; + } + + bool CanvasHelper::repaint( const SurfaceSharedPtr& pSurface, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + OSL_TRACE("CanvasHelper::repaint"); + + if( mpCairo ) { + cairo_save( mpCairo.get() ); + + cairo_rectangle( mpCairo.get(), 0, 0, maSize.getX(), maSize.getY() ); + cairo_clip( mpCairo.get() ); + + useStates( viewState, renderState, true ); + + Matrix aMatrix; + + cairo_get_matrix( mpCairo.get(), &aMatrix ); + aMatrix.xx = aMatrix.yy = 1; + cairo_set_matrix( mpCairo.get(), &aMatrix ); + + // if( !bHasAlpha ) + // cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE ); + + cairo_set_source_surface( mpCairo.get(), pSurface->getCairoSurface().get(), 0, 0 ); + cairo_paint( mpCairo.get() ); + cairo_restore( mpCairo.get() ); + } + + return true; + } +} diff --git a/canvas/source/cairo/cairo_canvashelper.hxx b/canvas/source/cairo/cairo_canvashelper.hxx new file mode 100644 index 000000000000..d89429b77a25 --- /dev/null +++ b/canvas/source/cairo/cairo_canvashelper.hxx @@ -0,0 +1,335 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_CANVASHELPER_HXX_ +#define _CAIROCANVAS_CANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <com/sun/star/rendering/XLinePolyPolygon2D.hpp> + +#include <boost/utility.hpp> + +#include "cairo_cairo.hxx" +#include "cairo_surfaceprovider.hxx" + +class VirtualDevice; + +namespace basegfx { + class B2DPolyPolygon; +} + +namespace cairocanvas +{ + class SpriteCanvas; + + enum Operation { + Stroke, + Fill, + Clip + }; + + class CanvasHelper : private ::boost::noncopyable + { + public: + CanvasHelper(); + + /// Release all references + void disposing(); + + /** Initialize canvas helper + + This method late-initializes the canvas helper, providing + it with the necessary device and size. Note that the + CanvasHelper does <em>not</em> take ownership of the + passed rDevice reference, nor does it perform any + reference counting. Thus, to prevent the reference counted + SpriteCanvas object from deletion, the user of this class + is responsible for holding ref-counted references itself! + + @param rSizePixel + Size of the output surface in pixel. + + @param rDevice + Reference device this canvas is associated with + + */ + void init( const ::basegfx::B2ISize& rSizePixel, + SurfaceProvider& rSurfaceProvider, + ::com::sun::star::rendering::XGraphicDevice* pDevice ); + + void setSize( const ::basegfx::B2ISize& rSize ); + void setSurface( const ::cairo::SurfaceSharedPtr& pSurface, bool bHasAlpha ); + + // CanvasHelper functionality + // ========================== + + // XCanvas (only providing, not implementing the + // interface. Also note subtle method parameter differences) + void clear(); + void drawPoint( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::geometry::RealPoint2D& aPoint, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + void drawLine( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::geometry::RealPoint2D& aStartPoint, + const ::com::sun::star::geometry::RealPoint2D& aEndPoint, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + void drawBezier( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::geometry::RealBezierSegment2D& aBezierSegment, + const ::com::sun::star::geometry::RealPoint2D& aEndPoint, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + strokePolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + strokeTexturedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::rendering::Texture >& textures, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + strokeTextureMappedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::rendering::Texture >& textures, + const ::com::sun::star::uno::Reference< + ::com::sun::star::geometry::XMapping2D >& xMapping, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > + queryStrokeShapes( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + fillPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + fillTexturedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::rendering::Texture >& textures ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + fillTextureMappedPolyPolygon( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::rendering::Texture >& textures, + const ::com::sun::star::uno::Reference< + ::com::sun::star::geometry::XMapping2D >& xMapping ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > SAL_CALL + createFont( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::rendering::FontRequest& fontRequest, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue >& extraFontProperties, + const ::com::sun::star::geometry::Matrix2D& fontMatrix ); + + ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::FontInfo > + queryAvailableFonts( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::rendering::FontInfo& aFilter, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue >& aFontProperties ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawText( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::rendering::StringContext& text, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& xFont, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + sal_Int8 textDirection ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawTextLayout( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XTextLayout >& layoutetText, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawBitmap( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + drawBitmapModulated( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > + getDevice(); + + // BitmapCanvasHelper functionality + // ================================ + + void copyRect( const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmapCanvas >& sourceCanvas, + const ::com::sun::star::geometry::RealRectangle2D& sourceRect, + const ::com::sun::star::rendering::ViewState& sourceViewState, + const ::com::sun::star::rendering::RenderState& sourceRenderState, + const ::com::sun::star::geometry::RealRectangle2D& destRect, + const ::com::sun::star::rendering::ViewState& destViewState, + const ::com::sun::star::rendering::RenderState& destRenderState ); + + ::com::sun::star::geometry::IntegerSize2D getSize(); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > + getScaledBitmap( const ::com::sun::star::geometry::RealSize2D& newSize, + sal_Bool beFast ); + + ::com::sun::star::uno::Sequence< sal_Int8 > + getData( ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + void setData( const ::com::sun::star::uno::Sequence< sal_Int8 >& data, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + void setPixel( const ::com::sun::star::uno::Sequence< sal_Int8 >& color, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + + ::com::sun::star::uno::Sequence< sal_Int8 > + getPixel( ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapPalette > getPalette(); + + ::com::sun::star::rendering::IntegerBitmapLayout getMemoryLayout(); + + // Flush drawing queue to screen + void flush() const; + + /** Called from XCanvas base classes, to notify that content + is _about_ to change + */ + void modifying() {} + + bool hasAlpha() const; + + enum ColorType + { + LINE_COLOR, FILL_COLOR, TEXT_COLOR, IGNORE_COLOR + }; + + void doPolyPolygonPath( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >& xPolyPolygon, + Operation aOperation, + bool bNoLineJoin = false, + const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::Texture >* pTextures=NULL, + ::cairo::Cairo* pCairo=NULL ) const; + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + implDrawBitmapSurface( + const ::com::sun::star::rendering::XCanvas* pCanvas, + const ::cairo::SurfaceSharedPtr& pSurface, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::geometry::IntegerSize2D& rSize, + bool bModulateColors, + bool bHasAlpha ); + + bool repaint( const ::cairo::SurfaceSharedPtr& pSurface, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + protected: + /** Surface provider + + Deliberately not a refcounted reference, because of + potential circular references for canvas. Provides us with + our output surface and associated functionality. + */ + SurfaceProvider* mpSurfaceProvider; + + /** Phyical output device + + Deliberately not a refcounted reference, because of + potential circular references for spritecanvas. + */ + ::com::sun::star::rendering::XGraphicDevice* mpDevice; + + private: + + boost::shared_ptr<VirtualDevice> mpVirtualDevice; + + void useStates( const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + bool setColor ); + + /// When true, content is able to represent alpha + bool mbHaveAlpha; + + CairoSharedPtr mpCairo; + SurfaceSharedPtr mpSurface; + ::basegfx::B2ISize maSize; + }; + + /// also needed from SpriteHelper + void doPolyPolygonImplementation( ::basegfx::B2DPolyPolygon aPolyPolygon, + Operation aOperation, + ::cairo::Cairo* pCairo, + const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::Texture >* pTextures, + const SurfaceProviderRef& pDevice, + ::com::sun::star::rendering::FillRule eFillrule ); +} + +#endif /* _CAIROCANVAS_CANVASHELPER_HXX_ */ diff --git a/canvas/source/cairo/cairo_canvashelper_text.cxx b/canvas/source/cairo/cairo_canvashelper_text.cxx new file mode 100644 index 000000000000..35310e1c078d --- /dev/null +++ b/canvas/source/cairo/cairo_canvashelper_text.cxx @@ -0,0 +1,398 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <vcl/virdev.hxx> +#include <vcl/metric.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include "cairo_canvasfont.hxx" +#include "cairo_textlayout.hxx" +#include "cairo_canvashelper.hxx" + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + enum ColorType + { + LINE_COLOR, FILL_COLOR, TEXT_COLOR, IGNORE_COLOR + }; + + uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* , + const rendering::FontRequest& fontRequest, + const uno::Sequence< beans::PropertyValue >& extraFontProperties, + const geometry::Matrix2D& fontMatrix ) + { + return uno::Reference< rendering::XCanvasFont >( new CanvasFont( fontRequest, extraFontProperties, fontMatrix, mpSurfaceProvider )); + } + + uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* , + const rendering::FontInfo& /*aFilter*/, + const uno::Sequence< beans::PropertyValue >& /*aFontProperties*/ ) + { + // TODO + return uno::Sequence< rendering::FontInfo >(); + } + + static bool + setupFontTransform( ::OutputDevice& rOutDev, + ::Point& o_rPoint, + ::Font& io_rVCLFont, + const rendering::ViewState& rViewState, + const rendering::RenderState& rRenderState ) + { + ::basegfx::B2DHomMatrix aMatrix; + + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, + rViewState, + rRenderState); + + ::basegfx::B2DTuple aScale; + ::basegfx::B2DTuple aTranslate; + double nRotate, nShearX; + + aMatrix.decompose( aScale, aTranslate, nRotate, nShearX ); + + // query font metric _before_ tampering with width and height + if( !::rtl::math::approxEqual(aScale.getX(), aScale.getY()) ) + { + // retrieve true font width + const sal_Int32 nFontWidth( rOutDev.GetFontMetric( io_rVCLFont ).GetWidth() ); + + const sal_Int32 nScaledFontWidth( ::basegfx::fround(nFontWidth * aScale.getX()) ); + + if( !nScaledFontWidth ) + { + // scale is smaller than one pixel - disable text + // output altogether + return false; + } + + io_rVCLFont.SetWidth( nScaledFontWidth ); + } + + if( !::rtl::math::approxEqual(aScale.getY(), 1.0) ) + { + const sal_Int32 nFontHeight( io_rVCLFont.GetHeight() ); + io_rVCLFont.SetHeight( ::basegfx::fround(nFontHeight * aScale.getY()) ); + } + + io_rVCLFont.SetOrientation( static_cast< short >( ::basegfx::fround(-fmod(nRotate, 2*M_PI)*(1800.0/M_PI)) ) ); + + // TODO(F2): Missing functionality in VCL: shearing + o_rPoint.X() = ::basegfx::fround(aTranslate.getX()); + o_rPoint.Y() = ::basegfx::fround(aTranslate.getY()); + + return true; + } + + static int + setupOutDevState( OutputDevice& rOutDev, + const rendering::XCanvas* pOwner, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + ColorType eColorType ) + { + ::canvas::tools::verifyInput( renderState, + BOOST_CURRENT_FUNCTION, + const_cast<rendering::XCanvas*>(pOwner), // only for refcount + 2, + eColorType == IGNORE_COLOR ? 0 : 3 ); + + int nTransparency(0); + + // TODO(P2): Don't change clipping all the time, maintain current clip + // state and change only when update is necessary + + // accumulate non-empty clips into one region + // ========================================== + + Region aClipRegion; + + if( viewState.Clip.is() ) + { + ::basegfx::B2DPolyPolygon aClipPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( + viewState.Clip) ); + + if( aClipPoly.count() ) + { + // setup non-empty clipping + ::basegfx::B2DHomMatrix aMatrix; + aClipPoly.transform( + ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix, + viewState.AffineTransform ) ); + + aClipRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) ); + } + } + + if( renderState.Clip.is() ) + { + ::basegfx::B2DPolyPolygon aClipPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( + renderState.Clip) ); + + ::basegfx::B2DHomMatrix aMatrix; + aClipPoly.transform( + ::canvas::tools::mergeViewAndRenderTransform( aMatrix, + viewState, + renderState ) ); + + if( aClipPoly.count() ) + { + // setup non-empty clipping + Region aRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) ); + + if( aClipRegion.IsEmpty() ) + aClipRegion = aRegion; + else + aClipRegion.Intersect( aRegion ); + } + else + { + // clip polygon is empty + aClipRegion.SetEmpty(); + } + } + + // setup accumulated clip region. Note that setting an + // empty clip region denotes "clip everything" on the + // OutputDevice (which is why we translate that into + // SetClipRegion() here). When both view and render clip + // are empty, aClipRegion remains default-constructed, + // i.e. empty, too. + if( aClipRegion.IsEmpty() ) + { + rOutDev.SetClipRegion(); + } + else + { + rOutDev.SetClipRegion( aClipRegion ); + } + + if( eColorType != IGNORE_COLOR ) + { + Color aColor( COL_WHITE ); + + if( renderState.DeviceColor.getLength() > 2 ) + { + aColor = ::vcl::unotools::stdColorSpaceSequenceToColor( renderState.DeviceColor ); + } + + // extract alpha, and make color opaque + // afterwards. Otherwise, OutputDevice won't draw anything + nTransparency = aColor.GetTransparency(); + aColor.SetTransparency(0); + + switch( eColorType ) + { + case LINE_COLOR: + rOutDev.SetLineColor( aColor ); + rOutDev.SetFillColor(); + + break; + + case FILL_COLOR: + rOutDev.SetFillColor( aColor ); + rOutDev.SetLineColor(); + + break; + + case TEXT_COLOR: + rOutDev.SetTextColor( aColor ); + + break; + + default: + ENSURE_OR_THROW( false, + "CanvasHelper::setupOutDevState(): Unexpected color type"); + break; + } + } + + return nTransparency; + } + + bool setupTextOutput( OutputDevice& rOutDev, + const rendering::XCanvas* pOwner, + ::Point& o_rOutPos, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Reference< rendering::XCanvasFont >& xFont ) + { + setupOutDevState( rOutDev, pOwner, viewState, renderState, TEXT_COLOR ); + + ::Font aVCLFont; + + CanvasFont* pFont = dynamic_cast< CanvasFont* >( xFont.get() ); + + ENSURE_ARG_OR_THROW( pFont, + "CanvasHelper::setupTextOutput(): Font not compatible with this canvas" ); + + aVCLFont = pFont->getVCLFont(); + + Color aColor( COL_BLACK ); + + if( renderState.DeviceColor.getLength() > 2 ) + { + aColor = ::vcl::unotools::stdColorSpaceSequenceToColor(renderState.DeviceColor ); + } + + // setup font color + aVCLFont.SetColor( aColor ); + aVCLFont.SetFillColor( aColor ); + + // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here. + if( !setupFontTransform( rOutDev, o_rOutPos, aVCLFont, viewState, renderState ) ) + return false; + + rOutDev.SetFont( aVCLFont ); + + + return true; + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* pOwner, + const rendering::StringContext& text, + const uno::Reference< rendering::XCanvasFont >& xFont, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + sal_Int8 textDirection ) + { +#ifdef CAIRO_CANVAS_PERF_TRACE + struct timespec aTimer; + mxDevice->startPerfTrace( &aTimer ); +#endif + + ENSURE_ARG_OR_THROW( xFont.is(), + "CanvasHelper::drawText(): font is NULL"); + + if( !mpVirtualDevice ) + mpVirtualDevice = mpSurface->createVirtualDevice(); + + if( mpVirtualDevice ) + { +#if defined CAIRO_HAS_WIN32_SURFACE + // FIXME: Some kind of work-araound... + cairo_rectangle (mpSurface->getCairo().get(), 0, 0, 0, 0); + cairo_fill(mpSurface->getCairo().get()); +#endif + ::Point aOutpos; + if( !setupTextOutput( *mpVirtualDevice, pOwner, aOutpos, viewState, renderState, xFont ) ) + return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary + + // change text direction and layout mode + ULONG nLayoutMode(0); + switch( textDirection ) + { + case rendering::TextDirection::WEAK_LEFT_TO_RIGHT: + nLayoutMode |= TEXT_LAYOUT_BIDI_LTR; + // FALLTHROUGH intended + case rendering::TextDirection::STRONG_LEFT_TO_RIGHT: + nLayoutMode |= TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG; + nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_LEFT; + break; + + case rendering::TextDirection::WEAK_RIGHT_TO_LEFT: + nLayoutMode |= TEXT_LAYOUT_BIDI_RTL; + // FALLTHROUGH intended + case rendering::TextDirection::STRONG_RIGHT_TO_LEFT: + nLayoutMode |= TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG; + nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_RIGHT; + break; + } + + // TODO(F2): alpha + mpVirtualDevice->SetLayoutMode( nLayoutMode ); + + OSL_TRACE(":cairocanvas::CanvasHelper::drawText(O,t,f,v,r,d): %s", ::rtl::OUStringToOString( text.Text.copy( text.StartPosition, text.Length ), + RTL_TEXTENCODING_UTF8 ).getStr()); + + TextLayout* pTextLayout = new TextLayout(text, textDirection, 0, CanvasFont::Reference(dynamic_cast< CanvasFont* >( xFont.get() )), mpSurfaceProvider); + pTextLayout->draw( mpSurface, *mpVirtualDevice, aOutpos, viewState, renderState ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* pOwner, + const uno::Reference< rendering::XTextLayout >& xLayoutedText, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_ARG_OR_THROW( xLayoutedText.is(), + "CanvasHelper::drawTextLayout(): layout is NULL"); + + TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() ); + + if( pTextLayout ) + { + if( !mpVirtualDevice ) + mpVirtualDevice = mpSurface->createVirtualDevice(); + + if( mpVirtualDevice ) + { +#if defined CAIRO_HAS_WIN32_SURFACE + // FIXME: Some kind of work-araound... + cairo_rectangle( mpSurface->getCairo().get(), 0, 0, 0, 0); + cairo_fill(mpSurface->getCairo().get()); +#endif + // TODO(T3): Race condition. We're taking the font + // from xLayoutedText, and then calling draw() at it, + // without exclusive access. Move setupTextOutput(), + // e.g. to impltools? + + ::Point aOutpos; + if( !setupTextOutput( *mpVirtualDevice, pOwner, aOutpos, viewState, renderState, xLayoutedText->getFont() ) ) + return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary + + // TODO(F2): What about the offset scalings? + pTextLayout->draw( mpSurface, *mpVirtualDevice, aOutpos, viewState, renderState ); + } + } + else + { + ENSURE_ARG_OR_THROW( false, + "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + +} diff --git a/canvas/source/cairo/cairo_canvashelper_texturefill.cxx b/canvas/source/cairo/cairo_canvashelper_texturefill.cxx new file mode 100644 index 000000000000..ee8aff6980cf --- /dev/null +++ b/canvas/source/cairo/cairo_canvashelper_texturefill.cxx @@ -0,0 +1,144 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> + +#include <rtl/math.hxx> + +#include <com/sun/star/rendering/TextDirection.hpp> +#include <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> + +#include <tools/poly.hxx> +#include <vcl/window.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dlinegeometry.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <utility> + +#include <comphelper/sequence.hxx> +#include <canvas/canvastools.hxx> + +#include "cairo_textlayout.hxx" +#include "cairo_parametricpolypolygon.hxx" +#include "cairo_canvashelper.hxx" +#include "cairo_canvasbitmap.hxx" +#include "cairo_impltools.hxx" +#include "cairo_canvasfont.hxx" + +using namespace ::com::sun::star; + +namespace cairocanvas +{ + namespace + { + bool textureFill( OutputDevice& rOutDev, + GraphicObject& rGraphic, + const ::Point& rPosPixel, + const ::Size& rNextTileX, + const ::Size& rNextTileY, + sal_Int32 nTilesX, + sal_Int32 nTilesY, + const ::Size& rTileSize, + const GraphicAttr& rAttr) + { + BOOL bRet( false ); + Point aCurrPos; + int nX, nY; + + for( nY=0; nY < nTilesY; ++nY ) + { + aCurrPos.X() = rPosPixel.X() + nY*rNextTileY.Width(); + aCurrPos.Y() = rPosPixel.Y() + nY*rNextTileY.Height(); + + for( nX=0; nX < nTilesX; ++nX ) + { + // update return value. This method should return true, if + // at least one of the looped Draws succeeded. + bRet |= rGraphic.Draw( &rOutDev, + aCurrPos, + rTileSize, + &rAttr ); + + aCurrPos.X() += rNextTileX.Width(); + aCurrPos.Y() += rNextTileX.Height(); + } + } + + return bRet; + } + + inline sal_Int32 roundDown( const double& rVal ) + { + return static_cast< sal_Int32 >( floor( rVal ) ); + } + + inline sal_Int32 roundUp( const double& rVal ) + { + return static_cast< sal_Int32 >( ceil( rVal ) ); + } + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas& rCanvas, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures ) + { + ENSURE_ARG_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::fillPolyPolygon(): polygon is NULL"); + ENSURE_ARG_OR_THROW( textures.getLength(), + "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence"); + + cairo_save( mpCairo ); + + useStates( viewState, renderState, true ); + mpTextures = &textures; + drawPolyPolygonPath( xPolyPolygon, Fill ); + mpTextures = NULL; + + cairo_restore( mpCairo ); + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } +} diff --git a/canvas/source/cairo/cairo_devicehelper.cxx b/canvas/source/cairo/cairo_devicehelper.cxx new file mode 100644 index 000000000000..70a5ea51c0ea --- /dev/null +++ b/canvas/source/cairo/cairo_devicehelper.cxx @@ -0,0 +1,302 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> + +#include <osl/mutex.hxx> +#include <cppuhelper/compbase1.hxx> + +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <toolkit/helper/vclunohelper.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/tools/unopolypolygon.hxx> + +#include <vcl/canvastools.hxx> + +#include <tools/stream.hxx> + +#include "cairo_spritecanvas.hxx" +#include "cairo_canvasbitmap.hxx" +#include "cairo_devicehelper.hxx" + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + DeviceHelper::DeviceHelper() : + mpSurfaceProvider( NULL ), + mpRefDevice( NULL ), + mpSurface() + { + } + + void DeviceHelper::implInit( SurfaceProvider& rSurfaceProvider, + OutputDevice& rRefDevice ) + { + mpSurfaceProvider = &rSurfaceProvider; + mpRefDevice = &rRefDevice; + + // no own surface, this is handled by derived classes + } + + void DeviceHelper::init( SurfaceProvider& rSurfaceProvider, + OutputDevice& rRefDevice ) + { + implInit(rSurfaceProvider, rRefDevice); + + OutputDevice* pOutDev=getOutputDevice(); + mpSurface = cairo::createSurface( *pOutDev, + pOutDev->GetOutOffXPixel(), + pOutDev->GetOutOffYPixel(), + pOutDev->GetOutputWidthPixel(), + pOutDev->GetOutputHeightPixel() ); + } + + void DeviceHelper::disposing() + { + // release all references + mpSurface.reset(); + mpRefDevice = NULL; + mpSurfaceProvider = NULL; + } + + void DeviceHelper::setSize( const ::basegfx::B2ISize& rSize ) + { + OSL_TRACE("DeviceHelper::setSize(): device size %d x %d", rSize.getX(), rSize.getY() ); + + if( !mpRefDevice ) + return; // disposed + + OutputDevice* pOutDev=getOutputDevice(); + +#if defined (UNX) && !defined (QUARTZ) + // X11 only + if( mpSurface ) + mpSurface->Resize( rSize.getX() + pOutDev->GetOutOffXPixel(), + rSize.getY() + pOutDev->GetOutOffYPixel() ); + else +#endif + mpSurface = cairo::createSurface( + *pOutDev, + pOutDev->GetOutOffXPixel(), + pOutDev->GetOutOffYPixel(), + rSize.getX(), rSize.getY() ); + } + + geometry::RealSize2D DeviceHelper::getPhysicalResolution() + { + // Map a one-by-one millimeter box to pixel + const MapMode aOldMapMode( mpRefDevice->GetMapMode() ); + mpRefDevice->SetMapMode( MapMode(MAP_MM) ); + const Size aPixelSize( mpRefDevice->LogicToPixel(Size(1,1)) ); + mpRefDevice->SetMapMode( aOldMapMode ); + + return ::vcl::unotools::size2DFromSize( aPixelSize ); + } + + geometry::RealSize2D DeviceHelper::getPhysicalSize() + { + if( !mpRefDevice ) + return ::canvas::tools::createInfiniteSize2D(); // we're disposed + + // Map the pixel dimensions of the output window to millimeter + const MapMode aOldMapMode( mpRefDevice->GetMapMode() ); + mpRefDevice->SetMapMode( MapMode(MAP_MM) ); + const Size aLogSize( mpRefDevice->PixelToLogic(mpRefDevice->GetOutputSizePixel()) ); + mpRefDevice->SetMapMode( aOldMapMode ); + + return ::vcl::unotools::size2DFromSize( aLogSize ); + } + + uno::Reference< rendering::XLinePolyPolygon2D > DeviceHelper::createCompatibleLinePolyPolygon( + const uno::Reference< rendering::XGraphicDevice >& , + const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) + { + // disposed? + if( !mpSurfaceProvider ) + return uno::Reference< rendering::XLinePolyPolygon2D >(); // we're disposed + + return uno::Reference< rendering::XLinePolyPolygon2D >( + new ::basegfx::unotools::UnoPolyPolygon( + ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points ) ) ); + } + + uno::Reference< rendering::XBezierPolyPolygon2D > DeviceHelper::createCompatibleBezierPolyPolygon( + const uno::Reference< rendering::XGraphicDevice >& , + const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points ) + { + // disposed? + if( !mpSurfaceProvider ) + return uno::Reference< rendering::XBezierPolyPolygon2D >(); // we're disposed + + return uno::Reference< rendering::XBezierPolyPolygon2D >( + new ::basegfx::unotools::UnoPolyPolygon( + ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points ) ) ); + } + + uno::Reference< rendering::XBitmap > DeviceHelper::createCompatibleBitmap( + const uno::Reference< rendering::XGraphicDevice >& rDevice, + const geometry::IntegerSize2D& size ) + { + // disposed? + if( !mpSurfaceProvider ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + return uno::Reference< rendering::XBitmap >( + new CanvasBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D( size ), + SurfaceProviderRef(mpSurfaceProvider), + rDevice.get(), + false )); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileBitmap( + const uno::Reference< rendering::XGraphicDevice >& , + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + uno::Reference< rendering::XBitmap > DeviceHelper::createCompatibleAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& rDevice, + const geometry::IntegerSize2D& size ) + { + // disposed? + if( !mpSurfaceProvider ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + return uno::Reference< rendering::XBitmap >( + new CanvasBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D( size ), + SurfaceProviderRef(mpSurfaceProvider), + rDevice.get(), + true )); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& , + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + sal_Bool DeviceHelper::hasFullScreenMode() + { + // TODO(F3): offer fullscreen mode the XCanvas way + return false; + } + + sal_Bool DeviceHelper::enterFullScreenMode( sal_Bool /*bEnter*/ ) + { + // TODO(F3): offer fullscreen mode the XCanvas way + return false; + } + + uno::Any DeviceHelper::isAccelerated() const + { + return ::com::sun::star::uno::makeAny(false); + } + + uno::Any DeviceHelper::getDeviceHandle() const + { + return uno::makeAny( reinterpret_cast< sal_Int64 >(mpRefDevice) ); + } + + uno::Any DeviceHelper::getSurfaceHandle() const + { + return uno::Any(); + } + + namespace + { + struct DeviceColorSpace: public rtl::StaticWithInit<uno::Reference<rendering::XColorSpace>, + DeviceColorSpace> + { + uno::Reference<rendering::XColorSpace> operator()() + { + return vcl::unotools::createStandardColorSpace(); + } + }; + } + + uno::Reference<rendering::XColorSpace> DeviceHelper::getColorSpace() const + { + // always the same + return DeviceColorSpace::get(); + } + + void DeviceHelper::dumpScreenContent() const + { + static sal_uInt32 nFilePostfixCount(0); + + if( mpRefDevice ) + { + String aFilename( String::CreateFromAscii("dbg_frontbuffer") ); + aFilename += String::CreateFromInt32(nFilePostfixCount); + aFilename += String::CreateFromAscii(".bmp"); + + SvFileStream aStream( aFilename, STREAM_STD_READWRITE ); + + const ::Point aEmptyPoint; + bool bOldMap( mpRefDevice->IsMapModeEnabled() ); + mpRefDevice->EnableMapMode( FALSE ); + aStream << mpRefDevice->GetBitmap(aEmptyPoint, + mpRefDevice->GetOutputSizePixel()); + mpRefDevice->EnableMapMode( bOldMap ); + + ++nFilePostfixCount; + } + } + + SurfaceSharedPtr DeviceHelper::getSurface() + { + return mpSurface; + } + + SurfaceSharedPtr DeviceHelper::createSurface( const ::basegfx::B2ISize& rSize, Content aContent ) + { + if( mpSurface ) + return mpSurface->getSimilar( aContent, rSize.getX(), rSize.getY() ); + + return SurfaceSharedPtr(); + } + + SurfaceSharedPtr DeviceHelper::createSurface( BitmapSystemData& rData, const Size& rSize ) + { + if( mpRefDevice ) + return createBitmapSurface( *mpRefDevice, rData, rSize ); + + return SurfaceSharedPtr(); + } +} diff --git a/canvas/source/cairo/cairo_devicehelper.hxx b/canvas/source/cairo/cairo_devicehelper.hxx new file mode 100644 index 000000000000..84c5a84926ca --- /dev/null +++ b/canvas/source/cairo/cairo_devicehelper.hxx @@ -0,0 +1,143 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_DEVICEHELPER_HXX +#define _CAIROCANVAS_DEVICEHELPER_HXX + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include <boost/utility.hpp> + +#include <vcl/window.hxx> +#include <vcl/bitmap.hxx> + +#include "cairo_cairo.hxx" +#include "cairo_surfaceprovider.hxx" + +/* Definition of DeviceHelper class */ + +struct SystemEnvData; +class Window; + +namespace cairocanvas +{ + class Canvas; + class CanvasHelper; + + class DeviceHelper : private ::boost::noncopyable + { + public: + DeviceHelper(); + + /** init helper + + @param rCanvas + Owning canvas. + + @param rRefDevice + Reference output device. Needed for resolution + calculations etc. + */ + void init( SurfaceProvider& rSurfaceProvider, + OutputDevice& rRefDevice ); + + /// Dispose all internal references + void disposing(); + + // XWindowGraphicDevice + ::com::sun::star::geometry::RealSize2D getPhysicalResolution(); + ::com::sun::star::geometry::RealSize2D getPhysicalSize(); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XLinePolyPolygon2D > createCompatibleLinePolyPolygon( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > >& points ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBezierPolyPolygon2D > createCompatibleBezierPolyPolygon( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealBezierSegment2D > >& points ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > createCompatibleBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XVolatileBitmap > createVolatileBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > createCompatibleAlphaBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XVolatileBitmap > createVolatileAlphaBitmap( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::geometry::IntegerSize2D& size ); + sal_Bool hasFullScreenMode( ); + sal_Bool enterFullScreenMode( sal_Bool bEnter ); + + ::com::sun::star::uno::Any isAccelerated() const; + ::com::sun::star::uno::Any getDeviceHandle() const; + ::com::sun::star::uno::Any getSurfaceHandle() const; + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XColorSpace > getColorSpace() const; + + /** called when DumpScreenContent property is enabled on + XGraphicDevice, and writes out bitmaps of current screen. + */ + void dumpScreenContent() const; + + OutputDevice* getOutputDevice() const { return mpRefDevice; } + const void* getSysData() { return mpSysData; } + ::cairo::SurfaceSharedPtr getSurface(); + ::cairo::SurfaceSharedPtr createSurface( const ::basegfx::B2ISize& rSize, ::cairo::Content aContent = CAIRO_CONTENT_COLOR_ALPHA ); + ::cairo::SurfaceSharedPtr createSurface( BitmapSystemData& rData, const Size& rSize ); + + protected: + /** init helper + + @param rCanvas + Owning canvas. + + @param rRefDevice + Reference output device. Needed for resolution + calculations etc. + */ + void implInit( SurfaceProvider& rSurfaceProvider, + OutputDevice& rRefDevice ); + void setSize( const ::basegfx::B2ISize& rSize ); + + private: + /** Surface provider + + Deliberately not a refcounted reference, because of + potential circular references for canvas. Provides us with + our output surface and associated functionality. + */ + SurfaceProvider* mpSurfaceProvider; + + OutputDevice* mpRefDevice; + const void* mpSysData; + ::cairo::SurfaceSharedPtr mpSurface; + }; +} + +#endif diff --git a/canvas/source/cairo/cairo_quartz_cairo.cxx b/canvas/source/cairo/cairo_quartz_cairo.cxx new file mode 100644 index 000000000000..52626a0ae849 --- /dev/null +++ b/canvas/source/cairo/cairo_quartz_cairo.cxx @@ -0,0 +1,347 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#ifdef QUARTZ +/************************************************************************ + * Mac OS X/Quartz surface backend for OpenOffice.org Cairo Canvas * + ************************************************************************/ + +#include <osl/diagnose.h> +#include <vcl/sysdata.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/virdev.hxx> + +#include "cairo_cairo.hxx" + +#if defined CAIRO_HAS_QUARTZ_SURFACE + +#include "cairo_quartz_cairo.hxx" + +namespace cairo +{ + bool IsCairoWorking( OutputDevice* ) + { + // trivially true for Mac + return true; + } + + /** + * QuartzSurface::Surface: Create generic Canvas surface using given Cairo Surface + * + * @param pSurface Cairo Surface + * + * This constructor only stores data, it does no processing. + * It is used with e.g. cairo_image_surface_create_for_data() + * and QuartzSurface::getSimilar() + * + * Set the mpSurface to the new surface or NULL + **/ + QuartzSurface::QuartzSurface( const CairoSurfaceSharedPtr& pSurface ) : + mpView(NULL), + mpSurface( pSurface ) + { + // Necessary, context is lost otherwise + CGContextRetain( getCGContext() ); // == NULL for non-native surfaces + } + + /** + * QuartzSurface::Surface: Create Canvas surface from Window reference. + * @param NSView + * @param x horizontal location of the new surface + * @param y vertical location of the new surface + * @param width width of the new surface + * @param height height of the new surface + * + * pSysData contains the platform native Window reference. + * pSysData is used to create a surface on the Window + * + * Set the mpSurface to the new surface or NULL + **/ + QuartzSurface::QuartzSurface( NSView* pView, int x, int y, int width, int height ) : + mpView(pView), + mpSurface() + { + OSL_TRACE("Canvas::cairo::Surface(NSView*, x:%d, y:%d, w:%d, h:%d): New Surface for window", x, y, width, height); + + // on Mac OS X / Quartz we are not drawing directly to the screen, but via regular CGContextRef. + // The actual drawing to NSView (i.e. screen) is done in QuartzSurface::flush() + + // HACK: currently initial size for windowsurface is 0x0, which is not possible for us. + if (width == 0 || height == 0) { + width = [mpView bounds].size.width; + height = [mpView bounds].size.height; + OSL_TRACE("Canvas::cairo::Surface(): BUG!! size is ZERO! fixing to %d x %d...", width, height); + } + + // create a generic surface, NSView/Window is ARGB32. + mpSurface.reset( + cairo_quartz_surface_create(CAIRO_FORMAT_ARGB32, width, height), + &cairo_surface_destroy); + + cairo_surface_set_device_offset( mpSurface.get(), x, y ); + } + + /** + * QuartzSurface::Surface: Create Canvas surface from CGContextRef. + * @param CGContext Native graphics context + * @param x horizontal location of the new surface + * @param y vertical location of the new surface + * @param width width of the new surface + * @param height height of the new surface + * + * Set the mpSurface to the new surface or NULL + **/ + QuartzSurface::QuartzSurface( CGContextRef rContext, int x, int y, int width, int height ) : + mpView(NULL), + mpSurface() + { + OSL_TRACE("Canvas::cairo::Surface(CGContext:%p, x:%d, y:%d, w:%d, h:%d): New Surface.", rContext, x, y, width, height); + // create surface based on CGContext + + // ensure kCGBitmapByteOrder32Host flag, otherwise Cairo breaks (we are practically always using CGBitmapContext) + OSL_ASSERT ((CGBitmapContextGetBitsPerPixel(rContext) != 32) || + (CGBitmapContextGetBitmapInfo(rContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host); + + mpSurface.reset(cairo_quartz_surface_create_for_cg_context(rContext, width, height), + &cairo_surface_destroy); + + cairo_surface_set_device_offset( mpSurface.get(), x, y ); + + // Necessary, context is lost otherwise + CGContextRetain(rContext); + } + + + /** + * QuartzSurface::getCairo: Create Cairo (drawing object) for the Canvas surface + * + * @return new Cairo or NULL + **/ + CairoSharedPtr QuartzSurface::getCairo() const + { + if (mpSurface.get()){ + return CairoSharedPtr( cairo_create(mpSurface.get()), + &cairo_destroy ); + } else { + return CairoSharedPtr(); + } + } + + /** + * QuartzSurface::getSimilar: Create new similar Canvas surface + * @param aContent format of the new surface (cairo_content_t from cairo/src/cairo.h) + * @param width width of the new surface + * @param height height of the new surface + * + * Creates a new Canvas surface. This normally creates platform native surface, even though + * generic function is used. + * + * Cairo surface from aContent (cairo_content_t) + * + * @return new surface or NULL + **/ + SurfaceSharedPtr QuartzSurface::getSimilar( Content aContent, int width, int height ) const + { + return SurfaceSharedPtr( + new QuartzSurface( + CairoSurfaceSharedPtr( + cairo_surface_create_similar( mpSurface.get(), aContent, width, height ), + &cairo_surface_destroy ))); + } + + /** + * QuartzSurface::Resize: Resizes the Canvas surface. + * @param width new width of the surface + * @param height new height of the surface + * + * Only used on X11. + * + * @return The new surface or NULL + **/ + void QuartzSurface::Resize( int width, int height ) + { + OSL_ENSURE(false,"not supposed to be called!"); + } + + + /** + * QuartzSurface::flush: Draw the data to screen + **/ + void QuartzSurface::flush() const + { + // can only flush surfaces with NSView + if( !mpView ) return; + + OSL_TRACE("Canvas::cairo::QuartzSurface::flush(): flush to NSView"); + + CGContextRef mrContext = getCGContext(); + + if (!mrContext) return; + + [mpView lockFocus]; + + /** + * This code is using same screen update code as in VCL (esp. AquaSalGraphics::UpdateWindow() ) + */ + CGContextRef rViewContext = reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); + CGImageRef xImage = CGBitmapContextCreateImage(mrContext); + CGContextDrawImage(rViewContext, + CGRectMake( 0, 0, + CGImageGetWidth(xImage), + CGImageGetHeight(xImage)), + xImage); + CGImageRelease( xImage ); + CGContextFlush( rViewContext ); + + [mpView unlockFocus]; + } + + /** + * QuartzSurface::getDepth: Get the color depth of the Canvas surface. + * + * @return color depth + **/ + int QuartzSurface::getDepth() const + { + if (mpSurface.get()) { + switch (cairo_surface_get_content (mpSurface.get())) { + case CAIRO_CONTENT_ALPHA: return 8; break; + case CAIRO_CONTENT_COLOR: return 24; break; + case CAIRO_CONTENT_COLOR_ALPHA: return 32; break; + } + } + OSL_TRACE("Canvas::cairo::QuartzSurface::getDepth(): ERROR - depth unspecified!"); + + return -1; + } + + /** + * QuartzSurface::getCGContext: Get the native CGContextRef of the Canvas's cairo surface + * + * @return graphics context + **/ + CGContextRef QuartzSurface::getCGContext() const + { + if (mpSurface.get()) + return cairo_quartz_surface_get_cg_context(mpSurface.get()); + else + return NULL; + } + + /** + * cairo::createVirtualDevice: Create a VCL virtual device for the CGContext in the cairo Surface + * + * @return The new virtual device + **/ + boost::shared_ptr<VirtualDevice> QuartzSurface::createVirtualDevice() const + { + SystemGraphicsData aSystemGraphicsData; + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.rCGContext = getCGContext(); + return boost::shared_ptr<VirtualDevice>( + new VirtualDevice( &aSystemGraphicsData, getDepth() )); + } + + /** + * cairo::createSurface: Create generic Canvas surface using given Cairo Surface + * + * @param rSurface Cairo Surface + * + * @return new Surface + */ + SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface ) + { + return SurfaceSharedPtr(new QuartzSurface(rSurface)); + } + + /** + * cairo::createSurface: Create Canvas surface using given VCL Window or Virtualdevice + * + * @param rSurface Cairo Surface + * + * For VCL Window, use platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx) + * For VCL Virtualdevice, use platform native system graphics data (struct SystemGraphicsData in vcl/inc/sysdata.hxx) + * + * @return new Surface + */ + SurfaceSharedPtr createSurface( const OutputDevice& rRefDevice, + int x, int y, int width, int height ) + { + SurfaceSharedPtr surf; + + if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW ) + { + const Window &rWindow = (const Window &) rRefDevice; + const SystemEnvData* pSysData = GetSysData(&rWindow); + if (pSysData) + surf = SurfaceSharedPtr(new QuartzSurface(pSysData->pView, x, y, width, height)); + } + else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV ) + { + SystemGraphicsData aSysData = ((const VirtualDevice&) rRefDevice).GetSystemGfxData(); + + if (aSysData.rCGContext) + surf = SurfaceSharedPtr(new QuartzSurface(aSysData.rCGContext, x, y, width, height)); + } + return surf; + } + + /** + * cairo::createBitmapSurface: Create platfrom native Canvas surface from BitmapSystemData + * @param OutputDevice (not used) + * @param rData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx) + * @param rSize width and height of the new surface + * + * Create a surface based on image data on rData + * + * @return new surface or empty surface + **/ + SurfaceSharedPtr createBitmapSurface( const OutputDevice& /* rRefDevice */, + const BitmapSystemData& rData, + const Size& rSize ) + { + OSL_TRACE( "requested size: %d x %d available size: %d x %d", + rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight ); + + if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() ) + { + CGContextRef rContext = (CGContextRef)rData.rImageContext; + OSL_TRACE("Canvas::cairo::createBitmapSurface(): New native image surface, context = %p.", rData.rImageContext); + + return SurfaceSharedPtr(new QuartzSurface(rContext, 0, 0, rData.mnWidth, rData.mnHeight)); + } + return SurfaceSharedPtr(); + } + +} // namespace cairo + +#endif // CAIRO_HAS_QUARTZ_SURFACE + +#endif // QUARTZ diff --git a/canvas/source/cairo/cairo_quartz_cairo.hxx b/canvas/source/cairo/cairo_quartz_cairo.hxx new file mode 100644 index 000000000000..104016751293 --- /dev/null +++ b/canvas/source/cairo/cairo_quartz_cairo.hxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_QUARTZ_CAIRO_HXX +#define _CAIROCANVAS_QUARTZ_CAIRO_HXX + +#include "cairo_cairo.hxx" + +#include "premac.h" +#include <Cocoa/Cocoa.h> +#include <cairo-quartz.h> +#include "postmac.h" + +namespace cairo { + + class QuartzSurface : public Surface + { + NSView* mpView; // if NULL - bg surface + CairoSurfaceSharedPtr mpSurface; + + public: + /// takes over ownership of passed cairo_surface + explicit QuartzSurface( const CairoSurfaceSharedPtr& pSurface ); + + /// create surface on subarea of given CGContext + explicit QuartzSurface( CGContextRef rContext, int x, int y, int width, int height ); + + /// create a offscreen surface for given NSView + QuartzSurface( NSView* pView, int x, int y, int width, int height ); + + // Surface interface + virtual CairoSharedPtr getCairo() const; + virtual CairoSurfaceSharedPtr getCairoSurface() const { return mpSurface; } + virtual SurfaceSharedPtr getSimilar( Content aContent, int width, int height ) const; + + virtual boost::shared_ptr<VirtualDevice> createVirtualDevice() const; + + virtual void Resize( int width, int height ); + + virtual void flush() const; + + int getDepth() const; + + CGContextRef getCGContext() const; + + }; +} + +#endif diff --git a/canvas/source/cairo/cairo_repainttarget.hxx b/canvas/source/cairo/cairo_repainttarget.hxx new file mode 100644 index 000000000000..3e4d40f1efe7 --- /dev/null +++ b/canvas/source/cairo/cairo_repainttarget.hxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_REPAINTTARGET_HXX +#define _CAIROCANVAS_REPAINTTARGET_HXX + +#ifndef _RTL_REF_HXX_ +#include <rtl/ref.hxx> +#endif + +#include "cairo_cairo.hxx" + +using namespace ::cairo; + +namespace cairocanvas +{ + /* Definition of RepaintTarget interface */ + + /** Target interface for XCachedPrimitive implementations + + This interface must be implemented on all canvas + implementations that hand out XCachedPrimitives + */ + class RepaintTarget + { + public: + virtual ~RepaintTarget() {} + + // call this when a bitmap is repainted + virtual bool repaint( const ::cairo::SurfaceSharedPtr& pSurface, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ) = 0; + }; +} + +#endif /* _CAIROCANVAS_REPAINTTARGET_HXX */ diff --git a/canvas/source/cairo/cairo_services.cxx b/canvas/source/cairo/cairo_services.cxx new file mode 100644 index 000000000000..a43b281c56bf --- /dev/null +++ b/canvas/source/cairo/cairo_services.cxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> + +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <comphelper/servicedecl.hxx> + +#include <algorithm> + +#include "cairo_canvas.hxx" +#include "cairo_spritecanvas.hxx" + + +using namespace ::com::sun::star; + +namespace cairocanvas +{ + static uno::Reference<uno::XInterface> initCanvas( Canvas* pCanvas ) + { + uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas)); + pCanvas->initialize(); + return xRet; + } + + namespace sdecl = comphelper::service_decl; + sdecl::class_< Canvas, sdecl::with_args<true> > serviceImpl1(&initCanvas); + const sdecl::ServiceDecl cairoCanvasDecl( + serviceImpl1, + CANVAS_IMPLEMENTATION_NAME, + CANVAS_SERVICE_NAME ); + + static uno::Reference<uno::XInterface> initSpriteCanvas( SpriteCanvas* pCanvas ) + { + uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas)); + pCanvas->initialize(); + return xRet; + } + + namespace sdecl = comphelper::service_decl; + sdecl::class_< SpriteCanvas, sdecl::with_args<true> > serviceImpl2(&initSpriteCanvas); + const sdecl::ServiceDecl cairoSpriteCanvasDecl( + serviceImpl2, + SPRITECANVAS_IMPLEMENTATION_NAME, + SPRITECANVAS_SERVICE_NAME ); +} + +// The C shared lib entry points +COMPHELPER_SERVICEDECL_EXPORTS2(cairocanvas::cairoCanvasDecl, cairocanvas::cairoSpriteCanvasDecl) diff --git a/canvas/source/cairo/cairo_sprite.hxx b/canvas/source/cairo/cairo_sprite.hxx new file mode 100644 index 000000000000..8f5a0d2d3ddd --- /dev/null +++ b/canvas/source/cairo/cairo_sprite.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_SPRITE_HXX +#define _CAIROCANVAS_SPRITE_HXX + +#include <canvas/base/sprite.hxx> + +#include "cairo_cairo.hxx" + +namespace cairocanvas +{ + /** Specialization of ::canvas::Sprite interface, to also provide + redraw methods. + */ + class Sprite : public ::canvas::Sprite + { + public: + + /** Redraw sprite at the stored position. + + @param bBufferedUpdate + When true, the redraw does <em>not</em> happen directly on + the front buffer, but within a VDev. Used to speed up + drawing. + */ + virtual void redraw( const ::cairo::CairoSharedPtr& pCairo, + bool bBufferedUpdate ) const = 0; + + /** Redraw sprite at the given position. + + @param rPos + Output position of the sprite. Overrides the sprite's own + output position. + + @param bBufferedUpdate + When true, the redraw does <em>not</em> happen directly on + the front buffer, but within a VDev. Used to speed up + drawing. + */ + virtual void redraw( const ::cairo::CairoSharedPtr& pCairo, + const ::basegfx::B2DPoint& rOrigOutputPos, + bool bBufferedUpdate ) const = 0; + }; +} + +#endif /* _CAIROCANVAS_SPRITE_HXX */ diff --git a/canvas/source/cairo/cairo_spritecanvas.cxx b/canvas/source/cairo/cairo_spritecanvas.cxx new file mode 100644 index 000000000000..43911c1113d6 --- /dev/null +++ b/canvas/source/cairo/cairo_spritecanvas.cxx @@ -0,0 +1,232 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <osl/mutex.hxx> + +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <toolkit/helper/vclunohelper.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include "cairo_spritecanvas.hxx" + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ) + { + } + + void SpriteCanvas::initialize() + { + VERBOSE_TRACE("CairoSpriteCanvas created %p\n", this); + + // #i64742# Only call initialize when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + /* maArguments: + 0: ptr to creating instance (Window or VirtualDevice) + 1: SystemEnvData as a streamed Any (or empty for VirtualDevice) + 2: current bounds of creating instance + 3: bool, denoting always on top state for Window (always false for VirtualDevice) + 4: XWindow for creating Window (or empty for VirtualDevice) + 5: SystemGraphicsData as a streamed Any + */ + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 4 && + maArguments[0].getValueTypeClass() == uno::TypeClass_HYPER && + maArguments[4].getValueTypeClass() == uno::TypeClass_INTERFACE, + "CairoSpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + awt::Rectangle aRect; + maArguments[2] >>= aRect; + + sal_Bool bIsFullscreen( sal_False ); + maArguments[3] >>= bIsFullscreen; + + uno::Reference< awt::XWindow > xParentWindow; + maArguments[4] >>= xParentWindow; + + Window* pParentWindow = VCLUnoHelper::GetWindow(xParentWindow); + if( !pParentWindow ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Parent window not VCL window, or canvas out-of-process!")), + NULL); + + bool bHasXRender = IsCairoWorking(pParentWindow); + ENSURE_ARG_OR_THROW( bHasXRender == true, + "CairoSpriteCanvas::SpriteCanvas: No RENDER extension" ); + + Size aPixelSize( pParentWindow->GetOutputSizePixel() ); + const ::basegfx::B2ISize aSize( aPixelSize.Width(), + aPixelSize.Height() ); + + ENSURE_ARG_OR_THROW( pParentWindow != NULL, + "CairoSpriteCanvas::initialize: invalid Window pointer" ); + + // setup helper + maDeviceHelper.init( *pParentWindow, + *this, + aSize, + bIsFullscreen ); + + setWindow(uno::Reference<awt::XWindow2>(xParentWindow, uno::UNO_QUERY_THROW)); + + maCanvasHelper.init( maRedrawManager, + *this, + aSize ); + + maArguments.realloc(0); + } + + void SAL_CALL SpriteCanvas::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mxComponentContext.clear(); + + // forward to parent + SpriteCanvasBaseT::disposing(); + } + + ::sal_Bool SAL_CALL SpriteCanvas::showBuffer( ::sal_Bool bUpdateAll ) throw (uno::RuntimeException) + { + return updateScreen( bUpdateAll ); + } + + ::sal_Bool SAL_CALL SpriteCanvas::switchBuffer( ::sal_Bool bUpdateAll ) throw (uno::RuntimeException) + { + return updateScreen( bUpdateAll ); + } + + sal_Bool SAL_CALL SpriteCanvas::updateScreen( sal_Bool bUpdateAll ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // avoid repaints on hidden window (hidden: not mapped to + // screen). Return failure, since the screen really has _not_ + // been updated (caller should try again later) + return !mbIsVisible ? false : maCanvasHelper.updateScreen( + ::basegfx::unotools::b2IRectangleFromAwtRectangle(maBounds), + bUpdateAll, + mbSurfaceDirty); + } + + ::rtl::OUString SAL_CALL SpriteCanvas::getServiceName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SPRITECANVAS_SERVICE_NAME ) ); + } + + SurfaceSharedPtr SpriteCanvas::getSurface() + { + return maDeviceHelper.getBufferSurface(); + } + + SurfaceSharedPtr SpriteCanvas::createSurface( const ::basegfx::B2ISize& rSize, Content aContent ) + { + return maDeviceHelper.createSurface( rSize, aContent ); + } + + SurfaceSharedPtr SpriteCanvas::createSurface( ::Bitmap& rBitmap ) + { + BitmapSystemData aData; + if( rBitmap.GetSystemData( aData ) ) { + const Size& rSize = rBitmap.GetSizePixel(); + + return maDeviceHelper.createSurface( aData, rSize ); + } + + return SurfaceSharedPtr(); + } + + SurfaceSharedPtr SpriteCanvas::changeSurface( bool, bool ) + { + // non-modifiable surface here + return SurfaceSharedPtr(); + } + + OutputDevice* SpriteCanvas::getOutputDevice() + { + return maDeviceHelper.getOutputDevice(); + } + + SurfaceSharedPtr SpriteCanvas::getBufferSurface() + { + return maDeviceHelper.getBufferSurface(); + } + + SurfaceSharedPtr SpriteCanvas::getWindowSurface() + { + return maDeviceHelper.getWindowSurface(); + } + + const ::basegfx::B2ISize& SpriteCanvas::getSizePixel() + { + return maDeviceHelper.getSizePixel(); + } + + void SpriteCanvas::setSizePixel( const ::basegfx::B2ISize& rSize ) + { + maCanvasHelper.setSize( rSize ); + // re-set background surface, in case it needed recreation + maCanvasHelper.setSurface( maDeviceHelper.getBufferSurface(), + false ); + } + + void SpriteCanvas::flush() + { + maDeviceHelper.flush(); + } + + bool SpriteCanvas::repaint( const SurfaceSharedPtr& pSurface, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return maCanvasHelper.repaint( pSurface, viewState, renderState ); + } +} diff --git a/canvas/source/cairo/cairo_spritecanvas.hxx b/canvas/source/cairo/cairo_spritecanvas.hxx new file mode 100644 index 000000000000..fcc0ae76839b --- /dev/null +++ b/canvas/source/cairo/cairo_spritecanvas.hxx @@ -0,0 +1,174 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_SPRITECANVAS_HXX_ +#define _CAIROCANVAS_SPRITECANVAS_HXX_ + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/awt/XWindowListener.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include <cppuhelper/compbase9.hxx> +#include <comphelper/uno3.hxx> + +#include <canvas/base/spritecanvasbase.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/bufferedgraphicdevicebase.hxx> + +#include <basegfx/vector/b2isize.hxx> + +#include "cairo_spritedevicehelper.hxx" +#include "cairo_repainttarget.hxx" +#include "cairo_surfaceprovider.hxx" +#include "cairo_spritecanvashelper.hxx" + +#define SPRITECANVAS_SERVICE_NAME "com.sun.star.rendering.SpriteCanvas.Cairo" +#define SPRITECANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.SpriteCanvas.Cairo" + +namespace cairocanvas +{ + typedef ::cppu::WeakComponentImplHelper9< ::com::sun::star::rendering::XSpriteCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::rendering::XGraphicDevice, + ::com::sun::star::lang::XMultiServiceFactory, + ::com::sun::star::rendering::XBufferController, + ::com::sun::star::awt::XWindowListener, + ::com::sun::star::util::XUpdatable, + ::com::sun::star::beans::XPropertySet, + ::com::sun::star::lang::XServiceName > WindowGraphicDeviceBase_Base; + typedef ::canvas::BufferedGraphicDeviceBase< ::canvas::BaseMutexHelper< WindowGraphicDeviceBase_Base >, + SpriteDeviceHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > SpriteCanvasBase_Base; + /** Mixin SpriteSurface + + Have to mixin the SpriteSurface before deriving from + ::canvas::SpriteCanvasBase, as this template should already + implement some of those interface methods. + + The reason why this appears kinda convoluted is the fact that + we cannot specify non-IDL types as WeakComponentImplHelperN + template args, and furthermore, don't want to derive + ::canvas::SpriteCanvasBase directly from + ::canvas::SpriteSurface (because derivees of + ::canvas::SpriteCanvasBase have to explicitely forward the + XInterface methods (e.g. via DECLARE_UNO3_AGG_DEFAULTS) + anyway). Basically, ::canvas::CanvasCustomSpriteBase should + remain a base class that provides implementation, not to + enforce any specific interface on its derivees. + */ + class SpriteCanvasBaseSpriteSurface_Base : public SpriteCanvasBase_Base, + public ::canvas::SpriteSurface, + public SurfaceProvider + { + }; + + typedef ::canvas::SpriteCanvasBase< SpriteCanvasBaseSpriteSurface_Base, + SpriteCanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > SpriteCanvasBaseT; + + /** Product of this component's factory. + + The SpriteCanvas object combines the actual Window canvas with + the XGraphicDevice interface. This is because there's a + one-to-one relation between them, anyway, since each window + can have exactly one canvas and one associated + XGraphicDevice. And to avoid messing around with circular + references, this is implemented as one single object. + */ + class SpriteCanvas : public SpriteCanvasBaseT, + public RepaintTarget + { + public: + SpriteCanvas( const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Any >& aArguments, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& rxContext ); + + void initialize(); + +#if defined __SUNPRO_CC + using SpriteCanvasBaseT::disposing; +#endif + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // Forwarding the XComponent implementation to the + // cppu::ImplHelper templated base + // Classname Base doing refcounting Base implementing the XComponent interface + // | | | + // V V V + DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( SpriteCanvas, WindowGraphicDeviceBase_Base, ::cppu::WeakComponentImplHelperBase ); + + // XBufferController (partial) + virtual ::sal_Bool SAL_CALL showBuffer( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL switchBuffer( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException); + + // XSpriteCanvas (partial) + virtual sal_Bool SAL_CALL updateScreen( sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException); + + // XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (::com::sun::star::uno::RuntimeException); + + // SurfaceProvider + virtual SurfaceSharedPtr getSurface(); + virtual SurfaceSharedPtr createSurface( const ::basegfx::B2ISize& rSize, Content aContent = CAIRO_CONTENT_COLOR_ALPHA ); + virtual SurfaceSharedPtr createSurface( ::Bitmap& rBitmap ); + virtual SurfaceSharedPtr changeSurface( bool bHasAlpha, bool bCopyContent ); + virtual OutputDevice* getOutputDevice(); + + // RepaintTarget + virtual bool repaint( const ::cairo::SurfaceSharedPtr& pSurface, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + SurfaceSharedPtr getWindowSurface(); + SurfaceSharedPtr getBufferSurface(); + + const ::basegfx::B2ISize& getSizePixel(); + void setSizePixel( const ::basegfx::B2ISize& rSize ); + void flush(); + + private: + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > maArguments; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > mxComponentContext; + }; + + typedef ::rtl::Reference< SpriteCanvas > SpriteCanvasRef; +} + +#endif diff --git a/canvas/source/cairo/cairo_spritecanvashelper.cxx b/canvas/source/cairo/cairo_spritecanvashelper.cxx new file mode 100644 index 000000000000..bb4b44201043 --- /dev/null +++ b/canvas/source/cairo/cairo_spritecanvashelper.cxx @@ -0,0 +1,544 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <vcl/canvastools.hxx> + +#include <comphelper/scopeguard.hxx> + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <boost/cast.hpp> + +#include "cairo_spritecanvashelper.hxx" +#include "cairo_canvascustomsprite.hxx" + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + namespace + { + /** Sprite redraw at original position + + Used to repaint the whole canvas (background and all + sprites) + */ + void spriteRedraw( const CairoSharedPtr& pCairo, + const ::canvas::Sprite::Reference& rSprite ) + { + // downcast to derived cairocanvas::Sprite interface, which + // provides the actual redraw methods. + ::boost::polymorphic_downcast< Sprite* >(rSprite.get())->redraw( pCairo, true); + } + + void repaintBackground( const CairoSharedPtr& pCairo, + const SurfaceSharedPtr& pBackgroundSurface, + const ::basegfx::B2DRange& rArea ) + { + cairo_save( pCairo.get() ); + cairo_rectangle( pCairo.get(), ceil( rArea.getMinX() ), ceil( rArea.getMinY() ), + floor( rArea.getWidth() ), floor( rArea.getHeight() ) ); + cairo_clip( pCairo.get() ); + cairo_set_source_surface( pCairo.get(), pBackgroundSurface->getCairoSurface().get(), 0, 0 ); + cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pCairo.get() ); + cairo_restore( pCairo.get() ); + } + + void opaqueUpdateSpriteArea( const ::canvas::Sprite::Reference& rSprite, + const CairoSharedPtr& pCairo, + const ::basegfx::B2IRange& rArea ) + { + // clip output to actual update region (otherwise a) + // wouldn't save much render time, and b) will clutter + // scrolled sprite content outside this area) + cairo_save( pCairo.get() ); + cairo_rectangle( pCairo.get(), rArea.getMinX(), rArea.getMinY(), + sal::static_int_cast<sal_Int32>(rArea.getWidth()), + sal::static_int_cast<sal_Int32>(rArea.getHeight()) ); + cairo_clip( pCairo.get() ); + + // repaint affected sprite directly to output device (at + // the actual screen output position) + // rendering directly to device buffer + ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw( pCairo, false ); + + cairo_restore( pCairo.get() ); + } + + /** Repaint sprite at original position + + Used for opaque updates, which render directly to the + device buffer. + */ + void spriteRedrawStub( const CairoSharedPtr& pCairo, + const ::canvas::Sprite::Reference& rSprite ) + { + if( rSprite.is() ) + { + ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw( pCairo, false ); + } + } + + /** Repaint sprite at given position + + Used for generic update, which renders into device buffer. + */ + void spriteRedrawStub2( const CairoSharedPtr& pCairo, + const ::canvas::Sprite::Reference& rSprite ) + { + if( rSprite.is() ) + { + ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw( pCairo, true );; + } + } + + /** Repaint sprite at original position + + Used for opaque updates from scrollUpdate(), which render + directly to the front buffer. + */ + void spriteRedrawStub3( const CairoSharedPtr& pCairo, + const ::canvas::SpriteRedrawManager::AreaComponent& rComponent ) + { + const ::canvas::Sprite::Reference& rSprite( rComponent.second.getSprite() ); + + if( rSprite.is() ) + ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw( pCairo, false ); + } + } + + SpriteCanvasHelper::SpriteCanvasHelper() : + mpRedrawManager( NULL ), + mpOwningSpriteCanvas( NULL ), + mpCompositingSurface(), + maCompositingSurfaceSize() + { + } + + void SpriteCanvasHelper::init( ::canvas::SpriteRedrawManager& rManager, + SpriteCanvas& rDevice, + const ::basegfx::B2ISize& rSize ) + { + mpRedrawManager = &rManager; + mpOwningSpriteCanvas = &rDevice; + + CanvasHelper::init( rSize, rDevice, &rDevice ); + } + + void SpriteCanvasHelper::disposing() + { + mpCompositingSurface.reset(); + mpOwningSpriteCanvas = NULL; + mpRedrawManager = NULL; + + // forward to base + CanvasHelper::disposing(); + } + + uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromAnimation( + const uno::Reference< rendering::XAnimation >& ) + { + return uno::Reference< rendering::XAnimatedSprite >(); + } + + uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromBitmaps( + const uno::Sequence< uno::Reference< rendering::XBitmap > >& /*animationBitmaps*/, + sal_Int8 /*interpolationMode*/ ) + { + return uno::Reference< rendering::XAnimatedSprite >(); + } + + uno::Reference< rendering::XCustomSprite > SpriteCanvasHelper::createCustomSprite( const geometry::RealSize2D& spriteSize ) + { + if( !mpRedrawManager ) + return uno::Reference< rendering::XCustomSprite >(); // we're disposed + + return uno::Reference< rendering::XCustomSprite >( + new CanvasCustomSprite( spriteSize, + mpOwningSpriteCanvas ) ); + } + + uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite( + const uno::Reference< rendering::XSprite >& ) + { + return uno::Reference< rendering::XSprite >(); + } + + sal_Bool SpriteCanvasHelper::updateScreen( const ::basegfx::B2IRange& /*rCurrArea*/, + sal_Bool bUpdateAll, + bool& io_bSurfaceDirty ) + { + if( !mpRedrawManager || + !mpOwningSpriteCanvas || + !mpOwningSpriteCanvas->getWindowSurface() || + !mpOwningSpriteCanvas->getBufferSurface() ) + { + return sal_False; // disposed, or otherwise dysfunctional + } + + OSL_TRACE("SpriteCanvasHelper::updateScreen called"); + + const ::basegfx::B2ISize& rSize = mpOwningSpriteCanvas->getSizePixel(); + + // force compositing surface to be available before using it + // inside forEachSpriteArea + SurfaceSharedPtr pCompositingSurface = getCompositingSurface(rSize); + SurfaceSharedPtr pWindowSurface = mpOwningSpriteCanvas->getWindowSurface(); + CairoSharedPtr pCompositingCairo = pCompositingSurface->getCairo(); + CairoSharedPtr pWindowCairo = pWindowSurface->getCairo(); + + // TODO(P1): Might be worthwile to track areas of background + // changes, too. + if( !bUpdateAll && !io_bSurfaceDirty ) + { + // background has not changed, so we're free to optimize + // repaint to areas where a sprite has changed + + // process each independent area of overlapping sprites + // separately. + mpRedrawManager->forEachSpriteArea( *this ); + } + else + { + OSL_TRACE("SpriteCanvasHelper::updateScreen update ALL"); + + // background has changed, so we currently have no choice + // but repaint everything (or caller requested that) + + cairo_rectangle( pCompositingCairo.get(), 0, 0, rSize.getX(), rSize.getY() ); + cairo_clip( pCompositingCairo.get() ); + cairo_save( pCompositingCairo.get() ); + cairo_set_source_surface( pCompositingCairo.get(), + mpOwningSpriteCanvas->getBufferSurface()->getCairoSurface().get(), + 0, 0 ); + cairo_set_operator( pCompositingCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pCompositingCairo.get() ); + cairo_restore( pCompositingCairo.get() ); + + // repaint all active sprites on top of background into + // VDev. + mpRedrawManager->forEachSprite( + ::boost::bind( + &spriteRedraw, + boost::cref(pCompositingCairo), + _1 ) ); + + // flush to screen + cairo_rectangle( pWindowCairo.get(), 0, 0, rSize.getX(), rSize.getY() ); + cairo_clip( pWindowCairo.get() ); + cairo_set_source_surface( pWindowCairo.get(), + pCompositingSurface->getCairoSurface().get(), + 0, 0 ); + cairo_set_operator( pWindowCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pWindowCairo.get() ); + } + + // change record vector must be cleared, for the next turn of + // rendering and sprite changing + mpRedrawManager->clearChangeRecords(); + + io_bSurfaceDirty = false; + + // commit to screen + mpOwningSpriteCanvas->flush(); + + return sal_True; + } + + void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& rUpdateRect ) + { + if( mpOwningSpriteCanvas && mpCompositingSurface ) + repaintBackground( mpCompositingSurface->getCairo(), + mpOwningSpriteCanvas->getBufferSurface(), + rUpdateRect ); + } + + void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& rMoveStart, + const ::basegfx::B2DRange& rMoveEnd, + const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ) + { + ENSURE_OR_THROW( mpOwningSpriteCanvas && + mpOwningSpriteCanvas->getBufferSurface(), + "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " ); + + OSL_TRACE("SpriteCanvasHelper::scrollUpdate called"); + + const ::basegfx::B2ISize& rSize = mpOwningSpriteCanvas->getSizePixel(); + const ::basegfx::B2IRange aOutputBounds( 0,0, + rSize.getX(), + rSize.getY() ); + + SurfaceSharedPtr pCompositingSurface = getCompositingSurface(rSize); + SurfaceSharedPtr pWindowSurface = mpOwningSpriteCanvas->getWindowSurface(); + CairoSharedPtr pCompositingCairo = pCompositingSurface->getCairo(); + CairoSharedPtr pWindowCairo = pWindowSurface->getCairo(); + + // round rectangles to integer pixel. Note: have to be + // extremely careful here, to avoid off-by-one errors for + // the destination area: otherwise, the next scroll update + // would copy pixel that are not supposed to be part of + // the sprite. + ::basegfx::B2IRange aSourceRect( + ::canvas::tools::spritePixelAreaFromB2DRange( rMoveStart ) ); + const ::basegfx::B2IRange& rDestRect( + ::canvas::tools::spritePixelAreaFromB2DRange( rMoveEnd ) ); + ::basegfx::B2IPoint aDestPos( rDestRect.getMinimum() ); + + ::std::vector< ::basegfx::B2IRange > aUnscrollableAreas; + + // TODO(E3): This is plain buggy (but copies the behaviour of + // the old Impress slideshow) - the scrolled area might + // actually lie _below_ another window! + + // clip to output bounds (cannot properly scroll stuff + // _outside_ our screen area) + if( !::canvas::tools::clipScrollArea( aSourceRect, + aDestPos, + aUnscrollableAreas, + aOutputBounds ) ) + { + // fully clipped scroll area: cannot simply scroll + // then. Perform normal opaque update (can use that, since + // one of the preconditions for scrollable update is + // opaque sprite content) + + // repaint all affected sprites directly to output device + ::std::for_each( rUpdateArea.maComponentList.begin(), + rUpdateArea.maComponentList.end(), + ::boost::bind( + &spriteRedrawStub3, + boost::cref(pCompositingCairo), + _1 ) ); + } + else + { + const ::basegfx::B2IVector aSourceUpperLeftPos( aSourceRect.getMinimum() ); + + // clip dest area (which must be inside rDestBounds) + ::basegfx::B2IRange aDestRect( rDestRect ); + aDestRect.intersect( aOutputBounds ); + + cairo_save( pCompositingCairo.get() ); + // scroll content in device back buffer + cairo_set_source_surface( pCompositingCairo.get(), + mpOwningSpriteCanvas->getBufferSurface()->getCairoSurface().get(), + aDestPos.getX() - aSourceUpperLeftPos.getX(), + aDestPos.getY() - aSourceUpperLeftPos.getY() ); + cairo_rectangle( pCompositingCairo.get(), + aDestPos.getX(), aDestPos.getY(), + sal::static_int_cast<sal_Int32>(aDestRect.getWidth()), + sal::static_int_cast<sal_Int32>(aDestRect.getHeight()) ); + cairo_clip( pCompositingCairo.get() ); + cairo_set_operator( pCompositingCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pCompositingCairo.get() ); + cairo_restore( pCompositingCairo.get() ); + + const ::canvas::SpriteRedrawManager::SpriteConnectedRanges::ComponentListType::const_iterator + aFirst( rUpdateArea.maComponentList.begin() ); + ::canvas::SpriteRedrawManager::SpriteConnectedRanges::ComponentListType::const_iterator + aSecond( aFirst ); ++aSecond; + + ENSURE_OR_THROW( aFirst->second.getSprite().is(), + "VCLCanvas::scrollUpdate(): no sprite" ); + + // repaint uncovered areas from sprite. Need to actually + // clip here, since we're only repainting _parts_ of the + // sprite + ::std::for_each( aUnscrollableAreas.begin(), + aUnscrollableAreas.end(), + ::boost::bind( &opaqueUpdateSpriteArea, + ::boost::cref(aFirst->second.getSprite()), + boost::cref(pCompositingCairo), + _1 ) ); + } + + // repaint uncovered areas from backbuffer - take the + // _rounded_ rectangles from above, to have the update + // consistent with the scroll above. + ::std::vector< ::basegfx::B2DRange > aUncoveredAreas; + ::basegfx::computeSetDifference( aUncoveredAreas, + rUpdateArea.maTotalBounds, + ::basegfx::B2DRange( rDestRect ) ); + ::std::for_each( aUncoveredAreas.begin(), + aUncoveredAreas.end(), + ::boost::bind( &repaintBackground, + boost::cref(pCompositingCairo), + boost::cref(mpOwningSpriteCanvas->getBufferSurface()), + _1 ) ); + + cairo_rectangle( pWindowCairo.get(), 0, 0, rSize.getX(), rSize.getY() ); + cairo_clip( pWindowCairo.get() ); + cairo_set_source_surface( pWindowCairo.get(), + pCompositingSurface->getCairoSurface().get(), + 0, 0 ); + cairo_set_operator( pWindowCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pWindowCairo.get() ); + } + + void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) + { + ENSURE_OR_THROW( mpOwningSpriteCanvas && + mpOwningSpriteCanvas->getBufferSurface(), + "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " ); + + OSL_TRACE("SpriteCanvasHelper::opaqueUpdate called"); + + const ::basegfx::B2ISize& rDeviceSize = mpOwningSpriteCanvas->getSizePixel(); + + SurfaceSharedPtr pCompositingSurface = getCompositingSurface(rDeviceSize); + SurfaceSharedPtr pWindowSurface = mpOwningSpriteCanvas->getWindowSurface(); + CairoSharedPtr pCompositingCairo = pCompositingSurface->getCairo(); + CairoSharedPtr pWindowCairo = pWindowSurface->getCairo(); + + cairo_rectangle( pCompositingCairo.get(), 0, 0, rDeviceSize.getX(), rDeviceSize.getY() ); + cairo_clip( pCompositingCairo.get() ); + + ::basegfx::B2DVector aPos( ceil( rTotalArea.getMinX() ), ceil( rTotalArea.getMinY() ) ); + ::basegfx::B2DVector aSize( floor( rTotalArea.getMaxX() - aPos.getX() ), floor( rTotalArea.getMaxY() - aPos.getY() ) ); + + cairo_rectangle( pCompositingCairo.get(), aPos.getX(), aPos.getY(), aSize.getX(), aSize.getY() ); + cairo_clip( pCompositingCairo.get() ); + + // repaint all affected sprites directly to output device + ::std::for_each( rSortedUpdateSprites.begin(), + rSortedUpdateSprites.end(), + ::boost::bind( + &spriteRedrawStub, + boost::cref(pCompositingCairo), + _1 ) ); + + // flush to screen + cairo_rectangle( pWindowCairo.get(), 0, 0, rDeviceSize.getX(), rDeviceSize.getY() ); + cairo_clip( pWindowCairo.get() ); + cairo_rectangle( pWindowCairo.get(), aPos.getX(), aPos.getY(), aSize.getX(), aSize.getY() ); + cairo_clip( pWindowCairo.get() ); + cairo_set_source_surface( pWindowCairo.get(), + pCompositingSurface->getCairoSurface().get(), + 0, 0 ); + cairo_set_operator( pWindowCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pWindowCairo.get() ); + } + + void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange& rRequestedArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) + { + // TODO + OSL_TRACE("SpriteCanvasHelper::genericUpdate called"); + + ENSURE_OR_THROW( mpOwningSpriteCanvas && + mpOwningSpriteCanvas->getBufferSurface(), + "SpriteCanvasHelper::genericUpdate(): NULL device pointer " ); + + // limit size of update VDev to target outdev's size + const ::basegfx::B2ISize& rSize = mpOwningSpriteCanvas->getSizePixel(); + + SurfaceSharedPtr pCompositingSurface = getCompositingSurface(rSize); + SurfaceSharedPtr pWindowSurface = mpOwningSpriteCanvas->getWindowSurface(); + CairoSharedPtr pCompositingCairo = pCompositingSurface->getCairo(); + CairoSharedPtr pWindowCairo = pWindowSurface->getCairo(); + + // round output position towards zero. Don't want to truncate + // a fraction of a sprite pixel... Clip position at origin, + // otherwise, truncation of size below might leave visible + // areas uncovered by VDev. + const Point aOutputPosition( + ::std::max( sal_Int32( 0 ), + static_cast< sal_Int32 >(rRequestedArea.getMinX()) ), + ::std::max( sal_Int32( 0 ), + static_cast< sal_Int32 >(rRequestedArea.getMinY()) ) ); + // round output size towards +infty. Don't want to truncate a + // fraction of a sprite pixel... Limit size of VDev to output + // device's area. + const Size aOutputSize( + ::std::min( rSize.getX(), + ::canvas::tools::roundUp( rRequestedArea.getMaxX() - aOutputPosition.X()) ), + ::std::min( rSize.getY(), + ::canvas::tools::roundUp( rRequestedArea.getMaxY() - aOutputPosition.Y()) ) ); + + cairo_rectangle( pCompositingCairo.get(), aOutputPosition.X(), aOutputPosition.Y(), aOutputSize.Width(), aOutputSize.Height() ); + cairo_clip( pCompositingCairo.get() ); + + // paint background + cairo_save( pCompositingCairo.get() ); + cairo_set_source_surface( pCompositingCairo.get(), + mpOwningSpriteCanvas->getBufferSurface()->getCairoSurface().get(), + 0, 0 ); + cairo_set_operator( pCompositingCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pCompositingCairo.get() ); + cairo_restore( pCompositingCairo.get() ); + + // repaint all affected sprites on top of background into + // VDev. + ::std::for_each( rSortedUpdateSprites.begin(), + rSortedUpdateSprites.end(), + ::boost::bind( &spriteRedrawStub2, + boost::cref(pCompositingCairo), + _1 ) ); + + // flush to screen + cairo_rectangle( pWindowCairo.get(), aOutputPosition.X(), aOutputPosition.Y(), aOutputSize.Width(), aOutputSize.Height() ); + cairo_clip( pWindowCairo.get() ); + cairo_set_source_surface( pWindowCairo.get(), + pCompositingSurface->getCairoSurface().get(), + 0, 0 ); + cairo_set_operator( pWindowCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_paint( pWindowCairo.get() ); + } + + ::cairo::SurfaceSharedPtr SpriteCanvasHelper::getCompositingSurface( const ::basegfx::B2ISize& rNeededSize ) + { + if( rNeededSize.getX() < maCompositingSurfaceSize.getX() || + rNeededSize.getY() < maCompositingSurfaceSize.getY() ) + { + // need to give buffer more size + mpCompositingSurface.reset(); + } + + if( !mpCompositingSurface ) + { + mpCompositingSurface = + mpOwningSpriteCanvas->getWindowSurface()->getSimilar( + CAIRO_CONTENT_COLOR, + rNeededSize.getX(), rNeededSize.getY() ); + maCompositingSurfaceSize = rNeededSize; + } + + return mpCompositingSurface; + } +} diff --git a/canvas/source/cairo/cairo_spritecanvashelper.hxx b/canvas/source/cairo/cairo_spritecanvashelper.hxx new file mode 100644 index 000000000000..2adc245fe4e1 --- /dev/null +++ b/canvas/source/cairo/cairo_spritecanvashelper.hxx @@ -0,0 +1,147 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_SPRITECANVASHELPER_HXX_ +#define _CAIROCANVAS_SPRITECANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <canvas/spriteredrawmanager.hxx> + +#include "cairo_cairo.hxx" +#include "cairo_canvashelper.hxx" + +namespace basegfx +{ + class B2IRange; +} + +namespace cairocanvas +{ + class SpriteCanvas; + + class SpriteCanvasHelper : public CanvasHelper + { + public: + SpriteCanvasHelper(); + + void init( ::canvas::SpriteRedrawManager& rManager, + SpriteCanvas& rOwningSpriteCanvas, + const ::basegfx::B2ISize& rSize ); + + /// Dispose all internal references + void disposing(); + + // XSpriteCanvas + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XAnimatedSprite > createSpriteFromAnimation( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XAnimation >& animation ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XAnimatedSprite > createSpriteFromBitmaps( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap > >& animationBitmaps, + sal_Int8 interpolationMode ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCustomSprite > createCustomSprite( + const ::com::sun::star::geometry::RealSize2D& spriteSize ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSprite > createClonedSprite( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XSprite >& original ); + + /** Actually perform the screen update + + @param rCurrArea + Current window area in absolute screen coordinates + + @param bUpdateAll + sal_True, if everything must be updated, not only changed + sprites + + @param io_bSurfaceDirty + In/out parameter, whether backbuffer surface is dirty (if + yes, we're performing a full update, anyway) + */ + sal_Bool updateScreen( const ::basegfx::B2IRange& rCurrArea, + sal_Bool bUpdateAll, + bool& io_bSurfaceDirty ); + + + // SpriteRedrawManager functor calls + // ------------------------------------------------- + + /** Gets called for simple background repaints + */ + void backgroundPaint( const ::basegfx::B2DRange& rUpdateRect ); + + /** Gets called when area can be handled by scrolling. + + Called method must copy screen content from rMoveStart to + rMoveEnd, and restore the background in the uncovered + areas. + + @param rMoveStart + Source rect of the scroll + + @param rMoveEnd + Dest rect of the scroll + + @param rUpdateArea + All info necessary, should rMoveStart be partially or + fully outside the outdev + */ + void scrollUpdate( const ::basegfx::B2DRange& rMoveStart, + const ::basegfx::B2DRange& rMoveEnd, + const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ); + + void opaqueUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ); + + void genericUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ); + + private: + ::cairo::SurfaceSharedPtr getCompositingSurface( const ::basegfx::B2ISize& rNeededSize ); + + /// Set from the SpriteCanvas: instance coordinating sprite redraw + ::canvas::SpriteRedrawManager* mpRedrawManager; + + /// Set from the init method. used to generate sprites + SpriteCanvas* mpOwningSpriteCanvas; + + /// a temporary surface used to composite the frontbuffer image + ::cairo::SurfaceSharedPtr mpCompositingSurface; + ::basegfx::B2ISize maCompositingSurfaceSize; + }; +} + +#endif /* _CAIROCANVAS_SPRITECANVASHELPER_HXX_ */ + diff --git a/canvas/source/cairo/cairo_spritedevicehelper.cxx b/canvas/source/cairo/cairo_spritedevicehelper.cxx new file mode 100644 index 000000000000..ef345cd60eaf --- /dev/null +++ b/canvas/source/cairo/cairo_spritedevicehelper.cxx @@ -0,0 +1,201 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> + +#include <osl/mutex.hxx> +#include <cppuhelper/compbase1.hxx> + +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <toolkit/helper/vclunohelper.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/tools/unopolypolygon.hxx> + +#include <vcl/syschild.hxx> +#include <vcl/canvastools.hxx> + +#include "cairo_spritecanvas.hxx" +#include "cairo_canvasbitmap.hxx" +#include "cairo_devicehelper.hxx" +#include "cairo_cairo.hxx" + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + + SpriteDeviceHelper::SpriteDeviceHelper() : + mpSpriteCanvas( NULL ), + mpBufferSurface(), + maSize(), + mbFullScreen( false ) + {} + + void SpriteDeviceHelper::init( Window& rOutputWindow, + SpriteCanvas& rSpriteCanvas, + const ::basegfx::B2ISize& rSize, + bool bFullscreen ) + { + DeviceHelper::init(rSpriteCanvas, + rOutputWindow); + + mpSpriteCanvas = &rSpriteCanvas; + mbFullScreen = bFullscreen; + + setSize( rSize ); + } + + void SpriteDeviceHelper::disposing() + { + // release all references + mpBufferSurface.reset(); + mpSpriteCanvas = NULL; + } + + ::sal_Int32 SpriteDeviceHelper::createBuffers( ::sal_Int32 /*nBuffers*/ ) + { + // TODO(F3): implement XBufferStrategy interface. For now, we + // _always_ will have exactly one backbuffer + return 1; + } + + void SpriteDeviceHelper::destroyBuffers() + { + // TODO(F3): implement XBufferStrategy interface. For now, we + // _always_ will have exactly one backbuffer + } + + ::sal_Bool SpriteDeviceHelper::showBuffer( bool, ::sal_Bool ) + { + OSL_ENSURE(false,"Not supposed to be called, handled by SpriteCanvas"); + return sal_False; + } + + ::sal_Bool SpriteDeviceHelper::switchBuffer( bool, ::sal_Bool ) + { + OSL_ENSURE(false,"Not supposed to be called, handled by SpriteCanvas"); + return sal_False; + } + + uno::Any SpriteDeviceHelper::isAccelerated() const + { + return ::com::sun::star::uno::makeAny(true); + } + + uno::Any SpriteDeviceHelper::getDeviceHandle() const + { + return DeviceHelper::getDeviceHandle(); + } + + uno::Any SpriteDeviceHelper::getSurfaceHandle() const + { + return DeviceHelper::getSurfaceHandle(); + } + + void SpriteDeviceHelper::setSize( const ::basegfx::B2ISize& rSize ) + { + OSL_TRACE("SpriteDeviceHelper::setSize(): device size %d x %d", rSize.getX(), rSize.getY() ); + + if( !mpSpriteCanvas ) + return; // disposed + + DeviceHelper::setSize(rSize); + + if( mpBufferSurface && maSize != rSize ) + mpBufferSurface.reset(); + if( !mpBufferSurface ) + mpBufferSurface = getWindowSurface()->getSimilar( + CAIRO_CONTENT_COLOR, + rSize.getX(), rSize.getY() ); + + if( maSize != rSize ) + maSize = rSize; + + mpSpriteCanvas->setSizePixel( maSize ); + } + + const ::basegfx::B2ISize& SpriteDeviceHelper::getSizePixel() + { + return maSize; + } + + void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds ) + { + setSize( ::basegfx::B2ISize(rBounds.Width, rBounds.Height) ); + } + + SurfaceSharedPtr SpriteDeviceHelper::getSurface() + { + return mpBufferSurface; + } + + SurfaceSharedPtr SpriteDeviceHelper::getBufferSurface() + { + return mpBufferSurface; + } + + SurfaceSharedPtr SpriteDeviceHelper::getWindowSurface() + { + return DeviceHelper::getSurface(); + } + + SurfaceSharedPtr SpriteDeviceHelper::createSurface( const ::basegfx::B2ISize& rSize, Content aContent ) + { + if( mpBufferSurface ) + return mpBufferSurface->getSimilar( aContent, rSize.getX(), rSize.getY() ); + + return SurfaceSharedPtr(); + } + + SurfaceSharedPtr SpriteDeviceHelper::createSurface( BitmapSystemData& rData, const Size& rSize ) + { + if( getOutputDevice() ) + return createBitmapSurface( *getOutputDevice(), rData, rSize ); + + return SurfaceSharedPtr(); + } + + + /** SpriteDeviceHelper::flush Flush the platform native window + * + * Flushes the window by using the internally stored mpSysData. + * + **/ + void SpriteDeviceHelper::flush() + { + SurfaceSharedPtr pWinSurface=getWindowSurface(); + if( pWinSurface ) + pWinSurface->flush(); + } +} diff --git a/canvas/source/cairo/cairo_spritedevicehelper.hxx b/canvas/source/cairo/cairo_spritedevicehelper.hxx new file mode 100644 index 000000000000..3e46014f28b0 --- /dev/null +++ b/canvas/source/cairo/cairo_spritedevicehelper.hxx @@ -0,0 +1,95 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_SPRITEDEVICEHELPER_HXX +#define _CAIROCANVAS_SPRITEDEVICEHELPER_HXX + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include <boost/utility.hpp> + +#include <vcl/window.hxx> +#include <vcl/bitmap.hxx> + +#include "cairo_cairo.hxx" +#include "cairo_devicehelper.hxx" + +/* Definition of DeviceHelper class */ + +namespace cairocanvas +{ + class SpriteCanvas; + class SpriteCanvasHelper; + + class SpriteDeviceHelper : public DeviceHelper + { + public: + SpriteDeviceHelper(); + + void init( Window& rOutputWindow, + SpriteCanvas& rSpriteCanvas, + const ::basegfx::B2ISize& rSize, + bool bFullscreen ); + + /// Dispose all internal references + void disposing(); + + // XWindowGraphicDevice + ::sal_Int32 createBuffers( ::sal_Int32 nBuffers ); + void destroyBuffers( ); + ::sal_Bool showBuffer( bool, ::sal_Bool ); + ::sal_Bool switchBuffer( bool, ::sal_Bool bUpdateAll ); + + ::com::sun::star::uno::Any isAccelerated() const; + ::com::sun::star::uno::Any getDeviceHandle() const; + ::com::sun::star::uno::Any getSurfaceHandle() const; + + void notifySizeUpdate( const ::com::sun::star::awt::Rectangle& rBounds ); + void setSize( const ::basegfx::B2ISize& rSize ); + + ::cairo::SurfaceSharedPtr getSurface(); + ::cairo::SurfaceSharedPtr getBufferSurface(); + ::cairo::SurfaceSharedPtr getWindowSurface(); + ::cairo::SurfaceSharedPtr createSurface( const ::basegfx::B2ISize& rSize, ::cairo::Content aContent = CAIRO_CONTENT_COLOR_ALPHA ); + ::cairo::SurfaceSharedPtr createSurface( BitmapSystemData& rData, const Size& rSize ); + const ::basegfx::B2ISize& getSizePixel(); + void flush(); + + private: + /// Pointer to sprite canvas (owner of this helper), needed to create bitmaps + SpriteCanvas* mpSpriteCanvas; + + ::cairo::SurfaceSharedPtr mpBufferSurface; + + ::basegfx::B2ISize maSize; + bool mbFullScreen; + }; +} + +#endif diff --git a/canvas/source/cairo/cairo_spritehelper.cxx b/canvas/source/cairo/cairo_spritehelper.cxx new file mode 100644 index 000000000000..a3ba84648f3b --- /dev/null +++ b/canvas/source/cairo/cairo_spritehelper.cxx @@ -0,0 +1,183 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> + +#include <canvas/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygonrasterconverter.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <basegfx/polygon/b2dpolygoncutandtouch.hxx> + +#include "cairo_canvascustomsprite.hxx" +#include "cairo_spritehelper.hxx" + +#include <memory> + + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + SpriteHelper::SpriteHelper() : + mpSpriteCanvas(), + mpBufferSurface(), + mbTextureDirty(true) + {} + + void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rSpriteCanvas ) + { + ENSURE_OR_THROW( rSpriteCanvas.get(), + "SpriteHelper::init(): Invalid device, sprite canvas or surface" ); + + mpSpriteCanvas = rSpriteCanvas; + mbTextureDirty = true; + + // also init base class + CanvasCustomSpriteHelper::init( rSpriteSize, + rSpriteCanvas.get() ); + } + + void SpriteHelper::setSurface( const SurfaceSharedPtr& pBufferSurface ) + { + mpBufferSurface = pBufferSurface; + } + + void SpriteHelper::disposing() + { + mpBufferSurface.reset(); + mpSpriteCanvas.clear(); + + // forward to parent + CanvasCustomSpriteHelper::disposing(); + } + + void SpriteHelper::redraw( const CairoSharedPtr& pCairo, + const ::basegfx::B2DPoint& rPos, + bool& /*io_bSurfacesDirty*/, + bool /*bBufferedUpdate*/ ) const + { +#ifdef CAIRO_CANVAS_PERF_TRACE + struct timespec aTimer; + mxDevice->startPerfTrace( &aTimer ); +#endif + + const double fAlpha( getAlpha() ); + const ::basegfx::B2DHomMatrix aTransform( getTransformation() ); + + if( isActive() && !::basegfx::fTools::equalZero( fAlpha ) ) { + OSL_TRACE ("CanvasCustomSprite::redraw called"); + if( pCairo ) { + basegfx::B2DVector aSize = getSizePixel(); + cairo_save( pCairo.get() ); + + double fX, fY; + + fX = rPos.getX(); + fY = rPos.getY(); + + if( !aTransform.isIdentity() ) { + cairo_matrix_t aMatrix, aInverseMatrix; + cairo_matrix_init( &aMatrix, + aTransform.get( 0, 0 ), aTransform.get( 1, 0 ), aTransform.get( 0, 1 ), + aTransform.get( 1, 1 ), aTransform.get( 0, 2 ), aTransform.get( 1, 2 ) ); + + aMatrix.x0 = basegfx::fround( aMatrix.x0 ); + aMatrix.y0 = basegfx::fround( aMatrix.y0 ); + + cairo_matrix_init( &aInverseMatrix, aMatrix.xx, aMatrix.yx, aMatrix.xy, aMatrix.yy, aMatrix.x0, aMatrix.y0 ); + cairo_matrix_invert( &aInverseMatrix ); + cairo_matrix_transform_distance( &aInverseMatrix, &fX, &fY ); + + cairo_set_matrix( pCairo.get(), &aMatrix ); + } + + fX = basegfx::fround( fX ); + fY = basegfx::fround( fY ); + + cairo_matrix_t aOrigMatrix; + cairo_get_matrix( pCairo.get(), &aOrigMatrix ); + cairo_translate( pCairo.get(), fX, fY ); + + if( getClip().is() ) + { + const uno::Reference<rendering::XPolyPolygon2D>& rClip( getClip() ); + + ::basegfx::B2DPolyPolygon aClipPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( + rClip )); + + doPolyPolygonImplementation( aClipPoly, Clip, pCairo.get(), + NULL, SurfaceProviderRef(mpSpriteCanvas.get()), + rClip->getFillRule() ); + } + + OSL_TRACE ("aSize %f x %f position: %f,%f", aSize.getX(), aSize.getY(), fX, fY ); + cairo_rectangle( pCairo.get(), 0, 0, floor( aSize.getX() ), floor( aSize.getY() ) ); + cairo_clip( pCairo.get() ); + cairo_set_matrix( pCairo.get(), &aOrigMatrix ); + + if( isContentFullyOpaque() ) + cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE ); + cairo_set_source_surface( pCairo.get(), + mpBufferSurface->getCairoSurface().get(), + fX, fY ); + if( ::rtl::math::approxEqual( fAlpha, 1.0 ) ) + cairo_paint( pCairo.get() ); + else + cairo_paint_with_alpha( pCairo.get(), fAlpha ); + + cairo_restore( pCairo.get() ); + } + } + +#ifdef CAIRO_CANVAS_PERF_TRACE + mxDevice->stopPerfTrace( &aTimer, "sprite redraw" ); +#endif + } + + ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const + { + return ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPoly); + } +} diff --git a/canvas/source/cairo/cairo_spritehelper.hxx b/canvas/source/cairo/cairo_spritehelper.hxx new file mode 100644 index 000000000000..0d770e25003e --- /dev/null +++ b/canvas/source/cairo/cairo_spritehelper.hxx @@ -0,0 +1,115 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_SPRITEHELPER_HXX +#define _CAIROCANVAS_SPRITEHELPER_HXX + +#include <com/sun/star/rendering/XCustomSprite.hpp> + +#include <canvas/base/canvascustomspritehelper.hxx> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include "cairo_spritecanvas.hxx" + + +namespace cairocanvas +{ + /* Definition of SpriteHelper class */ + + /** Helper class for canvas sprites. + + This class implements all sprite-related functionality, like + that available on the XSprite interface. + */ + class SpriteHelper : public ::canvas::CanvasCustomSpriteHelper + { + public: + /** Create sprite helper + */ + SpriteHelper(); + + /** Late-init the sprite helper + + @param rSpriteSize + Size of the sprite + + @param rSpriteCanvas + Sprite canvas this sprite is part of. Object stores + ref-counted reference to it, thus, don't forget to pass on + disposing()! + + @param rDevice + DX device to use + + @param rSpriteSurface + The surface of the sprite (not the DX texture, but the + persistent target of content rendering) + + @param bShowSpriteBounds + When true, little debug bound rects for sprites are shown + */ + void init( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rSpriteCanvas ); + + void disposing(); + + void setSurface( const ::cairo::SurfaceSharedPtr& pBufferSurface ); + + /** Repaint sprite content to associated sprite canvas + + @param rPos + Output position (sprite's own position is disregarded) + + @param io_bSurfacesDirty + When true, the referenced sprite surfaces (backBuffer and + backBufferMask) have been modified since last call. + + @param bBufferedUpdate + When true, the redraw does <em>not</em> happen directly on + the front buffer, but within a VDev. Used to speed up + drawing. + */ + void redraw( const ::cairo::CairoSharedPtr& pCairo, + const ::basegfx::B2DPoint& rPos, + bool& bSurfacesDirty, + bool bBufferedUpdate ) const; + + private: + virtual ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >& xPoly ) const; + + + SpriteCanvasRef mpSpriteCanvas; + ::cairo::SurfaceSharedPtr mpBufferSurface; + mutable bool mbTextureDirty; // when true, texture needs update + }; +} + +#endif /* _CAIROCANVAS_SPRITEHELPER_HXX */ diff --git a/canvas/source/cairo/cairo_spritesurface.hxx b/canvas/source/cairo/cairo_spritesurface.hxx new file mode 100644 index 000000000000..343d51e5d816 --- /dev/null +++ b/canvas/source/cairo/cairo_spritesurface.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _VCLCANVAS_SPRITESURFACE_HXX +#define _VCLCANVAS_SPRITESURFACE_HXX + +#include <sal/config.h> + +#include "cairo_sprite.hxx" + +class Point; +class Size; +class Rectangle; + +namespace cairocanvas +{ + /* Definition of SpriteSurface interface */ + + class SpriteSurface + { + public: + virtual ~SpriteSurface() {} + + // call this when XSprite::show() is called + virtual void showSprite( const Sprite::ImplRef& sprite ) = 0; + + // call this when XSprite::hide() is called + virtual void hideSprite( const Sprite::ImplRef& sprite ) = 0; + + // call this when XSprite::move() is called + virtual void moveSprite( const Sprite::ImplRef& sprite, + const Point& rOldPos, + const Point& rNewPos, + const Size& rSpriteSize ) = 0; + + // call this when some part of your sprite has changed. That + // includes show/hide´, i.e. for show, both showSprite and + // updateSprite must be called. + virtual void updateSprite( const Sprite::ImplRef& sprite, + const Point& rPos, + const Rectangle& rUpdateArea ) = 0; + + }; +} + +#endif /* _VCLCANVAS_SPRITESURFACE_HXX */ diff --git a/canvas/source/cairo/cairo_surfaceprovider.hxx b/canvas/source/cairo/cairo_surfaceprovider.hxx new file mode 100644 index 000000000000..a6ec53be333f --- /dev/null +++ b/canvas/source/cairo/cairo_surfaceprovider.hxx @@ -0,0 +1,82 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_SURFACEPROVIDER_HXX +#define _CAIROCANVAS_SURFACEPROVIDER_HXX + +#include <rtl/ref.hxx> +#include <com/sun/star/uno/XInterface.hpp> + +#include "cairo_cairo.hxx" + +using namespace ::cairo; + +class OutputDevice; +class Bitmap; + +namespace cairocanvas +{ + class Bitmap; + + /* Definition of RepaintTarget interface */ + + /** Target interface for XCachedPrimitive implementations + + This interface must be implemented on all canvas + implementations that hand out XCachedPrimitives + */ + class SurfaceProvider : public ::com::sun::star::uno::XInterface + { + public: + virtual ~SurfaceProvider() {} + + /** Query surface from this provider + + This should return the default surface to render on. + */ + virtual SurfaceSharedPtr getSurface() = 0; + + /// create new surface in given size + virtual SurfaceSharedPtr createSurface( const ::basegfx::B2ISize& rSize, + Content aContent = CAIRO_CONTENT_COLOR_ALPHA ) = 0; + /// create new surface from given bitmap + virtual SurfaceSharedPtr createSurface( ::Bitmap& rBitmap ) = 0; + + /** convert surface between alpha and non-alpha + channel. returns new surface on success, NULL otherwise + */ + virtual SurfaceSharedPtr changeSurface( bool bHasAlpha, bool bCopyContent ) = 0; + + /** Provides the underlying vcl outputdevice this surface renders on + */ + virtual OutputDevice* getOutputDevice() = 0; + }; + + typedef ::rtl::Reference< SurfaceProvider > SurfaceProviderRef; +} + +#endif diff --git a/canvas/source/cairo/cairo_textlayout.cxx b/canvas/source/cairo/cairo_textlayout.cxx new file mode 100644 index 000000000000..d0873b63f5f0 --- /dev/null +++ b/canvas/source/cairo/cairo_textlayout.cxx @@ -0,0 +1,656 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <math.h> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <vcl/metric.hxx> +#include <vcl/virdev.hxx> + +#ifdef WNT +#include <tools/prewin.h> +#include <windows.h> +#include <tools/postwin.h> +#ifdef max +#undef max +#endif +#ifdef min +#undef min +#endif +#endif +#include <vcl/sysdata.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <boost/scoped_array.hpp> + +#include "cairo_textlayout.hxx" +#include "cairo_spritecanvas.hxx" + +#ifdef CAIRO_HAS_QUARTZ_SURFACE +# include "cairo_quartz_cairo.hxx" +#elif defined CAIRO_HAS_WIN32_SURFACE +# include "cairo_win32_cairo.hxx" +# include <cairo-win32.h> +#elif defined CAIRO_HAS_XLIB_SURFACE +# include "cairo_xlib_cairo.hxx" +# include <cairo-ft.h> +#else +# error Native API needed. +#endif + +using namespace ::cairo; +using namespace ::com::sun::star; + +namespace cairocanvas +{ + namespace + { + void setupLayoutMode( OutputDevice& rOutDev, + sal_Int8 nTextDirection ) + { + // TODO(P3): avoid if already correctly set + ULONG nLayoutMode; + switch( nTextDirection ) + { + default: + nLayoutMode = 0; + break; + case rendering::TextDirection::WEAK_LEFT_TO_RIGHT: + nLayoutMode = TEXT_LAYOUT_BIDI_LTR; + break; + case rendering::TextDirection::STRONG_LEFT_TO_RIGHT: + nLayoutMode = TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG; + break; + case rendering::TextDirection::WEAK_RIGHT_TO_LEFT: + nLayoutMode = TEXT_LAYOUT_BIDI_RTL; + break; + case rendering::TextDirection::STRONG_RIGHT_TO_LEFT: + nLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG; + break; + } + + // set calculated layout mode. Origin is always the left edge, + // as required at the API spec + rOutDev.SetLayoutMode( nLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT ); + } + } + + TextLayout::TextLayout( const rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 /*nRandomSeed*/, + const CanvasFont::Reference& rFont, + const SurfaceProviderRef& rRefDevice ) : + TextLayout_Base( m_aMutex ), + maText( aText ), + maLogicalAdvancements(), + mpFont( rFont ), + mpRefDevice( rRefDevice ), + mnTextDirection( nDirection ) + { + } + + TextLayout::~TextLayout() + { + } + + void SAL_CALL TextLayout::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpFont.reset(); + mpRefDevice.clear(); + } + + // XTextLayout + uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > >(); + } + + uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< geometry::RealRectangle2D >(); + } + + uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< geometry::RealRectangle2D >(); + } + + uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maLogicalAdvancements; + } + + void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if( aAdvancements.getLength() != maText.Length ) + { + OSL_TRACE( "TextLayout::applyLogicalAdvancements(): mismatching number of advancements" ); + throw lang::IllegalArgumentException(); + } + + maLogicalAdvancements = aAdvancements; + } + + geometry::RealRectangle2D SAL_CALL TextLayout::queryTextBounds( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + OutputDevice* pOutDev = mpRefDevice->getOutputDevice(); + if( !pOutDev ) + return geometry::RealRectangle2D(); + + VirtualDevice aVDev( *pOutDev ); + aVDev.SetFont( mpFont->getVCLFont() ); + + // need metrics for Y offset, the XCanvas always renders + // relative to baseline + const ::FontMetric& aMetric( aVDev.GetFontMetric() ); + + setupLayoutMode( aVDev, mnTextDirection ); + + const sal_Int32 nAboveBaseline( -aMetric.GetIntLeading() - aMetric.GetAscent() ); + const sal_Int32 nBelowBaseline( aMetric.GetDescent() ); + + if( maLogicalAdvancements.getLength() ) + { + return geometry::RealRectangle2D( 0, nAboveBaseline, + maLogicalAdvancements[ maLogicalAdvancements.getLength()-1 ], + nBelowBaseline ); + } + else + { + return geometry::RealRectangle2D( 0, nAboveBaseline, + aVDev.GetTextWidth( + maText.Text, + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.Length) ), + nBelowBaseline ); + } + } + + double SAL_CALL TextLayout::justify( double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return 0.0; + } + + double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& /*aNextLayouts*/, + double /*nSize*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return 0.0; + } + + rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& /*aHitPoint*/ ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return rendering::TextHit(); + } + + rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 /*nInsertionIndex*/, + sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return rendering::Caret(); + } + + sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 /*nStartIndex*/, + sal_Int32 /*nCaretAdvancement*/, + sal_Bool /*bExcludeLigatures*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return 0; + } + + uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 /*nStartIndex*/, + sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Reference< rendering::XPolyPolygon2D >(); + } + + uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 /*nStartIndex*/, + sal_Int32 /*nEndIndex*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Reference< rendering::XPolyPolygon2D >(); + } + + double SAL_CALL TextLayout::getBaselineOffset( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return 0.0; + } + + sal_Int8 SAL_CALL TextLayout::getMainTextDirection( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mnTextDirection; + } + + uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mpFont.getRef(); + } + + rendering::StringContext SAL_CALL TextLayout::getText( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maText; + } + + void TextLayout::useFont( Cairo* pCairo ) + { + rendering::FontRequest aFontRequest = mpFont->getFontRequest(); + rendering::FontInfo aFontInfo = aFontRequest.FontDescription; + + cairo_select_font_face( pCairo, ::rtl::OUStringToOString( aFontInfo.FamilyName, RTL_TEXTENCODING_UTF8 ), CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL ); + cairo_set_font_size( pCairo, aFontRequest.CellSize ); + } + + /** TextLayout:draw + * + * This function uses the "toy" api of the cairo library + * + **/ + bool TextLayout::draw( Cairo* pCairo ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + ::rtl::OUString aSubText = maText.Text.copy( maText.StartPosition, maText.Length ); + ::rtl::OString aUTF8String = ::rtl::OUStringToOString( aSubText, RTL_TEXTENCODING_UTF8 ); + + cairo_save( pCairo ); + /* move to 0, 0 as cairo_show_text advances current point and current point is not restored by cairo_restore. + before we were depending on unmodified current point which I believed was preserved by save/restore */ + cairo_move_to( pCairo, 0, 0 ); + useFont( pCairo ); + cairo_show_text( pCairo, aUTF8String ); + cairo_restore( pCairo ); + + return true; + } + + + /** + * TextLayout::isCairoRenderable + * + * Features currenly not supported by Cairo (VCL rendering is used as fallback): + * - vertical glyphs + * + * @return true, if text/font can be rendered with cairo + **/ + bool TextLayout::isCairoRenderable(SystemFontData aSysFontData) const + { +#if defined UNX && !defined QUARTZ + // is font usable? + if (!aSysFontData.nFontId) return false; +#endif + + // vertical glyph rendering is not supported in cairo for now + if (aSysFontData.bVerticalCharacterType) { + OSL_TRACE(":cairocanvas::TextLayout::isCairoRenderable(): ***************** VERTICAL CHARACTER STYLE!!! ****************"); + return false; + } + + return true; + } + + + /** + * TextLayout::draw + * + * Cairo-based text rendering. Draw text directly on the cairo surface with cairo fonts. + * Avoid using VCL VirtualDevices for that, bypassing VCL DrawText functions, when possible + * + * Note: some text effects are not rendered due to lacking generic canvas or cairo canvas + * implementation. See issues 92657, 92658, 92659, 92660, 97529 + * + * @return true, if successful + **/ + bool TextLayout::draw( SurfaceSharedPtr& pSurface, + OutputDevice& rOutDev, + const Point& rOutpos, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + SystemTextLayoutData aSysLayoutData; +#if (defined CAIRO_HAS_WIN32_SURFACE) && (OSL_DEBUG_LEVEL > 1) + LOGFONTW logfont; +#endif + setupLayoutMode( rOutDev, mnTextDirection ); + + // TODO(P2): cache that + ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[maLogicalAdvancements.getLength()]); + + if( maLogicalAdvancements.getLength() ) + { + setupTextOffsets( aOffsets.get(), maLogicalAdvancements, viewState, renderState ); + + // TODO(F3): ensure correct length and termination for DX + // array (last entry _must_ contain the overall width) + } + + aSysLayoutData = rOutDev.GetSysTextLayoutData(rOutpos, maText.Text, + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.Length), + maLogicalAdvancements.getLength() ? aOffsets.get() : NULL); + + // The ::GetSysTextLayoutData(), i.e. layouting of text to glyphs can change the font being used. + // The fallback checks need to be done after final font is known. + if (!isCairoRenderable(aSysLayoutData.aSysFontData)) // VCL FALLBACKS + { + OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): VCL FALLBACK %s%s%s%s - %s", + maLogicalAdvancements.getLength() ? "ADV " : "", + aSysLayoutData.aSysFontData.bAntialias ? "AA " : "", + aSysLayoutData.aSysFontData.bFakeBold ? "FB " : "", + aSysLayoutData.aSysFontData.bFakeItalic ? "FI " : "", + ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, maText.Length ), + RTL_TEXTENCODING_UTF8 ).getStr()); + + if (maLogicalAdvancements.getLength()) // VCL FALLBACK - with glyph advances + { + rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets.get(), + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.Length) ); + return true; + } + else // VCL FALLBACK - without advances + { + rOutDev.DrawText( rOutpos, maText.Text, + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.Length) ); + return true; + } + } + + if (aSysLayoutData.rGlyphData.empty()) return false; //??? false? + + /** + * Setup platform independent glyph vector into cairo-based glyphs vector. + **/ + + // setup glyphs + std::vector<cairo_glyph_t> cairo_glyphs; + cairo_glyphs.reserve( 256 ); + + for( int nStart = 0; nStart < (int) aSysLayoutData.rGlyphData.size(); nStart++ ) + { + cairo_glyph_t aGlyph; + SystemGlyphData systemGlyph = aSysLayoutData.rGlyphData.at(nStart); + aGlyph.index = systemGlyph.index; +#ifdef CAIRO_HAS_WIN32_SURFACE + // Cairo requires standard glyph indexes (ETO_GLYPH_INDEX), while vcl/win/* uses ucs4 chars. + // Convert to standard indexes + aGlyph.index = cairo::ucs4toindex((unsigned int) aGlyph.index, aSysLayoutData.aSysFontData.hFont); +#endif + aGlyph.x = systemGlyph.x; + aGlyph.y = systemGlyph.y; + cairo_glyphs.push_back(aGlyph); + } + + if (cairo_glyphs.empty()) return true; //true or false?? + + /** + * Setup font + **/ + cairo_font_face_t* font_face = NULL; + +#ifdef CAIRO_HAS_QUARTZ_SURFACE + // TODO: use cairo_quartz_font_face_create_for_cgfont(cgFont) + // when CGFont (Mac OS X 10.5 API) is provided by the AQUA VCL backend. + font_face = cairo_quartz_font_face_create_for_atsu_font_id((ATSUFontID) aSysLayoutData.aSysFontData.aATSUFontID); + +#elif defined CAIRO_HAS_WIN32_SURFACE + #if (OSL_DEBUG_LEVEL > 1) + GetObjectW( aSysLayoutData.aSysFontData.hFont, sizeof(logfont), &logfont ); + #endif + // Note: cairo library uses logfont fallbacks when lfEscapement, lfOrientation and lfWidth are not zero. + // VCL always has non-zero value for lfWidth + font_face = cairo_win32_font_face_create_for_hfont(aSysLayoutData.aSysFontData.hFont); + +#elif defined CAIRO_HAS_XLIB_SURFACE + font_face = cairo_ft_font_face_create_for_ft_face((FT_Face)aSysLayoutData.aSysFontData.nFontId, + aSysLayoutData.aSysFontData.nFontFlags); +#else +# error Native API needed. +#endif + + CairoSharedPtr pSCairo = pSurface->getCairo(); + + cairo_set_font_face( pSCairo.get(), font_face); + + // create default font options. cairo_get_font_options() does not retrieve the surface defaults, + // only what has been set before with cairo_set_font_options() + cairo_font_options_t* options = cairo_font_options_create(); + if (aSysLayoutData.aSysFontData.bAntialias) { + // CAIRO_ANTIALIAS_GRAY provides more similar result to VCL Canvas, + // so we're not using CAIRO_ANTIALIAS_SUBPIXEL + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); + } + cairo_set_font_options( pSCairo.get(), options); + + // Font color + Color mTextColor = rOutDev.GetTextColor(); + cairo_set_source_rgb(pSCairo.get(), + mTextColor.GetRed()/255.0, + mTextColor.GetGreen()/255.0, + mTextColor.GetBlue()/255.0); + + // Font rotation and scaling + cairo_matrix_t m; + Font aFont = rOutDev.GetFont(); + FontMetric aMetric( rOutDev.GetFontMetric(aFont) ); + long nWidth = 0; + + // width calculation is deep magic and platform/font dependant. + // width == 0 means no scaling, and usually width == height means the same. + // Other values mean horizontal scaling (narrow or stretching) + // see issue #101566 + + //proper scale calculation across platforms + if (aFont.GetWidth() == 0) { + nWidth = aFont.GetHeight(); + } else { + // any scaling needs to be relative to the platform-dependent definition + // of height of the font + nWidth = aFont.GetWidth() * aFont.GetHeight() / aMetric.GetHeight(); + } + + cairo_matrix_init_identity(&m); + + if (aSysLayoutData.orientation) cairo_matrix_rotate(&m, (3600 - aSysLayoutData.orientation) * M_PI / 1800.0); + + cairo_matrix_scale(&m, nWidth, aFont.GetHeight()); + + //faux italics + if (aSysLayoutData.aSysFontData.bFakeItalic) m.xy = -m.xx * 0x6000L / 0x10000L; + + cairo_set_font_matrix(pSCairo.get(), &m); + + OSL_TRACE("\r\n:cairocanvas::TextLayout::draw(S,O,p,v,r): Size:(%d,%d), W:%d->%d, Pos (%d,%d), G(%d,%d,%d) %s%s%s%s || Name:%s - %s", + aFont.GetWidth(), + aFont.GetHeight(), + aMetric.GetWidth(), + nWidth, + (int) rOutpos.X(), + (int) rOutpos.Y(), + cairo_glyphs[0].index, cairo_glyphs[1].index, cairo_glyphs[2].index, + maLogicalAdvancements.getLength() ? "ADV " : "", + aSysLayoutData.aSysFontData.bAntialias ? "AA " : "", + aSysLayoutData.aSysFontData.bFakeBold ? "FB " : "", + aSysLayoutData.aSysFontData.bFakeItalic ? "FI " : "", +#if (defined CAIRO_HAS_WIN32_SURFACE) && (OSL_DEBUG_LEVEL > 1) + ::rtl::OUStringToOString( reinterpret_cast<const sal_Unicode*> (logfont.lfFaceName), RTL_TEXTENCODING_UTF8 ).getStr(), +#else + ::rtl::OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), +#endif + ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, maText.Length ), + RTL_TEXTENCODING_UTF8 ).getStr() + ); + + cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size()); + + //faux bold + if (aSysLayoutData.aSysFontData.bFakeBold) { + double bold_dx = 0.5 * sqrt( 0.7 * aFont.GetHeight() ); + int total_steps = 2 * ((int) (bold_dx + 0.5)); + + // loop to draw the text for every half pixel of displacement + for (int nSteps = 0; nSteps < total_steps; nSteps++) { + for(int nGlyphIdx = 0; nGlyphIdx < (int) cairo_glyphs.size(); nGlyphIdx++) { + cairo_glyphs[nGlyphIdx].x += bold_dx * nSteps / total_steps; + } + cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size()); + } + OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): FAKEBOLD - dx:%d", (int) bold_dx); + } + + cairo_restore( pSCairo.get() ); + cairo_font_face_destroy(font_face); + return true; + } + + + namespace + { + class OffsetTransformer + { + public: + OffsetTransformer( const ::basegfx::B2DHomMatrix& rMat ) : + maMatrix( rMat ) + { + } + + sal_Int32 operator()( const double& rOffset ) + { + // This is an optimization of the normal rMat*[x,0] + // transformation of the advancement vector (in x + // direction), followed by a length calculation of the + // resulting vector: advancement' = + // ||rMat*[x,0]||. Since advancements are vectors, we + // can ignore translational components, thus if [x,0], + // it follows that rMat*[x,0]=[x',0] holds. Thus, we + // just have to calc the transformation of the x + // component. + + // TODO(F2): Handle non-horizontal advancements! + return ::basegfx::fround( hypot(maMatrix.get(0,0)*rOffset, + maMatrix.get(1,0)*rOffset) ); + } + + private: + ::basegfx::B2DHomMatrix maMatrix; + }; + } + + void TextLayout::setupTextOffsets( sal_Int32* outputOffsets, + const uno::Sequence< double >& inputOffsets, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) const + { + ENSURE_OR_THROW( outputOffsets!=NULL, + "TextLayout::setupTextOffsets offsets NULL" ); + + ::basegfx::B2DHomMatrix aMatrix; + + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, + viewState, + renderState); + + // fill integer offsets + ::std::transform( const_cast< uno::Sequence< double >& >(inputOffsets).getConstArray(), + const_cast< uno::Sequence< double >& >(inputOffsets).getConstArray()+inputOffsets.getLength(), + outputOffsets, + OffsetTransformer( aMatrix ) ); + } + +#define SERVICE_NAME "com.sun.star.rendering.TextLayout" +#define IMPLEMENTATION_NAME "CairoCanvas::TextLayout" + + ::rtl::OUString SAL_CALL TextLayout::getImplementationName() throw( uno::RuntimeException ) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL TextLayout::supportsService( const ::rtl::OUString& ServiceName ) throw( uno::RuntimeException ) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL TextLayout::getSupportedServiceNames() throw( uno::RuntimeException ) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } +} diff --git a/canvas/source/cairo/cairo_textlayout.hxx b/canvas/source/cairo/cairo_textlayout.hxx new file mode 100644 index 000000000000..6e14907c01bb --- /dev/null +++ b/canvas/source/cairo/cairo_textlayout.hxx @@ -0,0 +1,120 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_TEXTLAYOUT_HXX +#define _CAIROCANVAS_TEXTLAYOUT_HXX + +#include <cppuhelper/compbase2.hxx> +#include <comphelper/broadcasthelper.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/XTextLayout.hpp> + +#include <basegfx/vector/b2isize.hxx> + +#include <vcl/outdev.hxx> + +#include <boost/utility.hpp> + +#include "cairo_cairo.hxx" +#include "cairo_canvasfont.hxx" + + +/* Definition of TextLayout class */ + +namespace cairocanvas +{ + typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XTextLayout, + ::com::sun::star::lang::XServiceInfo > TextLayout_Base; + + class TextLayout : public ::comphelper::OBaseMutex, + public TextLayout_Base, + private ::boost::noncopyable + { + public: + TextLayout( const ::com::sun::star::rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 nRandomSeed, + const CanvasFont::Reference& rFont, + const SurfaceProviderRef& rRefDevice ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // XTextLayout + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > > SAL_CALL queryTextShapes( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealRectangle2D > SAL_CALL queryInkMeasures( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealRectangle2D > SAL_CALL queryMeasures( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< double > SAL_CALL queryLogicalAdvancements( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL applyLogicalAdvancements( const ::com::sun::star::uno::Sequence< double >& aAdvancements ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::geometry::RealRectangle2D SAL_CALL queryTextBounds( ) throw (::com::sun::star::uno::RuntimeException); + virtual double SAL_CALL justify( double nSize ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual double SAL_CALL combinedJustify( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XTextLayout > >& aNextLayouts, double nSize ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::TextHit SAL_CALL getTextHit( const ::com::sun::star::geometry::RealPoint2D& aHitPoint ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::Caret SAL_CALL getCaret( sal_Int32 nInsertionIndex, sal_Bool bExcludeLigatures ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getNextInsertionIndex( sal_Int32 nStartIndex, sal_Int32 nCaretAdvancement, sal_Bool bExcludeLigatures ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > SAL_CALL queryVisualHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > SAL_CALL queryLogicalHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual double SAL_CALL getBaselineOffset( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int8 SAL_CALL getMainTextDirection( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > SAL_CALL getFont( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::rendering::StringContext SAL_CALL getText( ) throw (::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ); + + bool draw( ::cairo::Cairo* pCairo ); + bool draw( SurfaceSharedPtr& pSurface, + OutputDevice& rOutDev, + const Point& rOutpos, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ) const; + + void setupTextOffsets( sal_Int32* outputOffsets, + const ::com::sun::star::uno::Sequence< double >& inputOffsets, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ) const; + + protected: + ~TextLayout(); // we're a ref-counted UNO class. _We_ destroy ourselves. + + private: + ::com::sun::star::rendering::StringContext maText; + ::com::sun::star::uno::Sequence< double > maLogicalAdvancements; + CanvasFont::Reference mpFont; + SurfaceProviderRef mpRefDevice; + sal_Int8 mnTextDirection; + + void useFont( ::cairo::Cairo* pCairo ); + bool isCairoRenderable(SystemFontData aSysFontData) const; + }; + +} + +#endif /* _CAIROCANVAS_TEXTLAYOUT_HXX */ diff --git a/canvas/source/cairo/cairo_win32_cairo.cxx b/canvas/source/cairo/cairo_win32_cairo.cxx new file mode 100644 index 000000000000..d0d6558c2fdd --- /dev/null +++ b/canvas/source/cairo/cairo_win32_cairo.cxx @@ -0,0 +1,325 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#ifdef WNT +/************************************************************************ + * Win32 surface backend for OpenOffice.org Cairo Canvas * + ************************************************************************/ + +#include <tools/prewin.h> +#include <windows.h> +#include <tools/postwin.h> + +#include <osl/diagnose.h> +#include <vcl/bitmap.hxx> +#include <vcl/virdev.hxx> +#include <vcl/sysdata.hxx> + +#include "cairo_win32_cairo.hxx" + +#ifdef CAIRO_HAS_WIN32_SURFACE + +namespace cairo +{ + +#include <cairo-win32.h> + + bool IsCairoWorking( OutputDevice* ) + { + // trivially true for Windows + return true; + } + + /** + * Surface::Surface: Create generic Canvas surface using given Cairo Surface + * + * @param pSurface Cairo Surface + * + * This constructor only stores data, it does no processing. + * It is used with e.g. cairo_image_surface_create_for_data() + * and Surface::getSimilar() + * + * Set the mpSurface to the new surface or NULL + **/ + Win32Surface::Win32Surface( const CairoSurfaceSharedPtr& pSurface ) : + mpSurface( pSurface ) + {} + + /** + * Surface::Surface: Create Canvas surface from Window reference. + * @param pSysData Platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx) + * @param x horizontal location of the new surface + * @param y vertical location of the new surface + * + * pSysData contains the platform native Window reference. + * pSysData is used to create a surface on the Window + * + * Set the mpSurface to the new surface or NULL + **/ + Win32Surface::Win32Surface( HDC hDC, int x, int y) : + mpSurface( + cairo_win32_surface_create(hDC), + &cairo_surface_destroy) + { + cairo_surface_set_device_offset( mpSurface.get(), x, y ); + } + + /** + * Surface::Surface: Create platfrom native Canvas surface from BitmapSystemData + * @param pBmpData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx) + * + * Create a surface based on image data on pBmpData + * + * Set the mpSurface to the new surface or NULL + **/ + Win32Surface::Win32Surface( const BitmapSystemData& rBmpData ) : + mpSurface() + { + OSL_ASSERT(rBmpData.pDIB == NULL); + + if(rBmpData.pDIB != NULL) { + // So just leave mpSurface to NULL, little else we can do at + // this stage. Hopefully the Win32 patch to + // cairocanvas::DeviceHelper::getSurface(BitmapSystemData&, + // const Size&) will catch the cases where this + // constructor would be called with a DIB bitmap, and we + // will never get here. At least it worked for Ballmer.ppt. + } + else + { + HDC hDC = CreateCompatibleDC(NULL); + void* hOrigBitmap; + OSL_TRACE ("Surface::Surface(): Selecting bitmap %p into DC %p", rBmpData.pDDB, hDC); + hOrigBitmap = SelectObject( hDC, (HANDLE)rBmpData.pDDB ); + if(hOrigBitmap == NULL) + OSL_TRACE ("SelectObject failed: %d", GetLastError ()); + mpSurface.reset( + cairo_win32_surface_create(hDC), + &cairo_surface_destroy); + } + } + + /** + * Surface::getCairo: Create Cairo (drawing object) for the Canvas surface + * + * @return new Cairo or NULL + **/ + CairoSharedPtr Win32Surface::getCairo() const + { + return CairoSharedPtr( cairo_create(mpSurface.get()), + &cairo_destroy ); + } + + /** + * Surface::getSimilar: Create new similar Canvas surface + * @param aContent format of the new surface (cairo_content_t from cairo/src/cairo.h) + * @param width width of the new surface + * @param height height of the new surface + * + * Creates a new Canvas surface. This normally creates platform native surface, even though + * generic function is used. + * + * Cairo surface from aContent (cairo_content_t) + * + * @return new surface or NULL + **/ + SurfaceSharedPtr Win32Surface::getSimilar( Content aContent, int width, int height ) const + { + return SurfaceSharedPtr( + new Win32Surface( + CairoSurfaceSharedPtr( + cairo_surface_create_similar( mpSurface.get(), aContent, width, height ), + &cairo_surface_destroy ))); + } + + /** + * Surface::Resize: Resizes the Canvas surface. + * @param width new width of the surface + * @param height new height of the surface + * + * Only used on X11. + * + * @return The new surface or NULL + **/ + void Win32Surface::Resize( int /*width*/, int /*height*/ ) + { + OSL_ENSURE(false,"not supposed to be called!"); + } + + void Win32Surface::flush() const + { + GdiFlush(); + } + + /** + * Surface::getDepth: Get the color depth of the Canvas surface. + * + * @return color depth + **/ + int Win32Surface::getDepth() const + { + if (mpSurface) { + switch (cairo_surface_get_content (mpSurface.get())) { + case CAIRO_CONTENT_ALPHA: return 8; break; + case CAIRO_CONTENT_COLOR: return 24; break; + case CAIRO_CONTENT_COLOR_ALPHA: return 32; break; + } + } + OSL_TRACE("Canvas::cairo::Surface::getDepth(): ERROR - depth unspecified!"); + return -1; + } + + + /** + * cairo::createVirtualDevice: Create a VCL virtual device for the CGContext in the cairo Surface + * + * @return The new virtual device + **/ + boost::shared_ptr<VirtualDevice> Win32Surface::createVirtualDevice() const + { + SystemGraphicsData aSystemGraphicsData; + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.hDC = cairo_win32_surface_get_dc( mpSurface.get() ); + + return boost::shared_ptr<VirtualDevice>( + new VirtualDevice( &aSystemGraphicsData, sal::static_int_cast<USHORT>(getDepth()) )); + } + + + /** + * cairo::createSurface: Create generic Canvas surface using given Cairo Surface + * + * @param rSurface Cairo Surface + * + * @return new Surface + */ + SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface ) + { + return SurfaceSharedPtr(new Win32Surface(rSurface)); + } + + + /** + * cairo::createSurface: Create Canvas surface using given VCL Window or Virtualdevice + * + * @param rSurface Cairo Surface + * + * For VCL Window, use platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx) + * For VCL Virtualdevice, use platform native system graphics data (struct SystemGraphicsData in vcl/inc/sysdata.hxx) + * + * @return new Surface + */ + SurfaceSharedPtr createSurface( const OutputDevice& rRefDevice, + int x, int y, int /* width */, int /* height */) + { + SurfaceSharedPtr surf; + + if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW ) + { + const Window &rWindow = (const Window &) rRefDevice; + const SystemEnvData* pSysData = GetSysData(&rWindow); + if (pSysData && pSysData->hWnd) + surf = SurfaceSharedPtr(new Win32Surface(GetDC((HWND) pSysData->hWnd), x, y)); + } + else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV ) + { + SystemGraphicsData aSysData = ((const VirtualDevice&) rRefDevice).GetSystemGfxData(); + if (aSysData.hDC) + surf = SurfaceSharedPtr(new Win32Surface((HDC) aSysData.hDC, x, y)); + } + return surf; + } + + + /** + * cairo::createBitmapSurface: Create platfrom native Canvas surface from BitmapSystemData + * @param OutputDevice (not used) + * @param rData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx) + * @param rSize width and height of the new surface + * + * Create a surface based on image data on rData + * + * @return new surface or empty surface + **/ + SurfaceSharedPtr createBitmapSurface( const OutputDevice& /* rRefDevice */, + const BitmapSystemData& rData, + const Size& rSize ) + { + OSL_TRACE( "requested size: %d x %d available size: %d x %d", + rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight ); + + if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() ) + return SurfaceSharedPtr(new Win32Surface( rData )); + else + return SurfaceSharedPtr(); + } + + + /** + * cairo::ucs4toindex: Convert ucs4 char to glyph index + * @param ucs4 an ucs4 char + * @param hfont current font + * + * @return true if successful + **/ + unsigned long ucs4toindex(unsigned int ucs4, HFONT hfont) + { + wchar_t unicode[2]; + WORD glyph_index; + HDC hdc = NULL; + int i = 0; + + hdc = CreateCompatibleDC (NULL); + + if (!hdc) return 0; + if (!SetGraphicsMode (hdc, GM_ADVANCED)) { + DeleteDC (hdc); + return 0; + } + + SelectObject (hdc, hfont); + SetMapMode (hdc, MM_TEXT); + + unicode[0] = ucs4; + unicode[1] = 0; + if (GetGlyphIndicesW (hdc, unicode, 1, &glyph_index, 0) == GDI_ERROR) { + glyph_index = 0; + } + + DeleteDC (hdc); + return glyph_index; + } + + +} // namespace cairo + +#endif // CAIRO_HAS_WIN32_SURFACE + +#endif // WNT diff --git a/canvas/source/cairo/cairo_win32_cairo.hxx b/canvas/source/cairo/cairo_win32_cairo.hxx new file mode 100644 index 000000000000..3b083d28e748 --- /dev/null +++ b/canvas/source/cairo/cairo_win32_cairo.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_WIN32_CAIRO_HXX +#define _CAIROCANVAS_WIN32_CAIRO_HXX + +#ifdef WNT +# include <tools/prewin.h> +# include <windows.h> +# include <tools/postwin.h> +#endif + +#include "cairo_cairo.hxx" + +namespace cairo { + + class Win32Surface : public Surface + { + CairoSurfaceSharedPtr mpSurface; + + public: + /// takes over ownership of passed cairo_surface + explicit Win32Surface( const CairoSurfaceSharedPtr& pSurface ); + /// create surface on subarea of given drawable + Win32Surface( HDC hDC, int x, int y ); + /// create surface for given bitmap data + Win32Surface( const BitmapSystemData& rBmpData ); + + // Surface interface + virtual CairoSharedPtr getCairo() const; + virtual CairoSurfaceSharedPtr getCairoSurface() const { return mpSurface; } + virtual SurfaceSharedPtr getSimilar( Content aContent, int width, int height ) const; + + virtual boost::shared_ptr<VirtualDevice> createVirtualDevice() const; + + virtual void Resize( int width, int height ); + + virtual void flush() const; + + int getDepth() const; + }; + + unsigned long ucs4toindex(unsigned int ucs4, HFONT hfont); +} + +#endif diff --git a/canvas/source/cairo/cairo_xlib_cairo.cxx b/canvas/source/cairo/cairo_xlib_cairo.cxx new file mode 100644 index 000000000000..823ad05e426f --- /dev/null +++ b/canvas/source/cairo/cairo_xlib_cairo.cxx @@ -0,0 +1,352 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <tools/prex.h> +#include <X11/extensions/Xrender.h> +#include <X11/Xlib.h> +#include <tools/postx.h> + +#include "cairo_xlib_cairo.hxx" + +#include <vcl/sysdata.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/virdev.hxx> +#include <basegfx/vector/b2isize.hxx> + +namespace cairo +{ + +#include <cairo-xlib.h> +#include <cairo-xlib-xrender.h> + + // TODO(F3): svp headless case! + + bool IsCairoWorking( OutputDevice* pOutDev ) + { + if( !pOutDev ) + return false; + + Display* pDisplay = (Display*)pOutDev->GetSystemGfxData().pDisplay; + int nDummy; + return XQueryExtension( pDisplay, "RENDER", &nDummy, &nDummy, &nDummy ); + } + + X11SysData::X11SysData() : + pDisplay(NULL), + hDrawable(0), + pVisual(NULL), + nScreen(0), + nDepth(-1), + aColormap(-1), + pRenderFormat(NULL) + {} + + X11SysData::X11SysData( const SystemGraphicsData& pSysDat ) : + pDisplay(pSysDat.pDisplay), + hDrawable(pSysDat.hDrawable), + pVisual(pSysDat.pVisual), + nScreen(pSysDat.nScreen), + nDepth(pSysDat.nDepth), + aColormap(pSysDat.aColormap), + pRenderFormat(pSysDat.pRenderFormat) + {} + + X11SysData::X11SysData( const SystemEnvData& pSysDat ) : + pDisplay(pSysDat.pDisplay), + hDrawable(pSysDat.aWindow), + pVisual(pSysDat.pVisual), + nScreen(pSysDat.nScreen), + nDepth(pSysDat.nDepth), + aColormap(pSysDat.aColormap), + pRenderFormat(NULL) + {} + + X11Pixmap::~X11Pixmap() + { + if( mpDisplay && mhDrawable ) + XFreePixmap( (Display*)mpDisplay, mhDrawable ); + } + + /** + * Surface::Surface: Create Canvas surface with existing data + * @param pSysData Platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx) + * @param pSurface Cairo surface + * + * pSysData contains the platform native Drawable reference + * This constructor only stores data, it does no processing. + * It is used by e.g. Surface::getSimilar() + * + * Set the mpSurface as pSurface + **/ + X11Surface::X11Surface( const X11SysData& rSysData, + const X11PixmapSharedPtr& rPixmap, + const CairoSurfaceSharedPtr& pSurface ) : + maSysData(rSysData), + mpPixmap(rPixmap), + mpSurface(pSurface) + {} + + /** + * Surface::Surface: Create generic Canvas surface using given Cairo Surface + * + * @param pSurface Cairo Surface + * + * This constructor only stores data, it does no processing. + * It is used with e.g. cairo_image_surface_create_for_data() + * Unlike other constructors, mpSysData is set to NULL + * + * Set the mpSurface as pSurface + **/ + X11Surface::X11Surface( const CairoSurfaceSharedPtr& pSurface ) : + maSysData(), + mpPixmap(), + mpSurface(pSurface) + {} + + /** + * Surface::Surface: Create Canvas surface from Window reference. + * @param pSysData Platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx) + * @param x horizontal location of the new surface + * @param y vertical location of the new surface + * @param width width of the new surface + * @param height height of the new surface + * + * pSysData contains the platform native Window reference. + * + * pSysData is used to create a surface on the Window + * + * Set the mpSurface to the new surface or NULL + **/ + X11Surface::X11Surface( const X11SysData& rSysData, int x, int y, int width, int height ) : + maSysData(rSysData), + mpPixmap(), + mpSurface( + cairo_xlib_surface_create( (Display*)rSysData.pDisplay, + rSysData.hDrawable, + (Visual*)rSysData.pVisual, + width + x, height + y ), + &cairo_surface_destroy) + { + cairo_surface_set_device_offset(mpSurface.get(), x, y ); + } + + /** + * Surface::Surface: Create platfrom native Canvas surface from BitmapSystemData + * @param pSysData Platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx) + * @param pBmpData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx) + * @param width width of the new surface + * @param height height of the new surface + * + * The pBmpData provides the imagedata that the created surface should contain. + * + * Set the mpSurface to the new surface or NULL + **/ + X11Surface::X11Surface( const X11SysData& rSysData, + const BitmapSystemData& rData ) : + maSysData( rSysData ), + mpPixmap(), + mpSurface( + cairo_xlib_surface_create( (Display*)rSysData.pDisplay, + (Drawable)rData.aPixmap, + (Visual*) rSysData.pVisual, + rData.mnWidth, rData.mnHeight ), + &cairo_surface_destroy) + { + } + + /** + * Surface::getCairo: Create Cairo (drawing object) for the Canvas surface + * + * @return new Cairo or NULL + **/ + CairoSharedPtr X11Surface::getCairo() const + { + return CairoSharedPtr( cairo_create(mpSurface.get()), + &cairo_destroy ); + } + + /** + * Surface::getSimilar: Create new similar Canvas surface + * @param aContent format of the new surface (cairo_content_t from cairo/src/cairo.h) + * @param width width of the new surface + * @param height height of the new surface + * + * Creates a new Canvas surface. This normally creates platform native surface, even though + * generic function is used. + * + * Cairo surface from aContent (cairo_content_t) + * + * @return new surface or NULL + **/ + SurfaceSharedPtr X11Surface::getSimilar( Content aContent, int width, int height ) const + { + Pixmap hPixmap; + + if( maSysData.pDisplay && maSysData.hDrawable ) + { + XRenderPictFormat* pFormat; + int nFormat; + + switch (aContent) + { + case CAIRO_CONTENT_ALPHA: + nFormat = PictStandardA8; + break; + case CAIRO_CONTENT_COLOR: + nFormat = PictStandardRGB24; + break; + case CAIRO_CONTENT_COLOR_ALPHA: + default: + nFormat = PictStandardARGB32; + break; + } + + pFormat = XRenderFindStandardFormat( (Display*)maSysData.pDisplay, nFormat ); + hPixmap = XCreatePixmap( (Display*)maSysData.pDisplay, maSysData.hDrawable, + width > 0 ? width : 1, height > 0 ? height : 1, + pFormat->depth ); + + X11SysData aSysData(maSysData); + aSysData.pRenderFormat = pFormat; + return SurfaceSharedPtr( + new X11Surface( aSysData, + X11PixmapSharedPtr( + new X11Pixmap(hPixmap, maSysData.pDisplay)), + CairoSurfaceSharedPtr( + cairo_xlib_surface_create_with_xrender_format( + (Display*)maSysData.pDisplay, + hPixmap, + ScreenOfDisplay((Display *)maSysData.pDisplay, maSysData.nScreen), + pFormat, width, height ), + &cairo_surface_destroy) )); + } + else + return SurfaceSharedPtr( + new X11Surface( maSysData, + X11PixmapSharedPtr(), + CairoSurfaceSharedPtr( + cairo_surface_create_similar( mpSurface.get(), aContent, width, height ), + &cairo_surface_destroy ))); + } + + boost::shared_ptr<VirtualDevice> X11Surface::createVirtualDevice() const + { + SystemGraphicsData aSystemGraphicsData; + + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.hDrawable = getDrawable(); + aSystemGraphicsData.pRenderFormat = getRenderFormat(); + + return boost::shared_ptr<VirtualDevice>( + new VirtualDevice( &aSystemGraphicsData, getDepth() )); + } + + /** + * Surface::Resize: Resizes the Canvas surface. + * @param width new width of the surface + * @param height new height of the surface + * + * Only used on X11. + * + * @return The new surface or NULL + **/ + void X11Surface::Resize( int width, int height ) + { + cairo_xlib_surface_set_size( mpSurface.get(), width, height ); + } + + void X11Surface::flush() const + { + XSync( (Display*)maSysData.pDisplay, false ); + } + + /** + * Surface::getDepth: Get the color depth of the Canvas surface. + * + * @return color depth + **/ + int X11Surface::getDepth() const + { + if( maSysData.pRenderFormat ) + return ((XRenderPictFormat*) maSysData.pRenderFormat)->depth; + + return -1; + } + + SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface ) + { + return SurfaceSharedPtr(new X11Surface(rSurface)); + } + + static X11SysData getSysData( const Window& rWindow ) + { + const SystemEnvData* pSysData = GetSysData(&rWindow); + + if( !pSysData ) + return X11SysData(); + else + return X11SysData(*pSysData); + } + + static X11SysData getSysData( const VirtualDevice& rVirDev ) + { + return X11SysData( rVirDev.GetSystemGfxData() ); + } + + SurfaceSharedPtr createSurface( const OutputDevice& rRefDevice, + int x, int y, int width, int height ) + { + if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW ) + return SurfaceSharedPtr(new X11Surface(getSysData((const Window&)rRefDevice), + x,y,width,height)); + else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV ) + return SurfaceSharedPtr(new X11Surface(getSysData((const VirtualDevice&)rRefDevice), + x,y,width,height)); + else + return SurfaceSharedPtr(); + } + + SurfaceSharedPtr createBitmapSurface( const OutputDevice& rRefDevice, + const BitmapSystemData& rData, + const Size& rSize ) + { + OSL_TRACE( "requested size: %d x %d available size: %d x %d", + rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight ); + if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() ) + { + if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW ) + return SurfaceSharedPtr(new X11Surface(getSysData((const Window&)rRefDevice), rData )); + else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV ) + return SurfaceSharedPtr(new X11Surface(getSysData((const VirtualDevice&)rRefDevice), rData )); + } + + return SurfaceSharedPtr(); + } +} diff --git a/canvas/source/cairo/cairo_xlib_cairo.hxx b/canvas/source/cairo/cairo_xlib_cairo.hxx new file mode 100644 index 000000000000..aa5cfa67a2b6 --- /dev/null +++ b/canvas/source/cairo/cairo_xlib_cairo.hxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _CAIROCANVAS_XLIB_CAIRO_HXX +#define _CAIROCANVAS_XLIB_CAIRO_HXX + +#include "cairo_cairo.hxx" + +struct SystemEnvData; +struct SystemGraphicsData; + +namespace cairo { + + /// Holds all X11-output relevant data + struct X11SysData + { + X11SysData(); + explicit X11SysData( const SystemGraphicsData& ); + explicit X11SysData( const SystemEnvData& ); + + void* pDisplay; // the relevant display connection + long hDrawable; // a drawable + void* pVisual; // the visual in use + int nScreen; // the current screen of the drawable + int nDepth; // depth of said visual + long aColormap; // the colormap being used + void* pRenderFormat; // render format for drawable + }; + + /// RAII wrapper for a pixmap + struct X11Pixmap + { + void* mpDisplay; // the relevant display connection + long mhDrawable; // a drawable + + X11Pixmap( long hDrawable, void* pDisplay ) : + mpDisplay(pDisplay), + mhDrawable(hDrawable) + {} + + ~X11Pixmap(); + + void clear() { mpDisplay=NULL; mhDrawable=0; } + }; + + typedef boost::shared_ptr<X11Pixmap> X11PixmapSharedPtr; + + class X11Surface : public Surface + { + const X11SysData maSysData; + X11PixmapSharedPtr mpPixmap; + CairoSurfaceSharedPtr mpSurface; + + X11Surface( const X11SysData& rSysData, const X11PixmapSharedPtr& rPixmap, const CairoSurfaceSharedPtr& pSurface ); + + public: + /// takes over ownership of passed cairo_surface + explicit X11Surface( const CairoSurfaceSharedPtr& pSurface ); + /// create surface on subarea of given drawable + X11Surface( const X11SysData& rSysData, int x, int y, int width, int height ); + /// create surface for given bitmap data + X11Surface( const X11SysData& rSysData, const BitmapSystemData& rBmpData ); + + // Surface interface + virtual CairoSharedPtr getCairo() const; + virtual CairoSurfaceSharedPtr getCairoSurface() const { return mpSurface; } + virtual SurfaceSharedPtr getSimilar( Content aContent, int width, int height ) const; + + virtual boost::shared_ptr<VirtualDevice> createVirtualDevice() const; + + virtual void Resize( int width, int height ); + + virtual void flush() const; + + int getDepth() const; + X11PixmapSharedPtr getPixmap() const { return mpPixmap; } + void* getRenderFormat() const { return maSysData.pRenderFormat; } + long getDrawable() const { return mpPixmap ? mpPixmap->mhDrawable : maSysData.hDrawable; } + }; +} + +#endif diff --git a/canvas/source/cairo/cairocanvas.component b/canvas/source/cairo/cairocanvas.component new file mode 100644 index 000000000000..126ad2b44ee1 --- /dev/null +++ b/canvas/source/cairo/cairocanvas.component @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--********************************************************************** +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2010 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org 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 version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +**********************************************************************--> + +<component loader="com.sun.star.loader.SharedLibrary" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.rendering.Canvas.Cairo"> + <service name="com.sun.star.rendering.Canvas.Cairo"/> + </implementation> + <implementation name="com.sun.star.comp.rendering.SpriteCanvas.Cairo"> + <service name="com.sun.star.rendering.SpriteCanvas.Cairo"/> + </implementation> +</component> diff --git a/canvas/source/cairo/exports.dxp b/canvas/source/cairo/exports.dxp new file mode 100644 index 000000000000..f0e1c69934bc --- /dev/null +++ b/canvas/source/cairo/exports.dxp @@ -0,0 +1,2 @@ +component_getImplementationEnvironment +component_getFactory diff --git a/canvas/source/cairo/makefile.mk b/canvas/source/cairo/makefile.mk new file mode 100644 index 000000000000..040acd9ade8f --- /dev/null +++ b/canvas/source/cairo/makefile.mk @@ -0,0 +1,140 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=canvas +TARGET=cairocanvas +TARGETTYPE=GUI +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +DLLPRE = + +# --- Nothing to do if we're compiling with --disable-cairo ----------- +.IF "$(ENABLE_CAIRO)" != "TRUE" +@all: + @echo "Building without cairo support..." +.ELSE +# --- X11 Mac build currently doesn't work with cairo ----------- +.IF "$(OS)" == "MACOSX" && "$(GUIBASE)" == "unx" +@all: + @echo "Cannot build cairocanvas with X11..." +.ENDIF +.ENDIF + +# --- Common ---------------------------------------------------------- + + +.IF "$(SYSTEM_CAIRO)" == "YES" +CFLAGS+=$(CAIRO_CFLAGS) +.ELSE +CFLAGS+=-I$(SOLARINCDIR)/cairo +.ENDIF + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF +.IF "$(L10N_framework)"=="" +SLOFILES = $(SLO)$/cairo_cachedbitmap.obj \ + $(SLO)$/cairo_cairo.obj \ + $(SLO)$/cairo_canvas.obj \ + $(SLO)$/cairo_canvasbitmap.obj \ + $(SLO)$/cairo_canvascustomsprite.obj \ + $(SLO)$/cairo_canvasfont.obj \ + $(SLO)$/cairo_canvashelper.obj \ + $(SLO)$/cairo_canvashelper_text.obj \ + $(SLO)$/cairo_devicehelper.obj \ + $(SLO)$/cairo_services.obj \ + $(SLO)$/cairo_spritecanvas.obj \ + $(SLO)$/cairo_spritecanvashelper.obj \ + $(SLO)$/cairo_spritedevicehelper.obj \ + $(SLO)$/cairo_spritehelper.obj \ + $(SLO)$/cairo_textlayout.obj + +SHL1TARGET=$(TARGET).uno + +SHL1STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(VCLLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(TOOLSLIB) $(I18NISOLANGLIB) + +.IF "$(GUI)"=="UNX" + +.IF "$(SYSTEM_CAIRO)" == "YES" +SHL1STDLIBS+= $(CAIRO_LIBS) +.ELSE +SHL1STDLIBS+= -lcairo -lpixman-1 +.ENDIF + +.IF "$(GUIBASE)"=="aqua" +# native Mac OS X (Quartz) +SLOFILES+= $(SLO)$/cairo_quartz_cairo.obj +CFLAGSCXX+=$(OBJCXXFLAGS) +.ELSE # "$(GUIBASE)"=="aqua" + +# Xlib +SLOFILES+= $(SLO)$/cairo_xlib_cairo.obj +SHL1STDLIBS+= -lfontconfig -lX11 -lXrender $(FREETYPE_LIBS) +CFLAGS+=$(FREETYPE_CFLAGS) + +.ENDIF # "$(GUIBASE)"=="aqua" + +.ELSE # "$(GUI)"=="UNX" + +.IF "$(GUI)"=="WNT" +SLOFILES+= $(SLO)$/cairo_win32_cairo.obj +.IF "$(COM)"=="GCC" +SHL1STDLIBS+= -lcairo +.ELSE +SHL1STDLIBS+= cairo.lib +.ENDIF +SHL1STDLIBS+= $(GDI32LIB) $(MSIMG32LIB) +.ENDIF + +.ENDIF # "$(GUI)"=="UNX" + +SHL1IMPLIB=i$(TARGET) +SHL1LIBS=$(SLB)$/$(TARGET).lib +SHL1DEF=$(MISC)$/$(SHL1TARGET).def + +SHL1VERSIONMAP=$(SOLARENV)/src/component.map + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=exports.dxp + +.ENDIF +# ========================================================================== + +.INCLUDE : target.mk + +ALLTAR : $(MISC)/cairocanvas.component + +$(MISC)/cairocanvas.component .ERRREMOVE : \ + $(SOLARENV)/bin/createcomponent.xslt cairocanvas.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt cairocanvas.component |