diff options
Diffstat (limited to 'canvas/source')
195 files changed, 46638 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 diff --git a/canvas/source/directx/directx5canvas.component b/canvas/source/directx/directx5canvas.component new file mode 100644 index 000000000000..80133e724df6 --- /dev/null +++ b/canvas/source/directx/directx5canvas.component @@ -0,0 +1,34 @@ +<?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.SpriteCanvas.DX5"> + <service name="com.sun.star.rendering.SpriteCanvas.DX5"/> + </implementation> +</component> diff --git a/canvas/source/directx/directx9canvas.component b/canvas/source/directx/directx9canvas.component new file mode 100644 index 000000000000..0d395892d4cb --- /dev/null +++ b/canvas/source/directx/directx9canvas.component @@ -0,0 +1,34 @@ +<?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.SpriteCanvas.DX9"> + <service name="com.sun.star.rendering.SpriteCanvas.DX9"/> + </implementation> +</component> diff --git a/canvas/source/directx/dx_5rm.cxx b/canvas/source/directx/dx_5rm.cxx new file mode 100755 index 000000000000..642ef7bd7db6 --- /dev/null +++ b/canvas/source/directx/dx_5rm.cxx @@ -0,0 +1,2283 @@ +/************************************************************************* + * + * 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" + +#if DIRECTX_VERSION < 0x0900 + +// Nvidia GeForce Go 6800 crashes with a bluescreen if we take the +// maximum texture size, which would be twice as large. this behaviors +// has only been observed on directx5. +// This value is simply the maximum size for textures we request from +// the system, it has absolutely nothing to do with the size of primitives +// we're able to render, both concepts are totally independent from each other. +#define MAX_TEXTURE_SIZE (2048) +#define MIN_TEXTURE_SIZE (32) +//#define FAKE_MAX_NUMBER_TEXTURES (2) +//#define FAKE_MAX_TEXTURE_SIZE (512) + +////////////////////////////////////////////////////////////////////////////////// +// includes +////////////////////////////////////////////////////////////////////////////////// +#include <vcl/syschild.hxx> +#include <vcl/window.hxx> +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/elapsedtime.hxx> +#include <canvas/canvastools.hxx> +#include <canvas/rendering/icolorbuffer.hxx> +#include <canvas/rendering/isurface.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <tools/diagnose_ex.h> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <boost/scoped_ptr.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#define COMPILE_MULTIMON_STUBS + +#include "dx_rendermodule.hxx" +#include "dx_surfacegraphics.hxx" +#include <vcl/sysdata.hxx> + +#undef WB_LEFT +#undef WB_RIGHT + +#include "dx_impltools.hxx" +#include <malloc.h> + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +#undef COMPILE_MULTIMON_STUBS + +#include <stdio.h> + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////////// +// 'dxcanvas' namespace +////////////////////////////////////////////////////////////////////////////////// + +namespace dxcanvas +{ + namespace + { + bool doBlit( const ::basegfx::B2IPoint& rDestPos, + IDirectDrawSurface& rOutSurface, + const ::basegfx::B2IRange& rSourceArea, + IDirectDrawSurface& rSourceSurface, + DDBLTFX* pBltFx, + bool bForceSoftware ) + { + if( !bForceSoftware ) + { + // blit surface to backbuffer + RECT aOutRect = + { + rDestPos.getX(), + rDestPos.getY(), + rDestPos.getX() + static_cast<sal_Int32>(rSourceArea.getWidth()), + rDestPos.getY() + static_cast<sal_Int32>(rSourceArea.getHeight()), + }; + RECT aSourceRect = + { + rSourceArea.getMinX(), + rSourceArea.getMinY(), + rSourceArea.getMaxX(), + rSourceArea.getMaxY() + }; + + if( SUCCEEDED(rOutSurface.Blt( &aOutRect, + &rSourceSurface, + &aSourceRect, + DDBLT_WAIT, + pBltFx )) ) + { + return true; + } + } + + // failed, or forced to use SW copy. attempt manual copy. + bool bResult = false; + + // lock source surface + DDSURFACEDESC aDescSrc; + rtl_fillMemory(&aDescSrc,sizeof(DDSURFACEDESC),0); + aDescSrc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwSrcFlags = DDLOCK_NOSYSLOCK| + DDLOCK_SURFACEMEMORYPTR| + DDLOCK_WAIT| + DDLOCK_READONLY; + if(SUCCEEDED(rSourceSurface.Lock(NULL, + &aDescSrc, + dwSrcFlags, + NULL))) + { + // lock destination surface + DDSURFACEDESC aDescDst; + rtl_fillMemory(&aDescDst,sizeof(DDSURFACEDESC),0); + aDescDst.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwDstFlags = DDLOCK_NOSYSLOCK| + DDLOCK_SURFACEMEMORYPTR| + DDLOCK_WAIT| + DDLOCK_WRITEONLY; + if(SUCCEEDED(rOutSurface.Lock(NULL, + &aDescDst, + dwDstFlags, + NULL))) + { + sal_uInt32 nSrcFormat; + nSrcFormat = ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwRGBAlphaBitMask)<<12; + nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwRBitMask)<<8; + nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwGBitMask)<<4; + nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwBBitMask); + + sal_uInt32 nDstFormat; + nDstFormat = ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwRGBAlphaBitMask)<<12; + nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwRBitMask)<<8; + nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwGBitMask)<<4; + nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwBBitMask); + + // TODO(E1): Use numeric_cast to catch overflow here + const sal_uInt32 nWidth( static_cast<sal_uInt32>( + rSourceArea.getWidth() ) ); + const sal_uInt32 nHeight( static_cast<sal_uInt32>( + rSourceArea.getHeight() ) ); + + if((nSrcFormat == 0x8888) && (nDstFormat == 0x0565)) + { + // medium range 8888 to 0565 pixel format conversion. + bResult = true; + sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface + + rSourceArea.getMinY()*aDescSrc.lPitch + + (rSourceArea.getMinX()<<2); + sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface + + rDestPos.getY()*aDescDst.lPitch + + (rDestPos.getX()<<1); + for(sal_uInt32 y=0; y<nHeight; ++y) + { + sal_uInt32 *pSrcScanline = (sal_uInt32 *)pSrcSurface; + sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface; + for(sal_uInt32 x=0; x<nWidth; ++x) + { + sal_uInt32 srcPixel = *pSrcScanline++; + sal_uInt16 dstPixel; + dstPixel = (sal_uInt16)((srcPixel & 0x0000F8) >> 3); + dstPixel |= (srcPixel & 0x00FC00) >> 5; + dstPixel |= (srcPixel & 0xF80000) >> 8; + *pDstScanline++ = dstPixel; + } + pSrcSurface += aDescSrc.lPitch; + pDstSurface += aDescDst.lPitch; + } + } + else if((nSrcFormat == 0x8888) && (nDstFormat == 0x0888)) + { + // medium range 8888 to 0888 pixel format conversion. + bResult = true; + sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface + + rSourceArea.getMinY()*aDescSrc.lPitch + + (rSourceArea.getMinX()<<2); + sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface + + rDestPos.getY()*aDescDst.lPitch + + (rDestPos.getX()<<2); + for(sal_uInt32 y=0; y<nHeight; ++y) + { + sal_uInt32 *pSrcScanline = (sal_uInt32 *)pSrcSurface; + sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface; + for(sal_uInt32 x=0; x<nWidth; ++x) + { + *pDstScanline++ = (sal_uInt16)*pSrcScanline++; + } + pSrcSurface += aDescSrc.lPitch; + pDstSurface += aDescDst.lPitch; + } + } + else if((nSrcFormat == 0x8888) && (nDstFormat == 0x1555)) + { + // medium range 8888 to 1555 pixel format conversion. + bResult = true; + sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface + + rSourceArea.getMinY()*aDescSrc.lPitch + + (rSourceArea.getMinX()<<2); + sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface + + rDestPos.getY()*aDescDst.lPitch + + (rDestPos.getX()<<1); + for(sal_uInt32 y=0; y<nHeight; ++y) + { + sal_uInt32 *pSrcScanline = (sal_uInt32*)pSrcSurface; + sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface; + for(sal_uInt32 x=0; x<nWidth; ++x) + { + sal_uInt32 srcPixel = *pSrcScanline++; + sal_uInt16 dstPixel; + dstPixel = (sal_uInt16)((srcPixel & 0x000000F8) >> 3); + dstPixel |= (srcPixel & 0x0000F800) >> 6; + dstPixel |= (srcPixel & 0x00F80000) >> 9; + dstPixel |= (srcPixel & 0x80000000) >> 16; + *pDstScanline++ = dstPixel; + } + pSrcSurface += aDescSrc.lPitch; + pDstSurface += aDescDst.lPitch; + } + } + + // unlock destination surface + rOutSurface.Unlock(NULL); + } + + // unlock source surface + rSourceSurface.Unlock(NULL); + } + + return bResult; + } + + void dumpSurface( const COMReference<IDirectDrawSurface> &pSurface, const char *szFilename ) + { + if(!(pSurface.get())) + return; + + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + + if( FAILED(pSurface->Lock( NULL, + &aSurfaceDesc, + DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY, + NULL)) ) + return; + + const std::size_t dwBitmapSize(aSurfaceDesc.dwWidth*aSurfaceDesc.dwHeight*4); + sal_uInt8 *pBuffer = static_cast<sal_uInt8 *>(_alloca(dwBitmapSize)); + if(pBuffer) + { + sal_uInt8 *pSource = reinterpret_cast<sal_uInt8 *>(aSurfaceDesc.lpSurface); + sal_uInt8 *pDest = reinterpret_cast<sal_uInt8 *>(pBuffer); + const std::size_t dwDestPitch(aSurfaceDesc.dwWidth<<2); + pDest += aSurfaceDesc.dwHeight*dwDestPitch; + for(sal_uInt32 y=0; y<aSurfaceDesc.dwHeight; ++y) + { + pDest -= dwDestPitch; + rtl_copyMemory( pDest, pSource, dwDestPitch ); + pSource += aSurfaceDesc.lPitch; + } + + if(FILE *fp = fopen(szFilename,"wb")) + { + BITMAPINFOHEADER bitmapInfo; + + bitmapInfo.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.biWidth = aSurfaceDesc.dwWidth; + bitmapInfo.biHeight = aSurfaceDesc.dwHeight; + bitmapInfo.biPlanes = 1; + bitmapInfo.biBitCount = 32; + bitmapInfo.biCompression = BI_RGB; + bitmapInfo.biSizeImage = 0; + bitmapInfo.biXPelsPerMeter = 0; + bitmapInfo.biYPelsPerMeter = 0; + bitmapInfo.biClrUsed = 0; + bitmapInfo.biClrImportant = 0; + + const std::size_t dwFileSize(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwBitmapSize); + + BITMAPFILEHEADER header; + header.bfType = 'MB'; + header.bfSize = dwFileSize; + header.bfReserved1 = 0; + header.bfReserved2 = 0; + header.bfOffBits = sizeof(BITMAPFILEHEADER) + bitmapInfo.biSize; + + fwrite(&header,1,sizeof(BITMAPFILEHEADER),fp); + fwrite(&bitmapInfo,1,sizeof(BITMAPINFOHEADER),fp); + fwrite(pBuffer,1,dwBitmapSize,fp); + + fclose(fp); + } + } + + pSurface->Unlock(NULL); + } + + void clearSurface( const COMReference<IDirectDrawSurface>& pSurface ) + { + if(!(pSurface.is())) + return; + + DDBLTFX aBltFx; + + rtl_fillMemory( &aBltFx, + sizeof(DDBLTFX), 0 ); + aBltFx.dwSize = sizeof(DDBLTFX); + aBltFx.dwFillColor = 0; + + pSurface->Blt( NULL, + NULL, + NULL, + DDBLT_COLORFILL | DDBLT_WAIT, + &aBltFx ); + } + + // Define struct for MonitorEntry + struct MonitorEntry + { + GUID mnGUID; + HMONITOR mhMonitor; + MONITORINFO maMonitorInfo; + }; + + // define type for MonitorList + typedef ::std::vector< MonitorEntry > MonitorList; + + // Win32 system callback for DirectDrawEnumerateExA call + BOOL WINAPI EnumerateExA_Callback( GUID FAR* lpGUID, + LPSTR /*lpDriverDescription*/, + LPSTR /*lpDriverName*/, + LPVOID lpContext, + HMONITOR hMonitor ) + { + if(lpGUID) + { + MonitorList* pMonitorList = (MonitorList*)lpContext; + MonitorEntry aEntry; + + aEntry.mnGUID = *lpGUID; + aEntry.mhMonitor = hMonitor; + aEntry.maMonitorInfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfo( hMonitor, + &aEntry.maMonitorInfo ); + + pMonitorList->push_back(aEntry); + } + + return DDENUMRET_OK; + } + + void fillMonitorList( MonitorList& rMonitorList ) + { + // Try to fill MonitorList. If neither lib or call to + // DirectDrawEnumerateExA does not exist, it's an old + // DX version (< 5.0), or system does not support + // multiple monitors. + HINSTANCE hInstance = LoadLibrary("ddraw.dll"); + + if(hInstance) + { + LPDIRECTDRAWENUMERATEEX lpDDEnumEx = + (LPDIRECTDRAWENUMERATEEX)GetProcAddress(hInstance,"DirectDrawEnumerateExA"); + + if(lpDDEnumEx) + lpDDEnumEx( (LPDDENUMCALLBACKEXA) EnumerateExA_Callback, + &rMonitorList, + DDENUM_ATTACHEDSECONDARYDEVICES ); + + FreeLibrary(hInstance); + } + } + + IDirectDraw2* createDirectDraw( const MonitorList& rMonitorList, + MONITORINFO& rMonitorInfo, + HWND renderWindow ) + { + GUID* gpSelectedDriverGUID = NULL; + + // if we have multiple monitors, choose a gpSelectedDriverGUID from monitor list + HMONITOR hMonitor = MonitorFromWindow(renderWindow, + MONITOR_DEFAULTTONEAREST); + + MonitorList::const_iterator aCurr = rMonitorList.begin(); + const MonitorList::const_iterator aEnd = rMonitorList.end(); + while( !gpSelectedDriverGUID && aCurr != aEnd ) + { + if(hMonitor == aCurr->mhMonitor) + { + // This is the monitor we are running on + gpSelectedDriverGUID = const_cast<GUID*>(&aCurr->mnGUID); + rMonitorInfo = aCurr->maMonitorInfo; + } + + ++aCurr; + } + + IDirectDraw* pDirectDraw; + if( FAILED( DirectDrawCreate( gpSelectedDriverGUID, &pDirectDraw, NULL ))) + return NULL; + + IDirectDraw2* pDirectDraw2; + if( FAILED( pDirectDraw->QueryInterface( IID_IDirectDraw2, (LPVOID*)&pDirectDraw2 ))) + return NULL; + + // queryInterface bumped up the refcount, so release the + // reference to the original IDirectDraw interface. + pDirectDraw->Release(); + + return pDirectDraw2; + } + + HRESULT WINAPI EnumTextureFormatsCallback( LPDDSURFACEDESC pSurfaceDesc, + LPVOID pContext ) + { + // dirty cast of given context back to result ModeSelectContext + DDPIXELFORMAT* pResult = (DDPIXELFORMAT*)pContext; + + if( pResult == NULL || pSurfaceDesc == NULL ) + return DDENUMRET_CANCEL; + + VERBOSE_TRACE( "EnumTextureFormatsCallback: advertised texture format has dwRGBBitCount %d, dwRBitMask %x, " + "dwGBitMask %x, dwBBitMask %x and dwRGBAlphaBitMask %x. The format uses %s alpha.", + pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount, + pSurfaceDesc->ddpfPixelFormat.dwRBitMask, + pSurfaceDesc->ddpfPixelFormat.dwGBitMask, + pSurfaceDesc->ddpfPixelFormat.dwBBitMask, + pSurfaceDesc->ddpfPixelFormat.dwRGBAlphaBitMask, + pSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPREMULT ? "premultiplied" : "non-premultiplied" ); + + // Only accept RGB surfaces with alpha channel + if( (DDPF_ALPHAPIXELS | DDPF_RGB) == + (pSurfaceDesc->ddpfPixelFormat.dwFlags & (DDPF_ALPHAPIXELS | DDPF_RGB)) ) + { + // ignore formats with the DDPF_ALPHAPREMULT flag + if(!(pSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPREMULT)) + { + // take widest alpha channel available + if( pSurfaceDesc->ddpfPixelFormat.dwAlphaBitDepth > pResult->dwAlphaBitDepth ) + { + // take new format + rtl_copyMemory( pResult, &pSurfaceDesc->ddpfPixelFormat, sizeof(DDPIXELFORMAT) ); + } + else if( pSurfaceDesc->ddpfPixelFormat.dwAlphaBitDepth == pResult->dwAlphaBitDepth ) + { + // tie-breaking: take highest bitcount + if( pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount > pResult->dwRGBBitCount ) + { + // take new format + rtl_copyMemory( pResult, &pSurfaceDesc->ddpfPixelFormat, sizeof(DDPIXELFORMAT) ); + } + } + } + } + + return DDENUMRET_OK; + } + + class DXRenderModule; + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + /** ISurface implemenation. + + @attention holds the DXRenderModule via non-refcounted + reference! This is safe with current state of affairs, since + the canvas::PageManager holds surface and render module via + shared_ptr (and makes sure all surfaces are deleted before its + render module member goes out of scope). + */ + class DXSurface : public canvas::ISurface + { + public: + DXSurface( DXRenderModule& rRenderModule, + const ::basegfx::B2ISize& rSize ); + ~DXSurface(); + + virtual bool selectTexture(); + virtual bool isValid(); + virtual bool update( const ::basegfx::B2IPoint& rDestPos, + const ::basegfx::B2IRange& rSourceRect, + ::canvas::IColorBuffer& rSource ); + virtual ::basegfx::B2IVector getSize(); + + private: + /// Guard local methods against concurrent acces to RenderModule + class ImplRenderModuleGuard : private ::boost::noncopyable + { + public: + explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule ); + inline ~ImplRenderModuleGuard(); + + private: + DXRenderModule& mrRenderModule; + }; + + DXRenderModule& mrRenderModule; + + COMReference<IDirectDrawSurface> mpSurface; + COMReference<IDirect3DTexture2> mpTexture; + + ::basegfx::B2IVector maSize; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + /// Default implementation of IDXRenderModule + class DXRenderModule : public IDXRenderModule + { + public: + explicit DXRenderModule( const ::Window& rWindow ); + + virtual void lock() const { maMutex.acquire(); } + virtual void unlock() const { maMutex.release(); } + + virtual COMReference<IDirectDrawSurface> + createSystemMemorySurface( const ::basegfx::B2IVector& rSize ); + + virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& rCurrWindowArea ); + + virtual void resize( const ::basegfx::B2IRange& rect ); + virtual HWND getHWND() const { return mhWnd; } + virtual void disposing(); + virtual void screenShot(); + virtual ::basegfx::B2IVector getPageSize(); + virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize ); + virtual void beginPrimitive( PrimitiveType eType ); + virtual void endPrimitive(); + virtual void pushVertex( const ::canvas::Vertex& vertex ); + virtual bool isError(); + + const D3DDEVICEDESC& getDeviceDesc() const { return maDeviceDesc; } + const DDPIXELFORMAT& getTextureFormat() const { return maTextureFormat; } + COMReference<IDirectDraw2> getDirectDraw() { return mpDirectDraw; } + COMReference< IDirect3DDevice2 > getDevice() { return mpDirect3DDevice; } + + void flushVertexCache(); + + struct ModeSelectContext + { + DDSURFACEDESC selectedDesc; + ::basegfx::B2ISize requestedSize; + }; + + /** Query actual size of the device + + This is especially interesting for fullscreen devices + */ + ::basegfx::B2ISize getFramebufferSize() const; + + /** Query the amount of memory available for new surfaces + + This might differ from getAvailableTextureMem() + @see getAvailableTextureMem() + + @param bWithAGPMema + When true, returned value includes non-local, + i.e. AGP-able memory, too. + + @return the amount of free surface mem + */ + std::size_t getAvailableSurfaceMem( bool bWithAGPMem=true ) const; + + /** Query the amount of memory available for new textures + + This might differ from getAvailableSurfaceMem() + @see getAvailableSurfaceMem() + + @param bWithAGPMema + When true, returned value includes non-local, + i.e. AGP-able memory, too. + + @return the amount of free texture mem + */ + std::size_t getAvailableTextureMem( bool bWithAGPMem=true ) const; + + private: + bool queryCaps(); + bool validateCaps(); + bool setup3DDevice(); + unsigned int getDisplayFormat() const; + + void convert2Screen( ::basegfx::B2IPoint& io_rDestPos, + ::basegfx::B2IRange& io_rDestArea ); + + void renderInfoText( const ::rtl::OUString& rStr, + const Gdiplus::PointF& rPos ) const; + void renderFPSCounter() const; + void renderMemAvailable() const; + + bool create( const ::Window& rWindow ); + bool validateMainSurfaces(); + + /** This object represents the DirectX state machine. In order + to serialize access to DirectX's global state, a global + mutex is required. + */ + static ::osl::Mutex maMutex; + + HWND mhWnd; + ::boost::scoped_ptr<SystemChildWindow> mpWindow; + ::basegfx::B2IVector maSize; + + ModeSelectContext maSelectedFullscreenMode; + DDPIXELFORMAT maTextureFormat; + + MONITORINFO maMonitorInfo; // monitor info for mpDirectDraw's monitor + COMReference<IDirectDraw2> mpDirectDraw; + COMReference<IDirectDrawSurface> mpPrimarySurface; + COMReference<IDirectDrawSurface> mpBackBufferSurface; + + COMReference< IDirect3D2 > mpDirect3D; + COMReference< IDirect3DDevice2 > mpDirect3DDevice; + + mutable ::canvas::tools::ElapsedTime maLastUpdate; // for the frame counter + + D3DDEVICEDESC maDeviceDesc; + + typedef std::vector<canvas::Vertex> vertexCache_t; + vertexCache_t maVertexCache; + std::size_t mnCount; + + int mnBeginSceneCount; + + const bool mbPageFlipping; + bool mbHasNoTearingBlt; + bool mbError; + PrimitiveType meType; + + ::canvas::ISurfaceSharedPtr mpTexture; + ::basegfx::B2IVector maPageSize; + }; + + ::osl::Mutex DXRenderModule::maMutex; + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::ImplRenderModuleGuard + ////////////////////////////////////////////////////////////////////////////////// + + inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard( + DXRenderModule& rRenderModule ) : + mrRenderModule( rRenderModule ) + { + mrRenderModule.lock(); + } + + inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard() + { + mrRenderModule.unlock(); + } + +#ifdef FAKE_MAX_NUMBER_TEXTURES + static sal_uInt32 gNumSurfaces = 0; +#endif + + void fillRect( sal_uInt32 *pDest, + sal_uInt32 dwWidth, + sal_uInt32 dwHeight, + sal_uInt32 dwPitch, + sal_uInt32 dwColor ) + { + for(sal_uInt32 i=0; i<dwWidth; ++i) + { + pDest[i]=dwColor; + pDest[((dwHeight-1)*dwPitch)+i]=dwColor; + } + + for(sal_uInt32 j=0; j<dwHeight; ++j) + { + pDest[0]=dwColor; + pDest[dwWidth-1]=dwColor; + pDest += dwPitch; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + DXSurface::DXSurface( DXRenderModule& rRenderModule, + const ::basegfx::B2ISize& rSize ) : + mrRenderModule(rRenderModule), + mpTexture(NULL), + mpSurface(NULL), + maSize() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + +#ifdef FAKE_MAX_NUMBER_TEXTURES + ++gNumSurfaces; + if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES) + return; +#endif + +#ifdef FAKE_MAX_TEXTURE_SIZE + if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE) + return; + if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE) + return; +#endif + + ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0, + "DXSurface::DXSurface(): request for zero-sized surface"); + + const D3DDEVICEDESC &deviceDesc = rRenderModule.getDeviceDesc(); + + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + aSurfaceDesc.dwWidth = ::std::min(deviceDesc.dwMaxTextureWidth,::canvas::tools::nextPow2(rSize.getX())); + aSurfaceDesc.dwHeight = ::std::min(deviceDesc.dwMaxTextureHeight,::canvas::tools::nextPow2(rSize.getY())); + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | + DDSCAPS_VIDEOMEMORY | + DDSCAPS_LOCALVIDMEM; + rtl_copyMemory(&aSurfaceDesc.ddpfPixelFormat,&rRenderModule.getTextureFormat(),sizeof(DDPIXELFORMAT)); + + IDirectDrawSurface *pSurface; + COMReference<IDirectDraw2> pDirectDraw(rRenderModule.getDirectDraw()); + HRESULT hr = pDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + if(FAILED(hr)) + { + // if the call failed due to 'out of videomemory', + // retry with request for AGP memory. + if(DDERR_OUTOFVIDEOMEMORY == hr) + { + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | + DDSCAPS_VIDEOMEMORY | + DDSCAPS_NONLOCALVIDMEM; + hr = pDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + } + } + + if(SUCCEEDED(hr)) + { + IDirect3DTexture2* pTexture; + if( FAILED(pSurface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&pTexture)) ) + { + pSurface->Release(); + return; + } + + maSize.setX(aSurfaceDesc.dwWidth); + maSize.setY(aSurfaceDesc.dwHeight); + + mpSurface=COMReference<IDirectDrawSurface>(pSurface); + mpTexture=COMReference<IDirect3DTexture2>(pTexture); + + // #122683# Clear texture, to avoid ugly artifacts at the + // border to invisible sprite areas (note that the textures + // are usually only partly utilized). + clearSurface( mpSurface ); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::~DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + DXSurface::~DXSurface() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + +#ifdef FAKE_MAX_NUMBER_TEXTURES + gNumSurfaces--; +#endif + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::selectTexture + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::selectTexture() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + mrRenderModule.flushVertexCache(); + + D3DTEXTUREHANDLE aTextureHandle; + if(FAILED(mpTexture->GetHandle( + mrRenderModule.getDevice().get(), + &aTextureHandle))) + { + return false; + } + + // select texture for next primitive + if(FAILED(mrRenderModule.getDevice()->SetRenderState( + D3DRENDERSTATE_TEXTUREHANDLE,aTextureHandle))) + { + return false; + } + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 + if( mpSurface.is() ) + { + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + + if( SUCCEEDED(mpSurface->Lock( NULL, + &aSurfaceDesc, + DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY, + NULL)) ) + { + imdebug( "rgba w=%d h=%d %p", + aSurfaceDesc.dwWidth, + aSurfaceDesc.dwHeight, + aSurfaceDesc.lpSurface ); + + mpSurface->Unlock(NULL); + } + } +# endif +#endif + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::isValid + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::isValid() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + if(!(mpSurface.is())) + return false; + + if(mpSurface->IsLost() == DDERR_SURFACELOST) + { + mpSurface->Restore(); + return false; + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::update + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos, + const ::basegfx::B2IRange& rSourceRect, + ::canvas::IColorBuffer& rSource ) + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + // can't update if surface is not valid, that means + // either not existent nor restored... + if(!(isValid())) + return false; + + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + + // TODO(P2): only lock the region we want to update + if( FAILED(mpSurface->Lock( NULL, + &aSurfaceDesc, + DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY, + NULL)) ) + return false; + + if(sal_uInt8* pImage = rSource.lock()) + { + switch( rSource.getFormat() ) + { + case ::canvas::IColorBuffer::FMT_A8R8G8B8: + { + const std::size_t nSourceBytesPerPixel(4); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+ + (rDestPos.getY()*aSurfaceDesc.lPitch) + + (4*rDestPos.getX())); + + const sal_uInt32 nNumBytesToCopy( + static_cast<sal_uInt32>( + rSourceRect.getWidth())* + nSourceBytesPerPixel); + const sal_uInt64 nNumLines(rSourceRect.getHeight()); + + for(sal_uInt32 i=0; i<nNumLines; ++i) + { + rtl_copyMemory(pDst,pImage,nNumBytesToCopy); + + pDst += aSurfaceDesc.lPitch; + pImage += nSourcePitchInBytes; + } + } + break; + + case ::canvas::IColorBuffer::FMT_R8G8B8: + { + const std::size_t nSourceBytesPerPixel(3); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+ + (rDestPos.getY()*aSurfaceDesc.lPitch) + + (4*rDestPos.getX())); + + const sal_uInt64 nNumColumns(rSourceRect.getWidth()); + const sal_uInt64 nNumLines(rSourceRect.getHeight()); + for(sal_uInt32 i=0; i<nNumLines; ++i) + { + sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst); + sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage); + for(sal_uInt32 x=0; x<nNumColumns; ++x) + { + sal_uInt32 color(0xFF000000); + color |= pSrcScanline[2]<<16; + color |= pSrcScanline[1]<<8; + color |= pSrcScanline[0]; + pSrcScanline += 3; + *pDstScanline++ = color; + } + + pDst += aSurfaceDesc.lPitch; + pImage += nSourcePitchInBytes; + } + } + break; + + case ::canvas::IColorBuffer::FMT_X8R8G8B8: + { + const std::size_t nSourceBytesPerPixel(4); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+ + (rDestPos.getY()*aSurfaceDesc.lPitch) + + (4*rDestPos.getX())); + + const sal_uInt64 nNumLines(rSourceRect.getHeight()); + + for(sal_uInt32 i=0; i<nNumLines; ++i) + { + sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage); + sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst); + for(sal_uInt32 j=0; j<rSourceRect.getWidth(); ++j) + pDst32[j] = 0xFF000000 | pSrc32[j]; + + pDst += aSurfaceDesc.lPitch; + pImage += nSourcePitchInBytes; + } + } + break; + + default: + ENSURE_OR_RETURN_FALSE(false, + "DXSurface::update(): Unknown/unimplemented buffer format" ); + break; + } + + rSource.unlock(); + } + + return SUCCEEDED(mpSurface->Unlock(NULL)); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::getSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXSurface::getSize() + { + return maSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + DXRenderModule::DXRenderModule( const ::Window& rWindow ) : + mhWnd(0), + mpWindow(), + maSize(), + maSelectedFullscreenMode(), + maTextureFormat(), + maMonitorInfo(), + mpDirectDraw(), + mpPrimarySurface(), + mpBackBufferSurface(), + mpDirect3D(), + mpDirect3DDevice(), + maLastUpdate(), + maDeviceDesc(), + maVertexCache(), + mnCount(0), + mnBeginSceneCount(0), + mbPageFlipping( false ), + mbHasNoTearingBlt( false ), + mbError( false ), + meType( PRIMITIVE_TYPE_UNKNOWN ), + mpTexture(), + maPageSize() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(!(create(rWindow))) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device!") ),NULL); + } + + // allocate a single texture surface which can be used later. + // we also use this to calibrate the page size. + ::basegfx::B2IVector aPageSize( + ::std::min( + static_cast<sal_uInt32>(maDeviceDesc.dwMaxTextureWidth), + static_cast<sal_uInt32>(MAX_TEXTURE_SIZE)), + ::std::min( + static_cast<sal_uInt32>(maDeviceDesc.dwMaxTextureHeight), + static_cast<sal_uInt32>(MAX_TEXTURE_SIZE))); + while(true) + { + mpTexture = ::canvas::ISurfaceSharedPtr( + new DXSurface(*this,aPageSize)); + if(mpTexture->isValid()) + break; + + aPageSize.setX(aPageSize.getX()>>1); + aPageSize.setY(aPageSize.getY()>>1); + if((aPageSize.getX() < MIN_TEXTURE_SIZE) || + (aPageSize.getY() < MIN_TEXTURE_SIZE)) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device!") ),NULL); + } + } + maPageSize=aPageSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::create + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::create( const ::Window& rWindow ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + maVertexCache.reserve(1024); + + mpWindow.reset( + new SystemChildWindow( + const_cast<Window *>(&rWindow), 0) ); + + // system child window must not receive mouse events + mpWindow->SetMouseTransparent( TRUE ); + + // parent should receive paint messages as well + // [PARENTCLIPMODE_NOCLIP], the argument is here + // passed as plain numeric value since the stupid + // define utilizes a USHORT cast. + mpWindow->SetParentClipMode(0x0002); + + // the system child window must not clear its background + mpWindow->EnableEraseBackground( FALSE ); + + mpWindow->SetControlForeground(); + mpWindow->SetControlBackground(); + mpWindow->EnablePaint(FALSE); + + const SystemEnvData *pData = mpWindow->GetSystemData(); + const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd)); + mhWnd = const_cast<HWND>(hwnd); + + ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ), + "DXRenderModuleDXRenderModuleWin32() No valid HWND given." ); + + // retrieve position and size of the parent window + const ::Size &rSizePixel(rWindow.GetSizePixel()); + + // remember the size of the parent window, since we + // need to use this for our child window. + maSize.setX(static_cast<sal_Int32>(rSizePixel.Width())); + maSize.setY(static_cast<sal_Int32>(rSizePixel.Height())); + + // let the child window cover the same size as the parent window. + mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY()); + + MonitorList aMonitorList; + fillMonitorList( aMonitorList ); + + mpDirectDraw = COMReference<IDirectDraw2>( + createDirectDraw(aMonitorList, maMonitorInfo, mhWnd)); + + if(!mpDirectDraw.is()) + return false; + + if( !queryCaps() ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): GetCaps failed" ); + mpDirectDraw.reset(); + return false; + } + + if( !validateCaps() ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): Insufficient DirectX capabilities, failed" ); + mpDirectDraw.reset(); + return false; + } + + if( FAILED( mpDirectDraw->SetCooperativeLevel( mhWnd, + DDSCL_NORMAL|DDSCL_MULTITHREADED|DDSCL_FPUPRESERVE ) ) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): SetCooperativeLevel failed" ); + mpDirectDraw.reset(); + return false; + } + + // setup query struct + rtl_fillMemory( &maSelectedFullscreenMode.selectedDesc, + sizeof(DDSURFACEDESC), 0 ); + maSelectedFullscreenMode.selectedDesc.dwSize = sizeof(DDSURFACEDESC); + + // read current display mode, e.g. for screen dimension + if( FAILED( mpDirectDraw->GetDisplayMode( &maSelectedFullscreenMode.selectedDesc )) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): GetDisplayMode failed" ); + mpDirectDraw.reset(); + return false; + } + + // check for supported primary surface formats... + unsigned int nDisplayFormat = getDisplayFormat() & 0x00000FFF; + if(nDisplayFormat != 0x888 && nDisplayFormat != 0x565) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): Unsupported DisplayFormat" ); + mpDirectDraw.reset(); + return false; + } + + // create primary surface reference + DDSURFACEDESC aSurfaceDesc; + IDirectDrawSurface* pPrimarySurface; + + rtl_fillMemory( &aSurfaceDesc, + sizeof(DDSURFACEDESC), 0 ); + aSurfaceDesc.dwSize = sizeof(aSurfaceDesc); + aSurfaceDesc.dwFlags = DDSD_CAPS; + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + + if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pPrimarySurface, NULL)) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): CreateSurface failed" ); + mpDirectDraw.reset(); + return false; + } + + mpPrimarySurface = COMReference< IDirectDrawSurface >(pPrimarySurface); + + // create a Clipper and associate it with the primary surface + // and the render window + LPDIRECTDRAWCLIPPER pClipper; + if( FAILED(mpDirectDraw->CreateClipper( 0, &pClipper, NULL )) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): CreateClipper failed" ); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + if( FAILED(pClipper->SetHWnd(0, mhWnd)) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): Clipper->SetHWnd failed" ); + pClipper->Release(); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + if( FAILED(mpPrimarySurface->SetClipper( pClipper )) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): SetClipper failed" ); + pClipper->Release(); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + + // clipper is now owned by mpPrimarySurface, release our reference + pClipper->Release(); + + // TODO(F3): Check whether palette needs any setup here + + // get us a backbuffer for simulated flipping + IDirectDrawSurface* pSurface; + + // Strictly speaking, we don't need a full screen worth of + // backbuffer here. We could also scale dynamically with + // the current window size, but this will make it + // necessary to temporarily have two buffers while copying + // from the old to the new one. What's more, at the time + // we need a larger buffer, DX might not have sufficient + // resources available, and we're then left with too small + // a back buffer, and no way of falling back to a + // different canvas implementation. + const ::basegfx::B2ISize aSize( getFramebufferSize() ); + + rtl_fillMemory( &aSurfaceDesc, + sizeof(DDSURFACEDESC), 0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + aSurfaceDesc.dwHeight= aSize.getY(); + aSurfaceDesc.dwWidth = aSize.getX(); + + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + + HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + + if( FAILED( nRes ) ) + { + if( nRes == DDERR_OUTOFVIDEOMEMORY ) + { + // local vid mem failed. Maybe AGP mem works? + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM; + if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL)) ) + { + // no chance, go defunct, and exit + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" ); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" ); + } + else + { + // no chance, go defunct, and exit + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" ); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + } + + VERBOSE_TRACE( "Device::Device(): created backbuffer of size %d times %d pixel", + aSurfaceDesc.dwWidth, + aSurfaceDesc.dwHeight ); + + mpBackBufferSurface = COMReference< IDirectDrawSurface >(pSurface); + clearSurface(mpBackBufferSurface); + + if( !setup3DDevice() ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::Device(): setup3DDevice failed" ); + mpBackBufferSurface.reset(); + mpPrimarySurface.reset(); + mpDirectDraw.reset(); + return false; + } + + mpWindow->Show(); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2ISize DXRenderModule::getFramebufferSize() const + { + return mpDirectDraw.is() ? + ::basegfx::B2ISize( maSelectedFullscreenMode.selectedDesc.dwWidth, + maSelectedFullscreenMode.selectedDesc.dwHeight ) : + ::basegfx::B2ISize(); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::setup3DDevice + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::setup3DDevice() + { + // create and setup 3D device + // ========================== + LPDIRECT3D2 pDirect3D; + if( FAILED( mpDirectDraw->QueryInterface( IID_IDirect3D2, (LPVOID*)&pDirect3D ) ) ) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::setup3DDevice(): QueryInterface() for Direct3D failed" ); + return false; + } + + mpDirect3D = COMReference< IDirect3D2 >(pDirect3D); + + LPDIRECT3DDEVICE2 pDirect3DDevice; + // try HW-accelerated device first + if( FAILED(mpDirect3D->CreateDevice( IID_IDirect3DHALDevice, + mpBackBufferSurface.get(), + &pDirect3DDevice )) ) + { + // no HW 3D support - go defunct, and exit + VERBOSE_TRACE( "Device::setup3DDevice(): CreateDevice() for HW Direct3D rendering failed" ); + mpDirect3D.reset(); + return false; + } + + D3DDEVICEDESC aHELDeviceDesc; + rtl_fillMemory(&maDeviceDesc,sizeof(maDeviceDesc),0); + rtl_fillMemory(&aHELDeviceDesc,sizeof(aHELDeviceDesc),0); + maDeviceDesc.dwSize = sizeof(maDeviceDesc); + aHELDeviceDesc.dwSize = sizeof(aHELDeviceDesc); + if(FAILED(pDirect3DDevice->GetCaps(&maDeviceDesc,&aHELDeviceDesc))) + { + // go defunct, and exit + VERBOSE_TRACE( "Device::setup3DDevice(): GetCaps() for Direct3DDevice failed" ); + mpDirect3D.reset(); + return false; + } + + mpDirect3DDevice = COMReference< IDirect3DDevice2 >(pDirect3DDevice); + + // select appropriate texture format (_need_ alpha channel here) + rtl_fillMemory( &maTextureFormat, + sizeof(DDPIXELFORMAT), 0 ); + maTextureFormat.dwSize = sizeof(DDPIXELFORMAT); + if( SUCCEEDED(mpDirect3DDevice->EnumTextureFormats( EnumTextureFormatsCallback, &maTextureFormat )) ) + { + bool bSupportedFormat = true; + if((maTextureFormat.dwFlags & (DDPF_ALPHAPIXELS | DDPF_RGB)) != (DDPF_ALPHAPIXELS | DDPF_RGB)) + bSupportedFormat = false; + else if(maTextureFormat.dwRGBAlphaBitMask != 0xFF000000) + bSupportedFormat = false; + else if(maTextureFormat.dwRBitMask != 0x00FF0000) + bSupportedFormat = false; + else if(maTextureFormat.dwGBitMask != 0x0000FF00) + bSupportedFormat = false; + else if(maTextureFormat.dwBBitMask != 0x000000FF) + bSupportedFormat = false; + + if(bSupportedFormat) + { + VERBOSE_TRACE( "Device::setup3DDevice(): chose texture format dwRGBBitCount %d, dwRBitMask %x, " + "dwGBitMask %x, dwBBitMask %x and dwRGBAlphaBitMask %x. The texture uses %s alpha.", + maTextureFormat.dwRGBBitCount, + maTextureFormat.dwRBitMask, + maTextureFormat.dwGBitMask, + maTextureFormat.dwBBitMask, + maTextureFormat.dwRGBAlphaBitMask, + maTextureFormat.dwFlags & DDPF_ALPHAPREMULT ? "premultiplied" : "non-premultiplied" ); + + // setup the device (with as much as we can possibly do here) + // ========================================================== + + LPDIRECT3DVIEWPORT2 pViewport; + + if( SUCCEEDED(mpDirect3D->CreateViewport( &pViewport, NULL )) ) + { + if( SUCCEEDED(mpDirect3DDevice->AddViewport( pViewport )) ) + { + // setup viewport (to whole backbuffer) + D3DVIEWPORT2 aViewport; + + aViewport.dwSize = sizeof(D3DVIEWPORT2); + aViewport.dwX = 0; + aViewport.dwY = 0; + aViewport.dwWidth = maSelectedFullscreenMode.selectedDesc.dwWidth; + aViewport.dwHeight = maSelectedFullscreenMode.selectedDesc.dwHeight; + aViewport.dvClipX = -1.0; + aViewport.dvClipY = -1.0; + aViewport.dvClipWidth = 2.0; + aViewport.dvClipHeight = 2.0; + aViewport.dvMinZ = 0.0; + aViewport.dvMaxZ = 1.0; + + if( SUCCEEDED(pViewport->SetViewport2( &aViewport )) ) + { + if( SUCCEEDED(mpDirect3DDevice->SetCurrentViewport( pViewport )) ) + { + // Viewport was handed over to 3DDevice, thus we can release now + pViewport->Release(); + + // currently, no need for any + // matrix or light source + // setup, since we only render + // transformed&lighted + // vertices + + // done; successfully + return true; + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): SetCurrentViewport failed" ); + } + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): SetViewport2 failed" ); + } + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): AddViewport failed" ); + } + + pViewport->Release(); + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): CreateViewport failed" ); + } + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): No supported pixelformat" ); + } + } + else + { + VERBOSE_TRACE( "Device::setup3DDevice(): EnumTextureFormats failed" ); + } + + // go defunct, and exit + mpDirect3DDevice.reset(); + mpDirect3D.reset(); + + return false; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::queryCaps + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::queryCaps() + { + DDCAPS aHWCaps; + DDCAPS aHELCaps; + + rtl_fillMemory( &aHWCaps, + sizeof(aHWCaps), 0 ); + rtl_fillMemory( &aHELCaps, + sizeof(aHELCaps), 0 ); + aHWCaps.dwSize = sizeof( aHWCaps ); + aHELCaps.dwSize = sizeof( aHELCaps ); + + if( FAILED( mpDirectDraw->GetCaps( &aHWCaps, + &aHELCaps ) ) ) + { + return false; + } + + mbHasNoTearingBlt = aHWCaps.dwFXCaps & DDBLTFX_NOTEARING; + + VERBOSE_TRACE( "dxcanvas initialization: %d bytes VRAM free for surfaces (%d with AGP mem), " + "%d bytes VRAM free for textures (%d with AGP mem)", + getAvailableSurfaceMem( false ), + getAvailableSurfaceMem( true ), + getAvailableTextureMem( false ), + getAvailableTextureMem( true ) ); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::validateCaps + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::validateCaps() + { + // TODO(E3): Validate HW capabilities. Depending on primary + // surface size, reject HW e.g. on the grounds of insufficient + // VRAM. + + // setup query struct + DDSURFACEDESC desc; + rtl_fillMemory(&desc,sizeof(DDSURFACEDESC),0); + desc.dwSize = sizeof(DDSURFACEDESC); + + // read current display mode, e.g. for screen dimension + if(FAILED( mpDirectDraw->GetDisplayMode(&desc))) + return false; + + // simple heuristic: we need at least 3 times the desktop + // resolution based on ARGB color values... + std::size_t nMinimumVRAMSize = ((desc.dwWidth*desc.dwHeight)<<2)*3; + if(getAvailableSurfaceMem() < nMinimumVRAMSize) + return false; + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getDisplayFormat + ////////////////////////////////////////////////////////////////////////////////// + + unsigned int DXRenderModule::getDisplayFormat() const + { + unsigned int nFormat; + nFormat = ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwRGBAlphaBitMask)<<12; + nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwRBitMask)<<8; + nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwGBitMask)<<4; + nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwBBitMask); + return nFormat; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getAvailableSurfaceMem + ////////////////////////////////////////////////////////////////////////////////// + + std::size_t DXRenderModule::getAvailableSurfaceMem( bool bWithAGPMem ) const + { + if( !mpDirectDraw.is() ) + return 0; + + std::size_t nRes( 0 ); + + DDSCAPS aSurfaceCaps; + DWORD nTotal, nFree; + + // real VRAM (const_cast, since GetAvailableVidMem is non-const) + aSurfaceCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) ) + return 0; + + nRes += nFree; + + if( bWithAGPMem ) + { + // AGP RAM (const_cast, since GetAvailableVidMem is non-const) + aSurfaceCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM; + if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) ) + return 0; + + nRes += nFree; + } + + return nRes; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getAvailableTextureMem + ////////////////////////////////////////////////////////////////////////////////// + + std::size_t DXRenderModule::getAvailableTextureMem( bool bWithAGPMem ) const + { + if( !mpDirectDraw.is() ) + return 0; + + std::size_t nRes( 0 ); + + DDSCAPS aSurfaceCaps; + DWORD nTotal, nFree; + + // TODO(F1): Check if flags are applicable + + // real VRAM (const_cast, since GetAvailableVidMem is non-const) + aSurfaceCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) ) + return 0; + + nRes += nFree; + + if( bWithAGPMem ) + { + // AGP RAM (const_cast, since GetAvailableVidMem is non-const) + aSurfaceCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM; + if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) ) + return 0; + + nRes += nFree; + } + + // TODO(F1): Add pool mem + + return nRes; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::convert2Screen + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::convert2Screen( ::basegfx::B2IPoint& io_rDestPos, + ::basegfx::B2IRange& io_rDestArea ) + { + POINT aPoint = { 0, 0 }; + ClientToScreen( mhWnd, &aPoint ); + + // i52230 make sure given screen coordinate is relative to + // this monitor's area (the device rendering is always + // contained to a single monitor) + aPoint.x -= maMonitorInfo.rcMonitor.left; + aPoint.y -= maMonitorInfo.rcMonitor.top; + + io_rDestPos.setX( io_rDestPos.getX() + aPoint.x ); + io_rDestPos.setY( io_rDestPos.getY() + aPoint.y ); + + const ::basegfx::B2ISize& rSize( getFramebufferSize() ); + + // calc output bounds (clip against framebuffer bounds) + io_rDestArea = ::basegfx::B2IRange( + ::std::max( sal_Int32(0), + ::std::min( sal_Int32(rSize.getX()), + sal_Int32(io_rDestArea.getMinX() + aPoint.x) ) ), + ::std::max( sal_Int32(0), + ::std::min( sal_Int32(rSize.getY()), + sal_Int32(io_rDestArea.getMinY() + aPoint.y) ) ), + ::std::max( sal_Int32(0), + ::std::min( sal_Int32(rSize.getX()), + sal_Int32(io_rDestArea.getMaxX() + aPoint.x) ) ), + ::std::max( sal_Int32(0), + ::std::min( sal_Int32(rSize.getY()), + sal_Int32(io_rDestArea.getMaxY() + aPoint.y) ) ) ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::createSystemMemorySurface + ////////////////////////////////////////////////////////////////////////////////// + + COMReference<IDirectDrawSurface> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize ) + { + DDSURFACEDESC aSurfaceDesc; + IDirectDrawSurface* pSurface; + + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;; + aSurfaceDesc.dwWidth = rSize.getX(); + aSurfaceDesc.dwHeight= rSize.getY(); + + rtl_copyMemory( &aSurfaceDesc.ddpfPixelFormat, &maTextureFormat, sizeof(DDPIXELFORMAT) ); + + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + + HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + if(FAILED(nRes)) + return COMReference<IDirectDrawSurface>(NULL); + + return COMReference<IDirectDrawSurface>(pSurface); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::flip + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& rCurrWindowArea ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + // see if the main surfaces got lost. if so, try to + // restore them. bail out if this operation fails. + if(!(validateMainSurfaces())) + return false; + + flushVertexCache(); + + ENSURE_OR_THROW( !mnBeginSceneCount, + "Device::flip(): within 3D scene" ); + + // TODO(E3): handle DX errors more thoroughly. For fullscreen + // exclusive mode, actually even our primary surface can get + // lost and needs restore! + + if( mpDirectDraw.is() && + mpPrimarySurface.is() && + mpBackBufferSurface.is() ) + { + // ignore area and offset for page flipping device + if( mbPageFlipping ) + { +#if defined(VERBOSE) && defined(DBG_UTIL) + renderFPSCounter(); + renderMemAvailable(); +#endif + VERBOSE_TRACE( "Device::flip(): Using true page flipping" ); + + // use true page flipping. Hopefully, the 3D hardware + // is flushed on this flip call (rumours have it that + // way), otherwise, perform the Lock hack as for the + // Blt below. + if( SUCCEEDED(mpPrimarySurface->Flip( NULL, DDFLIP_WAIT )) ) + return true; + } + else + { + VERBOSE_TRACE( "Device::flip(): Using blt for page flipping" ); + + // determine actual window position + ::basegfx::B2IPoint aDestPoint( rUpdateArea.getMinimum() ); + ::basegfx::B2IRange aSourceArea( rUpdateArea ); + ::basegfx::B2IRange aDestArea( 0,0, + static_cast<sal_Int32>(rCurrWindowArea.getWidth()), + static_cast<sal_Int32>(rCurrWindowArea.getHeight()) ); + convert2Screen( aDestPoint, aDestArea ); + + // perform clipping + if( !::canvas::tools::clipBlit( aSourceArea, + aDestPoint, + rUpdateArea, + aDestArea ) ) + return true; // fully clipped, but still, in a way, + // successful. + + // TODO(P1): Rumours have it that the 3D hardware + // _might_ still be rendering with flaky drivers, + // which don't flush properly on Blt(). It was said, + // that 'usually', it works to lock the 3D render + // target (the backbuffer in this case). OTOH, I've + // found that this tends to degrade performance + // significantly on complying cards... + + // TODO(P1): Up until rev. 1.3, this method contained + // code to make sure the blit will start _immediately_ + // after the Blt call. If this is not warranted, wait + // for the next vsync. As this case was found to be + // extremely seldom, kicked out (what's more, there's + // simply no guarantee that the blitter will be + // available at any point in the code - Windows still + // is a preemptive multi-processing environment. And + // _if_ we're competing with someone over the blitter, + // we will do so the next VBLANK interval, and the + // following...) + + // screen update seems to be smoother when waiting + // for vblank in every case - even when blitter + // supports the DDBLTFX_NOTEARING flag. + if( FAILED(mpDirectDraw->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, + NULL)) ) + return false; + + DDBLTFX aBltFx; + DDBLTFX* pBltFX = NULL; + if( mbHasNoTearingBlt ) + { + // Blt can internally schedule for no-tearing + // =========================================== + + rtl_fillMemory( &aBltFx, + sizeof(aBltFx), 0 ); + aBltFx.dwSize = sizeof(aBltFx); + aBltFx.dwDDFX = DDBLTFX_NOTEARING; + + pBltFX = &aBltFx; + } + + if( doBlit( aDestPoint, + *mpPrimarySurface, + aSourceArea, + *mpBackBufferSurface, + pBltFX,false ) ) + { +#if defined(VERBOSE) && defined(DBG_UTIL) + renderFPSCounter(); + renderMemAvailable(); +#endif + return true; + } + } + } + return false; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::disposing + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::disposing() + { + if(!(mhWnd)) + return; + + mpTexture.reset(); + mpWindow.reset(); + mhWnd=NULL; + + // refrain from releasing the DX5 objects - deleting the + // DX5 device seems to kill the whole engine, including + // all objects we might still hold references to + // (surfaces, e.g.) + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::screenshot + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::screenShot() + { + if(!(mpBackBufferSurface.get())) + return; + char filename[256]; + static sal_uInt32 counter = 0; + sprintf(filename,"c:\\shot%d.bmp",counter++); + dumpSurface(mpBackBufferSurface,filename); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::validateMainSurfaces + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::validateMainSurfaces() + { + if(mpPrimarySurface.get()) { + if(mpPrimarySurface->IsLost() == DDERR_SURFACELOST) { + if(FAILED(mpPrimarySurface->Restore())) + return false; + } + } + + if(mpBackBufferSurface.get()) { + if(mpBackBufferSurface->IsLost() == DDERR_SURFACELOST) + { + // TODO(F1): simply restoring the backbuffer does not + // work as expected, we need to re-create everything + // from scratch. find out why... + //if(SUCCEEDED(mpBackBufferSurface->Restore())) + // return setup3DDevice(); + + mpBackBufferSurface.reset(); + + // get us a backbuffer for simulated flipping + IDirectDrawSurface* pSurface; + + // TODO(P2): Strictly speaking, we don't need a full screen worth of + // backbuffer here. We could also scale dynamically with the current + // window size, but this will make it necessary to temporarily have two + // buffers while copying from the old to the new one. YMMV. + const ::basegfx::B2ISize aSize( getFramebufferSize() ); + + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc, sizeof(DDSURFACEDESC), 0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + aSurfaceDesc.dwHeight= aSize.getY(); + aSurfaceDesc.dwWidth = aSize.getX(); + + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; + + HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + + if( FAILED( nRes ) ) + { + if( nRes == DDERR_OUTOFVIDEOMEMORY ) + { + // local vid mem failed. Maybe AGP mem works? + aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM; + if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL)) ) + { + // no chance + return false; + } + + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" ); + } + else + { + // no chance + VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" ); + return false; + } + } + + VERBOSE_TRACE( "Device::Device(): created backbuffer of size %d times %d pixel", + aSurfaceDesc.dwWidth, + aSurfaceDesc.dwHeight ); + + mpBackBufferSurface = COMReference< IDirectDrawSurface >(pSurface); + + return setup3DDevice(); + } + } + + return true; + } + + void DXRenderModule::renderInfoText( const ::rtl::OUString& rStr, + const Gdiplus::PointF& rPos ) const + { + ENSURE_OR_THROW( !mnBeginSceneCount, + "Device::renderInfoText(): within 3D scene" ); + + // render text directly to primary surface + GraphicsSharedPtr pGraphics; + + if( mbPageFlipping ) + { + // render on top of backbuffer. We have + // page flipping, anyway, thus this will + // cost us nothing. + pGraphics = createSurfaceGraphics( mpBackBufferSurface ); + } + else + { + // render FPS directly to front buffer. + // That saves us another explicit blit, + // and for me, the FPS counter can blink, + // if it likes to... + pGraphics = createSurfaceGraphics( mpPrimarySurface ); + } + + if( !mbPageFlipping ) + { + // clear background. We might be doing optimized redraws, + // and the background under the FPS count will then not be + // cleared. + Gdiplus::SolidBrush aBrush( + Gdiplus::Color( 255, 255, 255 ) ); + + pGraphics->FillRectangle( &aBrush, + rPos.X, rPos.Y, 80.0, 20.0 ); + } + + Gdiplus::SolidBrush aBrush( + Gdiplus::Color( 255, 0, 255 ) ); + Gdiplus::Font aFont( NULL, + 16, + Gdiplus::FontStyleRegular, + Gdiplus::UnitWorld, + NULL ); + pGraphics->DrawString( reinterpret_cast<LPCWSTR>(rStr.getStr()), + rStr.getLength(), + &aFont, + rPos, + &aBrush ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::renderMemAvailable + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::renderMemAvailable() const + { + ENSURE_OR_THROW( !mnBeginSceneCount, + "DXRenderModule::renderMemAvailable(): within 3D scene" ); + + const double nSurfaceMem( getAvailableSurfaceMem()/1024 ); + + ::rtl::OUString text( ::rtl::math::doubleToUString( nSurfaceMem, + rtl_math_StringFormat_F, + 2,'.',NULL,' ') ); + + // pad with leading space + while( text.getLength() < 6 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("S: ")) + text; + + renderInfoText( text, + Gdiplus::PointF( 0.0, 20) ); + + + const double nTexMem( getAvailableTextureMem()/1024 ); + + text = ::rtl::math::doubleToUString( nTexMem, + rtl_math_StringFormat_F, + 2,'.',NULL,' '); + // pad with leading space + while( text.getLength() < 6 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("T: ")) + text; + + renderInfoText( text, + Gdiplus::PointF( 0.0, 40) ); + + VERBOSE_TRACE( "dxcanvas: %f free surface mem, %f free texture mem", + nSurfaceMem, nTexMem ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::renderFPSCounter + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::renderFPSCounter() const + { + ENSURE_OR_THROW( !mnBeginSceneCount, + "DXRenderModule::ren derFPSCounter(): within 3D scene" ); + + const double denominator( maLastUpdate.getElapsedTime() ); + maLastUpdate.reset(); + + ::rtl::OUString text( ::rtl::math::doubleToUString( denominator == 0.0 ? 100.0 : 1.0/denominator, + rtl_math_StringFormat_F, + 2,'.',NULL,' ') ); + + // pad with leading space + while( text.getLength() < 6 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" fps")); + + renderInfoText( text, + Gdiplus::PointF() ); + + VERBOSE_TRACE( "dxcanvas: %f FPS", + denominator == 0.0 ? 100.0 : 1.0/denominator ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::resize + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::resize( const ::basegfx::B2IRange& rect ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if( mhWnd==0 ) + return; + + // don't do anything if the size didn't change. + if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) && + maSize.getY() == static_cast<sal_Int32>(rect.getHeight())) + return; + + // TODO(Q2): use numeric cast to prevent overflow + maSize.setX(static_cast<sal_Int32>(rect.getWidth())); + maSize.setY(static_cast<sal_Int32>(rect.getHeight())); + + mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY()); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getPageSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXRenderModule::getPageSize() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + return maPageSize; + } + + ::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + const ::basegfx::B2IVector& rPageSize( getPageSize() ); + ::basegfx::B2ISize aSize(surfaceSize); + if(!(aSize.getX())) + aSize.setX(rPageSize.getX()); + if(!(aSize.getY())) + aSize.setY(rPageSize.getY()); + + if(mpTexture.use_count() == 1) + return mpTexture; + + return ::canvas::ISurfaceSharedPtr( + new DXSurface(*this, + aSize) ); + } + + void DXRenderModule::beginPrimitive( PrimitiveType eType ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + ENSURE_OR_THROW( !mnBeginSceneCount, + "DXRenderModule::beginPrimitive(): nested call" ); + + ++mnBeginSceneCount; + meType=eType; + mnCount=0; + } + + void DXRenderModule::endPrimitive() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + --mnBeginSceneCount; + meType=PRIMITIVE_TYPE_UNKNOWN; + mnCount=0; + } + + void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + switch(meType) + { + case PRIMITIVE_TYPE_TRIANGLE: + { + maVertexCache.push_back(vertex); + ++mnCount; + mnCount &= 3; + break; + } + + case PRIMITIVE_TYPE_QUAD: + { + if(mnCount == 3) + { + const std::size_t size(maVertexCache.size()); + ::canvas::Vertex v0(maVertexCache[size-1]); + ::canvas::Vertex v2(maVertexCache[size-3]); + maVertexCache.push_back(v0); + maVertexCache.push_back(vertex); + maVertexCache.push_back(v2); + mnCount=0; + } + else + { + maVertexCache.push_back(vertex); + ++mnCount; + } + break; + } + + default: + OSL_ENSURE( false, + "DXRenderModule::pushVertex(): unexpected primitive types" ); + break; + } + } + + bool DXRenderModule::isError() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + return mbError; + } + + void DXRenderModule::flushVertexCache() + { + if(!(maVertexCache.size())) + return; + + mbError=true; + + if( FAILED(mpDirect3DDevice->BeginScene()) ) + return; + + // enable texture alpha blending + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE))) + return; + + // enable texture alpha modulation, for honoring fAlpha + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, + D3DTBLEND_MODULATEALPHA)) ) + return; + + // enable texture magnification filtering (don't care if this + // fails, it's just visually more pleasant) + mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG, + D3DFILTER_LINEAR); + + // enable texture minification filtering (don't care if this + // fails, it's just visually more pleasant) + mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN, + D3DFILTER_LINEAR); + + // enable subpixel texture output (don't care if this + // fails, it's just visually more pleasant) + mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_SUBPIXEL, + TRUE); + + // normal combination of object... + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, + D3DBLEND_SRCALPHA)) ) + return; + + // ..and background color + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, + D3DBLEND_INVSRCALPHA)) ) + return; + + // disable backface culling; this enables us to mirror sprites + // by simply reverting the triangles, which, with enabled + // culling, would be invisible otherwise + if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, + D3DCULL_NONE)) ) + return; + + mbError=false; + + const float nHalfPixelSizeX(0.5f/maPageSize.getX()); + const float nHalfPixelSizeY(0.5f/maPageSize.getY()); + sal_uInt32 nIndex(0); + const std::size_t size(maVertexCache.size()); + D3DTLVERTEX *vertices = static_cast<D3DTLVERTEX *>(_alloca(sizeof(D3DTLVERTEX)*size)); + vertexCache_t::const_iterator it(maVertexCache.begin()); + while(it != maVertexCache.end()) + { + vertices[nIndex++] = D3DTLVERTEX( + D3DVECTOR(static_cast<D3DVALUE>(it->x), + static_cast<D3DVALUE>(it->y), + static_cast<D3DVALUE>(it->z)), + 1, + D3DRGBA(1,1,1,it->a), + D3DRGBA(0,0,0,0), + static_cast<float>(it->u + nHalfPixelSizeX), + static_cast<float>(it->v + nHalfPixelSizeY)); + ++it; + } + + maVertexCache.clear(); + + mbError |= FAILED(mpDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, + D3DVT_TLVERTEX, + (LPVOID)vertices, + size, + 0)); + + mbError |= FAILED(mpDirect3DDevice->EndScene()); + } + } + + IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent ) + { + return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) ); + } +} + +#endif diff --git a/canvas/source/directx/dx_9rm.cxx b/canvas/source/directx/dx_9rm.cxx new file mode 100755 index 000000000000..a0f485befa12 --- /dev/null +++ b/canvas/source/directx/dx_9rm.cxx @@ -0,0 +1,1363 @@ +/************************************************************************* + * + * 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" + +#if DIRECTX_VERSION == 0x0900 + +#define MAX_TEXTURE_SIZE (2048) +#define MIN_TEXTURE_SIZE (32) +//#define FAKE_MAX_NUMBER_TEXTURES (2) +//#define FAKE_MAX_TEXTURE_SIZE (4096) + +#define VERTEX_BUFFER_SIZE (341*3) // 1023, the size of the internal + // vertex buffer (must be divisable + // by 3, as each triangle primitive + // has 3 vertices) + + +////////////////////////////////////////////////////////////////////////////////// +// includes +////////////////////////////////////////////////////////////////////////////////// +#include <vcl/syschild.hxx> +#include <vcl/window.hxx> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <canvas/elapsedtime.hxx> +#include <canvas/canvastools.hxx> +#include <canvas/rendering/icolorbuffer.hxx> +#include <canvas/rendering/isurface.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <boost/scoped_ptr.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include "dx_rendermodule.hxx" +#include "dx_config.hxx" + +#undef WB_LEFT +#undef WB_RIGHT + +#include "dx_impltools.hxx" +#include <vcl/sysdata.hxx> + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////////// +// 'dxcanvas' namespace +////////////////////////////////////////////////////////////////////////////////// + +namespace dxcanvas +{ + namespace + { + ////////////////////////////////////////////////////////////////////////////////// + // monitorSupport + ////////////////////////////////////////////////////////////////////////////////// + + class monitorSupport + { + public: + + monitorSupport() : + mhLibrary(LoadLibrary("user32.dll")), + mpMonitorFromWindow(NULL) + { + if(mhLibrary) + mpMonitorFromWindow = reinterpret_cast<fMonitorFromWindow>( + GetProcAddress( + mhLibrary,"MonitorFromWindow")); + } + + ~monitorSupport() + { + if(mhLibrary) + FreeLibrary(mhLibrary); + mhLibrary=0; + } + + HMONITOR MonitorFromWindow( HWND hwnd ) + { + // return adapter_default in case something went wrong... + if(!(mpMonitorFromWindow)) + return HMONITOR(0); + // MONITOR_DEFAULTTONEAREST + const DWORD dwFlags(0x00000002); + return mpMonitorFromWindow(hwnd,dwFlags); + } + private: + + HINSTANCE mhLibrary; + typedef HMONITOR (WINAPI *fMonitorFromWindow )( HWND hwnd, DWORD dwFlags ); + fMonitorFromWindow mpMonitorFromWindow; + }; + + monitorSupport aMonitorSupport; + + + class DXRenderModule; + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + /** ISurface implemenation. + + @attention holds the DXRenderModule via non-refcounted + reference! This is safe with current state of affairs, since + the canvas::PageManager holds surface and render module via + shared_ptr (and makes sure all surfaces are deleted before its + render module member goes out of scope). + */ + class DXSurface : public canvas::ISurface + { + public: + DXSurface( DXRenderModule& rRenderModule, + const ::basegfx::B2ISize& rSize ); + ~DXSurface(); + + virtual bool selectTexture(); + virtual bool isValid(); + virtual bool update( const ::basegfx::B2IPoint& rDestPos, + const ::basegfx::B2IRange& rSourceRect, + ::canvas::IColorBuffer& rSource ); + virtual ::basegfx::B2IVector getSize(); + COMReference<IDirect3DTexture9> getTexture() const; + + private: + /// Guard local methods against concurrent acces to RenderModule + class ImplRenderModuleGuard : private ::boost::noncopyable + { + public: + explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule ); + inline ~ImplRenderModuleGuard(); + + private: + DXRenderModule& mrRenderModule; + }; + + DXRenderModule& mrRenderModule; + COMReference<IDirect3DTexture9> mpTexture; + + ::basegfx::B2IVector maSize; + }; + + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + /// Default implementation of IDXRenderModule + class DXRenderModule : public IDXRenderModule + { + public: + explicit DXRenderModule( const ::Window& rWindow ); + ~DXRenderModule(); + + virtual void lock() const { maMutex.acquire(); } + virtual void unlock() const { maMutex.release(); } + + virtual COMReference<IDirect3DSurface9> + createSystemMemorySurface( const ::basegfx::B2IVector& rSize ); + virtual void disposing(); + virtual HWND getHWND() const { return mhWnd; } + virtual void screenShot(); + + virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& rCurrWindowArea ); + + virtual void resize( const ::basegfx::B2IRange& rect ); + virtual ::basegfx::B2IVector getPageSize(); + virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize ); + virtual void beginPrimitive( PrimitiveType eType ); + virtual void endPrimitive(); + virtual void pushVertex( const ::canvas::Vertex& vertex ); + virtual bool isError(); + + COMReference<IDirect3DDevice9> getDevice() { return mpDevice; } + + void flushVertexCache(); + void commitVertexCache(); + + private: + + bool create( const ::Window& rWindow ); + bool createDevice(); + bool verifyDevice( const UINT nAdapter ); + UINT getAdapterFromWindow(); + + /** This object represents the DirectX state machine. In order + to serialize access to DirectX's global state, a global + mutex is required. + */ + static ::osl::Mutex maMutex; + + HWND mhWnd; + COMReference<IDirect3DDevice9> mpDevice; + COMReference<IDirect3D9> mpDirect3D9; + COMReference<IDirect3DSwapChain9> mpSwapChain; + COMReference<IDirect3DVertexBuffer9> mpVertexBuffer; + ::canvas::ISurfaceSharedPtr mpTexture; + ::boost::scoped_ptr<SystemChildWindow> mpWindow; + ::basegfx::B2IVector maSize; + typedef std::vector<canvas::Vertex> vertexCache_t; + vertexCache_t maVertexCache; + std::size_t mnCount; + int mnBeginSceneCount; + bool mbCanUseDynamicTextures; + bool mbError; + PrimitiveType meType; + ::basegfx::B2IVector maPageSize; + D3DPRESENT_PARAMETERS mad3dpp; + + inline bool isDisposed() const { return (mhWnd==NULL); } + + struct dxvertex + { + float x,y,z,rhw; + DWORD diffuse; + float u,v; + }; + + std::size_t maNumVertices; + std::size_t maWriteIndex; + std::size_t maReadIndex; + }; + + ::osl::Mutex DXRenderModule::maMutex; + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::ImplRenderModuleGuard + ////////////////////////////////////////////////////////////////////////////////// + + inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard( + DXRenderModule& rRenderModule ) : + mrRenderModule( rRenderModule ) + { + mrRenderModule.lock(); + } + + inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard() + { + mrRenderModule.unlock(); + } + +#ifdef FAKE_MAX_NUMBER_TEXTURES + static sal_uInt32 gNumSurfaces = 0; +#endif + + void fillRect( sal_uInt32 *pDest, + sal_uInt32 dwWidth, + sal_uInt32 dwHeight, + sal_uInt32 dwPitch, + sal_uInt32 dwColor ) + { + for(sal_uInt32 i=0; i<dwWidth; ++i) + { + pDest[i]=dwColor; + pDest[((dwHeight-1)*dwPitch)+i]=dwColor; + } + + for(sal_uInt32 j=0; j<dwHeight; ++j) + { + pDest[0]=dwColor; + pDest[dwWidth-1]=dwColor; + pDest += dwPitch; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + DXSurface::DXSurface( DXRenderModule& rRenderModule, + const ::basegfx::B2ISize& rSize ) : + mrRenderModule(rRenderModule), + mpTexture(NULL), + maSize() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + +#ifdef FAKE_MAX_NUMBER_TEXTURES + ++gNumSurfaces; + if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES) + return; +#endif + +#ifdef FAKE_MAX_TEXTURE_SIZE + if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE) + return; + if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE) + return; +#endif + + ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0, + "DXSurface::DXSurface(): request for zero-sized surface"); + + COMReference<IDirect3DDevice9> pDevice(rRenderModule.getDevice()); + + IDirect3DTexture9 *pTexture(NULL); + if(FAILED(pDevice->CreateTexture( + rSize.getX(), + rSize.getY(), + 1,0,D3DFMT_A8R8G8B8, + D3DPOOL_MANAGED, + &pTexture,NULL))) + return; + + mpTexture=COMReference<IDirect3DTexture9>(pTexture); + maSize = rSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::~DXSurface + ////////////////////////////////////////////////////////////////////////////////// + + DXSurface::~DXSurface() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + +#ifdef FAKE_MAX_NUMBER_TEXTURES + gNumSurfaces--; +#endif + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::selectTexture + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::selectTexture() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + mrRenderModule.flushVertexCache(); + COMReference<IDirect3DDevice9> pDevice(mrRenderModule.getDevice()); + + if( FAILED(pDevice->SetTexture(0,mpTexture.get())) ) + return false; + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::isValid + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::isValid() + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + if(!(mpTexture.is())) + return false; + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::update + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos, + const ::basegfx::B2IRange& rSourceRect, + ::canvas::IColorBuffer& rSource ) + { + ImplRenderModuleGuard aGuard( mrRenderModule ); + + // can't update if surface is not valid, that means + // either not existent nor restored... + if(!(isValid())) + return false; + + D3DLOCKED_RECT aLockedRect; + RECT rect; + rect.left = std::max(sal_Int32(0),rDestPos.getX()); + rect.top = std::max(sal_Int32(0),rDestPos.getY()); + // to avoid interpolation artifacts from other textures, + // the surface manager allocates one pixel gap between + // them. Clear that to transparent. + rect.right = std::min(maSize.getX(), + rect.left + sal_Int32(rSourceRect.getWidth()+1)); + rect.bottom = std::min(maSize.getY(), + rect.top + sal_Int32(rSourceRect.getHeight()+1)); + const bool bClearRightColumn( rect.right < maSize.getX() ); + const bool bClearBottomRow( rect.bottom < maSize.getY() ); + + if(SUCCEEDED(mpTexture->LockRect(0,&aLockedRect,&rect,D3DLOCK_NOSYSLOCK))) + { + if(sal_uInt8* pImage = rSource.lock()) + { + switch( rSource.getFormat() ) + { + case ::canvas::IColorBuffer::FMT_A8R8G8B8: + { + const std::size_t nSourceBytesPerPixel(4); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits; + + const sal_uInt32 nNumBytesToCopy( + static_cast<sal_uInt32>( + rSourceRect.getWidth())* + nSourceBytesPerPixel); + const sal_uInt64 nNumLines(rSourceRect.getHeight()); + + for(sal_uInt32 i=0; i<nNumLines; ++i) + { + rtl_copyMemory(pDst,pImage,nNumBytesToCopy); + + if( bClearRightColumn ) + { + // to avoid interpolation artifacts + // from other textures, the surface + // manager allocates one pixel gap + // between them. Clear that to + // transparent. + pDst[nNumBytesToCopy] = + pDst[nNumBytesToCopy+1] = + pDst[nNumBytesToCopy+2] = + pDst[nNumBytesToCopy+3] = 0x00; + } + pDst += aLockedRect.Pitch; + pImage += nSourcePitchInBytes; + } + + if( bClearBottomRow ) + rtl_zeroMemory(pDst,nNumBytesToCopy+4); + } + break; + + case ::canvas::IColorBuffer::FMT_R8G8B8: + { + const std::size_t nSourceBytesPerPixel(3); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits; + + const sal_Int32 nNumColumns( + sal::static_int_cast<sal_Int32>(rSourceRect.getWidth())); + const sal_Int32 nNumLines( + sal::static_int_cast<sal_Int32>(rSourceRect.getHeight())); + for(sal_Int32 i=0; i<nNumLines; ++i) + { + sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst); + sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage); + + for(sal_Int32 x=0; x<nNumColumns; ++x) + { + sal_uInt32 color(0xFF000000); + color |= pSrcScanline[2]<<16; + color |= pSrcScanline[1]<<8; + color |= pSrcScanline[0]; + pSrcScanline += 3; + *pDstScanline++ = color; + } + if( bClearRightColumn ) + *pDstScanline++ = 0xFF000000; + + pDst += aLockedRect.Pitch; + pImage += nSourcePitchInBytes; + } + + if( bClearBottomRow ) + rtl_zeroMemory(pDst,4*(nNumColumns+1)); + } + break; + + case ::canvas::IColorBuffer::FMT_X8R8G8B8: + { + const std::size_t nSourceBytesPerPixel(4); + const std::size_t nSourcePitchInBytes(rSource.getStride()); + pImage += rSourceRect.getMinY()*nSourcePitchInBytes; + pImage += rSourceRect.getMinX()*nSourceBytesPerPixel; + + // calculate the destination memory address + sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits; + + const sal_Int32 nNumLines( + sal::static_int_cast<sal_Int32>(rSourceRect.getHeight())); + const sal_Int32 nNumColumns( + sal::static_int_cast<sal_Int32>(rSourceRect.getWidth())); + for(sal_Int32 i=0; i<nNumLines; ++i) + { + sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage); + sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst); + for(sal_Int32 j=0; j<nNumColumns; ++j) + pDst32[j] = 0xFF000000 | pSrc32[j]; + + if( bClearRightColumn ) + pDst32[nNumColumns] = 0xFF000000; + + pDst += aLockedRect.Pitch; + pImage += nSourcePitchInBytes; + } + + if( bClearBottomRow ) + rtl_zeroMemory(pDst,4*(nNumColumns+1)); + } + break; + + default: + ENSURE_OR_RETURN_FALSE(false, + "DXSurface::update(): Unknown/unimplemented buffer format" ); + break; + } + + rSource.unlock(); + } + + return SUCCEEDED(mpTexture->UnlockRect(0)); + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurface::getSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXSurface::getSize() + { + return maSize; + } + + COMReference<IDirect3DTexture9> DXSurface::getTexture() const + { + return mpTexture; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + DXRenderModule::DXRenderModule( const ::Window& rWindow ) : + mhWnd(0), + mpDevice(), + mpDirect3D9(), + mpSwapChain(), + mpVertexBuffer(), + mpTexture(), + maSize(), + maVertexCache(), + mnCount(0), + mnBeginSceneCount(0), + mbCanUseDynamicTextures(false), + mbError( false ), + meType( PRIMITIVE_TYPE_UNKNOWN ), + maPageSize(), + mad3dpp(), + maNumVertices( VERTEX_BUFFER_SIZE ), + maWriteIndex(0), + maReadIndex(0) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(!(create(rWindow))) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device!") ),NULL); + } + + // allocate a single texture surface which can be used later. + // we also use this to calibrate the page size. + ::basegfx::B2IVector aPageSize(maPageSize); + while(true) + { + mpTexture = ::canvas::ISurfaceSharedPtr( + new DXSurface(*this,aPageSize)); + if(mpTexture->isValid()) + break; + + aPageSize.setX(aPageSize.getX()>>1); + aPageSize.setY(aPageSize.getY()>>1); + if((aPageSize.getX() < MIN_TEXTURE_SIZE) || + (aPageSize.getY() < MIN_TEXTURE_SIZE)) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device - " + "insufficient texture space!") ),NULL); + } + } + maPageSize=aPageSize; + + IDirect3DVertexBuffer9 *pVB(NULL); + DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1); + if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices, + D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, + aFVF, + D3DPOOL_DEFAULT, + &pVB, + NULL)) ) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device - out of memory!")),NULL); + } + + mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::~DXRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + DXRenderModule::~DXRenderModule() + { + disposing(); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::disposing + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::disposing() + { + if(!(mhWnd)) + return; + + mpTexture.reset(); + mpWindow.reset(); + mhWnd=NULL; + + // refrain from releasing the DX9 objects. We're the only + // ones holding references to them, and it might be + // dangerous to destroy the DX9 device, before all other + // objects are dead. + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::create + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::create( const ::Window& rWindow ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + maVertexCache.reserve(1024); + + mpWindow.reset( + new SystemChildWindow( + const_cast<Window *>(&rWindow), 0) ); + + // system child window must not receive mouse events + mpWindow->SetMouseTransparent( TRUE ); + + // parent should receive paint messages as well + // [PARENTCLIPMODE_NOCLIP], the argument is here + // passed as plain numeric value since the stupid + // define utilizes a USHORT cast. + mpWindow->SetParentClipMode(0x0002); + + // the system child window must not clear its background + mpWindow->EnableEraseBackground( FALSE ); + + mpWindow->SetControlForeground(); + mpWindow->SetControlBackground(); + mpWindow->EnablePaint(FALSE); + + const SystemEnvData *pData = mpWindow->GetSystemData(); + const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd)); + mhWnd = const_cast<HWND>(hwnd); + + ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ), + "DXRenderModule::create() No valid HWND given." ); + + // retrieve position and size of the parent window + const ::Size &rSizePixel(rWindow.GetSizePixel()); + + // remember the size of the parent window, since we + // need to use this for our child window. + maSize.setX(static_cast<sal_Int32>(rSizePixel.Width())); + maSize.setY(static_cast<sal_Int32>(rSizePixel.Height())); + + // let the child window cover the same size as the parent window. + mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY()); + + // TODO(F2): since we would like to share precious hardware + // resources, the direct3d9 object should be global. each new + // request for a canvas should only create a new swapchain. + mpDirect3D9 = COMReference<IDirect3D9>( + Direct3DCreate9(D3D_SDK_VERSION)); + if(!mpDirect3D9.is()) + return false; + + // create a device from the direct3d9 object. + if(!(createDevice())) + return false; + + mpWindow->Show(); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::verifyDevice + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::verifyDevice( const UINT nAdapter ) + { + ENSURE_OR_THROW( mpDirect3D9.is(), + "DXRenderModule::verifyDevice() No valid device." ); + + // ask direct3d9 about the capabilities of hardware devices on a specific adapter. + // here we decide if the underlying hardware of the machine 'is good enough'. + // since we only need a tiny little fraction of what could be used, this + // is basically a no-op. + D3DCAPS9 aCaps; + if(FAILED(mpDirect3D9->GetDeviceCaps(nAdapter,D3DDEVTYPE_HAL,&aCaps))) + return false; + if(!(aCaps.MaxTextureWidth)) + return false; + if(!(aCaps.MaxTextureHeight)) + return false; + maPageSize = ::basegfx::B2IVector(aCaps.MaxTextureWidth,aCaps.MaxTextureHeight); + + // check device against white & blacklist entries + D3DADAPTER_IDENTIFIER9 aIdent; + if(FAILED(mpDirect3D9->GetAdapterIdentifier(nAdapter,0,&aIdent))) + return false; + + DXCanvasItem aConfigItem; + DXCanvasItem::DeviceInfo aInfo; + aInfo.nVendorId = aIdent.VendorId; + aInfo.nDeviceId = aIdent.DeviceId; + aInfo.nDeviceSubSysId = aIdent.SubSysId; + aInfo.nDeviceRevision = aIdent.Revision; + + aInfo.nDriverId = HIWORD(aIdent.DriverVersion.HighPart); + aInfo.nDriverVersion = LOWORD(aIdent.DriverVersion.HighPart); + aInfo.nDriverSubVersion = HIWORD(aIdent.DriverVersion.LowPart); + aInfo.nDriverBuildId = LOWORD(aIdent.DriverVersion.LowPart); + + if( !aConfigItem.isDeviceUsable(aInfo) ) + return false; + + if( aConfigItem.isBlacklistCurrentDevice() ) + { + aConfigItem.blacklistDevice(aInfo); + return false; + } + + aConfigItem.adaptMaxTextureSize(maPageSize); + + mbCanUseDynamicTextures = (aCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0; + + return true; + } + + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::createDevice + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::createDevice() + { + // we expect that the caller provides us with a valid HWND + ENSURE_OR_THROW( IsWindow(mhWnd), + "DXRenderModule::createDevice() No valid HWND given." ); + + // we expect that the caller already created the direct3d9 object. + ENSURE_OR_THROW( mpDirect3D9.is(), + "DXRenderModule::createDevice() no direct3d?." ); + + // find the adapter identifier from the window. + const UINT aAdapter(getAdapterFromWindow()); + if(aAdapter == static_cast<UINT>(-1)) + return false; + + // verify that device possibly works + if( !verifyDevice(aAdapter) ) + return false; + + // query the display mode from the selected adapter. + // we'll later request the backbuffer format to be same + // same as the display format. + D3DDISPLAYMODE d3ddm; + mpDirect3D9->GetAdapterDisplayMode(aAdapter,&d3ddm); + + // we need to use D3DSWAPEFFECT_COPY here since the canvas-api has + // basically nothing to do with efficient resource handling. it tries + // to avoid drawing whenevery possible, which is simply not the most + // efficient way we could leverage the hardware in this case. it would + // be far better to redraw the backbuffer each time we would like to + // display the content of the backbuffer, but we need to face reality + // here and follow how the canvas was designed. + + // Strictly speaking, we don't need a full screen worth of + // backbuffer here. We could also scale dynamically with + // the current window size, but this will make it + // necessary to temporarily have two buffers while copying + // from the old to the new one. What's more, at the time + // we need a larger buffer, DX might not have sufficient + // resources available, and we're then left with too small + // a back buffer, and no way of falling back to a + // different canvas implementation. + ZeroMemory( &mad3dpp, sizeof(mad3dpp) ); + mad3dpp.BackBufferWidth = std::max(sal_Int32(maSize.getX()), + sal_Int32(d3ddm.Width)); + mad3dpp.BackBufferHeight = std::max(sal_Int32(maSize.getY()), + sal_Int32(d3ddm.Height)); + mad3dpp.BackBufferCount = 1; + mad3dpp.Windowed = TRUE; + mad3dpp.SwapEffect = D3DSWAPEFFECT_COPY; + mad3dpp.BackBufferFormat = d3ddm.Format; + mad3dpp.EnableAutoDepthStencil = FALSE; + mad3dpp.hDeviceWindow = mhWnd; + mad3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + + // now create the device, first try hardware vertex processing, + // then software vertex processing. if both queries fail, we give up + // and indicate failure. + IDirect3DDevice9 *pDevice(NULL); + if(FAILED(mpDirect3D9->CreateDevice(aAdapter, + D3DDEVTYPE_HAL, + mhWnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING| + D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE, + &mad3dpp, + &pDevice))) + if(FAILED(mpDirect3D9->CreateDevice(aAdapter, + D3DDEVTYPE_HAL, + mhWnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING| + D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE, + &mad3dpp, + &pDevice))) + return false; + + // got it, store it in a safe place... + mpDevice=COMReference<IDirect3DDevice9>(pDevice); + + // After CreateDevice, the first swap chain already exists, so just get it... + IDirect3DSwapChain9 *pSwapChain(NULL); + pDevice->GetSwapChain(0,&pSwapChain); + mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain); + if( !mpSwapChain.is() ) + return false; + + // clear the render target [which is the backbuffer in this case]. + // we are forced to do this once, and furthermore right now. + // please note that this is only possible since we created the + // backbuffer with copy semantics [the content is preserved after + // calls to Present()], which is an unnecessarily expensive operation. + LPDIRECT3DSURFACE9 pBackBuffer = NULL; + mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer); + mpDevice->SetRenderTarget( 0, pBackBuffer ); + mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L); + pBackBuffer->Release(); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::createSystemMemorySurface + ////////////////////////////////////////////////////////////////////////////////// + + COMReference<IDirect3DSurface9> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize ) + { + if(isDisposed()) + return COMReference<IDirect3DSurface9>(NULL); + + // please note that D3DFMT_X8R8G8B8 is the only format we're + // able to choose here, since GetDC() doesn't support any + // other 32bit-format. + IDirect3DSurface9 *pSurface(NULL); + if( FAILED(mpDevice->CreateOffscreenPlainSurface( + rSize.getX(), + rSize.getY(), + D3DFMT_X8R8G8B8, + D3DPOOL_SYSTEMMEM, + &pSurface, + NULL)) ) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create offscreen surface - out of mem!") ),NULL); + } + + return COMReference<IDirect3DSurface9>(pSurface); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::flip + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& /*rCurrWindowArea*/ ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed() || !mpSwapChain.is()) + return false; + + flushVertexCache(); + + // TODO(P2): Might be faster to actually pass update area here + RECT aRect = + { + rUpdateArea.getMinX(), + rUpdateArea.getMinY(), + rUpdateArea.getMaxX(), + rUpdateArea.getMaxY() + }; + HRESULT hr(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0)); + if(FAILED(hr)) + { + if(hr != D3DERR_DEVICELOST) + return false; + + // interestingly enough, sometimes the Reset() below + // *still* causes DeviceLost errors. So, cycle until + // DX was kind enough to really reset the device... + do + { + mpVertexBuffer.reset(); + hr = mpDevice->Reset(&mad3dpp); + if(SUCCEEDED(hr)) + { + IDirect3DVertexBuffer9 *pVB(NULL); + DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1); + if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices, + D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, + aFVF, + D3DPOOL_DEFAULT, + &pVB, + NULL)) ) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device - out of memory!")),NULL); + } + mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB); + + // retry after the restore + if(SUCCEEDED(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0))) + return true; + } + + TimeValue aTimeout; + aTimeout.Seconds=1; + aTimeout.Nanosec=0; + osl_waitThread(&aTimeout); + } + while(hr == D3DERR_DEVICELOST); + + return false; + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::screenShot + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::screenShot() + { + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::resize + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::resize( const ::basegfx::B2IRange& rect ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return; + + // don't do anything if the size didn't change. + if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) && + maSize.getY() == static_cast<sal_Int32>(rect.getHeight())) + return; + + // TODO(Q2): use numeric cast to prevent overflow + maSize.setX(static_cast<sal_Int32>(rect.getWidth())); + maSize.setY(static_cast<sal_Int32>(rect.getHeight())); + + mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY()); + + // resize back buffer, if necessary + // ------------------------------------------------------------- + + // don't attempt to create anything if the + // requested size is NULL. + if(!(maSize.getX())) + return; + if(!(maSize.getY())) + return; + + // backbuffer too small (might happen, if window is + // maximized across multiple monitors) + if( sal_Int32(mad3dpp.BackBufferWidth) < maSize.getX() || + sal_Int32(mad3dpp.BackBufferHeight) < maSize.getY() ) + { + mad3dpp.BackBufferWidth = maSize.getX(); + mad3dpp.BackBufferHeight = maSize.getY(); + + // clear before, save resources + mpSwapChain.reset(); + + IDirect3DSwapChain9 *pSwapChain(NULL); + if(FAILED(mpDevice->CreateAdditionalSwapChain(&mad3dpp,&pSwapChain))) + return; + mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain); + + // clear the render target [which is the backbuffer in this case]. + // we are forced to do this once, and furthermore right now. + // please note that this is only possible since we created the + // backbuffer with copy semantics [the content is preserved after + // calls to Present()], which is an unnecessarily expensive operation. + LPDIRECT3DSURFACE9 pBackBuffer = NULL; + mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer); + mpDevice->SetRenderTarget( 0, pBackBuffer ); + mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L); + pBackBuffer->Release(); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getPageSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXRenderModule::getPageSize() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + return maPageSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::createSurface + ////////////////////////////////////////////////////////////////////////////////// + + ::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return ::canvas::ISurfaceSharedPtr(); + + const ::basegfx::B2IVector& rPageSize( getPageSize() ); + ::basegfx::B2ISize aSize(surfaceSize); + if(!(aSize.getX())) + aSize.setX(rPageSize.getX()); + if(!(aSize.getY())) + aSize.setY(rPageSize.getY()); + + if(mpTexture.use_count() == 1) + return mpTexture; + + return ::canvas::ISurfaceSharedPtr( new DXSurface(*this,aSize) ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::beginPrimitive + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::beginPrimitive( PrimitiveType eType ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return; + + ENSURE_OR_THROW( !mnBeginSceneCount, + "DXRenderModule::beginPrimitive(): nested call" ); + + ++mnBeginSceneCount; + meType=eType; + mnCount=0; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::endPrimitive + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::endPrimitive() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return; + + --mnBeginSceneCount; + meType=PRIMITIVE_TYPE_UNKNOWN; + mnCount=0; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::pushVertex + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex ) + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + if(isDisposed()) + return; + + switch(meType) + { + case PRIMITIVE_TYPE_TRIANGLE: + { + maVertexCache.push_back(vertex); + ++mnCount; + mnCount &= 3; + break; + } + + case PRIMITIVE_TYPE_QUAD: + { + if(mnCount == 3) + { + const std::size_t size(maVertexCache.size()); + ::canvas::Vertex v0(maVertexCache[size-1]); + ::canvas::Vertex v2(maVertexCache[size-3]); + maVertexCache.push_back(v0); + maVertexCache.push_back(vertex); + maVertexCache.push_back(v2); + mnCount=0; + } + else + { + maVertexCache.push_back(vertex); + ++mnCount; + } + break; + } + + default: + OSL_ENSURE(false, + "DXRenderModule::pushVertex(): unexpected primitive type"); + break; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::isError + ////////////////////////////////////////////////////////////////////////////////// + + bool DXRenderModule::isError() + { + // TODO(P2): get rid of those fine-grained locking + ::osl::MutexGuard aGuard( maMutex ); + + return mbError; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::getAdapterFromWindow + ////////////////////////////////////////////////////////////////////////////////// + + UINT DXRenderModule::getAdapterFromWindow() + { + HMONITOR hMonitor(aMonitorSupport.MonitorFromWindow(mhWnd)); + UINT aAdapterCount(mpDirect3D9->GetAdapterCount()); + for(UINT i=0; i<aAdapterCount; ++i) + if(hMonitor == mpDirect3D9->GetAdapterMonitor(i)) + return i; + return static_cast<UINT>(-1); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::commitVertexCache + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::commitVertexCache() + { + if(maReadIndex != maWriteIndex) + { + const std::size_t nVertexStride = sizeof(dxvertex); + const unsigned int nNumVertices = maWriteIndex-maReadIndex; + const unsigned int nNumPrimitives = nNumVertices / 3; + + if(FAILED(mpDevice->SetStreamSource(0,mpVertexBuffer.get(),0,nVertexStride))) + return; + + if(FAILED(mpDevice->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1))) + return; + + if(FAILED(mpDevice->BeginScene())) + return; + + mbError |= FAILED(mpDevice->DrawPrimitive(D3DPT_TRIANGLELIST,maReadIndex,nNumPrimitives)); + mbError |= FAILED(mpDevice->EndScene()); + + maReadIndex += nNumVertices; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXRenderModule::flushVertexCache + ////////////////////////////////////////////////////////////////////////////////// + + void DXRenderModule::flushVertexCache() + { + if(!(maVertexCache.size())) + return; + + mbError=true; + + if( FAILED(mpDevice->SetRenderState(D3DRS_LIGHTING,FALSE))) + return; + + // enable texture alpha blending + if( FAILED(mpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE))) + return; + + mpDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR); + mpDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR); + mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSU ,D3DTADDRESS_CLAMP ); + mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSV ,D3DTADDRESS_CLAMP ); + + // configure the fixed-function pipeline. + // the only 'feature' we need here is to modulate the alpha-channels + // from the texture and the interpolated diffuse color. the result + // will then be blended with the backbuffer. + // fragment color = texture color * diffuse.alpha. + mpDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE); + mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE); + mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE); + + // normal combination of object... + if( FAILED(mpDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA)) ) + return; + + // ..and background color + if( FAILED(mpDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA)) ) + return; + + // disable backface culling; this enables us to mirror sprites + // by simply reverting the triangles, which, with enabled + // culling, would be invisible otherwise + if( FAILED(mpDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE)) ) + return; + + mbError=false; + + std::size_t nSize(maVertexCache.size()); + const std::size_t nVertexStride = sizeof(dxvertex); + + const ::basegfx::B2IVector aPageSize(getPageSize()); + const float nHalfPixelSizeX(0.5f/aPageSize.getX()); + const float nHalfPixelSizeY(0.5f/aPageSize.getY()); + vertexCache_t::const_iterator it(maVertexCache.begin()); + + while( nSize ) + { + DWORD dwLockFlags(D3DLOCK_NOOVERWRITE); + + // Check to see if there's space for the current set of + // vertices in the buffer. + if( maNumVertices - maWriteIndex < nSize ) + { + commitVertexCache(); + dwLockFlags = D3DLOCK_DISCARD; + maWriteIndex = 0; + maReadIndex = 0; + } + + dxvertex *vertices(NULL); + const std::size_t nNumVertices( + std::min(maNumVertices - maWriteIndex, + nSize)); + if(FAILED(mpVertexBuffer->Lock(maWriteIndex*nVertexStride, + nNumVertices*nVertexStride, + (void **)&vertices, + dwLockFlags))) + return; + + std::size_t nIndex(0); + while( nIndex < nNumVertices ) + { + dxvertex &dest = vertices[nIndex++]; + dest.x=it->x; + dest.y=it->y; + dest.z=it->z; + dest.rhw=1; + const sal_uInt32 alpha(static_cast<sal_uInt32>(it->a*255.0f)); + dest.diffuse=D3DCOLOR_ARGB(alpha,255,255,255); + dest.u=static_cast<float>(it->u + nHalfPixelSizeX); + dest.v=static_cast<float>(it->v + nHalfPixelSizeY); + ++it; + } + + mpVertexBuffer->Unlock(); + + // Advance to the next position in the vertex buffer. + maWriteIndex += nNumVertices; + nSize -= nNumVertices; + + commitVertexCache(); + } + + maVertexCache.clear(); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // createRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent ) + { + return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) ); + } +} + +#endif diff --git a/canvas/source/directx/dx_bitmap.cxx b/canvas/source/directx/dx_bitmap.cxx new file mode 100755 index 000000000000..d1468105a22b --- /dev/null +++ b/canvas/source/directx/dx_bitmap.cxx @@ -0,0 +1,219 @@ +/************************************************************************* + * + * 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 "dx_bitmap.hxx" +#include "dx_graphicsprovider.hxx" +#include "dx_impltools.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2irange.hxx> + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + ////////////////////////////////////////////////////////////////////////////////// + // DXBitmap::DXBitmap + ////////////////////////////////////////////////////////////////////////////////// + + DXBitmap::DXBitmap( const BitmapSharedPtr& rBitmap, + bool bWithAlpha ) : + mpGdiPlusUser( GDIPlusUser::createInstance() ), + maSize(rBitmap->GetWidth(),rBitmap->GetHeight()), + mpBitmap(rBitmap), + mpGraphics(tools::createGraphicsFromBitmap(mpBitmap)), + mbAlpha(bWithAlpha) + { + } + + DXBitmap::DXBitmap( const ::basegfx::B2IVector& rSize, + bool bWithAlpha ) : + mpGdiPlusUser( GDIPlusUser::createInstance() ), + maSize(rSize), + mpBitmap(), + mpGraphics(), + mbAlpha(bWithAlpha) + { + // create container for pixel data + if(mbAlpha) + { + mpBitmap.reset( + new Gdiplus::Bitmap( + maSize.getX(), + maSize.getY(), + PixelFormat32bppARGB)); + } + else + { + mpBitmap.reset( + new Gdiplus::Bitmap( + maSize.getX(), + maSize.getY(), + PixelFormat24bppRGB)); + } + + mpGraphics.reset( tools::createGraphicsFromBitmap(mpBitmap) ); + } + + BitmapSharedPtr DXBitmap::getBitmap() const + { + return mpBitmap; + } + + GraphicsSharedPtr DXBitmap::getGraphics() + { + return mpGraphics; + } + + ::basegfx::B2IVector DXBitmap::getSize() const + { + return maSize; + } + + bool DXBitmap::hasAlpha() const + { + return mbAlpha; + } + + uno::Sequence< sal_Int8 > DXBitmap::getData( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& rect ) + { + uno::Sequence< sal_Int8 > aRes( (rect.X2-rect.X1)*(rect.Y2-rect.Y1)*4 ); // TODO(F1): Be format-agnostic here + + const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rect.X2-rect.X1; + aBmpData.Height = rect.Y2-rect.Y1; + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = aRes.getArray(); + + // TODO(F1): Support more pixel formats natively + + // read data from bitmap + if( Gdiplus::Ok != mpBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, // TODO(F1): Adapt to + // Graphics native + // format/change + // getMemoryLayout + &aBmpData ) ) + { + // failed to lock, bail out + return uno::Sequence< sal_Int8 >(); + } + + mpBitmap->UnlockBits( &aBmpData ); + + return aRes; + } + + void DXBitmap::setData( const uno::Sequence< sal_Int8 >& data, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& rect ) + { + const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rect.X2-rect.X1; + aBmpData.Height = rect.Y2-rect.Y1; + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = (void*)data.getConstArray(); + + // TODO(F1): Support more pixel formats natively + + if( Gdiplus::Ok != mpBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, // TODO: Adapt to + // Graphics native + // format/change + // getMemoryLayout + &aBmpData ) ) + { + throw uno::RuntimeException(); + } + + // commit data to bitmap + mpBitmap->UnlockBits( &aBmpData ); + } + + void DXBitmap::setPixel( const uno::Sequence< sal_Int8 >& color, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& pos ) + { + const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width, + "CanvasHelper::setPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height, + "CanvasHelper::setPixel: Y coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( color.getLength() > 3, + "CanvasHelper::setPixel: not enough color components" ); + + if( Gdiplus::Ok != mpBitmap->SetPixel( pos.X, pos.Y, + Gdiplus::Color( tools::sequenceToArgb( color )))) + { + throw uno::RuntimeException(); + } + } + + uno::Sequence< sal_Int8 > DXBitmap::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& pos ) + { + const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width, + "CanvasHelper::getPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height, + "CanvasHelper::getPixel: Y coordinate out of bounds" ); + + Gdiplus::Color aColor; + + if( Gdiplus::Ok != mpBitmap->GetPixel( pos.X, pos.Y, &aColor ) ) + return uno::Sequence< sal_Int8 >(); + + return tools::argbToIntSequence(aColor.GetValue()); + } + +} + diff --git a/canvas/source/directx/dx_bitmap.hxx b/canvas/source/directx/dx_bitmap.hxx new file mode 100755 index 000000000000..5e767994e16c --- /dev/null +++ b/canvas/source/directx/dx_bitmap.hxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * 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 _DXCANVAS_DXBITMAP_HXX +#define _DXCANVAS_DXBITMAP_HXX + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <boost/shared_ptr.hpp> +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include "dx_winstuff.hxx" +#include "dx_ibitmap.hxx" +#include "dx_graphicsprovider.hxx" +#include "dx_gdiplususer.hxx" + +namespace dxcanvas +{ + class DXBitmap : public IBitmap + { + public: + DXBitmap( const BitmapSharedPtr& rBitmap, + bool bWithAlpha ); + DXBitmap( const ::basegfx::B2IVector& rSize, + bool bWithAlpha ); + + virtual GraphicsSharedPtr getGraphics(); + + virtual BitmapSharedPtr getBitmap() const; + virtual ::basegfx::B2IVector getSize() const; + virtual bool hasAlpha() const; + + ::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 ); + + private: + // Refcounted global GDI+ state container + GDIPlusUserSharedPtr mpGdiPlusUser; + + // size of this image in pixels [integral unit] + ::basegfx::B2IVector maSize; + + BitmapSharedPtr mpBitmap; + GraphicsSharedPtr mpGraphics; + + // true if the bitmap contains an alpha channel + bool mbAlpha; + }; + + typedef ::boost::shared_ptr< DXBitmap > DXBitmapSharedPtr; +} + +#endif diff --git a/canvas/source/directx/dx_bitmapcanvashelper.cxx b/canvas/source/directx/dx_bitmapcanvashelper.cxx new file mode 100755 index 000000000000..860b56401873 --- /dev/null +++ b/canvas/source/directx/dx_bitmapcanvashelper.cxx @@ -0,0 +1,246 @@ +/************************************************************************* + * + * 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 <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <comphelper/sequence.hxx> +#include <canvas/canvastools.hxx> + +#include "dx_spritecanvas.hxx" +#include "dx_impltools.hxx" +#include "dx_canvasfont.hxx" +#include "dx_textlayout.hxx" +#include "dx_bitmapcanvashelper.hxx" + +#include <algorithm> + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + BitmapCanvasHelper::BitmapCanvasHelper() : + mpTarget() + {} + + void BitmapCanvasHelper::disposing() + { + mpTarget.reset(); + CanvasHelper::disposing(); + } + + void BitmapCanvasHelper::setTarget( const IBitmapSharedPtr& rTarget ) + { + ENSURE_OR_THROW( rTarget, + "BitmapCanvasHelper::setTarget(): Invalid target" ); + ENSURE_OR_THROW( !mpTarget.get(), + "BitmapCanvasHelper::setTarget(): target set, old target would be overwritten" ); + + mpTarget = rTarget; + CanvasHelper::setTarget(rTarget); + } + + void BitmapCanvasHelper::setTarget( const IBitmapSharedPtr& rTarget, + const ::basegfx::B2ISize& rOutputOffset ) + { + ENSURE_OR_THROW( rTarget, + "BitmapCanvasHelper::setTarget(): invalid target" ); + ENSURE_OR_THROW( !mpTarget.get(), + "BitmapCanvasHelper::setTarget(): target set, old target would be overwritten" ); + + mpTarget = rTarget; + CanvasHelper::setTarget(rTarget,rOutputOffset); + } + + void BitmapCanvasHelper::clear() + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpTarget->getGraphics() ); + + Gdiplus::Color aClearColor = hasAlpha() ? + Gdiplus::Color( 0,255,255,255 ) : Gdiplus::Color((Gdiplus::ARGB)Gdiplus::Color::White); + + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->SetCompositingMode( + Gdiplus::CompositingModeSourceCopy ), // force set, don't blend + "BitmapCanvasHelper::clear(): GDI+ SetCompositingMode call failed" ); + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->Clear( aClearColor ), + "BitmapCanvasHelper::clear(): GDI+ Clear call failed" ); + } + } + + uno::Reference< rendering::XCachedPrimitive > BitmapCanvasHelper::drawTextLayout( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XTextLayout >& xLayoutetText, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xLayoutetText.is(), + "BitmapCanvasHelper::drawTextLayout: layout is NULL"); + + if( needOutput() ) + { + TextLayout* pTextLayout = + dynamic_cast< TextLayout* >( xLayoutetText.get() ); + + ENSURE_OR_THROW( pTextLayout, + "BitmapCanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" ); + + pTextLayout->draw( mpTarget->getGraphics(), + viewState, + renderState, + maOutputOffset, + mpDevice, + mpTarget->hasAlpha() ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + void BitmapCanvasHelper::copyRect( const rendering::XCanvas* /*pCanvas*/, + 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 BitmapCanvasHelper::getSize() + { + if( !mpTarget ) + return geometry::IntegerSize2D(1, 1); + + return basegfx::unotools::integerSize2DFromB2ISize(mpTarget->getSize()); + } + + uno::Reference< rendering::XBitmap > BitmapCanvasHelper::getScaledBitmap( const geometry::RealSize2D& /*newSize*/, + sal_Bool /*beFast*/ ) + { + // TODO(F1): + return uno::Reference< rendering::XBitmap >(); + } + + uno::Sequence< sal_Int8 > BitmapCanvasHelper::getData( rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerRectangle2D& rect ) + { + RTL_LOGFILE_CONTEXT( aLog, "::dxcanvas::BitmapCanvasHelper::getData()" ); + + ENSURE_OR_THROW( mpTarget, + "::dxcanvas::BitmapCanvasHelper::getData(): disposed" ); + + if( !mpTarget ) + return uno::Sequence< sal_Int8 >(); + + bitmapLayout = getMemoryLayout(); + return mpTarget->getData(bitmapLayout,rect); + } + + void BitmapCanvasHelper::setData( const uno::Sequence< sal_Int8 >& data, + const rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerRectangle2D& rect ) + { + RTL_LOGFILE_CONTEXT( aLog, "::dxcanvas::BitmapCanvasHelper::setData()" ); + + ENSURE_OR_THROW( mpTarget, + "::dxcanvas::BitmapCanvasHelper::setData(): disposed" ); + + if( !mpTarget ) + return; + + mpTarget->setData(data,bitmapLayout,rect); + } + + void BitmapCanvasHelper::setPixel( const uno::Sequence< sal_Int8 >& color, + const rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerPoint2D& pos ) + { + RTL_LOGFILE_CONTEXT( aLog, "::dxcanvas::BitmapCanvasHelper::setPixel()" ); + + ENSURE_OR_THROW( mpTarget, + "::dxcanvas::BitmapCanvasHelper::setPixel(): disposed" ); + + if( !mpTarget ) + return; + + mpTarget->setPixel(color,bitmapLayout,pos); + } + + uno::Sequence< sal_Int8 > BitmapCanvasHelper::getPixel( rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerPoint2D& pos ) + { + RTL_LOGFILE_CONTEXT( aLog, "::dxcanvas::BitmapCanvasHelper::getPixel()" ); + + ENSURE_OR_THROW( mpTarget, + "::dxcanvas::BitmapCanvasHelper::getPixel(): disposed" ); + + if( !mpTarget ) + return uno::Sequence< sal_Int8 >(); + + bitmapLayout = getMemoryLayout(); + return mpTarget->getPixel(bitmapLayout,pos); + } + + uno::Reference< rendering::XBitmapPalette > BitmapCanvasHelper::getPalette() + { + // TODO(F1): Palette bitmaps NYI + return uno::Reference< rendering::XBitmapPalette >(); + } + + rendering::IntegerBitmapLayout BitmapCanvasHelper::getMemoryLayout() + { + if( !mpTarget ) + return rendering::IntegerBitmapLayout(); // we're disposed + + return ::canvas::tools::getStdMemoryLayout(getSize()); + } + bool BitmapCanvasHelper::hasAlpha() const + { + return mpTarget ? mpTarget->hasAlpha() : false; + } +} diff --git a/canvas/source/directx/dx_bitmapcanvashelper.hxx b/canvas/source/directx/dx_bitmapcanvashelper.hxx new file mode 100755 index 000000000000..411d8764dfc7 --- /dev/null +++ b/canvas/source/directx/dx_bitmapcanvashelper.hxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * 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 _DXCANVAS_BITMAPCANVASHELPER_HXX_ +#define _DXCANVAS_BITMAPCANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/vector/b2dsize.hxx> + +#include "dx_graphicsprovider.hxx" +#include "dx_ibitmap.hxx" +#include "dx_gdiplususer.hxx" +#include "dx_impltools.hxx" +#include "dx_canvashelper.hxx" + +#include <boost/utility.hpp> + + +namespace dxcanvas +{ + /** Helper class for basic canvas functionality. Also offers + optional backbuffer painting, when providing it with a second + HDC to render into. + */ + class BitmapCanvasHelper : public CanvasHelper + { + public: + BitmapCanvasHelper(); + + /// Release all references + void disposing(); + + /** Set the target for rendering operations + + @param rTarget + Render target + */ + void setTarget( const IBitmapSharedPtr& rTarget ); + + /** Set the target for rendering operations + + @param rTarget + Render target + + @param rOutputOffset + Output offset in pixel + */ + void setTarget( const IBitmapSharedPtr& rTarget, + const ::basegfx::B2ISize& rOutputOffset ); + + + // CanvasHelper functionality is implementation-inherited. yuck. + // ============================================================= + void clear(); + + ::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 ); + + // 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(); + + bool hasAlpha() const; + + protected: + /// Render target + IBitmapSharedPtr mpTarget; + }; +} + +#endif /* _DXCANVAS_BITMAPCANVASHELPER_HXX_ */ diff --git a/canvas/source/directx/dx_bitmapprovider.hxx b/canvas/source/directx/dx_bitmapprovider.hxx new file mode 100644 index 000000000000..3eccf3c4939e --- /dev/null +++ b/canvas/source/directx/dx_bitmapprovider.hxx @@ -0,0 +1,45 @@ +/************************************************************************* + * + * 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 _DXCANVAS_BITMAPPROVIDER_HXX_ +#define _DXCANVAS_BITMAPPROVIDER_HXX_ + +#include "dx_ibitmap.hxx" +#include <boost/shared_ptr.hpp> + +namespace dxcanvas +{ + struct BitmapProvider + { + virtual ~BitmapProvider() {} + virtual IBitmapSharedPtr getBitmap() const = 0; + }; + + typedef boost::shared_ptr<BitmapProvider> BitmapProviderSharedPtr; +} + +#endif diff --git a/canvas/source/directx/dx_canvas.cxx b/canvas/source/directx/dx_canvas.cxx new file mode 100644 index 000000000000..f55467c1af50 --- /dev/null +++ b/canvas/source/directx/dx_canvas.cxx @@ -0,0 +1,255 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#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/awt/XWindow.hpp> +#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp> +#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 <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <comphelper/servicedecl.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include "dx_graphicsprovider.hxx" +#include "dx_winstuff.hxx" +#include "dx_canvas.hxx" + +#include <vcl/sysdata.hxx> + +#define CANVAS_TECH "GDI+" +#define CANVAS_SERVICE_NAME "com.sun.star.rendering.Canvas." CANVAS_TECH +#define CANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.Canvas." CANVAS_TECH +#define BITMAPCANVAS_SERVICE_NAME "com.sun.star.rendering.BitmapCanvas." CANVAS_TECH +#define BITMAPCANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.BitmapCanvas." CANVAS_TECH + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + /// Actual canonical implementation of the GraphicsProvider interface + class GraphicsProviderImpl : public GraphicsProvider + { + GraphicsSharedPtr mpGraphics; + public: + explicit GraphicsProviderImpl( Gdiplus::Graphics* pGraphics ) : mpGraphics( pGraphics ) {} + virtual GraphicsSharedPtr getGraphics() { return mpGraphics; } + }; + + 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; + + VERBOSE_TRACE( "Canvas::initialize called" ); + + // At index 1, we expect a HWND handle here, containing a + // pointer to a valid window, on which to output + // At index 2, we expect the current window bound rect + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 6 && + maArguments[5].getValueTypeClass() == uno::TypeClass_SEQUENCE, + "SpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + uno::Sequence<sal_Int8> aSeq; + maArguments[5] >>= aSeq; + + const SystemGraphicsData* pSysData=reinterpret_cast<const SystemGraphicsData*>(aSeq.getConstArray()); + if( !pSysData || !pSysData->hDC ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed SystemGraphicsData or HDC invalid!")), + NULL); + + // setup helper + maDeviceHelper.init( pSysData->hDC, + *this ); + maCanvasHelper.setDevice( *this ); + maCanvasHelper.setTarget( + GraphicsProviderSharedPtr( + new GraphicsProviderImpl( + Gdiplus::Graphics::FromHDC(pSysData->hDC)))); + + maArguments.realloc(0); + } + + 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 ) ); + } + + BitmapCanvas::BitmapCanvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ), + mpTarget() + { + } + + void BitmapCanvas::initialize() + { + // #i64742# Only perform initialization when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + VERBOSE_TRACE( "BitmapCanvas::initialize called" ); + + // At index 1, we expect a HWND handle here, containing a + // pointer to a valid window, on which to output + // At index 2, we expect the current window bound rect + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 6 && + maArguments[5].getValueTypeClass() == uno::TypeClass_SEQUENCE, + "SpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + uno::Sequence<sal_Int8> aSeq; + maArguments[5] >>= aSeq; + + const SystemGraphicsData* pSysData=reinterpret_cast<const SystemGraphicsData*>(aSeq.getConstArray()); + if( !pSysData || !pSysData->hDC ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed SystemGraphicsData or HDC invalid!")), + NULL); + + // setup helper + maDeviceHelper.init( pSysData->hDC, + *this ); + maCanvasHelper.setDevice( *this ); + + // check whether we can actually provide a BitmapCanvas + // here. for this, check whether the HDC has a bitmap + // selected. + HBITMAP hBmp; + hBmp=(HBITMAP)GetCurrentObject(pSysData->hDC, OBJ_BITMAP); + if( !hBmp || GetObjectType(pSysData->hDC) != OBJ_MEMDC ) + { + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed HDC is no mem DC/has no bitmap selected!")), + NULL); + } + + mpTarget.reset( new DXBitmap( + BitmapSharedPtr( + Gdiplus::Bitmap::FromHBITMAP( + hBmp, 0) ), + false )); + + maCanvasHelper.setTarget( mpTarget ); + + maArguments.realloc(0); + } + + void SAL_CALL BitmapCanvas::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpTarget.reset(); + mxComponentContext.clear(); + + // forward to parent + BitmapCanvasBaseT::disposing(); + } + + ::rtl::OUString SAL_CALL BitmapCanvas::getServiceName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( BITMAPCANVAS_SERVICE_NAME ) ); + } + + IBitmapSharedPtr BitmapCanvas::getBitmap() const + { + return mpTarget; + } + + 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 dxCanvasDecl( + serviceImpl1, + CANVAS_IMPLEMENTATION_NAME, + CANVAS_SERVICE_NAME ); + + static uno::Reference<uno::XInterface> initBitmapCanvas( BitmapCanvas* pCanvas ) + { + uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas)); + pCanvas->initialize(); + return xRet; + } + + namespace sdecl = comphelper::service_decl; + sdecl::class_<BitmapCanvas, sdecl::with_args<true> > serviceImpl2(&initBitmapCanvas); + const sdecl::ServiceDecl dxBitmapCanvasDecl( + serviceImpl2, + BITMAPCANVAS_IMPLEMENTATION_NAME, + BITMAPCANVAS_SERVICE_NAME ); +} + +// The C shared lib entry points +COMPHELPER_SERVICEDECL_EXPORTS2(dxcanvas::dxCanvasDecl, + dxcanvas::dxBitmapCanvasDecl); diff --git a/canvas/source/directx/dx_canvas.hxx b/canvas/source/directx/dx_canvas.hxx new file mode 100644 index 000000000000..be15b875c4b6 --- /dev/null +++ b/canvas/source/directx/dx_canvas.hxx @@ -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. + * + ************************************************************************/ + +#ifndef _DXCANVAS_CANVAS_HXX_ +#define _DXCANVAS_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/XServiceName.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.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 <cppuhelper/compbase6.hxx> +#include <comphelper/uno3.hxx> + +#include <canvas/base/integerbitmapbase.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/graphicdevicebase.hxx> + +#include "dx_bitmapprovider.hxx" +#include "dx_canvashelper.hxx" +#include "dx_bitmapcanvashelper.hxx" +#include "dx_impltools.hxx" +#include "dx_devicehelper.hxx" + + +namespace dxcanvas +{ + typedef ::cppu::WeakComponentImplHelper6< ::com::sun::star::rendering::XCanvas, + ::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 > GraphicDeviceBase1_Base; + typedef ::canvas::GraphicDeviceBase< ::canvas::BaseMutexHelper< GraphicDeviceBase1_Base >, + DeviceHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBase1_Base; + typedef ::canvas::CanvasBase< CanvasBase1_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: + 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(); + + /// 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, GraphicDeviceBase1_Base, ::cppu::WeakComponentImplHelperBase ); + + // XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (::com::sun::star::uno::RuntimeException); + + 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; + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + 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 > GraphicDeviceBase2_Base; + typedef ::canvas::GraphicDeviceBase< ::canvas::BaseMutexHelper< GraphicDeviceBase2_Base >, + DeviceHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBase2_Base; + typedef ::canvas::IntegerBitmapBase< CanvasBase2_Base, + BitmapCanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > BitmapCanvasBaseT; + + /** 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 BitmapCanvas : public BitmapCanvasBaseT, public BitmapProvider + { + public: + BitmapCanvas( 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(); + + /// 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( BitmapCanvas, GraphicDeviceBase2_Base, ::cppu::WeakComponentImplHelperBase ); + + // XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (::com::sun::star::uno::RuntimeException); + + // BitmapProvider + virtual IBitmapSharedPtr getBitmap() const; + + private: + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > maArguments; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > mxComponentContext; + IBitmapSharedPtr mpTarget; + }; + + typedef ::rtl::Reference< BitmapCanvas > BitmapCanvasRef; +} + +#endif diff --git a/canvas/source/directx/dx_canvasbitmap.cxx b/canvas/source/directx/dx_canvasbitmap.cxx new file mode 100755 index 000000000000..f15af7745422 --- /dev/null +++ b/canvas/source/directx/dx_canvasbitmap.cxx @@ -0,0 +1,277 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <vcl/bitmapex.hxx> + +#include <boost/preprocessor/repetition.hpp> +#include <boost/preprocessor/iteration/local.hpp> +#include <boost/scoped_array.hpp> + +#include "dx_canvasbitmap.hxx" +#include "dx_impltools.hxx" + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + CanvasBitmap::CanvasBitmap( const IBitmapSharedPtr& rBitmap, + const DeviceRef& rDevice ) : + mpDevice( rDevice ), + mpBitmap( rBitmap ) + { + ENSURE_OR_THROW( mpDevice.is() && mpBitmap, + "CanvasBitmap::CanvasBitmap(): Invalid surface or device" ); + + maCanvasHelper.setDevice( *mpDevice.get() ); + maCanvasHelper.setTarget( mpBitmap ); + } + + void SAL_CALL CanvasBitmap::disposing() + { + mpBitmap.reset(); + mpDevice.clear(); + + // forward to parent + CanvasBitmap_Base::disposing(); + } + + struct AlphaDIB + { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; + }; + + uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle ) throw (uno::RuntimeException) + { + uno::Any aRes; + // 0 ... get BitmapEx + // 1 ... get Pixbuf with bitmap RGB content + // 2 ... get Pixbuf with bitmap alpha mask + switch( nHandle ) + { + // sorry, no BitmapEx here... + case 0: + aRes = ::com::sun::star::uno::Any( reinterpret_cast<sal_Int64>( (BitmapEx*) NULL ) ); + break; + + case 1: + { + if(!mpBitmap->hasAlpha()) + { + HBITMAP aHBmp; + mpBitmap->getBitmap()->GetHBITMAP(Gdiplus::Color(), &aHBmp ); + + uno::Sequence< uno::Any > args(1); + args[0] = uno::Any( sal_Int64(aHBmp) ); + + aRes <<= args; + } + else + { + // need to copy&convert the bitmap, since dx + // canvas uses inline alpha channel + HDC hScreenDC=GetDC(NULL); + const basegfx::B2IVector aSize(mpBitmap->getSize()); + HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, + aSize.getX(), + aSize.getY() ); + if( !hBmpBitmap ) + return aRes; + + BITMAPINFOHEADER aBIH; + + aBIH.biSize = sizeof( BITMAPINFOHEADER ); + aBIH.biWidth = aSize.getX(); + aBIH.biHeight = -aSize.getY(); + aBIH.biPlanes = 1; + aBIH.biBitCount = 32; + aBIH.biCompression = BI_RGB; // expects pixel in + // bbggrrxx format + // (little endian) + aBIH.biSizeImage = 0; + aBIH.biXPelsPerMeter = 0; + aBIH.biYPelsPerMeter = 0; + aBIH.biClrUsed = 0; + aBIH.biClrImportant = 0; + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = aSize.getX(); + aBmpData.Height = aSize.getY(); + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = NULL; + const Gdiplus::Rect aRect( 0,0,aSize.getX(),aSize.getY() ); + BitmapSharedPtr pGDIPlusBitmap=mpBitmap->getBitmap(); + if( Gdiplus::Ok != pGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead, + PixelFormat32bppARGB, // outputs ARGB (big endian) + &aBmpData ) ) + { + // failed to lock, bail out + return aRes; + } + + // now aBmpData.Scan0 contains our bits - push + // them into HBITMAP, ignoring alpha + SetDIBits( hScreenDC, hBmpBitmap, 0, aSize.getY(), aBmpData.Scan0, (PBITMAPINFO)&aBIH, DIB_RGB_COLORS ); + + pGDIPlusBitmap->UnlockBits( &aBmpData ); + + uno::Sequence< uno::Any > args(1); + args[0] = uno::Any( sal_Int64(hBmpBitmap) ); + + aRes <<= args; + } + } + break; + + case 2: + { + if(!mpBitmap->hasAlpha()) + { + return aRes; + } + else + { + static AlphaDIB aDIB= + { + {0,0,0,1,8,BI_RGB,0,0,0,0,0}, + { + // this here fills palette with grey + // level colors, starting from 0,0,0 + // up to 255,255,255 +#define BOOST_PP_LOCAL_MACRO(n_) \ + BOOST_PP_COMMA_IF(n_) \ + {n_,n_,n_,n_} +#define BOOST_PP_LOCAL_LIMITS (0, 255) +#include BOOST_PP_LOCAL_ITERATE() + } + }; + + // need to copy&convert the bitmap, since dx + // canvas uses inline alpha channel + HDC hScreenDC=GetDC(NULL); + const basegfx::B2IVector aSize(mpBitmap->getSize()); + HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC, aSize.getX(), aSize.getY() ); + if( !hBmpBitmap ) + return aRes; + + aDIB.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); + aDIB.bmiHeader.biWidth = aSize.getX(); + aDIB.bmiHeader.biHeight = -aSize.getY(); + aDIB.bmiHeader.biPlanes = 1; + aDIB.bmiHeader.biBitCount = 8; + aDIB.bmiHeader.biCompression = BI_RGB; + aDIB.bmiHeader.biSizeImage = 0; + aDIB.bmiHeader.biXPelsPerMeter = 0; + aDIB.bmiHeader.biYPelsPerMeter = 0; + aDIB.bmiHeader.biClrUsed = 0; + aDIB.bmiHeader.biClrImportant = 0; + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = aSize.getX(); + aBmpData.Height = aSize.getY(); + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = NULL; + const Gdiplus::Rect aRect( 0,0,aSize.getX(),aSize.getY() ); + BitmapSharedPtr pGDIPlusBitmap=mpBitmap->getBitmap(); + if( Gdiplus::Ok != pGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead, + PixelFormat32bppARGB, // outputs ARGB (big endian) + &aBmpData ) ) + { + // failed to lock, bail out + return aRes; + } + + // copy only alpha channel to pAlphaBits + const sal_Int32 nScanWidth((aSize.getX() + 3) & ~3); + boost::scoped_array<sal_uInt8> pAlphaBits( new sal_uInt8[nScanWidth*aSize.getY()] ); + const sal_uInt8* pInBits=(sal_uInt8*)aBmpData.Scan0; + pInBits+=3; + sal_uInt8* pOutBits; + for( sal_Int32 y=0; y<aSize.getY(); ++y ) + { + pOutBits=pAlphaBits.get()+y*nScanWidth; + for( sal_Int32 x=0; x<aSize.getX(); ++x ) + { + *pOutBits++ = 255-*pInBits; + pInBits += 4; + } + } + + pGDIPlusBitmap->UnlockBits( &aBmpData ); + + // set bits to newly create HBITMAP + SetDIBits( hScreenDC, hBmpBitmap, 0, + aSize.getY(), pAlphaBits.get(), + (PBITMAPINFO)&aDIB, DIB_RGB_COLORS ); + + uno::Sequence< uno::Any > args(1); + args[0] = uno::Any( sal_Int64(hBmpBitmap) ); + + aRes <<= args; + } + } + break; + } + + return aRes; + } + +#define IMPLEMENTATION_NAME "DXCanvas.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/directx/dx_canvasbitmap.hxx b/canvas/source/directx/dx_canvasbitmap.hxx new file mode 100755 index 000000000000..75800f3c8abd --- /dev/null +++ b/canvas/source/directx/dx_canvasbitmap.hxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * 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 _DXCANVAS_CANVASBITMAP_HXX +#define _DXCANVAS_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 <basegfx/vector/b2isize.hxx> + +#include <boost/shared_ptr.hpp> + +#include <cppuhelper/compbase3.hxx> +#include <comphelper/uno3.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/integerbitmapbase.hxx> + +#include "dx_bitmapprovider.hxx" +#include "dx_bitmapcanvashelper.hxx" +#include "dx_devicehelper.hxx" +#include "dx_impltools.hxx" +#include "dx_ibitmap.hxx" + + +/* Definition of CanvasBitmap class */ + +namespace dxcanvas +{ + 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; + typedef ::canvas::IntegerBitmapBase< ::canvas::BaseMutexHelper< CanvasBitmapBase_Base >, + BitmapCanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBitmap_Base; + + class CanvasBitmap : public CanvasBitmap_Base, public BitmapProvider + { + public: + /** Create a canvas bitmap for the given surface + + @param rSurface + Surface to create API object for. + + @param rDevice + Reference device, with which bitmap should be compatible + */ + CanvasBitmap( const IBitmapSharedPtr& rSurface, + const DeviceRef& rDevice ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // 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); + + // BitmapProvider + virtual IBitmapSharedPtr getBitmap() const { return mpBitmap; } + + 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: + /** MUST hold here, too, since CanvasHelper only contains a + raw pointer (without refcounting) + */ + DeviceRef mpDevice; + IBitmapSharedPtr mpBitmap; + }; +} + +#endif /* _DXCANVAS_CANVASBITMAP_HXX */ diff --git a/canvas/source/directx/dx_canvascustomsprite.cxx b/canvas/source/directx/dx_canvascustomsprite.cxx new file mode 100755 index 000000000000..9c8309d5e39f --- /dev/null +++ b/canvas/source/directx/dx_canvascustomsprite.cxx @@ -0,0 +1,123 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#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 "dx_canvascustomsprite.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_impltools.hxx" + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + CanvasCustomSprite::CanvasCustomSprite( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rRefDevice, + const IDXRenderModuleSharedPtr& rRenderModule, + const ::canvas::ISurfaceProxyManagerSharedPtr& rSurfaceProxy, + bool bShowSpriteBounds ) : + mpSpriteCanvas( rRefDevice ), + mpSurface() + { + ENSURE_OR_THROW( rRefDevice.get(), + "CanvasCustomSprite::CanvasCustomSprite(): Invalid sprite canvas" ); + + mpSurface.reset( + new DXSurfaceBitmap( + ::basegfx::B2IVector( + ::canvas::tools::roundUp( rSpriteSize.Width ), + ::canvas::tools::roundUp( rSpriteSize.Height )), + rSurfaceProxy, + rRenderModule, + true)); + + maCanvasHelper.setDevice( *rRefDevice.get() ); + maCanvasHelper.setTarget( mpSurface ); + + maSpriteHelper.init( rSpriteSize, + rRefDevice, + rRenderModule, + mpSurface, + bShowSpriteBounds ); + + // clear sprite to 100% transparent + maCanvasHelper.clear(); + } + + void SAL_CALL CanvasCustomSprite::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpSurface.reset(); + mpSpriteCanvas.clear(); + + // forward to parent + CanvasCustomSpriteBaseT::disposing(); + } + +#define IMPLEMENTATION_NAME "DXCanvas.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; + } + + void CanvasCustomSprite::redraw() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + maSpriteHelper.redraw( mbSurfaceDirty ); + } +} diff --git a/canvas/source/directx/dx_canvascustomsprite.hxx b/canvas/source/directx/dx_canvascustomsprite.hxx new file mode 100755 index 000000000000..be83b26e1b52 --- /dev/null +++ b/canvas/source/directx/dx_canvascustomsprite.hxx @@ -0,0 +1,139 @@ +/************************************************************************* + * + * 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 _DXCANVAS_CANVASCUSTOMSPRITE_HXX +#define _DXCANVAS_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 "dx_sprite.hxx" +#include "dx_surfacebitmap.hxx" +#include "dx_bitmapcanvashelper.hxx" +#include "dx_spritehelper.hxx" +#include "dx_spritecanvas.hxx" + + +namespace dxcanvas +{ + 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 + { + }; + + typedef ::canvas::CanvasCustomSpriteBase< CanvasCustomSpriteSpriteBase_Base, + SpriteHelper, + BitmapCanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasCustomSpriteBaseT; + + /* Definition of CanvasCustomSprite class */ + + class CanvasCustomSprite : public CanvasCustomSpriteBaseT + { + 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, + const IDXRenderModuleSharedPtr& rRenderModule, + const ::canvas::ISurfaceProxyManagerSharedPtr& rSurfaceProxy, + bool bShowSpriteBounds ); + + 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; + + private: + /** MUST hold here, too, since BitmapCanvasHelper only contains a + raw pointer (without refcounting) + */ + SpriteCanvasRef mpSpriteCanvas; + DXSurfaceBitmapSharedPtr mpSurface; + }; +} + +#endif /* _DXCANVAS_CANVASCUSTOMSPRITE_HXX */ diff --git a/canvas/source/directx/dx_canvasfont.cxx b/canvas/source/directx/dx_canvasfont.cxx new file mode 100755 index 000000000000..d87079b34c0f --- /dev/null +++ b/canvas/source/directx/dx_canvasfont.cxx @@ -0,0 +1,180 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#include "dx_winstuff.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_canvasfont.hxx" +#include "dx_textlayout.hxx" + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/PanoseWeight.hpp> + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + INT calcFontStyle( const rendering::FontRequest& rFontRequest ) + { + INT nFontStyle( Gdiplus::FontStyleRegular ); + + if( rFontRequest.FontDescription.FontDescription.Weight > rendering::PanoseWeight::BOOK ) + nFontStyle = Gdiplus::FontStyleBold; + + return nFontStyle; + } + } + + CanvasFont::CanvasFont( const rendering::FontRequest& rFontRequest, + const uno::Sequence< beans::PropertyValue >& /*extraFontProperties*/, + const geometry::Matrix2D& fontMatrix ) : + CanvasFont_Base( m_aMutex ), + mpGdiPlusUser( GDIPlusUser::createInstance() ), + // TODO(F1): extraFontProperties, fontMatrix + mpFontFamily(), + mpFont(), + maFontRequest( rFontRequest ), + maFontMatrix( fontMatrix ) + { + const sal_Int32 nLen(rFontRequest.FontDescription.FamilyName.getLength()); + const sal_Unicode* pStr(rFontRequest.FontDescription.FamilyName.getStr()); + std::vector< sal_Unicode > pStrBuf(nLen+1,0); + std::copy(pStr,pStr+nLen,&pStrBuf[0]); + + mpFontFamily.reset( new Gdiplus::FontFamily(reinterpret_cast<LPCWSTR>(&pStrBuf[0]),NULL) ); + if( !mpFontFamily->IsAvailable() ) + mpFontFamily.reset( new Gdiplus::FontFamily(L"Arial",NULL) ); + + mpFont.reset( new Gdiplus::Font( mpFontFamily.get(), + static_cast<Gdiplus::REAL>(rFontRequest.CellSize), + calcFontStyle( rFontRequest ), + Gdiplus::UnitWorld )); + } + + void SAL_CALL CanvasFont::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpFont.reset(); + mpFontFamily.reset(); + mpGdiPlusUser.reset(); + } + + uno::Reference< rendering::XTextLayout > SAL_CALL CanvasFont::createTextLayout( const rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 nRandomSeed ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return new TextLayout( aText, nDirection, nRandomSeed, ImplRef( this ) ); + } + + uno::Sequence< double > SAL_CALL CanvasFont::getAvailableSizes( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< double >(); + } + + uno::Sequence< beans::PropertyValue > SAL_CALL CanvasFont::getExtraFontProperties( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< beans::PropertyValue >(); + } + + rendering::FontRequest SAL_CALL CanvasFont::getFontRequest( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maFontRequest; + } + + rendering::FontMetrics SAL_CALL CanvasFont::getFontMetrics( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return rendering::FontMetrics(); + } + +#define SERVICE_NAME "com.sun.star.rendering.CanvasFont" +#define IMPLEMENTATION_NAME "DXCanvas::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; + } + + double CanvasFont::getCellAscent() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mpFontFamily->GetCellAscent(0); // TODO(F1): rFontRequest.styleName + } + + double CanvasFont::getEmHeight() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mpFontFamily->GetEmHeight(0); // TODO(F1): rFontRequest.styleName + } + + FontSharedPtr CanvasFont::getFont() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mpFont; + } + + const ::com::sun::star::geometry::Matrix2D& CanvasFont::getFontMatrix() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maFontMatrix; + } +} diff --git a/canvas/source/directx/dx_canvasfont.hxx b/canvas/source/directx/dx_canvasfont.hxx new file mode 100755 index 000000000000..4a6c8b779ad0 --- /dev/null +++ b/canvas/source/directx/dx_canvasfont.hxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * 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 _DXCANVAS_CANVASFONT_HXX +#define _DXCANVAS_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/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> + +#include <rtl/ref.hxx> + +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +#include "dx_winstuff.hxx" +#include "dx_gdiplususer.hxx" + + +/* Definition of CanvasFont class */ + +namespace dxcanvas +{ + class SpriteCanvas; + + typedef ::boost::shared_ptr< Gdiplus::Font > FontSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::FontFamily > FontFamilySharedPtr; + + 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 > ImplRef; + + 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& fontMatrix ); + + /// 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 ); + + double getCellAscent() const; + double getEmHeight() const; + FontSharedPtr getFont() const; + const ::com::sun::star::geometry::Matrix2D& getFontMatrix() const; + + private: + GDIPlusUserSharedPtr mpGdiPlusUser; + FontFamilySharedPtr mpFontFamily; + FontSharedPtr mpFont; + ::com::sun::star::rendering::FontRequest maFontRequest; + ::com::sun::star::geometry::Matrix2D maFontMatrix; + }; + +} + +#endif /* _DXCANVAS_CANVASFONT_HXX */ diff --git a/canvas/source/directx/dx_canvashelper.cxx b/canvas/source/directx/dx_canvashelper.cxx new file mode 100755 index 000000000000..866cc0f03ec3 --- /dev/null +++ b/canvas/source/directx/dx_canvashelper.cxx @@ -0,0 +1,814 @@ +/************************************************************************* + * + * 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 <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include <comphelper/sequence.hxx> +#include <canvas/canvastools.hxx> + +#include "dx_spritecanvas.hxx" +#include "dx_impltools.hxx" +#include "dx_vcltools.hxx" +#include "dx_canvasfont.hxx" +#include "dx_textlayout.hxx" +#include "dx_canvashelper.hxx" + +#include <algorithm> + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + Gdiplus::LineCap gdiCapFromCap( sal_Int8 nCapType ) + { + switch( nCapType ) + { + case rendering::PathCapType::BUTT: + return Gdiplus::LineCapFlat; + + case rendering::PathCapType::ROUND: + return Gdiplus::LineCapRound; + + case rendering::PathCapType::SQUARE: + return Gdiplus::LineCapSquare; + + default: + ENSURE_OR_THROW( false, + "gdiCapFromCap(): Unexpected cap type" ); + } + + return Gdiplus::LineCapFlat; + } + + Gdiplus::LineJoin gdiJoinFromJoin( sal_Int8 nJoinType ) + { + switch( nJoinType ) + { + case rendering::PathJoinType::NONE: + OSL_ENSURE( false, + "gdiJoinFromJoin(): Join NONE not possible, mapping to MITER" ); + // FALLTHROUGH intended + case rendering::PathJoinType::MITER: + return Gdiplus::LineJoinMiter; + + case rendering::PathJoinType::ROUND: + return Gdiplus::LineJoinRound; + + case rendering::PathJoinType::BEVEL: + return Gdiplus::LineJoinBevel; + + default: + ENSURE_OR_THROW( false, + "gdiJoinFromJoin(): Unexpected join type" ); + } + + return Gdiplus::LineJoinMiter; + } + } + + CanvasHelper::CanvasHelper() : + mpGdiPlusUser( GDIPlusUser::createInstance() ), + mpDevice( NULL ), + mpGraphicsProvider(), + maOutputOffset() + { + } + + void CanvasHelper::disposing() + { + mpGraphicsProvider.reset(); + mpDevice = NULL; + mpGdiPlusUser.reset(); + } + + void CanvasHelper::setDevice( rendering::XGraphicDevice& rDevice ) + { + mpDevice = &rDevice; + } + + void CanvasHelper::setTarget( const GraphicsProviderSharedPtr& rTarget ) + { + ENSURE_OR_THROW( rTarget, + "CanvasHelper::setTarget(): Invalid target" ); + ENSURE_OR_THROW( !mpGraphicsProvider.get(), + "CanvasHelper::setTarget(): target set, old target would be overwritten" ); + + mpGraphicsProvider = rTarget; + } + + void CanvasHelper::setTarget( const GraphicsProviderSharedPtr& rTarget, + const ::basegfx::B2ISize& rOutputOffset ) + { + ENSURE_OR_THROW( rTarget, + "CanvasHelper::setTarget(): invalid target" ); + ENSURE_OR_THROW( !mpGraphicsProvider.get(), + "CanvasHelper::setTarget(): target set, old target would be overwritten" ); + + mpGraphicsProvider = rTarget; + maOutputOffset = rOutputOffset; + } + + void CanvasHelper::clear() + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + Gdiplus::Color aClearColor = Gdiplus::Color((Gdiplus::ARGB)Gdiplus::Color::White); + + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->SetCompositingMode( + Gdiplus::CompositingModeSourceCopy ), // force set, don't blend + "CanvasHelper::clear(): GDI+ SetCompositingMode call failed" ); + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->Clear( aClearColor ), + "CanvasHelper::clear(): GDI+ Clear call failed" ); + } + } + + void CanvasHelper::drawPoint( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealPoint2D& aPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::SolidBrush aBrush( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)) ); + + // determine size of one-by-one device pixel ellipse + Gdiplus::Matrix aMatrix; + pGraphics->GetTransform(&aMatrix); + aMatrix.Invert(); + Gdiplus::PointF vector(1, 1); + aMatrix.TransformVectors(&vector); + + // paint a one-by-one circle, with the given point + // in the middle (rounded to float) + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->FillEllipse( &aBrush, + // disambiguate call + Gdiplus::REAL(aPoint.X), + Gdiplus::REAL(aPoint.Y), + Gdiplus::REAL(vector.X), + Gdiplus::REAL(vector.Y) ), + "CanvasHelper::drawPoint(): GDI+ call failed" ); + } + } + + void CanvasHelper::drawLine( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealPoint2D& aStartPoint, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::Pen aPen( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)), + Gdiplus::REAL(0.0) ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + const Gdiplus::PixelOffsetMode aOldMode( + pGraphics->GetPixelOffsetMode() ); + pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + Gdiplus::Status hr = pGraphics->DrawLine( &aPen, + Gdiplus::REAL(aStartPoint.X), // disambiguate call + Gdiplus::REAL(aStartPoint.Y), + Gdiplus::REAL(aEndPoint.X), + Gdiplus::REAL(aEndPoint.Y) ); + pGraphics->SetPixelOffsetMode( aOldMode ); + + ENSURE_OR_THROW( + Gdiplus::Ok == hr, + "CanvasHelper::drawLine(): GDI+ call failed" ); + } + } + + void CanvasHelper::drawBezier( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealBezierSegment2D& aBezierSegment, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::Pen aPen( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)), + Gdiplus::REAL(0.0) ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + const Gdiplus::PixelOffsetMode aOldMode( + pGraphics->GetPixelOffsetMode() ); + pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + Gdiplus::Status hr = pGraphics->DrawBezier( &aPen, + Gdiplus::REAL(aBezierSegment.Px), // disambiguate call + Gdiplus::REAL(aBezierSegment.Py), + Gdiplus::REAL(aBezierSegment.C1x), + Gdiplus::REAL(aBezierSegment.C1y), + Gdiplus::REAL(aEndPoint.X), + Gdiplus::REAL(aEndPoint.Y), + Gdiplus::REAL(aBezierSegment.C2x), + Gdiplus::REAL(aBezierSegment.C2y) ); + + pGraphics->SetPixelOffsetMode( aOldMode ); + + ENSURE_OR_THROW( + Gdiplus::Ok == hr, + "CanvasHelper::drawBezier(): GDI+ call failed" ); + } + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::drawPolyPolygon: polygon is NULL"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::Pen aPen( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)), + Gdiplus::REAL(0.0) ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + const Gdiplus::PixelOffsetMode aOldMode( + pGraphics->GetPixelOffsetMode() ); + pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) ); + + // TODO(E1): Return value + Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() ); + + pGraphics->SetPixelOffsetMode( aOldMode ); + + ENSURE_OR_THROW( + Gdiplus::Ok == hr, + "CanvasHelper::drawPolyPolygon(): GDI+ call failed" ); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::StrokeAttributes& strokeAttributes ) + { + ENSURE_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::drawPolyPolygon: polygon is NULL"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + + // Setup stroke pen + // ---------------- + + Gdiplus::Pen aPen( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor)), + static_cast< Gdiplus::REAL >(strokeAttributes.StrokeWidth) ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + const Gdiplus::PixelOffsetMode aOldMode( + pGraphics->GetPixelOffsetMode() ); + pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + const bool bIsMiter(rendering::PathJoinType::MITER == strokeAttributes.JoinType); + const bool bIsNone(rendering::PathJoinType::NONE == strokeAttributes.JoinType); + + if(bIsMiter) + aPen.SetMiterLimit( static_cast< Gdiplus::REAL >(strokeAttributes.MiterLimit) ); + + const ::std::vector< Gdiplus::REAL >& rDashArray( + ::comphelper::sequenceToContainer< ::std::vector< Gdiplus::REAL > >( + strokeAttributes.DashArray ) ); + if( !rDashArray.empty() ) + { + aPen.SetDashPattern( &rDashArray[0], + rDashArray.size() ); + } + aPen.SetLineCap( gdiCapFromCap(strokeAttributes.StartCapType), + gdiCapFromCap(strokeAttributes.EndCapType), + Gdiplus::DashCapFlat ); + if(!bIsNone) + aPen.SetLineJoin( gdiJoinFromJoin(strokeAttributes.JoinType) ); + + GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon, bIsNone ) ); + + // TODO(E1): Return value + Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() ); + + pGraphics->SetPixelOffsetMode( aOldMode ); + + ENSURE_OR_THROW( + Gdiplus::Ok == hr, + "CanvasHelper::strokePolyPolygon(): GDI+ call failed" ); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + 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* /*pCanvas*/, + 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* /*pCanvas*/, + 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* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::fillPolyPolygon: polygon is NULL"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::SolidBrush aBrush( + tools::sequenceToArgb(renderState.DeviceColor)); + + GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) ); + + // TODO(F1): FillRule + ENSURE_OR_THROW( Gdiplus::Ok == pGraphics->FillPath( &aBrush, pPath.get() ), + "CanvasHelper::fillPolyPolygon(): GDI+ call failed " ); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + 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::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* /*pCanvas*/, + const rendering::FontRequest& fontRequest, + const uno::Sequence< beans::PropertyValue >& extraFontProperties, + const geometry::Matrix2D& fontMatrix ) + { + if( needOutput() ) + { + return uno::Reference< rendering::XCanvasFont >( + new CanvasFont(fontRequest, extraFontProperties, fontMatrix ) ); + } + + return uno::Reference< rendering::XCanvasFont >(); + } + + uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* /*pCanvas*/, + const rendering::FontInfo& /*aFilter*/, + const uno::Sequence< beans::PropertyValue >& /*aFontProperties*/ ) + { + // TODO + return uno::Sequence< rendering::FontInfo >(); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* /*pCanvas*/, + const rendering::StringContext& text, + const uno::Reference< rendering::XCanvasFont >& xFont, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + sal_Int8 /*textDirection*/ ) + { + ENSURE_OR_THROW( xFont.is(), + "CanvasHelper::drawText: font is NULL"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + Gdiplus::SolidBrush aBrush( + Gdiplus::Color( + tools::sequenceToArgb(renderState.DeviceColor))); + + CanvasFont::ImplRef pFont( + tools::canvasFontFromXFont(xFont) ); + + // Move glyphs up, such that output happens at the font + // baseline. + Gdiplus::PointF aPoint( 0.0, + static_cast<Gdiplus::REAL>(-(pFont->getFont()->GetSize()* + pFont->getCellAscent() / + pFont->getEmHeight())) ); + + // TODO(F1): According to + // http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q307208, + // we might have to revert to GDI and ExTextOut here, + // since GDI+ takes the scalability a little bit too + // far... + + // TODO(F2): Proper layout (BiDi, CTL)! IMHO must use + // DrawDriverString here, and perform layouting myself... + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->DrawString( reinterpret_cast<LPCWSTR>( + text.Text.copy( text.StartPosition, + text.Length ).getStr()), + text.Length, + pFont->getFont().get(), + aPoint, + &aBrush ), + "CanvasHelper::drawText(): GDI+ call failed" ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XTextLayout >& xLayoutetText, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xLayoutetText.is(), + "CanvasHelper::drawTextLayout: layout is NULL"); + + if( needOutput() ) + { + TextLayout* pTextLayout = + dynamic_cast< TextLayout* >( xLayoutetText.get() ); + + ENSURE_OR_THROW( pTextLayout, + "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" ); + + pTextLayout->draw( mpGraphicsProvider->getGraphics(), + viewState, + renderState, + maOutputOffset, + mpDevice, + false ); + } + + return 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 ) + { + ENSURE_OR_THROW( xBitmap.is(), + "CanvasHelper::drawBitmap: bitmap is NULL"); + + if( needOutput() ) + { + // check whether one of our own objects - need to retrieve + // bitmap _before_ calling + // GraphicsProvider::getGraphics(), to avoid locking our + // own surface. + BitmapSharedPtr pGdiBitmap; + BitmapProvider* pBitmap = dynamic_cast< BitmapProvider* >(xBitmap.get()); + if( pBitmap ) + { + IBitmapSharedPtr pDXBitmap( pBitmap->getBitmap() ); + if( pDXBitmap ) + pGdiBitmap = pDXBitmap->getBitmap(); + } + + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + setupGraphicsState( pGraphics, viewState, renderState ); + + if( pGdiBitmap ) + tools::drawGdiPlusBitmap(pGraphics,pGdiBitmap); + else + tools::drawVCLBitmapFromXBitmap(pGraphics, + xBitmap); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas, + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xBitmap.is(), + "CanvasHelper::drawBitmap: bitmap is NULL"); + + // no color set -> this is equivalent to a plain drawBitmap(), then + if( renderState.DeviceColor.getLength() < 3 ) + return drawBitmap( pCanvas, xBitmap, viewState, renderState ); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + BitmapSharedPtr pBitmap( tools::bitmapFromXBitmap( xBitmap ) ); + Gdiplus::Rect aRect( 0, 0, + pBitmap->GetWidth(), + pBitmap->GetHeight() ); + + // Setup an ImageAttributes with an alpha-modulating + // color matrix. + const rendering::ARGBColor& rARGBColor( + mpDevice->getDeviceColorSpace()->convertToARGB(renderState.DeviceColor)[0]); + + Gdiplus::ImageAttributes aImgAttr; + tools::setModulateImageAttributes( aImgAttr, + rARGBColor.Red, + rARGBColor.Green, + rARGBColor.Blue, + rARGBColor.Alpha ); + + ENSURE_OR_THROW( + Gdiplus::Ok == pGraphics->DrawImage( pBitmap.get(), + aRect, + 0, 0, + pBitmap->GetWidth(), + pBitmap->GetHeight(), + Gdiplus::UnitPixel, + &aImgAttr, + NULL, + NULL ), + "CanvasHelper::drawBitmapModulated(): GDI+ call failed" ); + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice() + { + return uno::Reference< rendering::XGraphicDevice >(mpDevice); + } + + // private helper + // -------------------------------------------------- + + Gdiplus::CompositingMode CanvasHelper::calcCompositingMode( sal_Int8 nMode ) + { + Gdiplus::CompositingMode aRet( Gdiplus::CompositingModeSourceOver ); + + switch( nMode ) + { + case rendering::CompositeOperation::OVER: + // FALLTHROUGH intended + case rendering::CompositeOperation::CLEAR: + aRet = Gdiplus::CompositingModeSourceOver; + break; + + case rendering::CompositeOperation::SOURCE: + aRet = Gdiplus::CompositingModeSourceCopy; + break; + + case rendering::CompositeOperation::DESTINATION: + // FALLTHROUGH intended + case rendering::CompositeOperation::UNDER: + // FALLTHROUGH intended + case rendering::CompositeOperation::INSIDE: + // FALLTHROUGH intended + case rendering::CompositeOperation::INSIDE_REVERSE: + // FALLTHROUGH intended + case rendering::CompositeOperation::OUTSIDE: + // FALLTHROUGH intended + case rendering::CompositeOperation::OUTSIDE_REVERSE: + // FALLTHROUGH intended + case rendering::CompositeOperation::ATOP: + // FALLTHROUGH intended + case rendering::CompositeOperation::ATOP_REVERSE: + // FALLTHROUGH intended + case rendering::CompositeOperation::XOR: + // FALLTHROUGH intended + case rendering::CompositeOperation::ADD: + // FALLTHROUGH intended + case rendering::CompositeOperation::SATURATE: + // TODO(F2): Problem, because GDI+ only knows about two compositing modes + aRet = Gdiplus::CompositingModeSourceOver; + break; + + default: + ENSURE_OR_THROW( false, "CanvasHelper::calcCompositingMode: unexpected mode" ); + break; + } + + return aRet; + } + + void CanvasHelper::setupGraphicsState( GraphicsSharedPtr& rGraphics, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( needOutput(), + "CanvasHelper::setupGraphicsState: primary graphics invalid" ); + ENSURE_OR_THROW( mpDevice, + "CanvasHelper::setupGraphicsState: reference device invalid" ); + + // setup view transform first. Clipping e.g. depends on it + ::basegfx::B2DHomMatrix aTransform; + ::canvas::tools::getViewStateTransform(aTransform, viewState); + + // add output offset + if( !maOutputOffset.equalZero() ) + { + const basegfx::B2DHomMatrix aOutputOffset(basegfx::tools::createTranslateB2DHomMatrix( + maOutputOffset.getX(), maOutputOffset.getY())); + aTransform = aOutputOffset * aTransform; + } + + Gdiplus::Matrix aMatrix; + tools::gdiPlusMatrixFromB2DHomMatrix( aMatrix, aTransform ); + + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetTransform( &aMatrix ), + "CanvasHelper::setupGraphicsState(): Failed to set GDI+ transformation" ); + + // setup view and render state clipping + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->ResetClip(), + "CanvasHelper::setupGraphicsState(): Failed to reset GDI+ clip" ); + + if( viewState.Clip.is() ) + { + GraphicsPathSharedPtr aClipPath( tools::graphicsPathFromXPolyPolygon2D( viewState.Clip ) ); + + // TODO(P3): Cache clip. SetClip( GraphicsPath ) performs abyssmally on GDI+. + // Try SetClip( Rect ) or similar for simple clip paths (need some support in + // LinePolyPolygon, then) + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetClip( aClipPath.get(), + Gdiplus::CombineModeIntersect ), + "CanvasHelper::setupGraphicsState(): Cannot set GDI+ clip" ); + } + + // setup overall transform only now. View clip above was relative to + // view transform + ::canvas::tools::mergeViewAndRenderTransform(aTransform, + viewState, + renderState); + + // add output offset + if( !maOutputOffset.equalZero() ) + { + const basegfx::B2DHomMatrix aOutputOffset(basegfx::tools::createTranslateB2DHomMatrix( + maOutputOffset.getX(), maOutputOffset.getY())); + aTransform = aOutputOffset * aTransform; + } + + tools::gdiPlusMatrixFromB2DHomMatrix( aMatrix, aTransform ); + + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetTransform( &aMatrix ), + "CanvasHelper::setupGraphicsState(): Cannot set GDI+ transformation" ); + + if( renderState.Clip.is() ) + { + GraphicsPathSharedPtr aClipPath( tools::graphicsPathFromXPolyPolygon2D( renderState.Clip ) ); + + // TODO(P3): Cache clip. SetClip( GraphicsPath ) performs abyssmally on GDI+. + // Try SetClip( Rect ) or similar for simple clip paths (need some support in + // LinePolyPolygon, then) + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetClip( aClipPath.get(), + Gdiplus::CombineModeIntersect ), + "CanvasHelper::setupGraphicsState(): Cannot set GDI+ clip" ); + } + + // setup compositing + const Gdiplus::CompositingMode eCompositing( calcCompositingMode( renderState.CompositeOperation ) ); + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->SetCompositingMode( eCompositing ), + "CanvasHelper::setupGraphicsState(): Cannot set GDI* compositing mode)" ); + } + + void CanvasHelper::flush() const + { + if( needOutput() ) + mpGraphicsProvider->getGraphics()->Flush( Gdiplus::FlushIntentionSync ); + } +} diff --git a/canvas/source/directx/dx_canvashelper.hxx b/canvas/source/directx/dx_canvashelper.hxx new file mode 100755 index 000000000000..2f175cce88e5 --- /dev/null +++ b/canvas/source/directx/dx_canvashelper.hxx @@ -0,0 +1,257 @@ +/************************************************************************* + * + * 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 _DXCANVAS_CANVASHELPER_HXX_ +#define _DXCANVAS_CANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/vector/b2dsize.hxx> + +#include "dx_graphicsprovider.hxx" +#include "dx_gdiplususer.hxx" +#include "dx_impltools.hxx" + +#include <boost/utility.hpp> + + +namespace dxcanvas +{ + /** Helper class for basic canvas functionality. Also offers + optional backbuffer painting, when providing it with a second + HDC to render into. + */ + 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 output objects. 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 rDevice + Reference device this canvas is associated with + + */ + void setDevice( com::sun::star::rendering::XGraphicDevice& rDevice ); + + /** Set the target for rendering operations + + @param rTarget + Render target + */ + void setTarget( const GraphicsProviderSharedPtr& rTarget ); + + /** Set the target for rendering operations + + @param rTarget + Render target + + @param rOutputOffset + Output offset in pixel + */ + void setTarget( const GraphicsProviderSharedPtr& rTarget, + const ::basegfx::B2ISize& rOutputOffset ); + + + // 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(); + + // Flush drawing queue to screen + void flush() const; + + /** Called from XCanvas base classes, to notify that content + is _about_ to change + */ + void modifying() {} + + protected: + /// Refcounted global GDI+ state container + GDIPlusUserSharedPtr mpGdiPlusUser; + + /** Phyical output device + + Deliberately not a refcounted reference, because of + potential circular references for spritecanvas. + */ + com::sun::star::rendering::XGraphicDevice* mpDevice; + + /// Provides the Gdiplus::Graphics to render into + GraphicsProviderSharedPtr mpGraphicsProvider; + + bool needOutput() const { return mpGraphicsProvider.get() != NULL; }; + + // returns transparency of color + void setupGraphicsState( GraphicsSharedPtr& rGraphics, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + Gdiplus::CompositingMode calcCompositingMode( sal_Int8 nMode ); + + /// Current (transformation-independent) output buffer offset + ::basegfx::B2ISize maOutputOffset; + }; +} + +#endif /* _DXCANVAS_CANVASHELPER_HXX_ */ diff --git a/canvas/source/directx/dx_canvashelper_texturefill.cxx b/canvas/source/directx/dx_canvashelper_texturefill.cxx new file mode 100755 index 000000000000..80224aa3d53c --- /dev/null +++ b/canvas/source/directx/dx_canvashelper_texturefill.cxx @@ -0,0 +1,625 @@ +/************************************************************************* + * + * 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/math.hxx> + +#include <com/sun/star/rendering/TexturingMode.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/tools/tools.hxx> +#include <basegfx/tools/lerp.hxx> +#include <basegfx/tools/keystoplerp.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include <canvas/parametricpolypolygon.hxx> + +#include "dx_spritecanvas.hxx" +#include "dx_canvashelper.hxx" +#include "dx_impltools.hxx" + +#include <boost/scoped_ptr.hpp> +#include <boost/bind.hpp> +#include <boost/tuple/tuple.hpp> + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + typedef ::boost::shared_ptr< Gdiplus::PathGradientBrush > PathGradientBrushSharedPtr; + + bool fillLinearGradient( GraphicsSharedPtr& rGraphics, + const ::canvas::ParametricPolyPolygon::Values& /*rValues*/, + const std::vector< Gdiplus::Color >& rColors, + const std::vector< Gdiplus::REAL >& rStops, + const GraphicsPathSharedPtr& rFillPath, + const rendering::Texture& texture ) + { + // setup a linear gradient with given colors + // ----------------------------------------- + + Gdiplus::LinearGradientBrush aBrush( + Gdiplus::PointF(0.0f, + 0.5f), + Gdiplus::PointF(1.0f, + 0.5f), + rColors[0], + rColors[1] ); + + aBrush.SetInterpolationColors(&rColors[0], + &rStops[0], + rColors.size()); + + // render background color, as LinearGradientBrush does not + // properly support the WrapModeClamp repeat mode + Gdiplus::SolidBrush aBackgroundBrush( rColors[0] ); + rGraphics->FillPath( &aBackgroundBrush, rFillPath.get() ); + + // TODO(F2): This does not yet support other repeat modes + // except clamp, and probably also no multi-texturing + + // calculate parallelogram of gradient in object space, extend + // top and bottom of it such that they cover the whole fill + // path bound area + ::basegfx::B2DHomMatrix aTextureTransform; + ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform, + texture.AffineTransform ); + + ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 ); + ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 ); + ::basegfx::B2DPoint aRightTop( 1.0, 0.0 ); + ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 ); + + aLeftTop *= aTextureTransform; + aLeftBottom *= aTextureTransform; + aRightTop *= aTextureTransform; + aRightBottom*= aTextureTransform; + + Gdiplus::RectF aBounds; + rFillPath->GetBounds( &aBounds, NULL, NULL ); + + // now, we potentially have to enlarge our gradient area + // atop and below the transformed [0,1]x[0,1] unit rect, + // for the gradient to fill the complete bound rect. + ::basegfx::tools::infiniteLineFromParallelogram( aLeftTop, + aLeftBottom, + aRightTop, + aRightBottom, + tools::b2dRangeFromGdiPlusRectF( aBounds ) ); + + // calc length of bound rect diagonal + const double nDiagonalLength( + hypot( aBounds.Width, + aBounds.Height ) ); + + // generate a path which covers the 'right' side of the + // gradient, extending two times the bound rect diagonal to + // the right (and thus covering the whole half plane 'right' + // of the gradient). Take the middle of the gradient as the + // 'left' side of the polygon, to not fall victim to rounding + // errors at the edge. + ::basegfx::B2DVector aDirection( aLeftTop - aLeftBottom ); + aDirection = ::basegfx::getNormalizedPerpendicular( aDirection ); + aDirection *= nDiagonalLength; + + const ::basegfx::B2DPoint aHalfPlaneLeftTop( (aLeftTop + aRightTop) * 0.5 ); + const ::basegfx::B2DPoint aHalfPlaneLeftBottom( (aLeftBottom + aRightBottom) * 0.5 ); + const ::basegfx::B2DPoint aHalfPlaneRightTop( aRightTop + aDirection ); + const ::basegfx::B2DPoint aHalfPlaneRightBottom( aRightBottom + aDirection ); + + Gdiplus::GraphicsPath aSolidFillPath; + aSolidFillPath.AddLine( static_cast<Gdiplus::REAL>(aHalfPlaneLeftTop.getX()), + static_cast<Gdiplus::REAL>(aHalfPlaneLeftTop.getY()), + static_cast<Gdiplus::REAL>(aHalfPlaneRightTop.getX()), + static_cast<Gdiplus::REAL>(aHalfPlaneRightTop.getY()) ); + aSolidFillPath.AddLine( static_cast<Gdiplus::REAL>(aHalfPlaneRightBottom.getX()), + static_cast<Gdiplus::REAL>(aHalfPlaneRightBottom.getY()), + static_cast<Gdiplus::REAL>(aHalfPlaneLeftBottom.getX()), + static_cast<Gdiplus::REAL>(aHalfPlaneLeftBottom.getY()) ); + aSolidFillPath.CloseFigure(); + + // limit output to fill path, we've just generated a path that + // might be substantially larger + if( Gdiplus::Ok != rGraphics->SetClip( rFillPath.get(), + Gdiplus::CombineModeIntersect ) ) + { + return false; + } + + Gdiplus::SolidBrush aBackgroundBrush2( rColors.back() ); + rGraphics->FillPath( &aBackgroundBrush2, &aSolidFillPath ); + + // generate clip polygon from the extended parallelogram + // (exploit the feature that distinct lines in a figure are + // automatically closed by a straight line) + Gdiplus::GraphicsPath aClipPath; + aClipPath.AddLine( static_cast<Gdiplus::REAL>(aLeftTop.getX()), + static_cast<Gdiplus::REAL>(aLeftTop.getY()), + static_cast<Gdiplus::REAL>(aRightTop.getX()), + static_cast<Gdiplus::REAL>(aRightTop.getY()) ); + aClipPath.AddLine( static_cast<Gdiplus::REAL>(aRightBottom.getX()), + static_cast<Gdiplus::REAL>(aRightBottom.getY()), + static_cast<Gdiplus::REAL>(aLeftBottom.getX()), + static_cast<Gdiplus::REAL>(aLeftBottom.getY()) ); + aClipPath.CloseFigure(); + + // limit output to a _single_ strip of the gradient (have to + // clip here, since GDI+ wrapmode clamp does not work here) + if( Gdiplus::Ok != rGraphics->SetClip( &aClipPath, + Gdiplus::CombineModeIntersect ) ) + { + return false; + } + + // now, finally, output the gradient + Gdiplus::Matrix aMatrix; + tools::gdiPlusMatrixFromAffineMatrix2D( aMatrix, + texture.AffineTransform ); + aBrush.SetTransform( &aMatrix ); + + rGraphics->FillRectangle( &aBrush, aBounds ); + + return true; + } + + int numColorSteps( const Gdiplus::Color& rColor1, const Gdiplus::Color& rColor2 ) + { + return ::std::max( + labs( rColor1.GetRed() - rColor2.GetRed() ), + ::std::max( + labs( rColor1.GetGreen() - rColor2.GetGreen() ), + labs( rColor1.GetBlue() - rColor2.GetBlue() ) ) ); + } + + bool fillPolygonalGradient( const ::canvas::ParametricPolyPolygon::Values& rValues, + const std::vector< Gdiplus::Color >& rColors, + const std::vector< Gdiplus::REAL >& rStops, + GraphicsSharedPtr& rGraphics, + const GraphicsPathSharedPtr& rPath, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::Texture& texture ) + { + // copy original fill path object, might have to change it + // below + GraphicsPathSharedPtr pFillPath( rPath ); + const ::basegfx::B2DPolygon& rGradientPoly( rValues.maGradientPoly ); + + PathGradientBrushSharedPtr pGradientBrush; + + // fill background uniformly with end color + Gdiplus::SolidBrush aBackgroundBrush( rColors[0] ); + rGraphics->FillPath( &aBackgroundBrush, pFillPath.get() ); + + // scale focus according to aspect ratio: for wider-than-tall + // bounds (nAspectRatio > 1.0), the focus must have non-zero + // width. Specifically, a bound rect twice as wide as tall has + // a focus of half it's width. + if( !::rtl::math::approxEqual(rValues.mnAspectRatio, + 1.0) ) + { + // KLUDGE 1: + // + // And here comes the greatest shortcoming of the GDI+ + // gradients ever: SetFocusScales completely ignores + // transformations, both when set at the PathGradientBrush + // and for the world coordinate system. Thus, to correctly + // display anisotrophic path gradients, we have to render + // them by hand. WTF. + + // TODO(F2): This does not yet support other repeat modes + // except clamp, and probably also no multi-texturing + + // limit output to to-be-filled polygon + if( Gdiplus::Ok != rGraphics->SetClip( pFillPath.get(), + Gdiplus::CombineModeIntersect ) ) + { + return false; + } + + // disable anti-aliasing, if any + const Gdiplus::SmoothingMode eOldAAMode( rGraphics->GetSmoothingMode() ); + rGraphics->SetSmoothingMode( Gdiplus::SmoothingModeHighSpeed ); + + + // determine number of steps to use + // -------------------------------- + + // TODO(Q2): Unify step calculations with VCL canvas + int nColorSteps = 0; + for( size_t i=0; i<rColors.size()-1; ++i ) + nColorSteps += numColorSteps(rColors[i],rColors[i+1]); + ::basegfx::B2DHomMatrix aTotalTransform; + const int nStepCount= + ::canvas::tools::calcGradientStepCount(aTotalTransform, + viewState, + renderState, + texture, + nColorSteps); + + ::basegfx::B2DHomMatrix aTextureTransform; + ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform, + texture.AffineTransform ); + // determine overall transformation for inner polygon (might + // have to be prefixed by anisotrophic scaling) + ::basegfx::B2DHomMatrix aInnerPolygonTransformMatrix; + + // For performance reasons, we create a temporary VCL polygon + // here, keep it all the way and only change the vertex values + // in the loop below (as ::Polygon is a pimpl class, creating + // one every loop turn would really stress the mem allocator) + ::basegfx::B2DPolygon aOuterPoly( rGradientPoly ); + ::basegfx::B2DPolygon aInnerPoly; + + // subdivide polygon _before_ rendering, would otherwise have + // to be performed on every loop turn. + if( aOuterPoly.areControlPointsUsed() ) + aOuterPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aOuterPoly); + + aInnerPoly = aOuterPoly; + aOuterPoly.transform(aTextureTransform); + + + // apply scaling (possibly anisotrophic) to inner polygon + // ------------------------------------------------------ + + // scale inner polygon according to aspect ratio: for + // wider-than-tall bounds (nAspectRatio > 1.0), the inner + // polygon, representing the gradient focus, must have + // non-zero width. Specifically, a bound rect twice as wide as + // tall has a focus polygon of half it's width. + const double nAspectRatio( rValues.mnAspectRatio ); + if( nAspectRatio > 1.0 ) + { + // width > height case + aInnerPolygonTransformMatrix.scale( 1.0 - 1.0/nAspectRatio, + 0.0 ); + } + else if( nAspectRatio < 1.0 ) + { + // width < height case + aInnerPolygonTransformMatrix.scale( 0.0, + 1.0 - nAspectRatio ); + } + else + { + // isotrophic case + aInnerPolygonTransformMatrix.scale( 0.0, 0.0 ); + } + + // and finally, add texture transform to it. + aInnerPolygonTransformMatrix *= aTextureTransform; + + // apply final matrix to polygon + aInnerPoly.transform( aInnerPolygonTransformMatrix ); + + Gdiplus::GraphicsPath aCurrPath; + Gdiplus::SolidBrush aFillBrush( rColors[0] ); + const sal_uInt32 nNumPoints( aOuterPoly.count() ); + basegfx::tools::KeyStopLerp aLerper(rValues.maStops); + for( int i=1; i<nStepCount; ++i ) + { + std::ptrdiff_t nIndex; + double fAlpha; + const double fT( i/double(nStepCount) ); + boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT); + + const Gdiplus::Color aFillColor( + static_cast<BYTE>( basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha) ), + static_cast<BYTE>( basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha) ), + static_cast<BYTE>( basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha) ) ); + + aFillBrush.SetColor( aFillColor ); + aCurrPath.Reset(); aCurrPath.StartFigure(); + for( unsigned int p=1; p<nNumPoints; ++p ) + { + const ::basegfx::B2DPoint& rOuterPoint1( aOuterPoly.getB2DPoint(p-1) ); + const ::basegfx::B2DPoint& rInnerPoint1( aInnerPoly.getB2DPoint(p-1) ); + const ::basegfx::B2DPoint& rOuterPoint2( aOuterPoly.getB2DPoint(p) ); + const ::basegfx::B2DPoint& rInnerPoint2( aInnerPoly.getB2DPoint(p) ); + + aCurrPath.AddLine( + Gdiplus::REAL(fT*rInnerPoint1.getX() + (1-fT)*rOuterPoint1.getX()), + Gdiplus::REAL(fT*rInnerPoint1.getY() + (1-fT)*rOuterPoint1.getY()), + Gdiplus::REAL(fT*rInnerPoint2.getX() + (1-fT)*rOuterPoint2.getX()), + Gdiplus::REAL(fT*rInnerPoint2.getY() + (1-fT)*rOuterPoint2.getY())); + } + aCurrPath.CloseFigure(); + + rGraphics->FillPath( &aFillBrush, &aCurrPath ); + } + + // reset to old anti-alias mode + rGraphics->SetSmoothingMode( eOldAAMode ); + } + else + { + // KLUDGE 2: + // + // We're generating a PathGradientBrush from scratch here, + // and put in a transformed GraphicsPath (transformed with + // the texture transform). This is because the + // straight-forward approach to store a Brush pointer at + // this class and set a texture transform via + // PathGradientBrush::SetTransform() is spoiled by MS: it + // seems that _either_ the texture transform, _or_ the + // transform at the Graphics can be set, but not both. If + // one sets both, only the translational components of the + // texture is respected. + + Gdiplus::Matrix aMatrix; + tools::gdiPlusMatrixFromAffineMatrix2D( aMatrix, + texture.AffineTransform ); + GraphicsPathSharedPtr pGradientPath( + tools::graphicsPathFromB2DPolygon( rValues.maGradientPoly )); + pGradientPath->Transform( &aMatrix ); + + pGradientBrush.reset( + new Gdiplus::PathGradientBrush( pGradientPath.get() ) ); + pGradientBrush->SetInterpolationColors( &rColors[0], + &rStops[0], + rStops.size() ); + + // explicitely setup center point. Since the center of GDI+ + // gradients are by default the _centroid_ of the path + // (i.e. the weighted sum of edge points), it will not + // necessarily coincide with our notion of center. + Gdiplus::PointF aCenterPoint(0, 0); + aMatrix.TransformPoints( &aCenterPoint ); + pGradientBrush->SetCenterPoint( aCenterPoint ); + + const bool bTileX( texture.RepeatModeX != rendering::TexturingMode::CLAMP ); + const bool bTileY( texture.RepeatModeY != rendering::TexturingMode::CLAMP ); + + if( bTileX && bTileY ) + pGradientBrush->SetWrapMode( Gdiplus::WrapModeTile ); + else + { + OSL_ENSURE( bTileY == bTileX, + "ParametricPolyPolygon::fillPolygonalGradient(): Cannot have repeat x and repeat y differ!" ); + + pGradientBrush->SetWrapMode( Gdiplus::WrapModeClamp ); + } + + // render actual gradient + rGraphics->FillPath( pGradientBrush.get(), pFillPath.get() ); + } + +#if defined(VERBOSE) && defined(DBG_UTIL) + Gdiplus::Pen aPen( Gdiplus::Color( 255, 255, 0, 0 ), + 0.0001f ); + + rGraphics->DrawRectangle( &aPen, + Gdiplus::RectF( 0.0f, 0.0f, + 1.0f, 1.0f ) ); +#endif + + return true; + } + + bool fillGradient( const ::canvas::ParametricPolyPolygon::Values& rValues, + const std::vector< Gdiplus::Color >& rColors, + const std::vector< Gdiplus::REAL >& rStops, + GraphicsSharedPtr& rGraphics, + const GraphicsPathSharedPtr& rPath, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::Texture& texture ) + { + switch( rValues.meType ) + { + case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR: + fillLinearGradient( rGraphics, + rValues, + rColors, + rStops, + rPath, + texture ); + break; + + case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL: + // FALLTHROUGH intended + case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR: + fillPolygonalGradient( rValues, + rColors, + rStops, + rGraphics, + rPath, + viewState, + renderState, + texture ); + break; + + default: + ENSURE_OR_THROW( false, + "CanvasHelper::fillGradient(): Unexpected case" ); + } + + return true; + } + + void fillBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, + GraphicsSharedPtr& rGraphics, + const GraphicsPathSharedPtr& rPath, + const rendering::Texture& rTexture ) + { + OSL_ENSURE( rTexture.RepeatModeX == + rTexture.RepeatModeY, + "CanvasHelper::fillBitmap(): GDI+ cannot handle differing X/Y repeat mode." ); + + const bool bClamp( rTexture.RepeatModeX == rendering::TexturingMode::NONE && + rTexture.RepeatModeY == rendering::TexturingMode::NONE ); + + const geometry::IntegerSize2D aBmpSize( xBitmap->getSize() ); + ENSURE_ARG_OR_THROW( aBmpSize.Width != 0 && + aBmpSize.Height != 0, + "CanvasHelper::fillBitmap(): zero-sized texture bitmap" ); + + // TODO(P3): Detect case that path is rectangle and + // bitmap is just scaled into that. Then, we can + // render directly, without generating a temporary + // GDI+ bitmap (this is significant, because drawing + // layer presents background object bitmap in that + // way!) + BitmapSharedPtr pBitmap( + tools::bitmapFromXBitmap( xBitmap ) ); + + TextureBrushSharedPtr pBrush; + if( ::rtl::math::approxEqual( rTexture.Alpha, + 1.0 ) ) + { + pBrush.reset( + new Gdiplus::TextureBrush( + pBitmap.get(), + bClamp ? Gdiplus::WrapModeClamp : Gdiplus::WrapModeTile ) ); + } + else + { + Gdiplus::ImageAttributes aImgAttr; + + tools::setModulateImageAttributes( aImgAttr, + 1.0, + 1.0, + 1.0, + rTexture.Alpha ); + + Gdiplus::Rect aRect(0,0, + aBmpSize.Width, + aBmpSize.Height); + pBrush.reset( + new Gdiplus::TextureBrush( + pBitmap.get(), + aRect, + &aImgAttr ) ); + + pBrush->SetWrapMode( + bClamp ? Gdiplus::WrapModeClamp : Gdiplus::WrapModeTile ); + } + + Gdiplus::Matrix aTextureTransform; + tools::gdiPlusMatrixFromAffineMatrix2D( aTextureTransform, + rTexture.AffineTransform ); + + // scale down bitmap to [0,1]x[0,1] rect, as required + // from the XCanvas interface. + pBrush->MultiplyTransform( &aTextureTransform ); + pBrush->ScaleTransform( static_cast< Gdiplus::REAL >(1.0/aBmpSize.Width), + static_cast< Gdiplus::REAL >(1.0/aBmpSize.Height) ); + + // TODO(F1): FillRule + ENSURE_OR_THROW( + Gdiplus::Ok == rGraphics->FillPath( pBrush.get(), + rPath.get() ), + "CanvasHelper::fillTexturedPolyPolygon(): GDI+ call failed" ); + } + } + + // ------------------------------------------------------------- + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures ) + { + ENSURE_OR_THROW( xPolyPolygon.is(), + "CanvasHelper::fillTexturedPolyPolygon: polygon is NULL"); + ENSURE_OR_THROW( textures.getLength(), + "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence"); + + if( needOutput() ) + { + GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); + + setupGraphicsState( pGraphics, viewState, renderState ); + + // TODO(F1): Multi-texturing + if( textures[0].Gradient.is() ) + { + // try to cast XParametricPolyPolygon2D reference to + // our implementation class. + ::canvas::ParametricPolyPolygon* pGradient = + dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() ); + + if( pGradient ) + { + const ::canvas::ParametricPolyPolygon::Values& rValues( + pGradient->getValues() ); + + OSL_ASSERT(rValues.maColors.getLength() == rValues.maStops.getLength() + && rValues.maColors.getLength() > 1); + + std::vector< Gdiplus::Color > aColors(rValues.maColors.getLength()); + std::transform(&rValues.maColors[0], + &rValues.maColors[0]+rValues.maColors.getLength(), + aColors.begin(), + boost::bind( + (Gdiplus::ARGB (*)( const uno::Sequence< double >& ))( + &tools::sequenceToArgb), + _1)); + std::vector< Gdiplus::REAL > aStops; + comphelper::sequenceToContainer(aStops,rValues.maStops); + + // TODO(E1): Return value + // TODO(F1): FillRule + fillGradient( rValues, + aColors, + aStops, + pGraphics, + tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ), + viewState, + renderState, + textures[0] ); + } + } + else if( textures[0].Bitmap.is() ) + { + // TODO(E1): Return value + // TODO(F1): FillRule + fillBitmap( textures[0].Bitmap, + pGraphics, + tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ), + textures[0] ); + } + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } +} diff --git a/canvas/source/directx/dx_config.cxx b/canvas/source/directx/dx_config.cxx new file mode 100755 index 000000000000..bfbb46a42d09 --- /dev/null +++ b/canvas/source/directx/dx_config.cxx @@ -0,0 +1,176 @@ +/************************************************************************* + * + * 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 "dx_config.hxx" + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <comphelper/anytostring.hxx> +#include <basegfx/vector/b2ivector.hxx> +#include <cppuhelper/exc_hlp.hxx> + +using namespace com::sun::star; + +namespace dxcanvas +{ + DXCanvasItem::DXCanvasItem() : + ConfigItem( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "Office.Canvas/DXCanvas" )), + CONFIG_MODE_IMMEDIATE_UPDATE ), + maValues(), + maMaxTextureSize(), + mbBlacklistCurrentDevice(false), + mbValuesDirty(false) + { + try + { + uno::Sequence< ::rtl::OUString > aName(1); + aName[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DeviceBlacklist" )); + + uno::Sequence< uno::Any > aProps( GetProperties( aName )); + uno::Sequence< sal_Int32 > aValues; + + if( aProps.getLength() > 0 && + (aProps[0] >>= aValues) ) + { + const sal_Int32* pValues = aValues.getConstArray(); + const sal_Int32 nNumEntries( aValues.getLength()*sizeof(sal_Int32)/sizeof(DeviceInfo) ); + for( sal_Int32 i=0; i<nNumEntries; ++i ) + { + DeviceInfo aInfo; + aInfo.nVendorId = *pValues++; + aInfo.nDeviceId = *pValues++; + aInfo.nDeviceSubSysId = *pValues++; + aInfo.nDeviceRevision = *pValues++; + aInfo.nDriverId = *pValues++; + aInfo.nDriverVersion = *pValues++; + aInfo.nDriverSubVersion = *pValues++; + aInfo.nDriverBuildId = *pValues++; + maValues.insert(aInfo); + } + } + + aName[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BlacklistCurrentDevice" )); + aProps = GetProperties( aName ); + if( aProps.getLength() > 0 ) + aProps[0] >>= mbBlacklistCurrentDevice; + + aName[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxTextureSize" )); + aProps = GetProperties( aName ); + if( aProps.getLength() > 0 ) + maMaxTextureSize.reset( aProps[0].get<sal_Int32>() ); + else + maMaxTextureSize.reset(); + } + catch( uno::Exception& ) + { + OSL_ENSURE( false, + rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + + DXCanvasItem::~DXCanvasItem() + { + if( !mbValuesDirty ) + return; + + try + { + uno::Sequence< ::rtl::OUString > aName(1); + aName[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DeviceBlacklist" )); + + uno::Sequence< sal_Int32 > aValues( sizeof(DeviceInfo)/sizeof(sal_Int32)*maValues.size() ); + + sal_Int32* pValues = aValues.getArray(); + ValueSet::const_iterator aIter( maValues.begin() ); + const ValueSet::const_iterator aEnd( maValues.end() ); + while( aIter != aEnd ) + { + const DeviceInfo& rInfo( *aIter ); + *pValues++ = rInfo.nVendorId; + *pValues++ = rInfo.nDeviceId; + *pValues++ = rInfo.nDeviceSubSysId; + *pValues++ = rInfo.nDeviceRevision; + *pValues++ = rInfo.nDriverId; + *pValues++ = rInfo.nDriverVersion; + *pValues++ = rInfo.nDriverSubVersion; + *pValues++ = rInfo.nDriverBuildId; + ++aIter; + } + + uno::Sequence< uno::Any > aValue(1); + aValue[0] <<= aValues; + PutProperties( aName, aValue ); + } + catch( uno::Exception& ) + { + OSL_ENSURE( false, + rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + + void DXCanvasItem::Notify( const com::sun::star::uno::Sequence<rtl::OUString>& ) {} + void DXCanvasItem::Commit() {} + + bool DXCanvasItem::isDeviceUsable( const DeviceInfo& rDeviceInfo ) const + { + return maValues.find(rDeviceInfo) == maValues.end(); + } + + bool DXCanvasItem::isBlacklistCurrentDevice() const + { + return mbBlacklistCurrentDevice; + } + + void DXCanvasItem::blacklistDevice( const DeviceInfo& rDeviceInfo ) + { + mbValuesDirty = true; + maValues.insert(rDeviceInfo); + } + + void DXCanvasItem::adaptMaxTextureSize( basegfx::B2IVector& io_maxTextureSize ) const + { + if( maMaxTextureSize ) + { + io_maxTextureSize.setX( + std::min( *maMaxTextureSize, + io_maxTextureSize.getX() )); + io_maxTextureSize.setY( + std::min( *maMaxTextureSize, + io_maxTextureSize.getY() )); + } + } + +} diff --git a/canvas/source/directx/dx_config.hxx b/canvas/source/directx/dx_config.hxx new file mode 100644 index 000000000000..a1499a64f44f --- /dev/null +++ b/canvas/source/directx/dx_config.hxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * 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 _DXCANVAS_DXCONFIG_HXX +#define _DXCANVAS_DXCONFIG_HXX + +#include <unotools/configitem.hxx> +#include <boost/optional.hpp> +#include <set> + +namespace basegfx { class B2IVector; } + +namespace dxcanvas +{ + /** Provide DX canvas config data + */ + class DXCanvasItem : public ::utl::ConfigItem + { + public: + DXCanvasItem(); + + struct DeviceInfo + { + sal_Int32 nVendorId; + sal_Int32 nDeviceId; + sal_Int32 nDeviceSubSysId; + sal_Int32 nDeviceRevision; + + sal_Int32 nDriverId; + sal_Int32 nDriverVersion; + sal_Int32 nDriverSubVersion; + sal_Int32 nDriverBuildId; + + bool operator<( const DeviceInfo& rRHS ) const + { + return nVendorId != rRHS.nVendorId ? nVendorId < rRHS.nVendorId : + (nDeviceId != rRHS.nDeviceId ? nDeviceId < rRHS.nDeviceId : + (nDeviceSubSysId != rRHS.nDeviceSubSysId ? nDeviceSubSysId < rRHS.nDeviceSubSysId : + (nDeviceRevision != rRHS.nDeviceRevision ? nDeviceRevision < rRHS.nDeviceRevision : + (nDriverId != rRHS.nDriverId ? nDriverId < rRHS.nDriverId : + (nDriverVersion != rRHS.nDriverVersion ? nDriverVersion < rRHS.nDriverVersion : + (nDriverSubVersion != rRHS.nDriverSubVersion ? nDriverSubVersion < rRHS.nDriverSubVersion : + (nDriverBuildId != rRHS.nDriverBuildId ? nDriverBuildId < rRHS.nDriverBuildId : false))))))); + } + }; + + ~DXCanvasItem(); + + bool isDeviceUsable( const DeviceInfo& rDeviceInfo ) const; + bool isBlacklistCurrentDevice() const; + void blacklistDevice( const DeviceInfo& rDeviceInfo ); + void adaptMaxTextureSize( basegfx::B2IVector& io_maxTextureSize ) const; + virtual void Notify( const com::sun::star::uno::Sequence<rtl::OUString>& aPropertyNames); + virtual void Commit(); + + private: + typedef std::set< DeviceInfo > ValueSet; + ValueSet maValues; + boost::optional<sal_Int32> maMaxTextureSize; + bool mbBlacklistCurrentDevice; + bool mbValuesDirty; + }; +} + +#endif /* #ifndef _DXCANVAS_DXCONFIG_HXX */ diff --git a/canvas/source/directx/dx_devicehelper.cxx b/canvas/source/directx/dx_devicehelper.cxx new file mode 100755 index 000000000000..731e28e2700f --- /dev/null +++ b/canvas/source/directx/dx_devicehelper.cxx @@ -0,0 +1,236 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#include <vcl/window.hxx> +#include <vcl/canvastools.hxx> +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#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 "dx_linepolypolygon.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_canvasbitmap.hxx" +#include "dx_devicehelper.hxx" + + +#undef WB_LEFT +#undef WB_RIGHT +#include "dx_winstuff.hxx" + + +#include <vcl/sysdata.hxx> + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + DeviceHelper::DeviceHelper() : + mpDevice( NULL ), + mnHDC(0) + { + } + + void DeviceHelper::init( HDC hdc, + rendering::XGraphicDevice& rDevice ) + { + mnHDC = hdc; + mpDevice = &rDevice; + } + + void DeviceHelper::disposing() + { + // release all references + mnHDC = 0; + mpDevice = NULL; + } + + geometry::RealSize2D DeviceHelper::getPhysicalResolution() + { + if( !mpDevice ) + return ::canvas::tools::createInfiniteSize2D(); // we're disposed + + HDC hDC = getHDC(); + ENSURE_OR_THROW( hDC, + "DeviceHelper::getPhysicalResolution(): cannot retrieve HDC from window" ); + + const int nHorzRes( GetDeviceCaps( hDC, + LOGPIXELSX ) ); + const int nVertRes( GetDeviceCaps( hDC, + LOGPIXELSY ) ); + + return geometry::RealSize2D( nHorzRes*25.4, + nVertRes*25.4 ); + } + + geometry::RealSize2D DeviceHelper::getPhysicalSize() + { + if( !mpDevice ) + return ::canvas::tools::createInfiniteSize2D(); // we're disposed + + HDC hDC=getHDC(); + ENSURE_OR_THROW( hDC, + "DeviceHelper::getPhysicalSize(): cannot retrieve HDC from window" ); + + const int nHorzSize( GetDeviceCaps( hDC, + HORZSIZE ) ); + const int nVertSize( GetDeviceCaps( hDC, + VERTSIZE ) ); + + return geometry::RealSize2D( nHorzSize, + nVertSize ); + } + + uno::Reference< rendering::XLinePolyPolygon2D > DeviceHelper::createCompatibleLinePolyPolygon( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) + { + if( !mpDevice ) + return uno::Reference< rendering::XLinePolyPolygon2D >(); // we're disposed + + return uno::Reference< rendering::XLinePolyPolygon2D >( + new LinePolyPolygon( + ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points ) ) ); + } + + uno::Reference< rendering::XBezierPolyPolygon2D > DeviceHelper::createCompatibleBezierPolyPolygon( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points ) + { + if( !mpDevice ) + return uno::Reference< rendering::XBezierPolyPolygon2D >(); // we're disposed + + return uno::Reference< rendering::XBezierPolyPolygon2D >( + new LinePolyPolygon( + ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points ) ) ); + } + + uno::Reference< rendering::XBitmap > DeviceHelper::createCompatibleBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& size ) + { + if( !mpDevice ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + DXBitmapSharedPtr pBitmap( + new DXBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D(size), + false)); + + // create a 24bit RGB system memory surface + return uno::Reference< rendering::XBitmap >(new CanvasBitmap(pBitmap,mpDevice)); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + 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 ) + { + if( !mpDevice ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + DXBitmapSharedPtr pBitmap( + new DXBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D(size), + true)); + + // create a 32bit ARGB system memory surface + return uno::Reference< rendering::XBitmap >(new CanvasBitmap(pBitmap,mpDevice)); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + sal_Bool DeviceHelper::hasFullScreenMode() + { + return false; + } + + sal_Bool DeviceHelper::enterFullScreenMode( sal_Bool /*bEnter*/ ) + { + return false; + } + + uno::Any DeviceHelper::isAccelerated() const + { + return ::com::sun::star::uno::makeAny(false); + } + + uno::Any DeviceHelper::getDeviceHandle() const + { + HDC hdc( getHDC() ); + if( hdc ) + return uno::makeAny( reinterpret_cast< sal_Int64 >(hdc) ); + else + return uno::Any(); + } + + uno::Any DeviceHelper::getSurfaceHandle() const + { + // TODO(F1): expose DirectDraw object + //return mpBackBuffer->getBitmap().get(); + 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(); + } +} diff --git a/canvas/source/directx/dx_devicehelper.hxx b/canvas/source/directx/dx_devicehelper.hxx new file mode 100755 index 000000000000..7c85f7a8f8de --- /dev/null +++ b/canvas/source/directx/dx_devicehelper.hxx @@ -0,0 +1,121 @@ +/************************************************************************* + * + * 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 _DXCANVAS_DEVICEHELPER_HXX +#define _DXCANVAS_DEVICEHELPER_HXX + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include "dx_rendermodule.hxx" +#include "dx_bitmap.hxx" + +#include <canvas/rendering/isurfaceproxymanager.hxx> + +#include <boost/utility.hpp> + + +/* Definition of DeviceHelper class */ + +namespace dxcanvas +{ + class DeviceHelper : private ::boost::noncopyable + { + public: + DeviceHelper(); + + /** Init the device helper + + @param hdc + private or class dc of the output device. is only stored, + not release + + @param rDevice + Ref back to owning UNO device + */ + void init( HDC hdc, + com::sun::star::rendering::XGraphicDevice& rDevice ); + + /// 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 {} + + protected: + HDC getHDC() const { return mnHDC; } + com::sun::star::rendering::XGraphicDevice* getDevice() const { return mpDevice; } + + private: + /** Phyical output device + + Deliberately not a refcounted reference, because of + potential circular references for canvas. Needed to + create bitmaps + */ + com::sun::star::rendering::XGraphicDevice* mpDevice; + HDC mnHDC; + }; + + typedef ::rtl::Reference< com::sun::star::rendering::XGraphicDevice > DeviceRef; +} + +#endif /* _DXCANVAS_DEVICEHELPER_HXX */ diff --git a/canvas/source/directx/dx_gdiplususer.cxx b/canvas/source/directx/dx_gdiplususer.cxx new file mode 100755 index 000000000000..f11965ac6860 --- /dev/null +++ b/canvas/source/directx/dx_gdiplususer.cxx @@ -0,0 +1,81 @@ +/************************************************************************* + * + * 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 <osl/mutex.hxx> + +#include "dx_winstuff.hxx" +#include "dx_gdiplususer.hxx" + + +namespace dxcanvas +{ + namespace + { + ::osl::Mutex* p_gdiPlusUsageCountMutex( osl::Mutex::getGlobalMutex() ); + int n_gdiPlusUsageCount( 0 ); + + ULONG_PTR a_GdiPlusToken; // GDI+ handle. Owned by this object + } + + GDIPlusUserSharedPtr GDIPlusUser::createInstance() + { + return GDIPlusUserSharedPtr( new GDIPlusUser() ); + } + + GDIPlusUser::~GDIPlusUser() + { + ::osl::MutexGuard aGuard( *p_gdiPlusUsageCountMutex ); + + --n_gdiPlusUsageCount; + + if( n_gdiPlusUsageCount == 0 ) + Gdiplus::GdiplusShutdown( a_GdiPlusToken ); + } + + GDIPlusUser::GDIPlusUser() + { + ::osl::MutexGuard aGuard( *p_gdiPlusUsageCountMutex ); + + if( n_gdiPlusUsageCount == 0 ) + { + // Setup GDI+ + + // No extras here, simply taking GdiplusStartupInput's + // default constructor + Gdiplus::GdiplusStartupInput gdiPlusStartupInput; + + Gdiplus::GdiplusStartup( &a_GdiPlusToken, + &gdiPlusStartupInput, + NULL ); + } + + ++n_gdiPlusUsageCount; + } +} diff --git a/canvas/source/directx/dx_gdiplususer.hxx b/canvas/source/directx/dx_gdiplususer.hxx new file mode 100755 index 000000000000..409449aab954 --- /dev/null +++ b/canvas/source/directx/dx_gdiplususer.hxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * 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 _DXCANVAS_GDIPLUSUSER_HXX +#define _DXCANVAS_GDIPLUSUSER_HXX + +#include <sal/config.h> + +#include <boost/shared_ptr.hpp> + +/* Definition of GDIPlusUser class */ + +namespace dxcanvas +{ + class GDIPlusUser + { + public: + typedef ::boost::shared_ptr< GDIPlusUser > GDIPlusUserSharedPtr; + + static GDIPlusUserSharedPtr createInstance(); + ~GDIPlusUser(); + + private: + GDIPlusUser(); // create us via factory method + }; + + typedef GDIPlusUser::GDIPlusUserSharedPtr GDIPlusUserSharedPtr; + +} + +#endif /* _DXCANVAS_GDIPLUSUSER_HXX */ diff --git a/canvas/source/directx/dx_graphicsprovider.hxx b/canvas/source/directx/dx_graphicsprovider.hxx new file mode 100644 index 000000000000..74c47e26a99a --- /dev/null +++ b/canvas/source/directx/dx_graphicsprovider.hxx @@ -0,0 +1,53 @@ +/************************************************************************* + * + * 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 _DXCANVAS_GRAPHICSPROVIDER_HXX +#define _DXCANVAS_GRAPHICSPROVIDER_HXX + +#include "dx_winstuff.hxx" + +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +namespace Gdiplus{ class Graphics; } + +namespace dxcanvas +{ + /** Provider of a Gdiplus::Graphics. Interface + */ + class GraphicsProvider : private ::boost::noncopyable + { + public: + virtual ~GraphicsProvider() {} + + virtual GraphicsSharedPtr getGraphics() = 0; + }; + + typedef ::boost::shared_ptr< GraphicsProvider > GraphicsProviderSharedPtr; +} + +#endif /* _DXCANVAS_GRAPHICSPROVIDER_HXX */ diff --git a/canvas/source/directx/dx_ibitmap.hxx b/canvas/source/directx/dx_ibitmap.hxx new file mode 100644 index 000000000000..6419d5a198fc --- /dev/null +++ b/canvas/source/directx/dx_ibitmap.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 _DXCANVAS_DXIBITMAP_HXX +#define _DXCANVAS_DXIBITMAP_HXX + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> +#include <boost/shared_ptr.hpp> +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include "dx_graphicsprovider.hxx" + +namespace dxcanvas +{ + /// Interface for internal canvas bitmap objects + struct IBitmap : public GraphicsProvider + { + virtual BitmapSharedPtr getBitmap() const = 0; + virtual ::basegfx::B2IVector getSize() const = 0; + virtual bool hasAlpha() const = 0; + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > getData( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ) = 0; + + virtual 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 ) = 0; + + virtual 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 ) = 0; + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > getPixel( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ) = 0; + }; + + typedef boost::shared_ptr<IBitmap> IBitmapSharedPtr; +} + +#endif diff --git a/canvas/source/directx/dx_impltools.cxx b/canvas/source/directx/dx_impltools.cxx new file mode 100755 index 000000000000..c298fb9238f9 --- /dev/null +++ b/canvas/source/directx/dx_impltools.cxx @@ -0,0 +1,668 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/geometry/IntegerRectangle2D.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <canvas/canvastools.hxx> +#include <canvas/verifyinput.hxx> + +#include "dx_impltools.hxx" +#include "dx_vcltools.hxx" +#include "dx_linepolypolygon.hxx" +#include "dx_canvasbitmap.hxx" +#include "dx_canvasfont.hxx" +#include "dx_canvas.hxx" +#include "dx_spritecanvas.hxx" + +#include <boost/scoped_array.hpp> + +#include <vector> +#include <algorithm> + + +using namespace ::com::sun::star; + + +namespace dxcanvas +{ + namespace tools + { + ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) + { + LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); + + if( pPolyImpl ) + { + return pPolyImpl->getPolyPolygon(); + } + else + { + const sal_Int32 nPolys( xPoly->getNumberOfPolygons() ); + + // not a known implementation object - try data source + // interfaces + uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly( + xPoly, + uno::UNO_QUERY ); + + if( xBezierPoly.is() ) + { + return ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( + xBezierPoly->getBezierSegments( 0, + nPolys, + 0, + -1 ) ); + } + else + { + uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly( + xPoly, + uno::UNO_QUERY ); + + // no implementation class and no data provider + // found - contract violation. + ENSURE_ARG_OR_THROW( xLinePoly.is(), + "VCLCanvas::polyPolygonFromXPolyPolygon2D(): Invalid input " + "poly-polygon, cannot retrieve vertex data" ); + + return ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( + xLinePoly->getPoints( 0, + nPolys, + 0, + -1 ) ); + } + } + } + + void setupGraphics( Gdiplus::Graphics& rGraphics ) + { + // setup graphics with (somewhat arbitrary) defaults + //rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighQuality ); + rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighSpeed ); + //rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBilinear ); // with prefiltering for shrinks + rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeBilinear ); + + // #122683# Switched precedence of pixel offset + // mode. Seemingly, polygon stroking needs + // PixelOffsetModeNone to achieve visually pleasing + // results, whereas all other operations (e.g. polygon + // fills, bitmaps) look better with PixelOffsetModeHalf. + rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeHalf ); // Pixel center at (0.5, 0.5) etc. + //rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); + + //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighSpeed ); // no line/curve antialiasing + //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighQuality ); + rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeAntiAlias ); + //rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintAntiAlias ); + rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintSystemDefault ); + rGraphics.SetPageUnit(Gdiplus::UnitPixel); + } + + Gdiplus::Graphics* createGraphicsFromHDC(HDC aHDC) + { + Gdiplus::Graphics* pRet = new Gdiplus::Graphics(aHDC); + if( pRet ) + setupGraphics( *pRet ); + return pRet; + } + + Gdiplus::Graphics* createGraphicsFromBitmap(const BitmapSharedPtr& rBitmap) + { + Gdiplus::Graphics* pRet = Gdiplus::Graphics::FromImage(rBitmap.get()); + if( pRet ) + setupGraphics( *pRet ); + return pRet; + } + + void gdiPlusMatrixFromB2DHomMatrix( Gdiplus::Matrix& rGdiplusMatrix, const ::basegfx::B2DHomMatrix& rMatrix ) + { + rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.get(0,0)), + static_cast<Gdiplus::REAL>(rMatrix.get(1,0)), + static_cast<Gdiplus::REAL>(rMatrix.get(0,1)), + static_cast<Gdiplus::REAL>(rMatrix.get(1,1)), + static_cast<Gdiplus::REAL>(rMatrix.get(0,2)), + static_cast<Gdiplus::REAL>(rMatrix.get(1,2)) ); + } + + void gdiPlusMatrixFromAffineMatrix2D( Gdiplus::Matrix& rGdiplusMatrix, + const geometry::AffineMatrix2D& rMatrix ) + { + rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.m00), + static_cast<Gdiplus::REAL>(rMatrix.m10), + static_cast<Gdiplus::REAL>(rMatrix.m01), + static_cast<Gdiplus::REAL>(rMatrix.m11), + static_cast<Gdiplus::REAL>(rMatrix.m02), + static_cast<Gdiplus::REAL>(rMatrix.m12) ); + } + + namespace + { + // TODO(P2): Check whether this gets inlined. If not, make functor + // out of it + inline Gdiplus::PointF implGdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) + { + return Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.X), + static_cast<Gdiplus::REAL>(rPoint.Y) ); + } + + void graphicsPathFromB2DPolygon( GraphicsPathSharedPtr& rOutput, + ::std::vector< Gdiplus::PointF >& rPoints, + const ::basegfx::B2DPolygon& rPoly, + bool bNoLineJoin) + { + const sal_uInt32 nPoints( rPoly.count() ); + + if( nPoints < 2 ) + return; + + rOutput->StartFigure(); + + const bool bClosedPolygon( rPoly.isClosed() ); + + if( rPoly.areControlPointsUsed() ) + { + // control points used -> for now, add all + // segments as curves to GraphicsPath + + // If the polygon is closed, we need to add the + // first point, thus, one more (can't simply + // GraphicsPath::CloseFigure() it, since the last + // point cannot have any control points for GDI+) + rPoints.resize( 3*nPoints + bClosedPolygon ); + + sal_uInt32 nCurrOutput=0; + for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) + { + const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); + rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), + static_cast<Gdiplus::REAL>(rPoint.getY()) ); + + const ::basegfx::B2DPoint& rControlPointA( rPoly.getNextControlPoint( nCurrPoint ) ); + rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointA.getX()), + static_cast<Gdiplus::REAL>(rControlPointA.getY()) ); + + const ::basegfx::B2DPoint& rControlPointB( rPoly.getPrevControlPoint( (nCurrPoint + 1) % nPoints) ); + rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointB.getX()), + static_cast<Gdiplus::REAL>(rControlPointB.getY()) ); + } + + if( bClosedPolygon ) + { + // add first point again (to be able to pass + // control points for the last point, see + // above) + const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint(0) ); + rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), + static_cast<Gdiplus::REAL>(rPoint.getY()) ); + + if(bNoLineJoin && nCurrOutput > 7) + { + for(sal_uInt32 a(3); a < nCurrOutput; a+=3) + { + rOutput->StartFigure(); + rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); + } + } + else + { + rOutput->AddBeziers( &rPoints[0], nCurrOutput ); + } + } + else + { + // GraphicsPath expects 3(n-1)+1 points (i.e. the + // last point must not have any trailing control + // points after it). + // Therefore, simply don't pass the last two + // points here. + if( nCurrOutput > 3 ) + { + if(bNoLineJoin && nCurrOutput > 7) + { + for(sal_uInt32 a(3); a < nCurrOutput; a+=3) + { + rOutput->StartFigure(); + rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); + } + } + else + { + rOutput->AddBeziers( &rPoints[0], nCurrOutput-2 ); + } + } + } + } + else + { + // no control points -> no curves, simply add + // straigt lines to GraphicsPath + rPoints.resize( nPoints ); + + for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) + { + const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); + rPoints[nCurrPoint] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), + static_cast<Gdiplus::REAL>(rPoint.getY()) ); + } + + if(bNoLineJoin && nPoints > 2) + { + for(sal_uInt32 a(1); a < nPoints; a++) + { + rOutput->StartFigure(); + rOutput->AddLine(rPoints[a - 1], rPoints[a]); + } + + if(bClosedPolygon) + { + rOutput->StartFigure(); + rOutput->AddLine(rPoints[nPoints - 1], rPoints[0]); + } + } + else + { + rOutput->AddLines( &rPoints[0], nPoints ); + } + } + + if( bClosedPolygon && !bNoLineJoin ) + rOutput->CloseFigure(); + } + } + + Gdiplus::PointF gdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) + { + return implGdiPlusPointFromRealPoint2D( rPoint ); + } + + Gdiplus::Rect gdiPlusRectFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRect ) + { + return Gdiplus::Rect( rRect.X1, + rRect.Y1, + rRect.X2 - rRect.X1, + rRect.Y2 - rRect.Y1 ); + } + + Gdiplus::RectF gdiPlusRectFFromRectangle2D( const geometry::RealRectangle2D& rRect ) + { + return Gdiplus::RectF( static_cast<Gdiplus::REAL>(rRect.X1), + static_cast<Gdiplus::REAL>(rRect.Y1), + static_cast<Gdiplus::REAL>(rRect.X2 - rRect.X1), + static_cast<Gdiplus::REAL>(rRect.Y2 - rRect.Y1) ); + } + + RECT gdiRectFromB2IRect( const ::basegfx::B2IRange& rRect ) + { + RECT aRect = {rRect.getMinX(), + rRect.getMinY(), + rRect.getMaxX(), + rRect.getMaxY()}; + + return aRect; + } + + geometry::RealPoint2D realPoint2DFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) + { + return geometry::RealPoint2D( rPoint.X, rPoint.Y ); + } + + geometry::RealRectangle2D realRectangle2DFromGdiPlusRectF( const Gdiplus::RectF& rRect ) + { + return geometry::RealRectangle2D( rRect.X, rRect.Y, + rRect.X + rRect.Width, + rRect.Y + rRect.Height ); + } + + ::basegfx::B2DPoint b2dPointFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) + { + return ::basegfx::B2DPoint( rPoint.X, rPoint.Y ); + } + + ::basegfx::B2DRange b2dRangeFromGdiPlusRectF( const Gdiplus::RectF& rRect ) + { + return ::basegfx::B2DRange( rRect.X, rRect.Y, + rRect.X + rRect.Width, + rRect.Y + rRect.Height ); + } + + uno::Sequence< double > argbToDoubleSequence( const Gdiplus::ARGB& rColor ) + { + // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice + uno::Sequence< double > aRet(4); + + aRet[0] = ((rColor >> 16) & 0xFF) / 255.0; // red + aRet[1] = ((rColor >> 8) & 0xFF) / 255.0; // green + aRet[2] = (rColor & 0xFF) / 255.0; // blue + aRet[3] = ((rColor >> 24) & 0xFF) / 255.0; // alpha + + return aRet; + } + + uno::Sequence< sal_Int8 > argbToIntSequence( const Gdiplus::ARGB& rColor ) + { + // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice + uno::Sequence< sal_Int8 > aRet(4); + + aRet[0] = static_cast<sal_Int8>((rColor >> 16) & 0xFF); // red + aRet[1] = static_cast<sal_Int8>((rColor >> 8) & 0xFF); // green + aRet[2] = static_cast<sal_Int8>(rColor & 0xFF); // blue + aRet[3] = static_cast<sal_Int8>((rColor >> 24) & 0xFF); // alpha + + return aRet; + } + + Gdiplus::ARGB sequenceToArgb( const uno::Sequence< sal_Int8 >& rColor ) + { + ENSURE_OR_THROW( rColor.getLength() > 2, + "sequenceToArgb: need at least three channels" ); + + // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice + Gdiplus::ARGB aColor; + + aColor = (static_cast<sal_uInt8>(rColor[0]) << 16) | (static_cast<sal_uInt8>(rColor[1]) << 8) | static_cast<sal_uInt8>(rColor[2]); + + if( rColor.getLength() > 3 ) + aColor |= static_cast<sal_uInt8>(rColor[3]) << 24; + + return aColor; + } + + Gdiplus::ARGB sequenceToArgb( const uno::Sequence< double >& rColor ) + { + ENSURE_OR_THROW( rColor.getLength() > 2, + "sequenceToColor: need at least three channels" ); + + // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice + Gdiplus::ARGB aColor; + + ::canvas::tools::verifyRange(rColor[0],0.0,1.0); + ::canvas::tools::verifyRange(rColor[1],0.0,1.0); + ::canvas::tools::verifyRange(rColor[2],0.0,1.0); + + aColor = + (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[0] ) ) << 16) | + (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[1] ) ) << 8) | + static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[2] ) ); + + if( rColor.getLength() > 3 ) + { + ::canvas::tools::verifyRange(rColor[3],0.0,1.0); + aColor |= static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[3] ) ) << 24; + } + + return aColor; + } + + GraphicsPathSharedPtr graphicsPathFromRealPoint2DSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) + { + GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); + ::std::vector< Gdiplus::PointF > aPoints; + + sal_Int32 nCurrPoly; + for( nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly ) + { + const sal_Int32 nCurrSize( points[nCurrPoly].getLength() ); + if( nCurrSize ) + { + aPoints.resize( nCurrSize ); + + // TODO(F1): Closed/open polygons + + // convert from RealPoint2D array to Gdiplus::PointF array + ::std::transform( const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray(), + const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray()+nCurrSize, + aPoints.begin(), + implGdiPlusPointFromRealPoint2D ); + + pRes->AddLines( &aPoints[0], nCurrSize ); + } + } + + return pRes; + } + + GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly, bool bNoLineJoin ) + { + GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); + ::std::vector< Gdiplus::PointF > aPoints; + + graphicsPathFromB2DPolygon( pRes, aPoints, rPoly, bNoLineJoin ); + + return pRes; + } + + GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, bool bNoLineJoin ) + { + GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); + ::std::vector< Gdiplus::PointF > aPoints; + + const sal_uInt32 nPolies( rPoly.count() ); + for( sal_uInt32 nCurrPoly=0; nCurrPoly<nPolies; ++nCurrPoly ) + { + graphicsPathFromB2DPolygon( pRes, + aPoints, + rPoly.getB2DPolygon( nCurrPoly ), + bNoLineJoin); + } + + return pRes; + } + + GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly, bool bNoLineJoin ) + { + LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); + + if( pPolyImpl ) + { + return pPolyImpl->getGraphicsPath( bNoLineJoin ); + } + else + { + return tools::graphicsPathFromB2DPolyPolygon( + polyPolygonFromXPolyPolygon2D( xPoly ), bNoLineJoin ); + } + } + + bool drawGdiPlusBitmap( const GraphicsSharedPtr& rGraphics, + const BitmapSharedPtr& rBitmap ) + { + Gdiplus::PointF aPoint; + return (Gdiplus::Ok == rGraphics->DrawImage( rBitmap.get(), + aPoint ) ); + } + + bool drawDIBits( const GraphicsSharedPtr& rGraphics, + const BITMAPINFO& rBI, + const void* pBits ) + { + BitmapSharedPtr pBitmap( + Gdiplus::Bitmap::FromBITMAPINFO( &rBI, + (void*)pBits ) ); + + return drawGdiPlusBitmap( rGraphics, + pBitmap ); + } + + bool drawRGBABits( const GraphicsSharedPtr& rGraphics, + const RawRGBABitmap& rRawRGBAData ) + { + BitmapSharedPtr pBitmap( new Gdiplus::Bitmap( rRawRGBAData.mnWidth, + rRawRGBAData.mnHeight, + PixelFormat32bppARGB ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rRawRGBAData.mnWidth; + aBmpData.Height = rRawRGBAData.mnHeight; + aBmpData.Stride = 4*aBmpData.Width; // bottom-up format + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = rRawRGBAData.mpBitmapData.get(); + + const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height ); + if( Gdiplus::Ok != pBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, + &aBmpData ) ) + { + return false; + } + + // commit data to bitmap + pBitmap->UnlockBits( &aBmpData ); + + return drawGdiPlusBitmap( rGraphics, + pBitmap ); + } + + BitmapSharedPtr bitmapFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) + { + BitmapProvider* pBitmapProvider = dynamic_cast< BitmapProvider* >(xBitmap.get()); + + if( pBitmapProvider ) + { + IBitmapSharedPtr pBitmap( pBitmapProvider->getBitmap() ); + return pBitmap->getBitmap(); + } + else + { + // not a native CanvasBitmap, extract VCL bitmap and + // render into GDI+ bitmap of similar size + // ================================================= + + const geometry::IntegerSize2D aBmpSize( xBitmap->getSize() ); + BitmapSharedPtr pBitmap; + + if( xBitmap->hasAlpha() ) + { + // TODO(P2): At least for the alpha bitmap case, it + // would be possible to generate the corresponding + // bitmap directly + pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, + aBmpSize.Height, + PixelFormat32bppARGB ) ); + } + else + { + // TODO(F2): Might be wise to create bitmap compatible + // to the VCL bitmap. Also, check whether the VCL + // bitmap's system handles can be used to create the + // GDI+ bitmap (currently, it does not seem so). + pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, + aBmpSize.Height, + PixelFormat24bppRGB ) ); + } + + GraphicsSharedPtr pGraphics(createGraphicsFromBitmap(pBitmap)); + tools::setupGraphics(*pGraphics); + if( !drawVCLBitmapFromXBitmap( + pGraphics, + xBitmap) ) + { + pBitmap.reset(); + } + + return pBitmap; + } + } + + CanvasFont::ImplRef canvasFontFromXFont( const uno::Reference< rendering::XCanvasFont >& xFont ) + { + CanvasFont* pCanvasFont = dynamic_cast< CanvasFont* >(xFont.get()); + + ENSURE_ARG_OR_THROW( pCanvasFont, + "canvasFontFromXFont(): Invalid XFont (or incompatible font for this XCanvas)" ); + + return CanvasFont::ImplRef( pCanvasFont ); + } + + void setModulateImageAttributes( Gdiplus::ImageAttributes& o_rAttr, + double nRedModulation, + double nGreenModulation, + double nBlueModulation, + double nAlphaModulation ) + { + // This gets rather verbose, but we have to setup a color + // transformation matrix, in order to incorporate the global + // alpha value mfAlpha into the bitmap rendering. + Gdiplus::ColorMatrix aColorMatrix; + + aColorMatrix.m[0][0] = static_cast<Gdiplus::REAL>(nRedModulation); + aColorMatrix.m[0][1] = 0.0; + aColorMatrix.m[0][2] = 0.0; + aColorMatrix.m[0][3] = 0.0; + aColorMatrix.m[0][4] = 0.0; + + aColorMatrix.m[1][0] = 0.0; + aColorMatrix.m[1][1] = static_cast<Gdiplus::REAL>(nGreenModulation); + aColorMatrix.m[1][2] = 0.0; + aColorMatrix.m[1][3] = 0.0; + aColorMatrix.m[1][4] = 0.0; + + aColorMatrix.m[2][0] = 0.0; + aColorMatrix.m[2][1] = 0.0; + aColorMatrix.m[2][2] = static_cast<Gdiplus::REAL>(nBlueModulation); + aColorMatrix.m[2][3] = 0.0; + aColorMatrix.m[2][4] = 0.0; + + aColorMatrix.m[3][0] = 0.0; + aColorMatrix.m[3][1] = 0.0; + aColorMatrix.m[3][2] = 0.0; + aColorMatrix.m[3][3] = static_cast<Gdiplus::REAL>(nAlphaModulation); + aColorMatrix.m[3][4] = 0.0; + + aColorMatrix.m[4][0] = 0.0; + aColorMatrix.m[4][1] = 0.0; + aColorMatrix.m[4][2] = 0.0; + aColorMatrix.m[4][3] = 0.0; + aColorMatrix.m[4][4] = 1.0; + + o_rAttr.SetColorMatrix( &aColorMatrix, + Gdiplus::ColorMatrixFlagsDefault, + Gdiplus::ColorAdjustTypeDefault ); + } + + } // namespace tools +} // namespace dxcanvas diff --git a/canvas/source/directx/dx_impltools.hxx b/canvas/source/directx/dx_impltools.hxx new file mode 100755 index 000000000000..6eb0bc415ea5 --- /dev/null +++ b/canvas/source/directx/dx_impltools.hxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * 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 _DXCANVAS_IMPLTOOLS_HXX +#define _DXCANVAS_IMPLTOOLS_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/util/TriState.hpp> + +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <boost/shared_ptr.hpp> +#include "dx_canvasfont.hxx" + +namespace basegfx +{ + class B2DPoint; + class B2DRange; + class B2DHomMatrix; + class B2IPoint; + class B2IRange; + class B2DPolyPolygon; +}; + +namespace com { namespace sun { namespace star { namespace geometry +{ + struct IntegerRectangle2D; + struct RealPoint2D; +} } } } + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XCanvas; + class XGraphicDevice; + class XBitmap; + class XPolyPolygon2D; + class XCanvasFont; +} } } } + + +namespace dxcanvas +{ + namespace tools + { + struct RawRGBABitmap; + + ::basegfx::B2DPolyPolygon + polyPolygonFromXPolyPolygon2D( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& ); + + Gdiplus::Graphics* createGraphicsFromHDC(HDC); + Gdiplus::Graphics* createGraphicsFromBitmap(const BitmapSharedPtr&); + + void setupGraphics( Gdiplus::Graphics& rGraphics ); + + void gdiPlusMatrixFromB2DHomMatrix( Gdiplus::Matrix& rGdiplusMatrix, + const ::basegfx::B2DHomMatrix& rMatrix ); + void gdiPlusMatrixFromAffineMatrix2D( Gdiplus::Matrix& rGdiplusMatrix, + const ::com::sun::star::geometry::AffineMatrix2D& rMatrix ); + + Gdiplus::PointF gdiPlusPointFFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& ); + Gdiplus::RectF gdiPlusRectFFromRectangle2D( const ::com::sun::star::geometry::RealRectangle2D& ); + Gdiplus::Rect gdiPlusRectFromIntegerRectangle2D( const ::com::sun::star::geometry::IntegerRectangle2D& ); + RECT gdiRectFromB2IRect( const ::basegfx::B2IRange& ); + + ::com::sun::star::geometry::RealPoint2D realPoint2DFromGdiPlusPointF( const Gdiplus::PointF& ); + ::com::sun::star::geometry::RealRectangle2D realRectangle2DFromGdiPlusRectF( const Gdiplus::RectF& ); + + ::basegfx::B2DPoint b2dPointFromGdiPlusPointF( const Gdiplus::PointF& ); + ::basegfx::B2DRange b2dRangeFromGdiPlusRectF( const Gdiplus::RectF& ); + + ::com::sun::star::uno::Sequence< double > argbToDoubleSequence( const Gdiplus::ARGB& rColor ); + ::com::sun::star::uno::Sequence< sal_Int8 > argbToIntSequence( const Gdiplus::ARGB& rColor ); + Gdiplus::ARGB sequenceToArgb( const ::com::sun::star::uno::Sequence< sal_Int8 >& rColor ); + Gdiplus::ARGB sequenceToArgb( const ::com::sun::star::uno::Sequence< double >& rColor ); + + GraphicsPathSharedPtr graphicsPathFromRealPoint2DSequence( const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > >& ); + + GraphicsPathSharedPtr graphicsPathFromB2DPolygon( + const ::basegfx::B2DPolygon& rPoly, + bool bNoLineJoin = false); + + GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( + const ::basegfx::B2DPolyPolygon& rPoly, + bool bNoLineJoin = false); + + GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >&, + bool bNoLineJoin = false ); + + bool drawGdiPlusBitmap( const GraphicsSharedPtr& rGraphics, + const BitmapSharedPtr& rBitmap ); + bool drawDIBits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const BITMAPINFO& rBI, + const void* pBits ); + + bool drawRGBABits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const RawRGBABitmap& rRawRGBAData ); + + BitmapSharedPtr bitmapFromXBitmap( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap ); + + CanvasFont::ImplRef canvasFontFromXFont( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& xFont ); + + void setModulateImageAttributes( Gdiplus::ImageAttributes& o_rAttr, + double nRedModulation, + double nGreenModulation, + double nBlueModulation, + double nAlphaModulation ); + } +} + +#endif /* _DXCANVAS_IMPLTOOLS_HXX */ diff --git a/canvas/source/directx/dx_linepolypolygon.cxx b/canvas/source/directx/dx_linepolypolygon.cxx new file mode 100755 index 000000000000..12bd4e98ae31 --- /dev/null +++ b/canvas/source/directx/dx_linepolypolygon.cxx @@ -0,0 +1,65 @@ +/************************************************************************* + * + * 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 <basegfx/tools/canvastools.hxx> +#include "dx_linepolypolygon.hxx" + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + LinePolyPolygon::LinePolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ) : + ::basegfx::unotools::UnoPolyPolygon( rPolyPoly ), + mpGdiPlusUser( GDIPlusUser::createInstance() ), + mpPath() + { + } + + GraphicsPathSharedPtr LinePolyPolygon::getGraphicsPath( bool bNoLineJoin ) const + { + // generate GraphicsPath only on demand (gets deleted as soon + // as any of the modifying methods above touches the + // B2DPolyPolygon). + if( !mpPath ) + { + mpPath = tools::graphicsPathFromB2DPolyPolygon( getPolyPolygonUnsafe(), bNoLineJoin ); + mpPath->SetFillMode( const_cast<LinePolyPolygon*>(this)->getFillRule() == rendering::FillRule_EVEN_ODD ? + Gdiplus::FillModeAlternate : Gdiplus::FillModeWinding ); + } + + return mpPath; + } + + void LinePolyPolygon::modifying() const + { + mpPath.reset(); + } +} diff --git a/canvas/source/directx/dx_linepolypolygon.hxx b/canvas/source/directx/dx_linepolypolygon.hxx new file mode 100755 index 000000000000..cb2d76587169 --- /dev/null +++ b/canvas/source/directx/dx_linepolypolygon.hxx @@ -0,0 +1,56 @@ +/************************************************************************* + * + * 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 _DXCANVAS_LINEPOLYPOLYGON_HXX_ +#define _DXCANVAS_LINEPOLYPOLYGON_HXX_ + +#include <canvas/canvastools.hxx> +#include <basegfx/tools/unopolypolygon.hxx> + +#include "dx_gdiplususer.hxx" +#include "dx_impltools.hxx" + + +namespace dxcanvas +{ + class LinePolyPolygon : public ::basegfx::unotools::UnoPolyPolygon + { + public: + explicit LinePolyPolygon( const ::basegfx::B2DPolyPolygon& ); + + GraphicsPathSharedPtr getGraphicsPath( bool bNoLineJoin = false) const; + + private: + // overridden, to clear mpPath + virtual void modifying() const; + + GDIPlusUserSharedPtr mpGdiPlusUser; + mutable GraphicsPathSharedPtr mpPath; + }; +} + +#endif /* _DXCANVAS_LINEPOLYPOLYGON_HXX_ */ diff --git a/canvas/source/directx/dx_rendermodule.hxx b/canvas/source/directx/dx_rendermodule.hxx new file mode 100755 index 000000000000..e6bd8a7b5701 --- /dev/null +++ b/canvas/source/directx/dx_rendermodule.hxx @@ -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. + * + ************************************************************************/ + +#ifndef _DXCANVAS_RENDERMODULE_HXX +#define _DXCANVAS_RENDERMODULE_HXX + +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <boost/shared_ptr.hpp> +#include "dx_winstuff.hxx" + +class Window; +namespace basegfx +{ + class B2IRange; + class B2DVector; +} + +namespace dxcanvas +{ + /// Specialization of IRenderModule for DirectX + struct IDXRenderModule : public canvas::IRenderModule + { + /** Flip front- and backbuffer, update only given area + + Note: Both update area and offset are ignored for + fullscreen canvas, that uses page flipping (cannot, by + definition, do anything else there except displaying the + full backbuffer instead of the front buffer) + + @param rUpdateArea + Area to copy from backbuffer to front + + @param rCurrWindowArea + Current area of VCL window (coordinates relative to VCL + HWND) + */ + virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea, + const ::basegfx::B2IRectangle& rCurrWindowArea ) = 0; + + /** Resize backbuffer area for this render module + */ + virtual void resize( const ::basegfx::B2IRange& rect ) = 0; + + /// Write a snapshot of the screen to disk + virtual void screenShot() = 0; + + virtual COMReference<surface_type> + createSystemMemorySurface( + const ::basegfx::B2IVector& rSize ) = 0; + + virtual void disposing() = 0; + virtual HWND getHWND() const = 0; + }; + + typedef ::boost::shared_ptr< IDXRenderModule > IDXRenderModuleSharedPtr; + + + /** Factory method, to create an IRenderModule instance for the + given VCL window instance + */ + IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent ); +} + +#endif diff --git a/canvas/source/directx/dx_sprite.hxx b/canvas/source/directx/dx_sprite.hxx new file mode 100755 index 000000000000..56c984439f45 --- /dev/null +++ b/canvas/source/directx/dx_sprite.hxx @@ -0,0 +1,51 @@ +/************************************************************************* + * + * 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 INCLUDED_DXCANVAS_SPRITE_HXX +#define INCLUDED_DXCANVAS_SPRITE_HXX + +#include <canvas/base/sprite.hxx> + +namespace dxcanvas +{ + /** Specialization of ::canvas::Sprite interface, to also provide + redraw methods. + */ + class Sprite : public ::canvas::Sprite + { + public: + + /** Redraw sprite using the hardware + + This method will silently fail, if the previous + restoreTextures() call failed. + */ + virtual void redraw() const = 0; + }; +} + +#endif /* INCLUDED_DXCANVAS_SPRITE_HXX */ diff --git a/canvas/source/directx/dx_spritecanvas.cxx b/canvas/source/directx/dx_spritecanvas.cxx new file mode 100755 index 000000000000..43350287d92a --- /dev/null +++ b/canvas/source/directx/dx_spritecanvas.cxx @@ -0,0 +1,211 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <tools/diagnose_ex.h> + +#include <canvas/canvastools.hxx> + +#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 <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <comphelper/servicedecl.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include "dx_winstuff.hxx" +#include "dx_spritecanvas.hxx" + +#if DIRECTX_VERSION < 0x0900 +# define CANVAS_TECH "DX5" +#else +# define CANVAS_TECH "DX9" +#endif + +#define SPRITECANVAS_SERVICE_NAME "com.sun.star.rendering.SpriteCanvas." CANVAS_TECH +#define SPRITECANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.SpriteCanvas." CANVAS_TECH + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ) + { + } + + void SpriteCanvas::initialize() + { + // #i64742# Only call initialize when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + VERBOSE_TRACE( "SpriteCanvas::initialize called" ); + + /* aArguments: + 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() >= 5 && + maArguments[4].getValueTypeClass() == uno::TypeClass_INTERFACE, + "VCLSpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + 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); + + awt::Rectangle aRect; + maArguments[2] >>= aRect; + + sal_Bool bIsFullscreen( sal_False ); + maArguments[3] >>= bIsFullscreen; + + // setup helper + maDeviceHelper.init( *pParentWindow, + *this, + aRect, + bIsFullscreen ); + maCanvasHelper.init( *this, + maRedrawManager, + maDeviceHelper.getRenderModule(), + maDeviceHelper.getSurfaceProxy(), + maDeviceHelper.getBackBuffer(), + ::basegfx::B2ISize() ); + 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) + { + ::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 : SpriteCanvasBaseT::showBuffer( bUpdateAll ); + } + + ::sal_Bool SAL_CALL SpriteCanvas::switchBuffer( ::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 : SpriteCanvasBaseT::switchBuffer( 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 ) ); + } + + const IDXRenderModuleSharedPtr& SpriteCanvas::getRenderModule() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maDeviceHelper.getRenderModule(); + } + + const DXSurfaceBitmapSharedPtr& SpriteCanvas::getBackBuffer() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maDeviceHelper.getBackBuffer(); + } + + IBitmapSharedPtr SpriteCanvas::getBitmap() const + { + return maDeviceHelper.getBackBuffer(); + } + + static uno::Reference<uno::XInterface> initCanvas( 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> > serviceImpl(&initCanvas); + const sdecl::ServiceDecl dxSpriteCanvasDecl( + serviceImpl, + SPRITECANVAS_IMPLEMENTATION_NAME, + SPRITECANVAS_SERVICE_NAME ); +} + +// The C shared lib entry points +COMPHELPER_SERVICEDECL_EXPORTS1(dxcanvas::dxSpriteCanvasDecl); diff --git a/canvas/source/directx/dx_spritecanvas.hxx b/canvas/source/directx/dx_spritecanvas.hxx new file mode 100755 index 000000000000..b14d79050ccf --- /dev/null +++ b/canvas/source/directx/dx_spritecanvas.hxx @@ -0,0 +1,155 @@ +/************************************************************************* + * + * 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 _DXCANVAS_SPRITECANVAS_HXX_ +#define _DXCANVAS_SPRITECANVAS_HXX_ + +#include <rtl/ref.hxx> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.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 "dx_bitmapprovider.hxx" +#include "dx_spritecanvashelper.hxx" +#include "dx_surfacebitmap.hxx" +#include "dx_impltools.hxx" +#include "dx_spritedevicehelper.hxx" + + +namespace dxcanvas +{ + 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 + { + }; + + 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 BitmapProvider + { + 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(); + + /// 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); + + /// Retrieve rendermodule object for this Canvas + const IDXRenderModuleSharedPtr& getRenderModule() const; + + /// Get backbuffer for this canvas + const DXSurfaceBitmapSharedPtr& getBackBuffer() const; + + // BitmapProvider + virtual IBitmapSharedPtr getBitmap() const; + + 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/directx/dx_spritecanvashelper.cxx b/canvas/source/directx/dx_spritecanvashelper.cxx new file mode 100755 index 000000000000..211fd5502919 --- /dev/null +++ b/canvas/source/directx/dx_spritecanvashelper.cxx @@ -0,0 +1,382 @@ +/************************************************************************* + * + * 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 <comphelper/scopeguard.hxx> + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <boost/cast.hpp> + +#include "dx_spritecanvashelper.hxx" +#include "dx_canvascustomsprite.hxx" + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + void repaintBackground( const ::basegfx::B2DRange& rUpdateArea, + const ::basegfx::B2IRange& rOutputArea, + const DXSurfaceBitmapSharedPtr& rBackBuffer ) + { + // TODO(E1): Use numeric_cast to catch overflow here + ::basegfx::B2IRange aActualArea( 0, 0, + static_cast<sal_Int32>(rOutputArea.getWidth()), + static_cast<sal_Int32>(rOutputArea.getHeight()) ); + aActualArea.intersect( fround( rUpdateArea ) ); + + // repaint the given area of the screen with background content + rBackBuffer->draw(aActualArea); + } + + void spriteRedraw( const ::canvas::Sprite::Reference& rSprite ) + { + // downcast to derived dxcanvas::Sprite interface, which + // provides the actual redraw methods. + ::boost::polymorphic_downcast< Sprite* >( + rSprite.get() )->redraw(); + } + + void spriteRedrawStub( const ::canvas::Sprite::Reference& rSprite ) + { + if( rSprite.is() ) + { + // downcast to derived dxcanvas::Sprite interface, which + // provides the actual redraw methods. + ::boost::polymorphic_downcast< Sprite* >( + rSprite.get() )->redraw(); + } + } + + void spriteRedrawStub2( const ::canvas::SpriteRedrawManager::AreaComponent& rComponent ) + { + if( rComponent.second.getSprite().is() ) + { + // downcast to derived dxcanvas::Sprite interface, which + // provides the actual redraw methods. + ::boost::polymorphic_downcast< Sprite* >( + rComponent.second.getSprite().get() )->redraw(); + } + } + } + + SpriteCanvasHelper::SpriteCanvasHelper() : + mpSpriteSurface( NULL ), + mpRedrawManager( NULL ), + mpRenderModule(), + mpSurfaceProxy(), + mpBackBuffer(), + maUpdateRect(), + maScrapRect(), + mbShowSpriteBounds( false ) + { +#if defined(VERBOSE) && defined(DBG_UTIL) + // inverse default for verbose debug mode + mbShowSpriteBounds = true; +#endif + } + + void SpriteCanvasHelper::init( SpriteCanvas& rParent, + ::canvas::SpriteRedrawManager& rManager, + const IDXRenderModuleSharedPtr& rRenderModule, + const ::canvas::ISurfaceProxyManagerSharedPtr& rSurfaceProxy, + const DXSurfaceBitmapSharedPtr& rBackBuffer, + const ::basegfx::B2ISize& rOutputOffset ) + { + // init base + setDevice( rParent ); + setTarget( rBackBuffer, rOutputOffset ); + + mpSpriteSurface = &rParent; + mpRedrawManager = &rManager; + mpRenderModule = rRenderModule; + mpSurfaceProxy = rSurfaceProxy; + mpBackBuffer = rBackBuffer; + } + + void SpriteCanvasHelper::disposing() + { + if(mpRenderModule) + mpRenderModule->disposing(); + + mpBackBuffer.reset(); + mpRenderModule.reset(); + mpRedrawManager = NULL; + mpSpriteSurface = NULL; + + // forward to base + CanvasHelper::disposing(); + } + + uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromAnimation( + const uno::Reference< rendering::XAnimation >& /*animation*/ ) + { + 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, + mpSpriteSurface, + mpRenderModule, + mpSurfaceProxy, + mbShowSpriteBounds ) ); + } + + uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite( const uno::Reference< rendering::XSprite >& /*original*/ ) + { + return uno::Reference< rendering::XSprite >(); + } + + sal_Bool SpriteCanvasHelper::updateScreen( const ::basegfx::B2IRectangle& rCurrArea, + sal_Bool bUpdateAll, + bool& io_bSurfaceDirty ) + { + if( !mpRedrawManager || + !mpRenderModule || + !mpBackBuffer ) + { + return sal_False; // disposed, or otherwise dysfunctional + } + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 + mpBackBuffer->imageDebugger(); +# endif +#endif + + // store current output area (need to tunnel that to the + // background, scroll, opaque and general sprite repaint + // routines) + maScrapRect = rCurrArea; + + // clear area that needs to be blitted to screen beforehand + maUpdateRect.reset(); + + // TODO(P1): Might be worthwile to track areas of background + // changes, too. + + // TODO(P2): Might be worthwhile to use page-flipping only if + // a certain percentage of screen area has changed - and + // compose directly to the front buffer otherwise. + 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 ); + + // flip primary surface to screen + // ============================== + + // perform buffer flipping + mpRenderModule->flip( maUpdateRect, + rCurrArea ); + } + else + { + // limit update to parent window area (ignored for fullscreen) + // TODO(E1): Use numeric_cast to catch overflow here + const ::basegfx::B2IRectangle aUpdateArea( 0,0, + static_cast<sal_Int32>(rCurrArea.getWidth()), + static_cast<sal_Int32>(rCurrArea.getHeight()) ); + + // background has changed, or called requested full + // update, or we're performing double buffering via page + // flipping, so we currently have no choice but repaint + // everything + + // repaint the whole screen with background content + mpBackBuffer->draw(aUpdateArea); + + // redraw sprites + mpRedrawManager->forEachSprite(::std::ptr_fun( &spriteRedraw ) ); + + // flip primary surface to screen + // ============================== + + // perform buffer flipping + mpRenderModule->flip( aUpdateArea, + rCurrArea ); + } + + // change record vector must be cleared, for the next turn of + // rendering and sprite changing + mpRedrawManager->clearChangeRecords(); + + io_bSurfaceDirty = false; + + return sal_True; + } + + void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& rUpdateRect ) + { + ENSURE_OR_THROW( mpRenderModule && + mpBackBuffer, + "SpriteCanvasHelper::backgroundPaint(): NULL device pointer " ); + + repaintBackground( rUpdateRect, + maScrapRect, + mpBackBuffer ); + } + + void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& /*rMoveStart*/, + const ::basegfx::B2DRange& rMoveEnd, + const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ) + { + ENSURE_OR_THROW( mpRenderModule && + mpBackBuffer, + "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " ); + + // 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. + const ::basegfx::B2IRange& rDestRect( + ::canvas::tools::spritePixelAreaFromB2DRange( rMoveEnd ) ); + + // not much sense in really implementing scrollUpdate here, + // since outputting a sprite only partially would result in + // expensive clipping. Furthermore, we cannot currently render + // 3D directly to the front buffer, thus, would have to blit + // the full sprite area, anyway. But at least optimized in the + // sense that unnecessary background paints behind the sprites + // are avoided. + ::std::for_each( rUpdateArea.maComponentList.begin(), + rUpdateArea.maComponentList.end(), + ::std::ptr_fun( &spriteRedrawStub2 ) ); + + // 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, + _1, + ::boost::cref(maScrapRect), + ::boost::cref(mpBackBuffer) ) ); + + // TODO(E1): Use numeric_cast to catch overflow here + ::basegfx::B2IRange aActualArea( 0, 0, + static_cast<sal_Int32>(maScrapRect.getWidth()), + static_cast<sal_Int32>(maScrapRect.getHeight()) ); + aActualArea.intersect( fround( rUpdateArea.maTotalBounds ) ); + + // add given update area to the 'blit to foreground' rect + maUpdateRect.expand( aActualArea ); + } + + void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) + { + ENSURE_OR_THROW( mpRenderModule && + mpBackBuffer, + "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " ); + + // TODO(P2): optimize this by truly rendering to the front + // buffer. Currently, we've the 3D device only for the back + // buffer. + ::std::for_each( rSortedUpdateSprites.begin(), + rSortedUpdateSprites.end(), + ::std::ptr_fun( &spriteRedrawStub ) ); + + // TODO(E1): Use numeric_cast to catch overflow here + ::basegfx::B2IRange aActualArea( 0, 0, + static_cast<sal_Int32>(maScrapRect.getWidth()), + static_cast<sal_Int32>(maScrapRect.getHeight()) ); + aActualArea.intersect( fround( rTotalArea ) ); + + // add given update area to the 'blit to foreground' rect + maUpdateRect.expand( aActualArea ); + } + + void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) + { + ENSURE_OR_THROW( mpRenderModule && + mpBackBuffer, + "SpriteCanvasHelper::genericUpdate(): NULL device pointer " ); + + // paint background + // ================ + + // TODO(E1): Use numeric_cast to catch overflow here + ::basegfx::B2IRange aActualArea( 0, 0, + static_cast<sal_Int32>(maScrapRect.getWidth()), + static_cast<sal_Int32>(maScrapRect.getHeight()) ); + aActualArea.intersect( fround( rTotalArea ) ); + + // repaint the given area of the screen with background content + mpBackBuffer->draw(aActualArea); + + // paint sprite + // ============ + + ::std::for_each( rSortedUpdateSprites.begin(), + rSortedUpdateSprites.end(), + ::std::ptr_fun( &spriteRedrawStub ) ); + + // add given update area to the 'blit to foreground' rect + maUpdateRect.expand( aActualArea ); + } +} diff --git a/canvas/source/directx/dx_spritecanvashelper.hxx b/canvas/source/directx/dx_spritecanvashelper.hxx new file mode 100755 index 000000000000..5015818e0c77 --- /dev/null +++ b/canvas/source/directx/dx_spritecanvashelper.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 _DXCANVAS_SPRITECANVASHELPER_HXX_ +#define _DXCANVAS_SPRITECANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <canvas/spriteredrawmanager.hxx> +#include <canvas/rendering/isurfaceproxy.hxx> +#include <canvas/rendering/isurfaceproxymanager.hxx> + +#include "dx_bitmapcanvashelper.hxx" +#include "dx_impltools.hxx" +#include "dx_rendermodule.hxx" +#include "dx_surfacebitmap.hxx" + +#include <basegfx/range/b2irectangle.hxx> + +namespace dxcanvas +{ + class SpriteCanvas; + + class SpriteCanvasHelper : public BitmapCanvasHelper + { + public: + SpriteCanvasHelper(); + + void init( SpriteCanvas& rParent, + ::canvas::SpriteRedrawManager& rManager, + const IDXRenderModuleSharedPtr& rRenderModule, + const ::canvas::ISurfaceProxyManagerSharedPtr& rSurfaceProxy, + const DXSurfaceBitmapSharedPtr& rBackBuffer, + const ::basegfx::B2ISize& rOutputOffset ); + + /// 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::B2IRectangle& 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: + /// For generating sprites + SpriteCanvas* mpSpriteSurface; + + /// Set from the SpriteCanvas: instance coordinating sprite redraw + ::canvas::SpriteRedrawManager* mpRedrawManager; + + /// DX device, handling all low-level rendering + IDXRenderModuleSharedPtr mpRenderModule; + + ::canvas::ISurfaceProxyManagerSharedPtr mpSurfaceProxy; + + /// Backbuffer, contains the static canvas render output + DXSurfaceBitmapSharedPtr mpBackBuffer; + + /// Completely temporary rect storage (used by sprite repaint) + mutable ::basegfx::B2IRange maUpdateRect; + + /// Completely temporary rect storage (used by sprite repaint) + mutable ::basegfx::B2IRange maScrapRect; + + /// When true, show small bound rects around each sprite + bool mbShowSpriteBounds; + }; +} + +#endif /* _DXCANVAS_SPRITECANVASHELPER_HXX_ */ diff --git a/canvas/source/directx/dx_spritedevicehelper.cxx b/canvas/source/directx/dx_spritedevicehelper.cxx new file mode 100644 index 000000000000..0437634a8d1e --- /dev/null +++ b/canvas/source/directx/dx_spritedevicehelper.cxx @@ -0,0 +1,259 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#include <ctype.h> // don't ask. msdev breaks otherwise... +#include <vcl/window.hxx> +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#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 "dx_linepolypolygon.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_canvasbitmap.hxx" +#include "dx_spritedevicehelper.hxx" + + +#undef WB_LEFT +#undef WB_RIGHT +#include "dx_winstuff.hxx" + + +#include <vcl/sysdata.hxx> + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + SpriteDeviceHelper::SpriteDeviceHelper() : + DeviceHelper(), + mpSpriteCanvas( NULL ), + mpSurfaceProxyManager(), + mpRenderModule(), + mpBackBuffer() + { + } + + void SpriteDeviceHelper::init( Window& rWindow, + SpriteCanvas& rSpriteCanvas, + const awt::Rectangle& rRect, + bool /*bFullscreen*/ ) + { + // #i60490# ensure backbuffer has sensible minimal size + const sal_Int32 w( ::std::max(sal_Int32(1),sal_Int32(rRect.Width))); + const sal_Int32 h( ::std::max(sal_Int32(1),sal_Int32(rRect.Height))); + + rSpriteCanvas.setWindow( + uno::Reference<awt::XWindow2>( + VCLUnoHelper::GetInterface(&rWindow), + uno::UNO_QUERY_THROW) ); + + const SystemEnvData *pData = rWindow.GetSystemData(); + const HWND hWnd = reinterpret_cast<HWND>(pData->hWnd); + if( !IsWindow( hWnd ) ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed window has invalid system window, or canvas out-of-process!")), + NULL); + + mpSpriteCanvas = &rSpriteCanvas; + + try + { + // setup directx rendermodule + mpRenderModule = createRenderModule( rWindow ); + } + catch (...) { + + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Could not create DirectX device!") ), + static_cast< ::cppu::OWeakObject* >(&rSpriteCanvas) ); + } + + // create the surfaceproxy manager + mpSurfaceProxyManager = ::canvas::createSurfaceProxyManager( mpRenderModule ); + + // #i60490# ensure backbuffer has sensible minimal size + mpBackBuffer.reset(new DXSurfaceBitmap( + ::basegfx::B2ISize(w,h), + mpSurfaceProxyManager, + mpRenderModule, + false)); + + // Assumes: SystemChildWindow() has CS_OWNDC + DeviceHelper::init(GetDC(mpRenderModule->getHWND()), + rSpriteCanvas); + } + + void SpriteDeviceHelper::disposing() + { + // release all references + mpBackBuffer.reset(); + mpSurfaceProxyManager.reset(); + mpRenderModule.reset(); + mpSpriteCanvas = NULL; + + DeviceHelper::disposing(); + } + + uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& size ) + { + if( !getDevice() ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + DXSurfaceBitmapSharedPtr pBitmap( + new DXSurfaceBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D(size), + mpSurfaceProxyManager, + mpRenderModule, + false)); + + // create a 24bit RGB system memory surface + return uno::Reference< rendering::XBitmap >(new CanvasBitmap(pBitmap,getDevice())); + } + + uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& size ) + { + if( !getDevice() ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + DXSurfaceBitmapSharedPtr pBitmap( + new DXSurfaceBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D(size), + mpSurfaceProxyManager, + mpRenderModule, + true)); + + // create a 32bit ARGB system memory surface + return uno::Reference< rendering::XBitmap >(new CanvasBitmap(pBitmap,getDevice())); + } + + uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const geometry::IntegerSize2D& /*size*/ ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + sal_Bool SpriteDeviceHelper::hasFullScreenMode() + { + // TODO(F3): offer fullscreen mode the XCanvas way + return false; + } + + sal_Bool SpriteDeviceHelper::enterFullScreenMode( sal_Bool /*bEnter*/ ) + { + // TODO(F3): offer fullscreen mode the XCanvas way + return false; + } + + ::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); + } + + void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds ) + { + // #i60490# ensure backbuffer has sensible minimal size + const sal_Int32 x(rBounds.X); + const sal_Int32 y(rBounds.Y); + const sal_Int32 w(::std::max(sal_Int32(1),sal_Int32(rBounds.Width))); + const sal_Int32 h(::std::max(sal_Int32(1),sal_Int32(rBounds.Height))); + + if( mpRenderModule ) + mpRenderModule->resize(::basegfx::B2IRange(x,y,x+w,y+h)); + + resizeBackBuffer(::basegfx::B2ISize(w,h)); + } + + void SpriteDeviceHelper::resizeBackBuffer( const ::basegfx::B2ISize& rNewSize ) + { + // disposed? + if(!(mpBackBuffer)) + return; + + mpBackBuffer->resize(rNewSize); + mpBackBuffer->clear(); + } + + HWND SpriteDeviceHelper::getHwnd() const + { + if( mpRenderModule ) + return mpRenderModule->getHWND(); + else + return 0; + } + + void SpriteDeviceHelper::dumpScreenContent() const + { + if( mpRenderModule ) + mpRenderModule->screenShot(); + } +} diff --git a/canvas/source/directx/dx_spritedevicehelper.hxx b/canvas/source/directx/dx_spritedevicehelper.hxx new file mode 100644 index 000000000000..f697b246929e --- /dev/null +++ b/canvas/source/directx/dx_spritedevicehelper.hxx @@ -0,0 +1,114 @@ +/************************************************************************* + * + * 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 _DXCANVAS_SPRITEDEVICEHELPER_HXX +#define _DXCANVAS_SPRITEDEVICEHELPER_HXX + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include "dx_rendermodule.hxx" +#include "dx_surfacebitmap.hxx" +#include "dx_devicehelper.hxx" + +#include <canvas/rendering/isurfaceproxymanager.hxx> + +#include <boost/utility.hpp> + + +namespace dxcanvas +{ + class SpriteCanvas; + class SpriteCanvasHelper; + + class SpriteDeviceHelper : public DeviceHelper + { + public: + SpriteDeviceHelper(); + + void init( Window& rWindow, + SpriteCanvas& rSpriteCanvas, + const ::com::sun::star::awt::Rectangle& rRect, + bool bFullscreen ); + + /// Dispose all internal references + void disposing(); + + // partial override XWindowGraphicDevice + ::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 ); + + ::sal_Int32 createBuffers( ::sal_Int32 nBuffers ); + void destroyBuffers( ); + ::sal_Bool showBuffer( bool bIsVisible, ::sal_Bool bUpdateAll ); + ::sal_Bool switchBuffer( bool bIsVisible, ::sal_Bool bUpdateAll ); + + const IDXRenderModuleSharedPtr& getRenderModule() const { return mpRenderModule; } + const DXSurfaceBitmapSharedPtr& getBackBuffer() const { return mpBackBuffer; } + const ::canvas::ISurfaceProxyManagerSharedPtr &getSurfaceProxy() const { return mpSurfaceProxyManager; } + + ::com::sun::star::uno::Any isAccelerated() const; + + void notifySizeUpdate( const ::com::sun::star::awt::Rectangle& rBounds ); + + /** called when DumpScreenContent property is enabled on + XGraphicDevice, and writes out bitmaps of current screen. + */ + void dumpScreenContent() const; + + private: + void resizeBackBuffer( const ::basegfx::B2ISize& rNewSize ); + HWND getHwnd() const; + + /// Pointer to sprite canvas (owner of this helper), needed to create bitmaps + SpriteCanvas* mpSpriteCanvas; + + DXSurfaceBitmapSharedPtr mpBackBuffer; + + /// Instance passing out HW textures + ::canvas::ISurfaceProxyManagerSharedPtr mpSurfaceProxyManager; + + /// Our encapsulation interface to DirectX + IDXRenderModuleSharedPtr mpRenderModule; + }; +} + +#endif /* _DXCANVAS_SPRITEDEVICEHELPER_HXX */ diff --git a/canvas/source/directx/dx_spritehelper.cxx b/canvas/source/directx/dx_spritehelper.cxx new file mode 100755 index 000000000000..d0b0c3e2101e --- /dev/null +++ b/canvas/source/directx/dx_spritehelper.cxx @@ -0,0 +1,216 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#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 "dx_canvascustomsprite.hxx" +#include "dx_spritehelper.hxx" +#include "dx_impltools.hxx" + +#include <memory> + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + SpriteHelper::SpriteHelper() : + mpSpriteCanvas(), + mpBitmap(), + mbTextureDirty( true ), + mbShowSpriteBounds( false ) + { + } + + void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rSpriteCanvas, + const IDXRenderModuleSharedPtr& rRenderModule, + const DXSurfaceBitmapSharedPtr rBitmap, + bool bShowSpriteBounds ) + { + ENSURE_OR_THROW( rSpriteCanvas.get() && + rRenderModule && + rBitmap, + "SpriteHelper::init(): Invalid device, sprite canvas or surface" ); + + mpSpriteCanvas = rSpriteCanvas; + mpBitmap = rBitmap; + mbTextureDirty = true; + mbShowSpriteBounds = bShowSpriteBounds; + + // also init base class + CanvasCustomSpriteHelper::init( rSpriteSize, + rSpriteCanvas.get() ); + } + + void SpriteHelper::disposing() + { + mpBitmap.reset(); + mpSpriteCanvas.clear(); + + // forward to parent + CanvasCustomSpriteHelper::disposing(); + } + + ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const + { + return tools::polyPolygonFromXPolyPolygon2D( xPoly ); + } + + bool SpriteHelper::needRedraw() const + { + if( !mpBitmap || + !mpSpriteCanvas.get() ) + { + return false; // we're disposed, no redraw necessary + } + + if( !isActive() || + ::basegfx::fTools::equalZero( getAlpha() ) ) + { + return false; // sprite is invisible + } + + return true; + } + + void SpriteHelper::redraw( bool& io_bSurfaceDirty ) const + { + if( !mpBitmap || + !mpSpriteCanvas.get() ) + { + return; // we're disposed + } + + const ::basegfx::B2DPoint& rPos( getPosPixel() ); + const double fAlpha( getAlpha() ); + + if( isActive() && + !::basegfx::fTools::equalZero( fAlpha ) ) + { + + // TODO(Q2): For the time being, Device does not take a target + // surface, but always unconditionally renders to the + // background buffer. + + // log output pos in device pixel + VERBOSE_TRACE( "SpriteHelper::redraw(): output pos is (%f, %f)", + rPos.getX(), + rPos.getY() ); + + const double fAlpha( getAlpha() ); + const ::basegfx::B2DVector& rSize( getSizePixel() ); + const ::basegfx::B2DHomMatrix& rTransform( getTransformation() ); + const uno::Reference< rendering::XPolyPolygon2D >& xClip( getClip() ); + + mbTextureDirty = false; + io_bSurfaceDirty = false; // state taken, and processed. + + ::basegfx::B2DPolyPolygon aClipPath; // empty for no clip + bool bIsClipRectangular( false ); // false, if no + // clip, or clip + // is complex + + // setup and apply clip (if any) + // ================================= + + if( xClip.is() ) + { + aClipPath = tools::polyPolygonFromXPolyPolygon2D( xClip ); + + const sal_Int32 nNumClipPolygons( aClipPath.count() ); + if( nNumClipPolygons ) + { + // TODO(P2): hold rectangle attribute directly + // at the XPolyPolygon2D + + // check whether the clip is rectangular + if( nNumClipPolygons == 1 ) + if( ::basegfx::tools::isRectangle( aClipPath.getB2DPolygon( 0 ) ) ) + bIsClipRectangular = true; + } + } + + const ::basegfx::B2DRectangle aSourceRect( 0.0, + 0.0, + rSize.getX(), + rSize.getY() ); + + // draw simple rectangular area if no clip is set. + if( !aClipPath.count() ) + { + mpBitmap->draw(fAlpha,rPos,rTransform); + } + else if( bIsClipRectangular ) + { + // apply a simple rect clip + // ======================== + + ::basegfx::B2DRectangle aClipBounds( + ::basegfx::tools::getRange( aClipPath ) ); + aClipBounds.intersect( aSourceRect ); + + mpBitmap->draw(fAlpha,rPos,aClipBounds,rTransform); + } + else + { + // apply clip the hard way + // ======================= + + mpBitmap->draw(fAlpha,rPos,aClipPath,rTransform); + } + + if( mbShowSpriteBounds ) + { + if( aClipPath.count() ) + { + // TODO(F2): Re-enable debug output + } + } + } + } +} diff --git a/canvas/source/directx/dx_spritehelper.hxx b/canvas/source/directx/dx_spritehelper.hxx new file mode 100755 index 000000000000..b83b8b6a988c --- /dev/null +++ b/canvas/source/directx/dx_spritehelper.hxx @@ -0,0 +1,111 @@ +/************************************************************************* + * + * 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 _DXCANVAS_SPRITEHELPER_HXX +#define _DXCANVAS_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 "dx_spritecanvas.hxx" +#include "dx_surfacebitmap.hxx" + +namespace dxcanvas +{ + /* 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 rRenderModule + rendermodule 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, + const IDXRenderModuleSharedPtr& rRenderModule, + const DXSurfaceBitmapSharedPtr rBitmap, + bool bShowSpriteBounds ); + + void disposing(); + + /** Repaint sprite content via hardware to associated sprite + canvas + + @param io_bSurfaceDirty + Input/output parameter, whether the sprite content is + dirty or not. If texture was updated, set to false + + */ + void redraw( bool& io_bSurfaceDirty ) const; + + private: + virtual ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >& xPoly ) const; + + /// Returns true, if the sprite _really_ needs redraw + bool needRedraw() const; + + SpriteCanvasRef mpSpriteCanvas; + + DXSurfaceBitmapSharedPtr mpBitmap; + mutable bool mbTextureDirty; // when true, texture needs update + bool mbShowSpriteBounds; // when true, debug bound rect for sprites is shown + }; +} + +#endif /* _DXCANVAS_SPRITEHELPER_HXX */ diff --git a/canvas/source/directx/dx_surfacebitmap.cxx b/canvas/source/directx/dx_surfacebitmap.cxx new file mode 100644 index 000000000000..258c10c4dd5c --- /dev/null +++ b/canvas/source/directx/dx_surfacebitmap.cxx @@ -0,0 +1,804 @@ +/************************************************************************* + * + * 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 "dx_surfacebitmap.hxx" +#include "dx_impltools.hxx" +#include "dx_surfacegraphics.hxx" +#include "dx_graphicsprovider.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2irange.hxx> + +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 +# include <imdebug.h> +# undef min +# undef max +# endif +#endif + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + ////////////////////////////////////////////////////////////////////////////////// + // DXColorBuffer + ////////////////////////////////////////////////////////////////////////////////// + + struct DXColorBuffer : public canvas::IColorBuffer + { + public: + DXColorBuffer( const COMReference<surface_type>& rSurface, + const ::basegfx::B2IVector& rSize ) : + mpSurface(rSurface), + maSize(rSize), + mbAlpha(false) + { + } + + // implementation of the 'IColorBuffer' interface + public: + + virtual sal_uInt8* lock() const; + virtual void unlock() const; + virtual sal_uInt32 getWidth() const; + virtual sal_uInt32 getHeight() const; + virtual sal_uInt32 getStride() const; + virtual Format getFormat() const; + + private: + + ::basegfx::B2IVector maSize; +#if DIRECTX_VERSION < 0x0900 + mutable DDSURFACEDESC aSurfaceDesc; +#else + mutable D3DLOCKED_RECT maLockedRect; +#endif + mutable COMReference<surface_type> mpSurface; + bool mbAlpha; + }; + + sal_uInt8* DXColorBuffer::lock() const + { +#if DIRECTX_VERSION < 0x0900 + rtl_fillMemory((void *)&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY; + if(SUCCEEDED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + return static_cast<sal_uInt8 *>(aSurfaceDesc.lpSurface); +#else + if(SUCCEEDED(mpSurface->LockRect(&maLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + return static_cast<sal_uInt8 *>(maLockedRect.pBits); +#endif + return NULL; + } + + void DXColorBuffer::unlock() const + { +#if DIRECTX_VERSION < 0x0900 + mpSurface->Unlock(NULL); +#else + mpSurface->UnlockRect(); +#endif + } + + sal_uInt32 DXColorBuffer::getWidth() const + { + return maSize.getX(); + } + + sal_uInt32 DXColorBuffer::getHeight() const + { + return maSize.getY(); + } + + sal_uInt32 DXColorBuffer::getStride() const + { +#if DIRECTX_VERSION < 0x0900 + return aSurfaceDesc.lPitch; +#else + return maLockedRect.Pitch; +#endif + } + + canvas::IColorBuffer::Format DXColorBuffer::getFormat() const + { + return canvas::IColorBuffer::FMT_X8R8G8B8; + } + + ////////////////////////////////////////////////////////////////////////////////// + // GDIColorBuffer + ////////////////////////////////////////////////////////////////////////////////// + + struct GDIColorBuffer : public canvas::IColorBuffer + { + public: + + GDIColorBuffer( const BitmapSharedPtr& rSurface, + const ::basegfx::B2IVector& rSize ) : + mpGDIPlusBitmap(rSurface), + maSize(rSize), + mbAlpha(true) + { + } + + // implementation of the 'IColorBuffer' interface + public: + + virtual sal_uInt8* lock() const; + virtual void unlock() const; + virtual sal_uInt32 getWidth() const; + virtual sal_uInt32 getHeight() const; + virtual sal_uInt32 getStride() const; + virtual Format getFormat() const; + + private: + + ::basegfx::B2IVector maSize; + mutable Gdiplus::BitmapData aBmpData; + BitmapSharedPtr mpGDIPlusBitmap; + bool mbAlpha; + }; + + sal_uInt8* GDIColorBuffer::lock() const + { + aBmpData.Width = maSize.getX(); + aBmpData.Height = maSize.getY(); + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = NULL; + const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height ); + if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead, + PixelFormat32bppARGB, + &aBmpData ) ) + { + return NULL; + } + + return static_cast<sal_uInt8*>(aBmpData.Scan0); + } + + void GDIColorBuffer::unlock() const + { + mpGDIPlusBitmap->UnlockBits( &aBmpData ); + } + + sal_uInt32 GDIColorBuffer::getWidth() const + { + return maSize.getX(); + } + + sal_uInt32 GDIColorBuffer::getHeight() const + { + return maSize.getY(); + } + + sal_uInt32 GDIColorBuffer::getStride() const + { + return aBmpData.Stride; + } + + canvas::IColorBuffer::Format GDIColorBuffer::getFormat() const + { + return canvas::IColorBuffer::FMT_A8R8G8B8; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::DXSurfaceBitmap + ////////////////////////////////////////////////////////////////////////////////// + + DXSurfaceBitmap::DXSurfaceBitmap( const ::basegfx::B2IVector& rSize, + const canvas::ISurfaceProxyManagerSharedPtr& rMgr, + const IDXRenderModuleSharedPtr& rRenderModule, + bool bWithAlpha ) : + mpGdiPlusUser( GDIPlusUser::createInstance() ), + maSize(rSize), + mpRenderModule(rRenderModule), + mpSurfaceManager(rMgr), + mpSurfaceProxy(), + mpSurface(), + mpGDIPlusBitmap(), + mpGraphics(), + mpColorBuffer(), + mbIsSurfaceDirty(true), + mbAlpha(bWithAlpha) + { + init(); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2IVector DXSurfaceBitmap::getSize() const + { + return maSize; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::init + ////////////////////////////////////////////////////////////////////////////////// + + void DXSurfaceBitmap::init() + { + // create container for pixel data + if(mbAlpha) + { + mpGDIPlusBitmap.reset( + new Gdiplus::Bitmap( + maSize.getX(), + maSize.getY(), + PixelFormat32bppARGB + )); + mpGraphics.reset( tools::createGraphicsFromBitmap(mpGDIPlusBitmap) ); + + // create the colorbuffer object, which is basically a simple + // wrapper around the directx surface. the colorbuffer is the + // interface which is used by the surfaceproxy to support any + // kind of underlying structure for the pixel data container. + mpColorBuffer.reset(new GDIColorBuffer(mpGDIPlusBitmap,maSize)); + } + else + { + mpSurface = mpRenderModule->createSystemMemorySurface(maSize); + + // create the colorbuffer object, which is basically a simple + // wrapper around the directx surface. the colorbuffer is the + // interface which is used by the surfaceproxy to support any + // kind of underlying structure for the pixel data container. + mpColorBuffer.reset(new DXColorBuffer(mpSurface,maSize)); + } + + // create a (possibly hardware accelerated) mirror surface. + mpSurfaceProxy = mpSurfaceManager->createSurfaceProxy(mpColorBuffer); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::resize + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::resize( const ::basegfx::B2IVector& rSize ) + { + if(maSize != rSize) + { + maSize = rSize; + init(); + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::clear + ////////////////////////////////////////////////////////////////////////////////// + + void DXSurfaceBitmap::clear() + { + GraphicsSharedPtr pGraphics(getGraphics()); + Gdiplus::Color transColor(255,0,0,0); + pGraphics->SetCompositingMode( Gdiplus::CompositingModeSourceCopy ); + pGraphics->Clear( transColor ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::hasAlpha + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::hasAlpha() const + { + return mbAlpha; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getGraphics + ////////////////////////////////////////////////////////////////////////////////// + + GraphicsSharedPtr DXSurfaceBitmap::getGraphics() + { + // since clients will most probably draw directly + // to the GDI+ bitmap, we need to mark it as dirty + // to ensure that the corrosponding dxsurface will + // be updated. + mbIsSurfaceDirty = true; + + if(hasAlpha()) + return mpGraphics; + else + return createSurfaceGraphics(mpSurface); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getBitmap + ////////////////////////////////////////////////////////////////////////////////// + + BitmapSharedPtr DXSurfaceBitmap::getBitmap() const + { + if(hasAlpha()) + return mpGDIPlusBitmap; + + BitmapSharedPtr pResult; + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(SUCCEEDED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + { + // decide about the format we pass the gdi+, the directx surface is always + // 32bit, either with or without alpha component. + Gdiplus::PixelFormat nFormat = hasAlpha() ? PixelFormat32bppARGB : PixelFormat32bppRGB; + + // construct a gdi+ bitmap from the raw pixel data. + pResult.reset(new Gdiplus::Bitmap( maSize.getX(),maSize.getY(), + aSurfaceDesc.lPitch, + nFormat, + (BYTE *)aSurfaceDesc.lpSurface )); + + // unlock the directx surface + mpSurface->Unlock(NULL); + } +#else + D3DLOCKED_RECT aLockedRect; + if(SUCCEEDED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + { + // decide about the format we pass the gdi+, the directx surface is always + // 32bit, either with or without alpha component. + Gdiplus::PixelFormat nFormat = hasAlpha() ? PixelFormat32bppARGB : PixelFormat32bppRGB; + + // construct a gdi+ bitmap from the raw pixel data. + pResult.reset(new Gdiplus::Bitmap( maSize.getX(),maSize.getY(), + aLockedRect.Pitch, + nFormat, + (BYTE *)aLockedRect.pBits )); + + mpSurface->UnlockRect(); + } +#endif + + return pResult; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolyPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rClipPoly, rTransform ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rArea, rTransform ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rTransform ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool DXSurfaceBitmap::draw( const ::basegfx::B2IRange& rArea ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + const double fAlpha(1.0); + const ::basegfx::B2DHomMatrix aTransform; + const ::basegfx::B2DRange aIEEEArea( rArea ); + return mpSurfaceProxy->draw(fAlpha, + ::basegfx::B2DPoint(), + aIEEEArea, + aTransform); + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::imageDebugger + ////////////////////////////////////////////////////////////////////////////////// +#if defined(DX_DEBUG_IMAGES) +# if OSL_DEBUG_LEVEL > 0 + void DXSurfaceBitmap::imageDebugger() + { +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 ); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + + if( FAILED(mpSurface->Lock( NULL, + &aSurfaceDesc, + DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY, + NULL)) ) + return; + + imdebug("bgra w=%d h=%d %p", aSurfaceDesc.dwWidth, aSurfaceDesc.dwHeight, aSurfaceDesc.lpSurface); + + mpSurface->Unlock(NULL); +#else + D3DLOCKED_RECT aLockedRect; + if( FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)) ) + return; + + imdebug("bgra w=%d h=%d %p", maSize.getX(), + maSize.getY(), aLockedRect.pBits); + mpSurface->UnlockRect(); +#endif + } +# endif +#endif + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getData + ////////////////////////////////////////////////////////////////////////////////// + + uno::Sequence< sal_Int8 > DXSurfaceBitmap::getData( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& rect ) + { + if(hasAlpha()) + { + uno::Sequence< sal_Int8 > aRes( (rect.X2-rect.X1)*(rect.Y2-rect.Y1)*4 ); // TODO(F1): Be format-agnostic here + + const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rect.X2-rect.X1; + aBmpData.Height = rect.Y2-rect.Y1; + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = aRes.getArray(); + + // TODO(F1): Support more pixel formats natively + + // read data from bitmap + if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, // TODO(F1): Adapt to + // Graphics native + // format/change + // getMemoryLayout + &aBmpData ) ) + { + // failed to lock, bail out + return uno::Sequence< sal_Int8 >(); + } + + mpGDIPlusBitmap->UnlockBits( &aBmpData ); + + return aRes; + } + else + { + sal_uInt32 nWidth = rect.X2-rect.X1; + sal_uInt32 nHeight = rect.Y2-rect.Y1; + + uno::Sequence< sal_Int8 > aRes(nWidth*nHeight*4); + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(FAILED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + return uno::Sequence< sal_Int8 >(); + + sal_uInt8 *pSrc = (sal_uInt8 *)((((BYTE *)aSurfaceDesc.lpSurface)+(rect.Y1*aSurfaceDesc.lPitch))+rect.X1); + sal_uInt8 *pDst = (sal_uInt8 *)aRes.getArray(); + sal_uInt32 nSegmentSizeInBytes = nWidth<<4; + for(sal_uInt32 y=0; y<nHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,nSegmentSizeInBytes); + pDst += nSegmentSizeInBytes; + pSrc += aSurfaceDesc.lPitch; + } + + mpSurface->Unlock(NULL); +#else + D3DLOCKED_RECT aLockedRect; + if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + return uno::Sequence< sal_Int8 >(); + + sal_uInt8 *pSrc = (sal_uInt8 *)((((BYTE *)aLockedRect.pBits)+(rect.Y1*aLockedRect.Pitch))+rect.X1); + sal_uInt8 *pDst = (sal_uInt8 *)aRes.getArray(); + sal_uInt32 nSegmentSizeInBytes = nWidth<<4; + for(sal_uInt32 y=0; y<nHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,nSegmentSizeInBytes); + pDst += nSegmentSizeInBytes; + pSrc += aLockedRect.Pitch; + } + + mpSurface->UnlockRect(); +#endif + return aRes; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::setData + ////////////////////////////////////////////////////////////////////////////////// + + void DXSurfaceBitmap::setData( const uno::Sequence< sal_Int8 >& data, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& rect ) + { + if(hasAlpha()) + { + const Gdiplus::Rect aRect( tools::gdiPlusRectFromIntegerRectangle2D( rect ) ); + + Gdiplus::BitmapData aBmpData; + aBmpData.Width = rect.X2-rect.X1; + aBmpData.Height = rect.Y2-rect.Y1; + aBmpData.Stride = 4*aBmpData.Width; + aBmpData.PixelFormat = PixelFormat32bppARGB; + aBmpData.Scan0 = (void*)data.getConstArray(); + + // TODO(F1): Support more pixel formats natively + + if( Gdiplus::Ok != mpGDIPlusBitmap->LockBits( &aRect, + Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, + PixelFormat32bppARGB, // TODO: Adapt to + // Graphics native + // format/change + // getMemoryLayout + &aBmpData ) ) + { + throw uno::RuntimeException(); + } + + // commit data to bitmap + mpGDIPlusBitmap->UnlockBits( &aBmpData ); + } + else + { + sal_uInt32 nWidth = rect.X2-rect.X1; + sal_uInt32 nHeight = rect.Y2-rect.Y1; + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(FAILED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + throw uno::RuntimeException(); + + sal_uInt8 *pSrc = (sal_uInt8 *)data.getConstArray(); + sal_uInt8 *pDst = (sal_uInt8 *)((((BYTE *)aSurfaceDesc.lpSurface)+(rect.Y1*aSurfaceDesc.lPitch))+rect.X1); + sal_uInt32 nSegmentSizeInBytes = nWidth<<4; + for(sal_uInt32 y=0; y<nHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,nSegmentSizeInBytes); + pSrc += nSegmentSizeInBytes; + pDst += aSurfaceDesc.lPitch; + } + + mpSurface->Unlock(NULL); +#else + // lock the directx surface to receive the pointer to the surface memory. + D3DLOCKED_RECT aLockedRect; + if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + throw uno::RuntimeException(); + + sal_uInt8 *pSrc = (sal_uInt8 *)data.getConstArray(); + sal_uInt8 *pDst = (sal_uInt8 *)((((BYTE *)aLockedRect.pBits)+(rect.Y1*aLockedRect.Pitch))+rect.X1); + sal_uInt32 nSegmentSizeInBytes = nWidth<<4; + for(sal_uInt32 y=0; y<nHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,nSegmentSizeInBytes); + pSrc += nSegmentSizeInBytes; + pDst += aLockedRect.Pitch; + } + + mpSurface->UnlockRect(); +#endif + } + + mbIsSurfaceDirty = true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::setPixel + ////////////////////////////////////////////////////////////////////////////////// + + void DXSurfaceBitmap::setPixel( const uno::Sequence< sal_Int8 >& color, + const rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& pos ) + { + if(hasAlpha()) + { + const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width, + "CanvasHelper::setPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height, + "CanvasHelper::setPixel: Y coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( color.getLength() > 3, + "CanvasHelper::setPixel: not enough color components" ); + + if( Gdiplus::Ok != mpGDIPlusBitmap->SetPixel( pos.X, pos.Y, + Gdiplus::Color( tools::sequenceToArgb( color )))) + { + throw uno::RuntimeException(); + } + } + else + { + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < maSize.getX(), + "CanvasHelper::setPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < maSize.getY(), + "CanvasHelper::setPixel: Y coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( color.getLength() > 3, + "CanvasHelper::setPixel: not enough color components" ); + + Gdiplus::Color aColor(tools::sequenceToArgb(color)); + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(FAILED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + throw uno::RuntimeException(); + + sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aSurfaceDesc.lpSurface)+(pos.Y*aSurfaceDesc.lPitch))+pos.X); + *pDst = aColor.GetValue(); + mpSurface->Unlock(NULL); +#else + // lock the directx surface to receive the pointer to the surface memory. + D3DLOCKED_RECT aLockedRect; + if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + throw uno::RuntimeException(); + + sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aLockedRect.pBits)+(pos.Y*aLockedRect.Pitch))+pos.X); + *pDst = aColor.GetValue(); + mpSurface->UnlockRect(); +#endif + } + + mbIsSurfaceDirty = true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // DXSurfaceBitmap::getPixel + ////////////////////////////////////////////////////////////////////////////////// + + uno::Sequence< sal_Int8 > DXSurfaceBitmap::getPixel( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerPoint2D& pos ) + { + if(hasAlpha()) + { + const geometry::IntegerSize2D aSize( maSize.getX(),maSize.getY() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aSize.Width, + "CanvasHelper::getPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aSize.Height, + "CanvasHelper::getPixel: Y coordinate out of bounds" ); + + Gdiplus::Color aColor; + + if( Gdiplus::Ok != mpGDIPlusBitmap->GetPixel( pos.X, pos.Y, &aColor ) ) + return uno::Sequence< sal_Int8 >(); + + return tools::argbToIntSequence(aColor.GetValue()); + } + else + { + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < maSize.getX(), + "CanvasHelper::getPixel: X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < maSize.getY(), + "CanvasHelper::getPixel: Y coordinate out of bounds" ); + +#if DIRECTX_VERSION < 0x0900 + DDSURFACEDESC aSurfaceDesc; + rtl_fillMemory(&aSurfaceDesc,sizeof(DDSURFACEDESC),0); + aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC); + const DWORD dwFlags = DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY; + + // lock the directx surface to receive the pointer to the surface memory. + if(FAILED(mpSurface->Lock(NULL,&aSurfaceDesc,dwFlags,NULL))) + throw uno::RuntimeException(); + + sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aSurfaceDesc.lpSurface)+(pos.Y*aSurfaceDesc.lPitch))+pos.X); + Gdiplus::Color aColor(*pDst); + mpSurface->Unlock(NULL); +#else + // lock the directx surface to receive the pointer to the surface memory. + D3DLOCKED_RECT aLockedRect; + if(FAILED(mpSurface->LockRect(&aLockedRect,NULL,D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY))) + throw uno::RuntimeException(); + + sal_uInt32 *pDst = (sal_uInt32 *)((((BYTE *)aLockedRect.pBits)+(pos.Y*aLockedRect.Pitch))+pos.X); + Gdiplus::Color aColor(*pDst); + mpSurface->UnlockRect(); +#endif + + return tools::argbToIntSequence(aColor.GetValue()); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // End of file + ////////////////////////////////////////////////////////////////////////////////// +} + diff --git a/canvas/source/directx/dx_surfacebitmap.hxx b/canvas/source/directx/dx_surfacebitmap.hxx new file mode 100644 index 000000000000..c3f1f9ed9074 --- /dev/null +++ b/canvas/source/directx/dx_surfacebitmap.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 _DXCANVAS_DXSURFACEBITMAP_HXX +#define _DXCANVAS_DXSURFACEBITMAP_HXX + +#include <canvas/rendering/isurfaceproxy.hxx> +#include <canvas/rendering/isurfaceproxymanager.hxx> +#include "dx_ibitmap.hxx" +#include "dx_canvasfont.hxx" //winstuff +#include "dx_gdiplususer.hxx" +#include "dx_rendermodule.hxx" + +namespace dxcanvas +{ + class DXSurfaceBitmap : public IBitmap + { + public: + DXSurfaceBitmap( const ::basegfx::B2IVector& rSize, + const canvas::ISurfaceProxyManagerSharedPtr& rMgr, + const IDXRenderModuleSharedPtr& rRenderModule, + bool bWithAlpha ); + + bool resize( const ::basegfx::B2IVector& rSize ); + void clear(); + + virtual GraphicsSharedPtr getGraphics(); + + virtual BitmapSharedPtr getBitmap() const; + virtual ::basegfx::B2IVector getSize() const; + virtual bool hasAlpha() const; + + COMReference<surface_type> getSurface() const { return mpSurface; } + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ); + + bool draw( const ::basegfx::B2IRange& rArea ); + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ); + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolyPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ); + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > getData( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ); + + virtual 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 ); + + virtual 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 ); + + virtual ::com::sun::star::uno::Sequence< sal_Int8 > getPixel( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ); + +#ifdef DX_DEBUG_IMAGES + void imageDebugger(); +#endif + private: + void init(); + + // Refcounted global GDI+ state container + GDIPlusUserSharedPtr mpGdiPlusUser; + + // size of this image in pixels [integral unit] + ::basegfx::B2IVector maSize; + + // pointer to the rendermodule, needed to create surfaces + // which are used as container for the actual pixel data. + // generally we could use any kind of storage, but GDI+ + // is not willing to render antialiased fonts unless we + // use this special kind of container, don't ask me why... + IDXRenderModuleSharedPtr mpRenderModule; + + // pointer to the surface manager, needed in case clients + // want to resize the bitmap. + canvas::ISurfaceProxyManagerSharedPtr mpSurfaceManager; + + // access point to the surface proxy which handles + // the hardware-dependent rendering stuff. + canvas::ISurfaceProxySharedPtr mpSurfaceProxy; + + // container for pixel data, we need to use a directx + // surface since GDI+ sucks... + COMReference<surface_type> mpSurface; + + // since GDI+ does not work correctly in case we + // run on a 16bit display [don't ask me why] we need + // to occasionally render to a native GDI+ bitmap. + BitmapSharedPtr mpGDIPlusBitmap; + // Graphics for the mpGDIPlusBitmap + GraphicsSharedPtr mpGraphics; + + // internal implementation of the iColorBuffer interface + canvas::IColorBufferSharedPtr mpColorBuffer; + + // indicates wether the associated surface needs + // to refresh its contents or not. in other words, + // this flag is set iff both representations are + // out of sync. + mutable bool mbIsSurfaceDirty; + + // true if the bitmap contains an alpha channel + bool mbAlpha; + }; + + typedef ::boost::shared_ptr< DXSurfaceBitmap > DXSurfaceBitmapSharedPtr; +} + +#endif diff --git a/canvas/source/directx/dx_surfacegraphics.cxx b/canvas/source/directx/dx_surfacegraphics.cxx new file mode 100755 index 000000000000..97a89b7e66cf --- /dev/null +++ b/canvas/source/directx/dx_surfacegraphics.cxx @@ -0,0 +1,85 @@ +/************************************************************************* + * + * 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 "dx_surfacegraphics.hxx" +#include "dx_impltools.hxx" + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace + { + struct GraphicsDeleter + { + COMReference<surface_type> mpSurface; + HDC maHDC; + + GraphicsDeleter(const COMReference<surface_type>& rSurface, HDC hdc) : + mpSurface(rSurface), + maHDC(hdc) + {} + + void operator()( Gdiplus::Graphics* pGraphics ) + { + if(!pGraphics) + return; + + pGraphics->Flush(Gdiplus::FlushIntentionSync); + delete pGraphics; + + if(mpSurface.is()) + mpSurface->ReleaseDC( maHDC ); + } + }; + } + + GraphicsSharedPtr createSurfaceGraphics(const COMReference<surface_type>& rSurface ) + { + Gdiplus::Graphics* pGraphics; + GraphicsSharedPtr pRet; + HDC aHDC; + if( SUCCEEDED(rSurface->GetDC( &aHDC )) ) + { + pGraphics = Gdiplus::Graphics::FromHDC( aHDC ); + if(pGraphics) + { + tools::setupGraphics( *pGraphics ); + pRet.reset(pGraphics, + GraphicsDeleter(rSurface, aHDC)); + return pRet; + } + else + rSurface->ReleaseDC( aHDC ); + } + + throw uno::RuntimeException(); + } +} diff --git a/canvas/source/directx/dx_surfacegraphics.hxx b/canvas/source/directx/dx_surfacegraphics.hxx new file mode 100755 index 000000000000..29b84ed81670 --- /dev/null +++ b/canvas/source/directx/dx_surfacegraphics.hxx @@ -0,0 +1,45 @@ +/************************************************************************* + * + * 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 _DXCANVAS_SURFACEGRAPHICS_HXX +#define _DXCANVAS_SURFACEGRAPHICS_HXX + +#include "dx_graphicsprovider.hxx" + +namespace dxcanvas +{ + /** Container providing a Gdiplus::Graphics for a Surface + + This wrapper class transparently handles allocation and + release of surface resources the RAII way (the + GraphicsSharedPtr returned has a deleter that does all the + necessary DX cleanup work). + */ + GraphicsSharedPtr createSurfaceGraphics(const COMReference<surface_type>& rSurface ); +} + +#endif /* _DXCANVAS_SURFACEGRAPHICS_HXX */ diff --git a/canvas/source/directx/dx_textlayout.cxx b/canvas/source/directx/dx_textlayout.cxx new file mode 100755 index 000000000000..1516b49d1620 --- /dev/null +++ b/canvas/source/directx/dx_textlayout.cxx @@ -0,0 +1,280 @@ +/************************************************************************* + * + * 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 <ctype.h> // don't ask. msdev breaks otherwise... +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/numeric/ftools.hxx> +#include "dx_bitmap.hxx" +#include "dx_textlayout.hxx" +#include "dx_spritecanvas.hxx" +#include "dx_textlayout_drawhelper.hxx" + + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + TextLayout::TextLayout( const rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 /*nRandomSeed*/, + const CanvasFont::ImplRef& rFont ) : + TextLayout_Base( m_aMutex ), + maText( aText ), + maLogicalAdvancements(), + mpFont( rFont ), + mnTextDirection( nDirection ) + { + } + + TextLayout::~TextLayout() + { + } + + void SAL_CALL TextLayout::disposing() + { + mpFont.reset(); + } + + // 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 ); + + uno::Reference< rendering::XGraphicDevice > xGraphicDevice; + ::dxcanvas::TextLayoutDrawHelper aDrawHelper(xGraphicDevice); + + // render text + const geometry::RealRectangle2D aBounds( + aDrawHelper.queryTextBounds( + maText, + maLogicalAdvancements, + mpFont.getRef(), + mpFont->getFontMatrix())); + + return aBounds; + } + + 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; + } + + namespace + { + // TODO(P2): Check whether this gets inlined. If not, make functor + // out of it + inline Gdiplus::PointF gdiPlusPointFromDx( const double& dx ) + { + return Gdiplus::PointF( static_cast<Gdiplus::REAL>(dx), + 0.0f ); + } + } + + bool TextLayout::draw( const GraphicsSharedPtr& rGraphics, + const rendering::ViewState& rViewState, + const rendering::RenderState& rRenderState, + const ::basegfx::B2ISize& rOutputOffset, + const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice, + bool bAlphaSurface ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + ::dxcanvas::TextLayoutDrawHelper aDrawHelper(xGraphicDevice); + + // render text + aDrawHelper.drawText( + rGraphics, + rViewState, + rRenderState, + rOutputOffset, + maText, + maLogicalAdvancements, + mpFont.getRef(), + mpFont->getFontMatrix(), + bAlphaSurface); + + return true; + } + + +#define SERVICE_NAME "com.sun.star.rendering.TextLayout" +#define IMPLEMENTATION_NAME "DXCanvas::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/directx/dx_textlayout.hxx b/canvas/source/directx/dx_textlayout.hxx new file mode 100755 index 000000000000..ca8c6793fe87 --- /dev/null +++ b/canvas/source/directx/dx_textlayout.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 _DXCANVAS_TEXTLAYOUT_HXX +#define _DXCANVAS_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 <boost/utility.hpp> + +#include "dx_canvasfont.hxx" +#include "dx_ibitmap.hxx" +#include "dx_winstuff.hxx" +#include "dx_gdiplususer.hxx" + + +/* Definition of TextLayout class */ +class DXBitmapSharedPtr; + +namespace dxcanvas +{ + 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::ImplRef& rFont ); + + /// 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( const GraphicsSharedPtr& rGraphics, + const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState, + const ::basegfx::B2ISize& rOutputOffset, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice, + bool bAlphaSurface ) const; + + protected: + ~TextLayout(); // we're a ref-counted UNO class. _We_ destroy ourselves. + + private: + // NOTE: no need for GDIPlusUserSharedPtr, mpFont implicitely has one already + + ::com::sun::star::rendering::StringContext maText; + ::com::sun::star::uno::Sequence< double > maLogicalAdvancements; + CanvasFont::ImplRef mpFont; + sal_Int8 mnTextDirection; + }; + +} + +#endif /* _DXCANVAS_TEXTLAYOUT_HXX */ diff --git a/canvas/source/directx/dx_textlayout_drawhelper.cxx b/canvas/source/directx/dx_textlayout_drawhelper.cxx new file mode 100755 index 000000000000..56ec00e9a648 --- /dev/null +++ b/canvas/source/directx/dx_textlayout_drawhelper.cxx @@ -0,0 +1,312 @@ +/************************************************************************* + * + * 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/poly.hxx> + +#include <vcl/metric.hxx> +#include <vcl/virdev.hxx> +#include <vcl/metric.hxx> +#include <vcl/canvastools.hxx> +#include <tools/diagnose_ex.h> + +#include <boost/scoped_array.hpp> +#include <boost/bind.hpp> +#include <com/sun/star/rendering/FontRequest.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/scopeguard.hxx> +#include <tools/color.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <canvas/canvastools.hxx> +#include <canvas/debug.hxx> +#include "dx_impltools.hxx" +#include <vcl/sysdata.hxx> +#include <i18npool/mslangid.hxx> +#include "dx_textlayout_drawhelper.hxx" +#include "dx_bitmap.hxx" +#include "dx_canvasfont.hxx" + +class ::com::sun::star::rendering::XCanvasFont; + +using namespace ::com::sun::star; + + +////////////////////////////////////////////////////////////////////////////// + +namespace dxcanvas +{ + class DXBitmap; + TextLayoutDrawHelper::TextLayoutDrawHelper( + const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice ) : + mxGraphicDevice(xGraphicDevice) + { + } + + TextLayoutDrawHelper::~TextLayoutDrawHelper() + { + } + + void TextLayoutDrawHelper::drawText( + const GraphicsSharedPtr& rGraphics, + const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState, + const ::basegfx::B2ISize& rOutputOffset, + const ::com::sun::star::rendering::StringContext& rText, + const ::com::sun::star::uno::Sequence< double >& rLogicalAdvancements, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& rCanvasFont, + const ::com::sun::star::geometry::Matrix2D& rFontMatrix, + bool bAlphaSurface ) + { + HDC hdc = rGraphics->GetHDC(); + + // issue an ReleaseHDC() when leaving the scope + const ::comphelper::ScopeGuard aGuard( + boost::bind( &Gdiplus::Graphics::ReleaseHDC, + rGraphics.get(), + hdc )); + + SystemGraphicsData aSystemGraphicsData; + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(hdc); + VirtualDevice aVirtualDevice(&aSystemGraphicsData, 0); + + // disable font antialiasing - GDI does not handle alpha + // surfaces properly. + if( bAlphaSurface ) + aVirtualDevice.SetAntialiasing(ANTIALIASING_DISABLE_TEXT); + + if(rText.Length) + { + sal_Bool test = mxGraphicDevice.is(); + ENSURE_OR_THROW( test, + "TextLayoutDrawHelper::drawText(): Invalid GraphicDevice" ); + + // set text color. Make sure to remove transparence part first. + Color aColor( COL_WHITE ); + + if( rRenderState.DeviceColor.getLength() > 2 ) + aColor = ::vcl::unotools::doubleSequenceToColor( + rRenderState.DeviceColor, + mxGraphicDevice->getDeviceColorSpace()); + aColor.SetTransparency(0); + aVirtualDevice.SetTextColor(aColor); + + // create the font + const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest(); + Font aFont( + rFontRequest.FontDescription.FamilyName, + rFontRequest.FontDescription.StyleName, + Size( 0, ::basegfx::fround(rFontRequest.CellSize))); + + aFont.SetAlign( ALIGN_BASELINE ); + aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); + aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? TRUE : FALSE ); + aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) ); + aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL ); + + aFont.SetLanguage(MsLangId::convertLocaleToLanguage(rFontRequest.Locale)); + + // setup font color + aFont.SetColor( aColor ); + aFont.SetFillColor( aColor ); + + // adjust to stretched font + if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11)) + { + const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize(); + const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 ); + double fStretch = (rFontMatrix.m00 + rFontMatrix.m01); + + if( !::basegfx::fTools::equalZero( fDividend) ) + fStretch /= fDividend; + + const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch ); + + aFont.SetWidth( nNewWidth ); + } + + // set font + aVirtualDevice.SetFont(aFont); + + // create world transformation matrix + ::basegfx::B2DHomMatrix aWorldTransform; + ::canvas::tools::mergeViewAndRenderTransform(aWorldTransform, rViewState, rRenderState); + + if(!rOutputOffset.equalZero()) + { + aWorldTransform.translate(rOutputOffset.getX(), rOutputOffset.getY()); + } + + // set ViewState clipping + if(rViewState.Clip.is()) + { + ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rViewState.Clip)); + ::basegfx::B2DHomMatrix aMatrix; + ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix, rViewState.AffineTransform ); + + if(!rOutputOffset.equalZero()) + { + aMatrix.translate(rOutputOffset.getX(), rOutputOffset.getY()); + } + + aClipPoly.transform(aMatrix); + const Region& rClipRegion = Region(PolyPolygon(aClipPoly)); + aVirtualDevice.IntersectClipRegion(rClipRegion); + } + + if(rRenderState.Clip.is()) + { + ::basegfx::B2DPolyPolygon aClipPoly(dxcanvas::tools::polyPolygonFromXPolyPolygon2D(rRenderState.Clip)); + aClipPoly.transform(aWorldTransform); + const Region& rClipRegion = Region(PolyPolygon(aClipPoly)); + aVirtualDevice.IntersectClipRegion(rClipRegion); + } + + // set world transform + XFORM aXForm; + aXForm.eM11 = (FLOAT)aWorldTransform.get(0, 0); + aXForm.eM12 = (FLOAT)aWorldTransform.get(1, 0); + aXForm.eM21 = (FLOAT)aWorldTransform.get(0, 1); + aXForm.eM22 = (FLOAT)aWorldTransform.get(1, 1); + aXForm.eDx = (FLOAT)aWorldTransform.get(0, 2); + aXForm.eDy = (FLOAT)aWorldTransform.get(1, 2); + + // TODO(F3): This is NOT supported on 95/98/ME! + SetGraphicsMode(hdc, GM_ADVANCED); + SetTextAlign(hdc, TA_BASELINE); + SetWorldTransform(hdc, &aXForm); + + // use a empty StartPosition for text rendering + const Point aEmptyPoint(0, 0); + + // create the String + const String aText(rText.Text.getStr()); + + if( rLogicalAdvancements.getLength() ) + { + // create the DXArray + const sal_Int32 nLen( rLogicalAdvancements.getLength() ); + ::boost::scoped_array<sal_Int32> pDXArray( new sal_Int32[nLen] ); + for( sal_Int32 i=0; i<nLen; ++i ) + pDXArray[i] = basegfx::fround( rLogicalAdvancements[i] ); + + // draw the String + aVirtualDevice.DrawTextArray( aEmptyPoint, + aText, + pDXArray.get(), + (xub_StrLen)rText.StartPosition, + (xub_StrLen)rText.Length ); + } + else + { + // draw the String + aVirtualDevice.DrawText( aEmptyPoint, + aText, + (xub_StrLen)rText.StartPosition, + (xub_StrLen)rText.Length ); + } + } + } + + geometry::RealRectangle2D TextLayoutDrawHelper::queryTextBounds( const rendering::StringContext& rText, + const uno::Sequence< double >& rLogicalAdvancements, + const uno::Reference< rendering::XCanvasFont >& rCanvasFont, + const geometry::Matrix2D& rFontMatrix ) + { + if(!(rText.Length)) + return geometry::RealRectangle2D(); + + // TODO(F1): Fetching default screen DC here, will yield wrong + // metrics when e.g. formatting for a printer! + SystemGraphicsData aSystemGraphicsData; + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.hDC = reinterpret_cast< ::HDC >(GetDC( NULL )); + VirtualDevice aVirtualDevice(&aSystemGraphicsData, 0); + + // create the font + const ::com::sun::star::rendering::FontRequest& rFontRequest = rCanvasFont->getFontRequest(); + Font aFont( + rFontRequest.FontDescription.FamilyName, + rFontRequest.FontDescription.StyleName, + Size( 0, ::basegfx::fround(rFontRequest.CellSize))); + + aFont.SetAlign( ALIGN_BASELINE ); + aFont.SetCharSet( (rFontRequest.FontDescription.IsSymbolFont==com::sun::star::util::TriState_YES) ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE ); + aFont.SetVertical( (rFontRequest.FontDescription.IsVertical==com::sun::star::util::TriState_YES) ? TRUE : FALSE ); + aFont.SetWeight( static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) ); + aFont.SetItalic( (rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : ITALIC_NORMAL ); + + // adjust to stretched font + if(!::rtl::math::approxEqual(rFontMatrix.m00, rFontMatrix.m11)) + { + const Size aSize = aVirtualDevice.GetFontMetric( aFont ).GetSize(); + const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 ); + double fStretch = (rFontMatrix.m00 + rFontMatrix.m01); + + if( !::basegfx::fTools::equalZero( fDividend) ) + fStretch /= fDividend; + + const sal_Int32 nNewWidth = ::basegfx::fround( aSize.Width() * fStretch ); + + aFont.SetWidth( nNewWidth ); + } + + // set font + aVirtualDevice.SetFont(aFont); + + // need metrics for Y offset, the XCanvas always renders + // relative to baseline + const ::FontMetric& aMetric( aVirtualDevice.GetFontMetric() ); + + const sal_Int32 nAboveBaseline( -aMetric.GetIntLeading() - aMetric.GetAscent() ); + const sal_Int32 nBelowBaseline( aMetric.GetDescent() ); + + if( rLogicalAdvancements.getLength() ) + { + return geometry::RealRectangle2D( 0, nAboveBaseline, + rLogicalAdvancements[ rLogicalAdvancements.getLength()-1 ], + nBelowBaseline ); + } + else + { + return geometry::RealRectangle2D( 0, nAboveBaseline, + aVirtualDevice.GetTextWidth( + rText.Text, + ::canvas::tools::numeric_cast<USHORT>(rText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(rText.Length) ), + nBelowBaseline ); + } + } +} + + +// eof diff --git a/canvas/source/directx/dx_textlayout_drawhelper.hxx b/canvas/source/directx/dx_textlayout_drawhelper.hxx new file mode 100755 index 000000000000..c484867055af --- /dev/null +++ b/canvas/source/directx/dx_textlayout_drawhelper.hxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * 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 _TEXTLAYOUT_DRAWHELPER_HXX +#define _TEXTLAYOUT_DRAWHELPER_HXX + +#include <boost/shared_ptr.hpp> + +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/rendering/StringContext.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> +#include <com/sun/star/geometry/Matrix2D.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2isize.hxx> + +class ::com::sun::star::rendering::XCanvasFont; + +namespace Gdiplus { class Graphics; } + +namespace dxcanvas +{ + struct Bitmap; + class TextLayoutDrawHelper + { + public: + TextLayoutDrawHelper( + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice); + ~TextLayoutDrawHelper(); + + // draw text + void drawText( const boost::shared_ptr<Gdiplus::Graphics>& rGraphics, + const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState, + const ::basegfx::B2ISize& rOutputOffset, + const ::com::sun::star::rendering::StringContext& rText, + const ::com::sun::star::uno::Sequence< double >& rLogicalAdvancements, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& rCanvasFont, + const ::com::sun::star::geometry::Matrix2D& rFontMatrix, + bool bAlphaSurface ); + + ::com::sun::star::geometry::RealRectangle2D queryTextBounds( + const ::com::sun::star::rendering::StringContext& rText, + const ::com::sun::star::uno::Sequence< double >& rLogicalAdvancements, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont >& rCanvasFont, + const ::com::sun::star::geometry::Matrix2D& rFontMatrix ); + +#ifdef DBG_UTIL + void test(); +#endif + + protected: + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice > mxGraphicDevice; + }; +} + +#endif /* _TEXTLAYOUT_DRAWHELPER_HXX */ +// eof diff --git a/canvas/source/directx/dx_vcltools.cxx b/canvas/source/directx/dx_vcltools.cxx new file mode 100755 index 000000000000..c48931b87eae --- /dev/null +++ b/canvas/source/directx/dx_vcltools.cxx @@ -0,0 +1,523 @@ +/************************************************************************* + * + * 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 <vcl/canvastools.hxx> + +#include <vcl/bitmap.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> +#include <tools/diagnose_ex.h> + +#include "dx_impltools.hxx" +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <boost/scoped_array.hpp> + +#include "dx_vcltools.hxx" + +using namespace ::com::sun::star; + +namespace dxcanvas +{ + namespace tools + { + namespace + { + /// Calc number of colors in given BitmapInfoHeader + sal_Int32 calcDIBColorCount( const BITMAPINFOHEADER& rBIH ) + { + if( rBIH.biSize != sizeof( BITMAPCOREHEADER ) ) + { + if( rBIH.biBitCount <= 8 ) + { + if( rBIH.biClrUsed ) + return rBIH.biClrUsed; + else + return 1L << rBIH.biBitCount; + } + } + else + { + BITMAPCOREHEADER* pCoreHeader = (BITMAPCOREHEADER*)&rBIH; + + if( pCoreHeader->bcBitCount <= 8 ) + return 1L << pCoreHeader->bcBitCount; + } + + return 0; // nothing known + } + + /// Draw DI bits to given Graphics + bool drawDIBits( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const void* hDIB ) + { + bool bRet( false ); + BitmapSharedPtr pBitmap; + + const BITMAPINFO* pBI = (BITMAPINFO*)GlobalLock( (HGLOBAL)hDIB ); + + if( pBI ) + { + const BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*)pBI; + const BYTE* pBits = (BYTE*) pBI + *(DWORD*)pBI + + calcDIBColorCount( *pBIH ) * sizeof( RGBQUAD ); + + // forward to outsourced GDI+ rendering method + // (header clashes) + bRet = tools::drawDIBits( rGraphics, *pBI, (void*)pBits ); + + GlobalUnlock( (HGLOBAL)hDIB ); + } + + return bRet; + } + + /** Draw VCL bitmap to given Graphics + + @param rBmp + Reference to bitmap. Might get modified, in such a way + that it will hold a DIB after a successful function call. + */ + bool drawVCLBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + ::Bitmap& rBmp ) + { + BitmapSystemData aBmpSysData; + + if( !rBmp.GetSystemData( aBmpSysData ) || + !aBmpSysData.pDIB ) + { + // first of all, ensure that Bitmap contains a DIB, by + // aquiring a read access + BitmapReadAccess* pReadAcc = rBmp.AcquireReadAccess(); + + // TODO(P2): Acquiring a read access can actually + // force a read from VRAM, thus, avoiding this + // step somehow will increase performance + // here. + if( pReadAcc ) + { + // try again: now, WinSalBitmap must have + // generated a DIB + if( rBmp.GetSystemData( aBmpSysData ) && + aBmpSysData.pDIB ) + { + return drawDIBits( rGraphics, + aBmpSysData.pDIB ); + } + + rBmp.ReleaseAccess( pReadAcc ); + } + } + else + { + return drawDIBits( rGraphics, + aBmpSysData.pDIB ); + } + + // failed to generate DIBits from vcl bitmap + return false; + } + + /** Create a chunk of raw RGBA data GDI+ Bitmap from VCL BbitmapEX + */ + RawRGBABitmap bitmapFromVCLBitmapEx( const ::BitmapEx& rBmpEx ) + { + // TODO(P2): Avoid temporary bitmap generation, maybe + // even ensure that created DIBs are copied back to + // BmpEx (currently, every AcquireReadAccess() will + // make the local bitmap copy unique, effectively + // duplicating the memory used) + + ENSURE_OR_THROW( rBmpEx.IsTransparent(), + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "BmpEx not transparent" ); + + // convert transparent bitmap to 32bit RGBA + // ======================================== + + const ::Size aBmpSize( rBmpEx.GetSizePixel() ); + + RawRGBABitmap aBmpData; + aBmpData.mnWidth = aBmpSize.Width(); + aBmpData.mnHeight = aBmpSize.Height(); + aBmpData.mpBitmapData.reset( new sal_uInt8[ 4*aBmpData.mnWidth*aBmpData.mnHeight ] ); + + Bitmap aBitmap( rBmpEx.GetBitmap() ); + + ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), + aBitmap ); + + const sal_Int32 nWidth( aBmpSize.Width() ); + const sal_Int32 nHeight( aBmpSize.Height() ); + + ENSURE_OR_THROW( pReadAccess.get() != NULL, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unable to acquire read acces to bitmap" ); + + if( rBmpEx.IsAlpha() ) + { + Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() ); + + ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.AcquireReadAccess(), + aAlpha ); + + // By convention, the access buffer always has + // one of the following formats: + // + // BMP_FORMAT_1BIT_MSB_PAL + // BMP_FORMAT_4BIT_MSN_PAL + // BMP_FORMAT_8BIT_PAL + // BMP_FORMAT_16BIT_TC_LSB_MASK + // BMP_FORMAT_24BIT_TC_BGR + // BMP_FORMAT_32BIT_TC_MASK + // + // and is always BMP_FORMAT_BOTTOM_UP + // + // This is the way + // WinSalBitmap::AcquireBuffer() sets up the + // buffer + + ENSURE_OR_THROW( pAlphaReadAccess.get() != NULL, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unable to acquire read acces to alpha" ); + + ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL || + pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unsupported alpha scanline format" ); + + BitmapColor aCol; + const sal_Int32 nWidth( aBmpSize.Width() ); + const sal_Int32 nHeight( aBmpSize.Height() ); + sal_uInt8* pCurrOutput( aBmpData.mpBitmapData.get() ); + int x, y; + + for( y=0; y<nHeight; ++y ) + { + switch( pReadAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + aCol = pReadAccess->GetPaletteColor( *pScan++ ); + + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + // store as RGBA + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + // TODO(P2): Might be advantageous + // to hand-formulate the following + // formats, too. + case BMP_FORMAT_1BIT_MSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_MSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_LSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_MASK: + { + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + // using fallback for those + // seldom formats + for( x=0; x<nWidth; ++x ) + { + // yes. x and y are swapped on Get/SetPixel + aCol = pReadAccess->GetColor(y,x); + + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + case BMP_FORMAT_1BIT_LSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_LSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_8BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_RGB: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_MSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ABGR: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ARGB: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_BGRA: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_RGBA: + // FALLTHROUGH intended + default: + ENSURE_OR_THROW( false, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unexpected scanline format - has " + "WinSalBitmap::AcquireBuffer() changed?" ); + } + } + } + else + { + Bitmap aMask( rBmpEx.GetMask() ); + + ScopedBitmapReadAccess pMaskReadAccess( aMask.AcquireReadAccess(), + aMask ); + + // By convention, the access buffer always has + // one of the following formats: + // + // BMP_FORMAT_1BIT_MSB_PAL + // BMP_FORMAT_4BIT_MSN_PAL + // BMP_FORMAT_8BIT_PAL + // BMP_FORMAT_16BIT_TC_LSB_MASK + // BMP_FORMAT_24BIT_TC_BGR + // BMP_FORMAT_32BIT_TC_MASK + // + // and is always BMP_FORMAT_BOTTOM_UP + // + // This is the way + // WinSalBitmap::AcquireBuffer() sets up the + // buffer + + ENSURE_OR_THROW( pMaskReadAccess.get() != NULL, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unable to acquire read acces to mask" ); + + ENSURE_OR_THROW( pMaskReadAccess->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unsupported mask scanline format" ); + + BitmapColor aCol; + int nCurrBit; + const int nMask( 1L ); + const int nInitialBit(7); + sal_uInt8* pCurrOutput( aBmpData.mpBitmapData.get() ); + int x, y; + + // mapping table, to get from mask index color to + // alpha value (which depends on the mask's palette) + sal_uInt8 aColorMap[2]; + + const BitmapColor& rCol0( pMaskReadAccess->GetPaletteColor( 0 ) ); + const BitmapColor& rCol1( pMaskReadAccess->GetPaletteColor( 1 ) ); + + // shortcut for true luminance calculation + // (assumes that palette is grey-level). Note the + // swapped the indices here, to account for the + // fact that VCL's notion of alpha is inverted to + // the rest of the world's. + aColorMap[0] = rCol1.GetRed(); + aColorMap[1] = rCol0.GetRed(); + + for( y=0; y<nHeight; ++y ) + { + switch( pReadAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + aCol = pReadAccess->GetPaletteColor( *pScan++ ); + + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + // store as RGBA + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + + *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + // TODO(P2): Might be advantageous + // to hand-formulate the following + // formats, too. + case BMP_FORMAT_1BIT_MSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_MSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_LSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_MASK: + { + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + // using fallback for those + // seldom formats + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + // yes. x and y are swapped on Get/SetPixel + aCol = pReadAccess->GetColor(y,x); + + // store as RGBA + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + *pCurrOutput++ = aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + case BMP_FORMAT_1BIT_LSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_LSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_8BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_RGB: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_MSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ABGR: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ARGB: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_BGRA: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_RGBA: + // FALLTHROUGH intended + default: + ENSURE_OR_THROW( false, + "::dxcanvas::tools::bitmapFromVCLBitmapEx(): " + "Unexpected scanline format - has " + "WinSalBitmap::AcquireBuffer() changed?" ); + } + } + } + + return aBmpData; + } + + bool drawVCLBitmapEx( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const ::BitmapEx& rBmpEx ) + { + if( !rBmpEx.IsTransparent() ) + { + Bitmap aBmp( rBmpEx.GetBitmap() ); + return drawVCLBitmap( rGraphics, aBmp ); + } + else + { + return drawRGBABits( rGraphics, + bitmapFromVCLBitmapEx( rBmpEx ) ); + } + } + } + + bool drawVCLBitmapFromXBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const uno::Reference< rendering::XBitmap >& xBitmap ) + { + // TODO(F2): add support for floating point bitmap formats + uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntBmp( + xBitmap, uno::UNO_QUERY ); + + if( !xIntBmp.is() ) + return false; + + ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap( xIntBmp ); + if( !aBmpEx ) + return false; + + return drawVCLBitmapEx( rGraphics, aBmpEx ); + } + } +} diff --git a/canvas/source/directx/dx_vcltools.hxx b/canvas/source/directx/dx_vcltools.hxx new file mode 100755 index 000000000000..fab96cb79e5a --- /dev/null +++ b/canvas/source/directx/dx_vcltools.hxx @@ -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. + * + ************************************************************************/ + +#ifndef _DXCANVAS_VCLTOOLS_HXX +#define _DXCANVAS_VCLTOOLS_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/util/TriState.hpp> + +#include <boost/shared_ptr.hpp> + + +namespace com { namespace sun { namespace star { namespace lang +{ + class XUnoTunnel; +} } } } + +namespace Gdiplus { class Graphics; } + +namespace dxcanvas +{ + namespace tools + { + /** Raw RGBA bitmap data, + contiguous in memory + */ + struct RawRGBABitmap + { + sal_Int32 mnWidth; + sal_Int32 mnHeight; + ::boost::shared_ptr< sal_uInt8 > mpBitmapData; + }; + + bool drawVCLBitmapFromXBitmap( const ::boost::shared_ptr< Gdiplus::Graphics >& rGraphics, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap ); + } +} + +#endif /* _DXCANVAS_VCLTOOLS_HXX */ diff --git a/canvas/source/directx/dx_winstuff.hxx b/canvas/source/directx/dx_winstuff.hxx new file mode 100755 index 000000000000..d1718b07f3d1 --- /dev/null +++ b/canvas/source/directx/dx_winstuff.hxx @@ -0,0 +1,219 @@ +/************************************************************************* + * + * 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 _DXCANVAS_WINSTUFF_HXX +#define _DXCANVAS_WINSTUFF_HXX + +#include <algorithm> + +#include <boost/shared_ptr.hpp> + +#include <basegfx/numeric/ftools.hxx> + +#ifdef _WINDOWS_ +#error someone else included <windows.h> +#endif + +// Enabling Direct3D Debug Information Further more, with registry key +// \\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Direct3D\D3D9Debugging\\EnableCreationStack +// set to 1, sets a backtrace each time an object is created to the +// following global variable: LPCWSTR CreationCallStack +#if OSL_DEBUG_LEVEL > 0 +# define D3D_DEBUG_INFO +#endif + +#ifndef DIRECTX_VERSION +#error please define for which directx version we should compile +#endif + +#if defined _MSC_VER +#pragma warning(push,1) +#endif + + +#define BOOL win32BOOL +#define INT32 win32INT32 +#define UINT32 win32UINT32 +#define GradientStyle_RECT win32GradientStyle_RECT +#define Polygon win32Polygon +#define PolyPolygon win32PolyPolygon +#undef WB_LEFT +#undef WB_RIGHT + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> // TODO(Q1): extract minimal set of required headers for gdiplus + +#if DIRECTX_VERSION < 0x0900 + + #include <multimon.h> + + // Be compatible with directdraw 3.0. Lets see how far this takes us + #define DIRECTDRAW_VERSION 0x0300 + #include <ddraw.h> + + // Be compatible with direct3d 5.0. Lets see how far this takes us + #define DIRECT3D_VERSION 0x0500 + #define D3D_OVERLOADS + #include <d3d.h> + + typedef IDirectDrawSurface surface_type; + +#else + + #include <d3d9.h> + #include <d3dx9.h> +// #include <dxerr9.h> #i107614# removing include, it has been changed in the latest sdk fron August2009 from dxerr9.h into dxerr.h + + typedef IDirect3DSurface9 surface_type; + +#endif + +#undef DrawText + +#ifdef __MINGW32__ +using ::std::max; +using ::std::min; +#endif + +#include <gdiplus.h> + +#ifdef min +# undef min +#endif +#ifdef max +# undef max +#endif + +namespace dxcanvas +{ + // some shared pointer typedefs to Gdiplus objects + typedef ::boost::shared_ptr< Gdiplus::Graphics > GraphicsSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::GraphicsPath > GraphicsPathSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::Bitmap > BitmapSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::CachedBitmap > CachedBitmapSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::Font > FontSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::Brush > BrushSharedPtr; + typedef ::boost::shared_ptr< Gdiplus::TextureBrush > TextureBrushSharedPtr; + + /** COM object RAII wrapper + + This template wraps a Windows COM object, transparently + handling lifetime issues the C++ way (i.e. releasing the + reference when the object is destroyed) + */ + template< typename T > class COMReference + { + public: + typedef T Wrappee; + + COMReference() : + mp( NULL ) + { + } + + /** Create from raw pointer + + @attention This constructor assumes the interface is + already acquired (unless p is NULL), no additional AddRef + is called here. + + This caters e.g. for all DirectX factory methods, which + return the created interfaces pre-acquired, into a raw + pointer. Simply pass the pointer to this class, but don't + call Release manually on it! + + @example IDirectDrawSurface* pSurface; + pDD->CreateSurface(&aSurfaceDesc, &pSurface, NULL); + mpSurface = COMReference< IDirectDrawSurface >(pSurface); + + */ + explicit COMReference( T* p ) : + mp( p ) + { + } + + COMReference( const COMReference& rNew ) : + mp( NULL ) + { + if( rNew.mp == NULL ) + return; + + rNew.mp->AddRef(); // do that _before_ assigning the + // pointer. Just in case... + mp = rNew.mp; + } + + COMReference& operator=( const COMReference& rRHS ) + { + COMReference aTmp(rRHS); + ::std::swap( mp, aTmp.mp ); + + return *this; + } + + ~COMReference() + { + reset(); + } + + int reset() + { + int refcount = 0; + if( mp ) + refcount = mp->Release(); + + mp = NULL; + return refcount; + } + + bool is() const { return mp != NULL; } + T* get() const { return mp; } + T* operator->() const { return mp; } + T& operator*() const { return *mp; } + + private: + T* mp; + }; + + // get_pointer() enables boost::mem_fn to recognize COMReference + template<class T> inline T * get_pointer(COMReference<T> const& p) + { + return p.get(); + } +} + +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#undef DELETE +#undef BOOL +#undef INT32 +#undef UINT32 +#undef PolyPolygon + +#endif /* _DXCANVAS_WINSTUFF_HXX */ diff --git a/canvas/source/directx/exports.dxp b/canvas/source/directx/exports.dxp new file mode 100644 index 000000000000..f0e1c69934bc --- /dev/null +++ b/canvas/source/directx/exports.dxp @@ -0,0 +1,2 @@ +component_getImplementationEnvironment +component_getFactory diff --git a/canvas/source/directx/gdipluscanvas.component b/canvas/source/directx/gdipluscanvas.component new file mode 100644 index 000000000000..e39e77444d59 --- /dev/null +++ b/canvas/source/directx/gdipluscanvas.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.BitmapCanvas.GDI+"> + <service name="com.sun.star.rendering.BitmapCanvas.GDI+"/> + </implementation> + <implementation name="com.sun.star.comp.rendering.Canvas.GDI+"> + <service name="com.sun.star.rendering.Canvas.GDI+"/> + </implementation> +</component> diff --git a/canvas/source/directx/makefile.mk b/canvas/source/directx/makefile.mk new file mode 100644 index 000000000000..9547fef40cc7 --- /dev/null +++ b/canvas/source/directx/makefile.mk @@ -0,0 +1,241 @@ +#************************************************************************* +# +# 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=directx9canvas +TARGET2=directx5canvas +TARGET3=gdipluscanvas +ENABLE_EXCEPTIONS=TRUE + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +DLLPRE = + +# --- Nothing to do if we're compiling with --disable-directx ----------- +.IF "$(ENABLE_DIRECTX)" == "" +@all: + @echo "Building without DirectX support..." +.ENDIF + + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF + +.IF "$(dx_debug_images)"!="" || "$(DX_DEBUG_IMAGES)"!="" +CDEFS+= -DDX_DEBUG_IMAGES +.ENDIF + +# --- This is Windows only! { ---------------------------------------------------------------- + +.IF "$(GUI)" == "WNT" + +SHARED_SLOFILES = \ + $(SLO)$/dx_bitmap.obj \ + $(SLO)$/dx_bitmapcanvashelper.obj \ + $(SLO)$/dx_canvasbitmap.obj \ + $(SLO)$/dx_canvasfont.obj \ + $(SLO)$/dx_canvashelper.obj \ + $(SLO)$/dx_canvashelper_texturefill.obj \ + $(SLO)$/dx_devicehelper.obj \ + $(SLO)$/dx_gdiplususer.obj \ + $(SLO)$/dx_impltools.obj \ + $(SLO)$/dx_linepolypolygon.obj \ + $(SLO)$/dx_textlayout.obj \ + $(SLO)$/dx_textlayout_drawhelper.obj \ + $(SLO)$/dx_vcltools.obj + +DX_SLOFILES = \ + $(SLO)$/dx_5rm.obj \ + $(SLO)$/dx_9rm.obj \ + $(SLO)$/dx_canvascustomsprite.obj \ + $(SLO)$/dx_config.obj \ + $(SLO)$/dx_spritecanvas.obj \ + $(SLO)$/dx_spritecanvashelper.obj \ + $(SLO)$/dx_spritedevicehelper.obj \ + $(SLO)$/dx_spritehelper.obj \ + $(SLO)$/dx_surfacebitmap.obj \ + $(SLO)$/dx_surfacegraphics.obj +DX_SLOFILES += $(SHARED_SLOFILES) + +GDIPLUS_SLOFILES = \ + $(SLO)$/dx_canvas.obj +GDIPLUS_SLOFILES += $(SHARED_SLOFILES) + +STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) $(TOOLSLIB) $(UNOTOOLSLIB) $(I18NISOLANGLIB) + + +######################################################## +# DX9 +######################################################## + +# Indicates the source obj files for the dx5 lib +LIB1TARGET= $(SLB)$/$(TARGET).lib +LIB1OBJFILES = $(DX_SLOFILES) + +# Indicates the filename of the shared library. +SHL1TARGET=$(TARGET).uno + +# Links import libraries. +SHL1STDLIBS= $(STDLIBS) + +# Specifies an import library to create. For Win32 only. +SHL1IMPLIB=i$(TARGET) + +# Specifies libraries from the same module to put into the shared library. +SHL1LIBS=$(SLB)$/$(TARGET).lib + +SHL1DEF=$(MISC)$/$(SHL1TARGET).def + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=exports.dxp + +CDEFS+=-DDIRECTX_VERSION=0x0900 + +SHL1STDLIBS += $(GDI32LIB) +.IF "$(COM)" == "GCC" +SHL1STDLIBS += $(DIRECTXSDK_LIB)/d3d9.lib +.ELSE +SHL1STDLIBS += d3d9.lib +.ENDIF +SHL1STDLIBS += $(GDIPLUSLIB) + +.IF "$(dx_debug_images)"!="" || "$(DX_DEBUG_IMAGES)"!="" +SHL1STDLIBS += imdebug.lib +.ENDIF + + +######################################################## +# DX5 +######################################################## + +.IF "$(USE_DIRECTX5)" != "" +SECOND_BUILD=DX5 +DX5_SLOFILES=$(DX_SLOFILES) +DX5CDEFS += -DDIRECTX_VERSION=0x0500 + +LIB2TARGET= $(SLB)$/$(TARGET2).lib +LIB2OBJFILES = $(REAL_DX5_SLOFILES) + +# Indicates the filename of the shared library. +SHL2TARGET=$(TARGET2).uno + +# Links import libraries. +SHL2STDLIBS= $(STDLIBS) + +# Specifies an import library to create. For Win32 only. +SHL2IMPLIB=i$(TARGET2).lib + +# Specifies libraries from the same module to put into the shared library. +SHL2LIBS=$(SLB)$/$(TARGET2).lib +SHL2DEF=$(MISC)$/$(SHL2TARGET).def + +DEF2NAME=$(SHL2TARGET) +DEF2EXPORTFILE=exports.dxp + +SHL2STDLIBS += $(GDI32LIB) +SHL2STDLIBS += $(DDRAWLIB) +SHL2STDLIBS += $(GDIPLUSLIB) + +.IF "$(COM)" == "GCC" +SHL2STDLIBS += $(DIRECTXSDK_LIB)/d3dx.lib +.ELSE +SHL2STDLIBS += d3dx.lib +.ENDIF + +.IF "$(dx_debug_images)"!="" || "$(DX_DEBUG_IMAGES)"!="" +SHL2STDLIBS += imdebug.lib +.ENDIF +.ENDIF # IF "$(USE_DIRECTX5)" != "" + + +######################################################## +# GDI+ +######################################################## + +LIB3TARGET= $(SLB)$/$(TARGET3).lib +LIB3OBJFILES = $(GDIPLUS_SLOFILES) + +# Indicates the filename of the shared library. +SHL3TARGET=$(TARGET3).uno + +# Links import libraries. +SHL3STDLIBS= $(CPPULIB) $(TKLIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) $(TOOLSLIB) $(UNOTOOLSLIB) $(I18NISOLANGLIB) + +# Specifies an import library to create. For Win32 only. +SHL3IMPLIB=i$(TARGET3).lib + +# Specifies libraries from the same module to put into the shared library. +SHL3LIBS=$(SLB)$/$(TARGET3).lib +SHL3DEF=$(MISC)$/$(SHL3TARGET).def + +DEF3NAME=$(SHL3TARGET) +DEF3EXPORTFILE=exports.dxp + +SHL3STDLIBS += $(GDI32LIB) +SHL3STDLIBS += $(GDIPLUSLIB) + +.IF "$(dx_debug_images)"!="" || "$(DX_DEBUG_IMAGES)"!="" +SHL3STDLIBS += imdebug.lib +.ENDIF + +.ENDIF # IF "$(GUI)" == "WNT" + +# --- This is Windows only! } ---------------------------------------------------------------- + +# ========================================================================== + +.INCLUDE : target.mk + +ALLTAR : \ + $(MISC)/directx5canvas.component \ + $(MISC)/directx9canvas.component \ + $(MISC)/gdipluscanvas.component + +$(MISC)/directx5canvas.component .ERRREMOVE : \ + $(SOLARENV)/bin/createcomponent.xslt directx5canvas.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL2TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt directx5canvas.component + +$(MISC)/directx9canvas.component .ERRREMOVE : \ + $(SOLARENV)/bin/createcomponent.xslt directx9canvas.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt directx9canvas.component + +$(MISC)/gdipluscanvas.component .ERRREMOVE : \ + $(SOLARENV)/bin/createcomponent.xslt gdipluscanvas.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL3TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt gdipluscanvas.component diff --git a/canvas/source/factory/canvasfactory.component b/canvas/source/factory/canvasfactory.component new file mode 100644 index 000000000000..3896f4197d2f --- /dev/null +++ b/canvas/source/factory/canvasfactory.component @@ -0,0 +1,34 @@ +<?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.CanvasFactory"> + <service name="com.sun.star.rendering.CanvasFactory"/> + </implementation> +</component> diff --git a/canvas/source/factory/cf_service.cxx b/canvas/source/factory/cf_service.cxx new file mode 100644 index 000000000000..f4bbb57e0e7d --- /dev/null +++ b/canvas/source/factory/cf_service.cxx @@ -0,0 +1,545 @@ +/************************************************************************* + * + * 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 <osl/mutex.hxx> +#include <osl/process.h> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase3.hxx> +#include <vcl/configsettings.hxx> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <boost/bind.hpp> +#include <vector> +#include <utility> +#include <functional> +#include <algorithm> + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) +#define ARLEN(x) (sizeof (x) / sizeof *(x)) + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +namespace +{ + +OUString SAL_CALL getImplName() +{ + return OUSTR("com.sun.star.comp.rendering.CanvasFactory"); +} + +Sequence<OUString> SAL_CALL getSuppServices() +{ + OUString name = OUSTR("com.sun.star.rendering.CanvasFactory"); + return Sequence<OUString>(&name, 1); +} + +//============================================================================== +class CanvasFactory + : public ::cppu::WeakImplHelper3< lang::XServiceInfo, + lang::XMultiComponentFactory, + lang::XMultiServiceFactory > +{ + typedef std::pair<OUString,Sequence<OUString> > AvailPair; + typedef std::pair<OUString,OUString> CachePair; + typedef std::vector< AvailPair > AvailVector; + typedef std::vector< CachePair > CacheVector; + + + mutable ::osl::Mutex m_mutex; + Reference<XComponentContext> m_xContext; + Reference<container::XNameAccess> m_xCanvasConfigNameAccess; + AvailVector m_aAvailableImplementations; + AvailVector m_aAcceleratedImplementations; + AvailVector m_aAAImplementations; + mutable CacheVector m_aCachedImplementations; + mutable bool m_bCacheHasForcedLastImpl; + mutable bool m_bCacheHasUseAcceleratedEntry; + mutable bool m_bCacheHasUseAAEntry; + + void checkConfigFlag( bool& r_bFlag, + bool& r_CacheFlag, + const OUString& nodeName ) const; + Reference<XInterface> use( + OUString const & serviceName, + Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) const; + Reference<XInterface> lookupAndUse( + OUString const & serviceName, Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) const; + +public: + virtual ~CanvasFactory(); + CanvasFactory( Reference<XComponentContext> const & xContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() throw (RuntimeException); + virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) + throw (RuntimeException); + virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() + throw (RuntimeException); + + // XMultiComponentFactory + virtual Sequence<OUString> SAL_CALL getAvailableServiceNames() + throw (RuntimeException); + virtual Reference<XInterface> SAL_CALL createInstanceWithContext( + OUString const & name, + Reference<XComponentContext> const & xContext ) throw (Exception); + virtual Reference<XInterface> SAL_CALL + createInstanceWithArgumentsAndContext( + OUString const & name, + Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) throw (Exception); + + // XMultiServiceFactory + virtual Reference<XInterface> SAL_CALL createInstance( + OUString const & name ) + throw (Exception); + virtual Reference<XInterface> SAL_CALL createInstanceWithArguments( + OUString const & name, Sequence<Any> const & args ) + throw (Exception); +}; + +CanvasFactory::CanvasFactory( Reference<XComponentContext> const & xContext ) : + m_mutex(), + m_xContext(xContext), + m_xCanvasConfigNameAccess(), + m_aAvailableImplementations(), + m_aAcceleratedImplementations(), + m_aAAImplementations(), + m_aCachedImplementations(), + m_bCacheHasForcedLastImpl(), + m_bCacheHasUseAcceleratedEntry(), + m_bCacheHasUseAAEntry() +{ + try + { + // read out configuration for preferred services: + Reference<lang::XMultiServiceFactory> xConfigProvider( + m_xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.configuration.ConfigurationProvider"), + m_xContext ), UNO_QUERY_THROW ); + + Any propValue( + makeAny( beans::PropertyValue( + OUSTR("nodepath"), -1, + makeAny( OUSTR("/org.openoffice.Office.Canvas") ), + beans::PropertyState_DIRECT_VALUE ) ) ); + + m_xCanvasConfigNameAccess.set( + xConfigProvider->createInstanceWithArguments( + OUSTR("com.sun.star.configuration.ConfigurationAccess"), + Sequence<Any>( &propValue, 1 ) ), + UNO_QUERY_THROW ); + + propValue = makeAny( + beans::PropertyValue( + OUSTR("nodepath"), -1, + makeAny( OUSTR("/org.openoffice.Office.Canvas/CanvasServiceList") ), + beans::PropertyState_DIRECT_VALUE ) ); + + Reference<container::XNameAccess> xNameAccess( + xConfigProvider->createInstanceWithArguments( + OUSTR("com.sun.star.configuration.ConfigurationAccess"), + Sequence<Any>( &propValue, 1 ) ), UNO_QUERY_THROW ); + Reference<container::XHierarchicalNameAccess> xHierarchicalNameAccess( + xNameAccess, UNO_QUERY_THROW); + + Sequence<OUString> serviceNames = xNameAccess->getElementNames(); + const OUString* pCurr = serviceNames.getConstArray(); + const OUString* const pEnd = pCurr + serviceNames.getLength(); + while( pCurr != pEnd ) + { + Reference<container::XNameAccess> xEntryNameAccess( + xHierarchicalNameAccess->getByHierarchicalName(*pCurr), + UNO_QUERY ); + + if( xEntryNameAccess.is() ) + { + Sequence<OUString> implementationList; + if( (xEntryNameAccess->getByName( OUSTR("PreferredImplementations") ) >>= implementationList) ) + m_aAvailableImplementations.push_back( std::make_pair(*pCurr,implementationList) ); + if( (xEntryNameAccess->getByName( OUSTR("AcceleratedImplementations") ) >>= implementationList) ) + m_aAcceleratedImplementations.push_back( std::make_pair(*pCurr,implementationList) ); + if( (xEntryNameAccess->getByName( OUSTR("AntialiasingImplementations") ) >>= implementationList) ) + m_aAAImplementations.push_back( std::make_pair(*pCurr,implementationList) ); + } + + ++pCurr; + } + } + catch (RuntimeException &) + { + throw; + } + catch (Exception&) + { + } + + if( m_aAvailableImplementations.empty() ) + { + // Ugh. Looks like configuration is borked. Fake minimal + // setup. + Sequence<OUString> aServices(1); + aServices[0] = OUSTR("com.sun.star.comp.rendering.Canvas.VCL"); + m_aAvailableImplementations.push_back( std::make_pair(OUSTR("com.sun.star.rendering.Canvas"), + aServices) ); + + aServices[0] = OUSTR("com.sun.star.comp.rendering.SpriteCanvas.VCL"); + m_aAvailableImplementations.push_back( std::make_pair(OUSTR("com.sun.star.rendering.SpriteCanvas"), + aServices) ); + } +} + +CanvasFactory::~CanvasFactory() +{ +} + +//------------------------------------------------------------------------------ +Reference<XInterface> create( Reference<XComponentContext> const & xContext ) +{ + return static_cast< ::cppu::OWeakObject * >( + new CanvasFactory( xContext ) ); +} + +// XServiceInfo +//______________________________________________________________________________ +OUString CanvasFactory::getImplementationName() throw (RuntimeException) +{ + return getImplName(); +} + +//______________________________________________________________________________ +sal_Bool CanvasFactory::supportsService( OUString const & serviceName ) + throw (RuntimeException) +{ + return serviceName.equals(getSuppServices()[0]); +} + +//______________________________________________________________________________ +Sequence<OUString> CanvasFactory::getSupportedServiceNames() + throw (RuntimeException) +{ + return getSuppServices(); +} + +// XMultiComponentFactory +//______________________________________________________________________________ +Sequence<OUString> CanvasFactory::getAvailableServiceNames() + throw (RuntimeException) +{ + Sequence<OUString> aServiceNames(m_aAvailableImplementations.size()); + std::transform(m_aAvailableImplementations.begin(), + m_aAvailableImplementations.end(), + aServiceNames.getArray(), + std::select1st<AvailPair>()); + return aServiceNames; +} + +//______________________________________________________________________________ +Reference<XInterface> CanvasFactory::createInstanceWithContext( + OUString const & name, Reference<XComponentContext> const & xContext ) + throw (Exception) +{ + return createInstanceWithArgumentsAndContext( + name, Sequence<Any>(), xContext ); +} + +//______________________________________________________________________________ +Reference<XInterface> CanvasFactory::use( + OUString const & serviceName, + Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) const +{ + try { + return m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + serviceName, args, xContext); + } + catch (RuntimeException &) + { + throw; + } + catch (Exception &) + { + return Reference<XInterface>(); + } +} + +//______________________________________________________________________________ +void CanvasFactory::checkConfigFlag( bool& r_bFlag, + bool& r_CacheFlag, + const OUString& nodeName ) const +{ + if( m_xCanvasConfigNameAccess.is() ) + { + m_xCanvasConfigNameAccess->getByName( nodeName ) >>= r_bFlag; + + if( r_CacheFlag != r_bFlag ) + { + // cache is invalid, because of different order of + // elements + r_CacheFlag = r_bFlag; + m_aCachedImplementations.clear(); + } + } +} + +//______________________________________________________________________________ +Reference<XInterface> CanvasFactory::lookupAndUse( + OUString const & serviceName, Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) const +{ + ::osl::MutexGuard guard(m_mutex); + + // forcing last entry from impl list, if config flag set + bool bForceLastEntry(false); + checkConfigFlag( bForceLastEntry, + m_bCacheHasForcedLastImpl, + OUSTR("ForceSafeServiceImpl") ); + + // use anti-aliasing canvas, if config flag set (or not existing) + bool bUseAAEntry(true); + checkConfigFlag( bUseAAEntry, + m_bCacheHasUseAAEntry, + OUSTR("UseAntialiasingCanvas") ); + + // use accelerated canvas, if config flag set (or not existing) + bool bUseAcceleratedEntry(true); + checkConfigFlag( bUseAcceleratedEntry, + m_bCacheHasUseAcceleratedEntry, + OUSTR("UseAcceleratedCanvas") ); + + // try to reuse last working implementation for given service name + const CacheVector::iterator aEnd(m_aCachedImplementations.end()); + CacheVector::iterator aMatch; + if( (aMatch=std::find_if(m_aCachedImplementations.begin(), + aEnd, + boost::bind(&OUString::equals, + boost::cref(serviceName), + boost::bind( + std::select1st<CachePair>(), + _1)))) != aEnd ) + { + Reference<XInterface> xCanvas( use( aMatch->second, args, xContext ) ); + if(xCanvas.is()) + return xCanvas; + } + + // lookup in available service list + const AvailVector::const_iterator aAvailEnd(m_aAvailableImplementations.end()); + AvailVector::const_iterator aAvailImplsMatch; + if( (aAvailImplsMatch=std::find_if(m_aAvailableImplementations.begin(), + aAvailEnd, + boost::bind(&OUString::equals, + boost::cref(serviceName), + boost::bind( + std::select1st<AvailPair>(), + _1)))) == aAvailEnd ) + { + return Reference<XInterface>(); + } + + const AvailVector::const_iterator aAAEnd(m_aAAImplementations.end()); + AvailVector::const_iterator aAAImplsMatch; + if( (aAAImplsMatch=std::find_if(m_aAAImplementations.begin(), + aAAEnd, + boost::bind(&OUString::equals, + boost::cref(serviceName), + boost::bind( + std::select1st<AvailPair>(), + _1)))) == aAAEnd ) + { + return Reference<XInterface>(); + } + + const AvailVector::const_iterator aAccelEnd(m_aAcceleratedImplementations.end()); + AvailVector::const_iterator aAccelImplsMatch; + if( (aAccelImplsMatch=std::find_if(m_aAcceleratedImplementations.begin(), + aAccelEnd, + boost::bind(&OUString::equals, + boost::cref(serviceName), + boost::bind( + std::select1st<AvailPair>(), + _1)))) == aAccelEnd ) + { + return Reference<XInterface>(); + } + + const Sequence<OUString> aPreferredImpls( aAvailImplsMatch->second ); + const OUString* pCurrImpl = aPreferredImpls.getConstArray(); + const OUString* const pEndImpl = pCurrImpl + aPreferredImpls.getLength(); + + const Sequence<OUString> aAAImpls( aAAImplsMatch->second ); + const OUString* const pFirstAAImpl = aAAImpls.getConstArray(); + const OUString* const pEndAAImpl = pFirstAAImpl + aAAImpls.getLength(); + + const Sequence<OUString> aAccelImpls( aAccelImplsMatch->second ); + const OUString* const pFirstAccelImpl = aAccelImpls.getConstArray(); + const OUString* const pEndAccelImpl = pFirstAccelImpl + aAccelImpls.getLength(); + + // force last entry from impl list, if config flag set + if( bForceLastEntry ) + pCurrImpl = pEndImpl-1; + + while( pCurrImpl != pEndImpl ) + { + const OUString aCurrName(pCurrImpl->trim()); + + // check whether given canvas service is listed in the + // sequence of "accelerated canvas implementations" + const bool bIsAcceleratedImpl( + std::find_if(pFirstAccelImpl, + pEndAccelImpl, + boost::bind(&OUString::equals, + boost::cref(aCurrName), + boost::bind( + &OUString::trim, + _1))) != pEndAccelImpl ); + + // check whether given canvas service is listed in the + // sequence of "antialiasing canvas implementations" + const bool bIsAAImpl( + std::find_if(pFirstAAImpl, + pEndAAImpl, + boost::bind(&OUString::equals, + boost::cref(aCurrName), + boost::bind( + &OUString::trim, + _1))) != pEndAAImpl ); + + // try to instantiate canvas *only* if either accel and AA + // property match preference, *or*, if there's a mismatch, only + // go for a less capable canvas (that effectively let those + // pour canvas impls still work as fallbacks, should an + // accelerated/AA one fail). Property implies configuration: + // http://en.wikipedia.org/wiki/Truth_table#Logical_implication + if( (!bIsAAImpl || bUseAAEntry) && (!bIsAcceleratedImpl || bUseAcceleratedEntry) ) + { + Reference<XInterface> xCanvas( + use( pCurrImpl->trim(), args, xContext ) ); + + if(xCanvas.is()) + { + if( aMatch != aEnd ) + { + // cache entry exists, replace dysfunctional + // implementation name + aMatch->second = pCurrImpl->trim(); + } + else + { + // new service name, add new cache entry + m_aCachedImplementations.push_back(std::make_pair(serviceName, + pCurrImpl->trim())); + } + + return xCanvas; + } + } + + ++pCurrImpl; + } + + return Reference<XInterface>(); +} + +//______________________________________________________________________________ +Reference<XInterface> CanvasFactory::createInstanceWithArgumentsAndContext( + OUString const & preferredOne, Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) throw (Exception) +{ + Reference<XInterface> xCanvas( + lookupAndUse( preferredOne, args, xContext ) ); + if(xCanvas.is()) + return xCanvas; + + // last resort: try service name directly + return use( preferredOne, args, xContext ); +} + +// XMultiServiceFactory +//______________________________________________________________________________ +Reference<XInterface> CanvasFactory::createInstance( OUString const & name ) + throw (Exception) +{ + return createInstanceWithArgumentsAndContext( + name, Sequence<Any>(), m_xContext ); +} + +//______________________________________________________________________________ +Reference<XInterface> CanvasFactory::createInstanceWithArguments( + OUString const & name, Sequence<Any> const & args ) throw (Exception) +{ + return createInstanceWithArgumentsAndContext( + name, args, m_xContext ); +} + +const ::cppu::ImplementationEntry s_entries [] = { + { + create, + getImplName, + getSuppServices, + ::cppu::createSingleComponentFactory, + 0, 0 + }, + { 0, 0, 0, 0, 0, 0 } +}; + +} // anon namespace + +extern "C" { + +void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +void * SAL_CALL component_getFactory( + sal_Char const * pImplName, + lang::XMultiServiceFactory * pServiceManager, + registry::XRegistryKey * pRegistryKey ) +{ + return ::cppu::component_getFactoryHelper( + pImplName, pServiceManager, pRegistryKey, s_entries ); +} + +} + diff --git a/canvas/source/factory/makefile.mk b/canvas/source/factory/makefile.mk new file mode 100644 index 000000000000..eee24ea8ba85 --- /dev/null +++ b/canvas/source/factory/makefile.mk @@ -0,0 +1,63 @@ +#************************************************************************* +# +# 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 = canvasfactory.uno +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk +DLLPRE = +.IF "$(L10N_framework)"=="" +SLOFILES = \ + $(SLO)$/cf_service.obj + +SHL1TARGET = $(TARGET) + +SHL1STDLIBS = \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(SALLIB) +SHL1VERSIONMAP = $(SOLARENV)/src/component.map + +SHL1DEPN = +SHL1IMPLIB = i$(TARGET) +SHL1LIBS = $(SLB)$/$(TARGET).lib +SHL1DEF = $(MISC)$/$(SHL1TARGET).def + +DEF1NAME = $(SHL1TARGET) +.ENDIF +.INCLUDE : target.mk + +ALLTAR : $(MISC)/canvasfactory.component + +$(MISC)/canvasfactory.component .ERRREMOVE : \ + $(SOLARENV)/bin/createcomponent.xslt canvasfactory.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt canvasfactory.component diff --git a/canvas/source/null/exports.dxp b/canvas/source/null/exports.dxp new file mode 100644 index 000000000000..f0e1c69934bc --- /dev/null +++ b/canvas/source/null/exports.dxp @@ -0,0 +1,2 @@ +component_getImplementationEnvironment +component_getFactory diff --git a/canvas/source/null/makefile.mk b/canvas/source/null/makefile.mk new file mode 100644 index 000000000000..07971ef8153e --- /dev/null +++ b/canvas/source/null/makefile.mk @@ -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. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=canvas +TARGET=nullcanvas +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +DLLPRE = + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF +.IF "$(L10N_framework)"=="" +SLOFILES = $(SLO)$/null_canvasbitmap.obj \ + $(SLO)$/null_canvascustomsprite.obj \ + $(SLO)$/null_canvasfont.obj \ + $(SLO)$/null_canvashelper.obj \ + $(SLO)$/null_devicehelper.obj \ + $(SLO)$/null_spritecanvas.obj \ + $(SLO)$/null_spritecanvashelper.obj \ + $(SLO)$/null_spritehelper.obj \ + $(SLO)$/null_textlayout.obj + +SHL1TARGET=$(TARGET).uno + +SHL1STDLIBS= $(CPPULIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(VCLLIB) + +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 diff --git a/canvas/source/null/null_canvasbitmap.cxx b/canvas/source/null/null_canvasbitmap.cxx new file mode 100644 index 000000000000..9bd2058a6d74 --- /dev/null +++ b/canvas/source/null/null_canvasbitmap.cxx @@ -0,0 +1,84 @@ +/************************************************************************* + * + * 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 <canvas/canvastools.hxx> + +#include "null_canvasbitmap.hxx" + + +using namespace ::com::sun::star; + +namespace nullcanvas +{ + CanvasBitmap::CanvasBitmap( const ::basegfx::B2ISize& rSize, + const DeviceRef& rDevice, + bool bHasAlpha ) : + mpDevice( rDevice ) + { + ENSURE_OR_THROW( mpDevice.is(), + "CanvasBitmap::CanvasBitmap(): Invalid surface or device" ); + + maCanvasHelper.init( rSize, + *mpDevice.get(), + bHasAlpha ); + } + + void SAL_CALL CanvasBitmap::disposing() + { + mpDevice.clear(); + + // forward to parent + CanvasBitmap_Base::disposing(); + } + +#define IMPLEMENTATION_NAME "NullCanvas.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/null/null_canvasbitmap.hxx b/canvas/source/null/null_canvasbitmap.hxx new file mode 100644 index 000000000000..3fa0c15cd314 --- /dev/null +++ b/canvas/source/null/null_canvasbitmap.hxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_CANVASBITMAP_HXX +#define _NULLCANVAS_CANVASBITMAP_HXX + +#include <cppuhelper/compbase3.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <basegfx/vector/b2isize.hxx> + +#include <boost/shared_ptr.hpp> + +#include <canvas/base/integerbitmapbase.hxx> + +#include "null_canvashelper.hxx" +#include "null_spritecanvas.hxx" +#include "null_usagecounter.hxx" + + +/* Definition of CanvasBitmap class */ + +namespace nullcanvas +{ + typedef ::cppu::WeakComponentImplHelper3< ::com::sun::star::rendering::XBitmapCanvas, + ::com::sun::star::rendering::XIntegerBitmap, + ::com::sun::star::lang::XServiceInfo > CanvasBitmapBase_Base; + typedef ::canvas::IntegerBitmapBase< ::canvas::BaseMutexHelper< CanvasBitmapBase_Base >, + CanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasBitmap_Base; + + class CanvasBitmap : public CanvasBitmap_Base, + private UsageCounter< CanvasBitmap > + { + 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 DeviceRef& rDevice, + bool bHasAlpha ); + + /// Dispose all internal references + virtual void SAL_CALL disposing(); + + // 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); + + private: + /** MUST hold here, too, since CanvasHelper only contains a + raw pointer (without refcounting) + */ + DeviceRef mpDevice; + }; +} + +#endif /* _NULLCANVAS_CANVASBITMAP_HXX */ diff --git a/canvas/source/null/null_canvascustomsprite.cxx b/canvas/source/null/null_canvascustomsprite.cxx new file mode 100644 index 000000000000..9c45c50954f9 --- /dev/null +++ b/canvas/source/null/null_canvascustomsprite.cxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * 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 <canvas/verbosetrace.hxx> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> + +#include <canvas/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> + +#include "null_canvascustomsprite.hxx" +#include "null_spritecanvas.hxx" + + +using namespace ::com::sun::star; + +namespace nullcanvas +{ + CanvasCustomSprite::CanvasCustomSprite( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rRefDevice ) : + mpSpriteCanvas( rRefDevice ) + { + ENSURE_OR_THROW( rRefDevice.get(), + "CanvasCustomSprite::CanvasCustomSprite(): Invalid sprite canvas" ); + + maCanvasHelper.init( ::basegfx::B2ISize( + ::canvas::tools::roundUp( rSpriteSize.Width ), + ::canvas::tools::roundUp( rSpriteSize.Height ) ), + *rRefDevice.get(), + true ); + + maSpriteHelper.init( rSpriteSize, + rRefDevice ); + } + + void SAL_CALL CanvasCustomSprite::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpSpriteCanvas.clear(); + + // forward to parent + CanvasCustomSpriteBaseT::disposing(); + } + + void CanvasCustomSprite::redraw() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + maSpriteHelper.redraw( mbSurfaceDirty ); + } + +#define IMPLEMENTATION_NAME "NullCanvas.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/null/null_canvascustomsprite.hxx b/canvas/source/null/null_canvascustomsprite.hxx new file mode 100644 index 000000000000..554fb3033b05 --- /dev/null +++ b/canvas/source/null/null_canvascustomsprite.hxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_CANVASCUSTOMSPRITE_HXX +#define _NULLCANVAS_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 "sprite.hxx" +#include "null_canvashelper.hxx" +#include "null_spritehelper.hxx" +#include "null_spritecanvas.hxx" +#include "null_usagecounter.hxx" + + +namespace nullcanvas +{ + 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 + { + }; + + typedef ::canvas::CanvasCustomSpriteBase< CanvasCustomSpriteSpriteBase_Base, + SpriteHelper, + CanvasHelper, + ::osl::MutexGuard, + ::cppu::OWeakObject > CanvasCustomSpriteBaseT; + + /* Definition of CanvasCustomSprite class */ + + class CanvasCustomSprite : public CanvasCustomSpriteBaseT, + private UsageCounter< CanvasCustomSprite > + { + 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; + + private: + /** MUST hold here, too, since CanvasHelper only contains a + raw pointer (without refcounting) + */ + SpriteCanvasRef mpSpriteCanvas; + }; +} + +#endif /* _NULLCANVAS_CANVASCUSTOMSPRITE_HXX */ diff --git a/canvas/source/null/null_canvasfont.cxx b/canvas/source/null/null_canvasfont.cxx new file mode 100644 index 000000000000..a8c6f027e40d --- /dev/null +++ b/canvas/source/null/null_canvasfont.cxx @@ -0,0 +1,121 @@ +/************************************************************************* + * + * 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 "null_canvasfont.hxx" +#include "null_textlayout.hxx" +#include "null_spritecanvas.hxx" + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/PanoseWeight.hpp> + +using namespace ::com::sun::star; + +namespace nullcanvas +{ + CanvasFont::CanvasFont( const rendering::FontRequest& rFontRequest, + const uno::Sequence< beans::PropertyValue >& /*extraFontProperties*/, + const geometry::Matrix2D& fontMatrix ) : + CanvasFont_Base( m_aMutex ), + maFontRequest( rFontRequest ), + maFontMatrix( fontMatrix ) + { + } + + void SAL_CALL CanvasFont::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + } + + uno::Reference< rendering::XTextLayout > SAL_CALL CanvasFont::createTextLayout( const rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 nRandomSeed ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return new TextLayout( aText, nDirection, nRandomSeed, ImplRef( this ) ); + } + + uno::Sequence< double > SAL_CALL CanvasFont::getAvailableSizes( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< double >(); + } + + uno::Sequence< beans::PropertyValue > SAL_CALL CanvasFont::getExtraFontProperties( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return uno::Sequence< beans::PropertyValue >(); + } + + rendering::FontRequest SAL_CALL CanvasFont::getFontRequest( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maFontRequest; + } + + rendering::FontMetrics SAL_CALL CanvasFont::getFontMetrics( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + return rendering::FontMetrics(); + } + +#define SERVICE_NAME "com.sun.star.rendering.CanvasFont" +#define IMPLEMENTATION_NAME "NullCanvas::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; + } + + const ::com::sun::star::geometry::Matrix2D& CanvasFont::getFontMatrix() const + { + return maFontMatrix; + } +} diff --git a/canvas/source/null/null_canvasfont.hxx b/canvas/source/null/null_canvasfont.hxx new file mode 100644 index 000000000000..01dc5cac5720 --- /dev/null +++ b/canvas/source/null/null_canvasfont.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 _NULLCANVAS_CANVASFONT_HXX +#define _NULLCANVAS_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/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> + +#include <rtl/ref.hxx> + +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +#include "null_usagecounter.hxx" + + +/* Definition of CanvasFont class */ + +namespace nullcanvas +{ + class SpriteCanvas; + + typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XCanvasFont, + ::com::sun::star::lang::XServiceInfo > CanvasFont_Base; + + class CanvasFont : public ::comphelper::OBaseMutex, + public CanvasFont_Base, + private UsageCounter< CanvasFont >, + private ::boost::noncopyable + { + public: + typedef ::comphelper::ImplementationReference< + CanvasFont, + ::com::sun::star::rendering::XCanvasFont > ImplRef; + + 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& fontMatrix ); + + /// 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 ); + + const ::com::sun::star::geometry::Matrix2D& getFontMatrix() const; + + private: + ::com::sun::star::rendering::FontRequest maFontRequest; + ::com::sun::star::geometry::Matrix2D maFontMatrix; + }; + +} + +#endif /* _NULLCANVAS_CANVASFONT_HXX */ diff --git a/canvas/source/null/null_canvashelper.cxx b/canvas/source/null/null_canvashelper.cxx new file mode 100644 index 000000000000..21e2c74f6b95 --- /dev/null +++ b/canvas/source/null/null_canvashelper.cxx @@ -0,0 +1,336 @@ +/************************************************************************* + * + * 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 <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 <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <comphelper/sequence.hxx> +#include <canvas/canvastools.hxx> + +#include "null_spritecanvas.hxx" +#include "null_canvasfont.hxx" +#include "null_textlayout.hxx" +#include "null_canvashelper.hxx" + +#include <algorithm> + + +using namespace ::com::sun::star; + +namespace nullcanvas +{ + CanvasHelper::CanvasHelper() : + mpDevice( NULL ), + maSize(), + mbHaveAlpha() + { + } + + void CanvasHelper::disposing() + { + mpDevice = NULL; + } + + void CanvasHelper::init( const ::basegfx::B2ISize& rSize, + SpriteCanvas& rDevice, + bool bHasAlpha ) + { + mpDevice = &rDevice; + maSize = rSize; + mbHaveAlpha = bHasAlpha; + } + + void CanvasHelper::clear() + { + } + + void CanvasHelper::drawPoint( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealPoint2D& /*aPoint*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/ ) + { + } + + void CanvasHelper::drawLine( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealPoint2D& /*aPoint1*/, + const geometry::RealPoint2D& /*aPoint2*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/ ) + { + } + + void CanvasHelper::drawBezier( const rendering::XCanvas* /*pCanvas*/, + const geometry::RealBezierSegment2D& /*aBezierSegment*/, + const geometry::RealPoint2D& /*aEndPoint*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/ ) + { + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/ ) + { + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const rendering::StrokeAttributes& /*strokeAttributes*/ ) + { + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + 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* /*pCanvas*/, + 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* /*pCanvas*/, + 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* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/ ) + { + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const uno::Sequence< rendering::Texture >& /*textures*/ ) + { + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, + 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::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* /*pCanvas*/, + const rendering::FontRequest& fontRequest, + const uno::Sequence< beans::PropertyValue >& extraFontProperties, + const geometry::Matrix2D& fontMatrix ) + { + return uno::Reference< rendering::XCanvasFont >( + new CanvasFont(fontRequest, extraFontProperties, fontMatrix ) ); + } + + uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* /*pCanvas*/, + const rendering::FontInfo& /*aFilter*/, + const uno::Sequence< beans::PropertyValue >& /*aFontProperties*/ ) + { + // TODO + return uno::Sequence< rendering::FontInfo >(); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* /*pCanvas*/, + const rendering::StringContext& /*text*/, + const uno::Reference< rendering::XCanvasFont >& /*xFont*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + sal_Int8 /*textDirection*/ ) + { + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XTextLayout >& xLayoutetText, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_OR_THROW( xLayoutetText.is(), + "CanvasHelper::drawTextLayout: layout is NULL"); + + TextLayout* pTextLayout = + dynamic_cast< TextLayout* >( xLayoutetText.get() ); + + ENSURE_OR_THROW( pTextLayout, + "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" ); + + pTextLayout->draw( viewState, + renderState, + mpDevice ); + + return 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*/ ) + { + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* /*pCanvas*/, + const uno::Reference< rendering::XBitmap >& /*xBitmap*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/ ) + { + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice() + { + return uno::Reference< rendering::XGraphicDevice >(mpDevice); + } + + void CanvasHelper::copyRect( const rendering::XCanvas* /*pCanvas*/, + 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( !mpDevice ) + 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*/ ) + { + // TODO(F1): + return uno::Reference< rendering::XBitmap >(); + } + + uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const geometry::IntegerRectangle2D& /*rect*/ ) + { + // TODO + 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 >(); + } + + rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout() + { + return ::canvas::tools::getStdMemoryLayout(getSize()); + } + + void CanvasHelper::flush() const + { + } + + bool CanvasHelper::hasAlpha() const + { + return mbHaveAlpha; + } + +} diff --git a/canvas/source/null/null_canvashelper.hxx b/canvas/source/null/null_canvashelper.hxx new file mode 100644 index 000000000000..976eb529b56f --- /dev/null +++ b/canvas/source/null/null_canvashelper.hxx @@ -0,0 +1,273 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_CANVASHELPER_HXX_ +#define _NULLCANVAS_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 <boost/utility.hpp> + + +namespace nullcanvas +{ + class SpriteCanvas; + + /** Helper class for basic canvas functionality. Also offers + optional backbuffer painting, when providing it with a second + HDC to render into. + */ + 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, + SpriteCanvas& rDevice, + 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; + + protected: + /** Phyical output device + + Deliberately not a refcounted reference, because of + potential circular references for spritecanvas. + */ + SpriteCanvas* mpDevice; + + private: + /// Current size of the output surface in pixel + ::basegfx::B2ISize maSize; + + /// When true, content is able to represent alpha + bool mbHaveAlpha; + }; +} + +#endif /* _NULLCANVAS_CANVASHELPER_HXX_ */ diff --git a/canvas/source/null/null_devicehelper.cxx b/canvas/source/null/null_devicehelper.cxx new file mode 100644 index 000000000000..b04820b15716 --- /dev/null +++ b/canvas/source/null/null_devicehelper.cxx @@ -0,0 +1,239 @@ +/************************************************************************* + * + * 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 <rtl/instance.hxx> +#include <cppuhelper/compbase1.hxx> + +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/tools/unopolypolygon.hxx> +#include <vcl/canvastools.hxx> + +#include "null_spritecanvas.hxx" +#include "null_canvasbitmap.hxx" +#include "null_devicehelper.hxx" + + +using namespace ::com::sun::star; + +namespace nullcanvas +{ + DeviceHelper::DeviceHelper() : + mpSpriteCanvas( NULL ), + maSize(), + mbFullScreen(false) + { + } + + void DeviceHelper::init( SpriteCanvas& rSpriteCanvas, + const ::basegfx::B2ISize& rSize, + bool bFullscreen ) + { + mpSpriteCanvas = &rSpriteCanvas; + maSize = rSize; + mbFullScreen = bFullscreen; + } + + void DeviceHelper::disposing() + { + // release all references + mpSpriteCanvas = NULL; + } + + geometry::RealSize2D DeviceHelper::getPhysicalResolution() + { + return geometry::RealSize2D( 75, 75 ); + } + + geometry::RealSize2D DeviceHelper::getPhysicalSize() + { + return geometry::RealSize2D( 210, 280 ); + } + + uno::Reference< rendering::XLinePolyPolygon2D > DeviceHelper::createCompatibleLinePolyPolygon( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) + { + // disposed? + if( !mpSpriteCanvas ) + 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 >& /*rDevice*/, + const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points ) + { + // disposed? + if( !mpSpriteCanvas ) + 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( !mpSpriteCanvas ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + return uno::Reference< rendering::XBitmap >( + new CanvasBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D( size ), + mpSpriteCanvas, + false )); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + 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( !mpSpriteCanvas ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + return uno::Reference< rendering::XBitmap >( + new CanvasBitmap( + ::basegfx::unotools::b2ISizeFromIntegerSize2D( size ), + mpSpriteCanvas, + true )); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/, + 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; + } + + ::sal_Int32 DeviceHelper::createBuffers( ::sal_Int32 /*nBuffers*/ ) + { + // TODO(F3): implement XBufferStrategy interface. For now, we + // _always_ will have exactly one backbuffer + return 1; + } + + void DeviceHelper::destroyBuffers() + { + // TODO(F3): implement XBufferStrategy interface. For now, we + // _always_ will have exactly one backbuffer + } + + ::sal_Bool DeviceHelper::showBuffer( bool bIsVisible, ::sal_Bool bUpdateAll ) + { + // forward to sprite canvas helper + if( !bIsVisible || !mpSpriteCanvas ) + return false; + + return mpSpriteCanvas->updateScreen( bUpdateAll ); + } + + ::sal_Bool DeviceHelper::switchBuffer( bool bIsVisible, ::sal_Bool bUpdateAll ) + { + // no difference for VCL canvas + return showBuffer( bIsVisible, bUpdateAll ); + } + + uno::Any DeviceHelper::isAccelerated() const + { + return ::com::sun::star::uno::makeAny(false); + } + + uno::Any DeviceHelper::getDeviceHandle() const + { + return uno::Any(); + } + + 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::notifySizeUpdate( const awt::Rectangle& /*rBounds*/ ) + { + // TODO + } + + void DeviceHelper::dumpScreenContent() const + { + OSL_TRACE( "%s\n", + BOOST_CURRENT_FUNCTION ); + } +} diff --git a/canvas/source/null/null_devicehelper.hxx b/canvas/source/null/null_devicehelper.hxx new file mode 100644 index 000000000000..2e6298c2e2b6 --- /dev/null +++ b/canvas/source/null/null_devicehelper.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_DEVICEHELPER_HXX +#define _NULLCANVAS_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> + + +/* Definition of DeviceHelper class */ + +namespace nullcanvas +{ + class SpriteCanvas; + class SpriteCanvasHelper; + + class DeviceHelper : private ::boost::noncopyable + { + public: + DeviceHelper(); + + void init( SpriteCanvas& rSpriteCanvas, + const ::basegfx::B2ISize& rSize, + bool bFullscreen ); + + /// 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 ); + + ::sal_Int32 createBuffers( ::sal_Int32 nBuffers ); + void destroyBuffers( ); + ::sal_Bool showBuffer( bool bIsVisible, ::sal_Bool bUpdateAll ); + ::sal_Bool switchBuffer( bool bIsVisible, ::sal_Bool bUpdateAll ); + + ::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; + + void notifySizeUpdate( const ::com::sun::star::awt::Rectangle& rBounds ); + + /** called when DumpScreenContent property is enabled on + XGraphicDevice, and writes out bitmaps of current screen. + */ + void dumpScreenContent() const; + + private: + /// Pointer to sprite canvas (owner of this helper), needed to create bitmaps + SpriteCanvas* mpSpriteCanvas; + ::basegfx::B2ISize maSize; + bool mbFullScreen; + }; +} + +#endif /* _NULLCANVAS_WINDOWGRAPHICDEVICE_HXX */ diff --git a/canvas/source/null/null_spritecanvas.cxx b/canvas/source/null/null_spritecanvas.cxx new file mode 100644 index 000000000000..ac41b3fe149a --- /dev/null +++ b/canvas/source/null/null_spritecanvas.cxx @@ -0,0 +1,166 @@ +/************************************************************************* + * + * 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 <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> + +#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 <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <comphelper/servicedecl.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include "null_spritecanvas.hxx" + + +using namespace ::com::sun::star; + +#define SERVICE_NAME "com.sun.star.rendering.NullCanvas" + +namespace nullcanvas +{ + SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ) + { + } + + void SpriteCanvas::initialize() + { + // #i64742# Only call initialize when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + VERBOSE_TRACE( "SpriteCanvas::initialize called" ); + + // At index 1, we expect a system window handle here, + // containing a pointer to a valid window, on which to output + // At index 2, we expect the current window bound rect + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 4 && + maArguments[1].getValueTypeClass() == uno::TypeClass_LONG, + "SpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + awt::Rectangle aRect; + maArguments[2] >>= aRect; + const ::basegfx::B2ISize aSize(aRect.Width, + aRect.Height); + + sal_Bool bIsFullscreen( sal_False ); + maArguments[3] >>= bIsFullscreen; + + // setup helper + maDeviceHelper.init( *this, + aSize, + bIsFullscreen ); + maCanvasHelper.init( maRedrawManager, + *this, + aSize, + false ); + + 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) + { + ::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 : SpriteCanvasBaseT::showBuffer( bUpdateAll ); + } + + ::sal_Bool SAL_CALL SpriteCanvas::switchBuffer( ::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 : SpriteCanvasBaseT::switchBuffer( 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( SERVICE_NAME ) ); + } + + static uno::Reference<uno::XInterface> initCanvas( 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> > serviceImpl(&initCanvas); + const sdecl::ServiceDecl nullCanvasDecl( + serviceImpl, + "com.sun.star.comp.rendering.NullCanvas", + SERVICE_NAME ); +} + +// The C shared lib entry points +COMPHELPER_SERVICEDECL_EXPORTS1(nullcanvas::nullCanvasDecl) diff --git a/canvas/source/null/null_spritecanvas.hxx b/canvas/source/null/null_spritecanvas.hxx new file mode 100644 index 000000000000..136e09a291db --- /dev/null +++ b/canvas/source/null/null_spritecanvas.hxx @@ -0,0 +1,149 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_SPRITECANVAS_HXX_ +#define _NULLCANVAS_SPRITECANVAS_HXX_ + +#include <rtl/ref.hxx> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/awt/XWindowListener.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 <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <cppuhelper/compbase8.hxx> +#include <comphelper/uno3.hxx> + +#include <canvas/base/spritecanvasbase.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/bufferedgraphicdevicebase.hxx> + +#include "null_spritecanvashelper.hxx" +#include "null_devicehelper.hxx" +#include "null_usagecounter.hxx" + + +namespace nullcanvas +{ + typedef ::cppu::WeakComponentImplHelper8< ::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::beans::XPropertySet, + ::com::sun::star::lang::XServiceName > WindowGraphicDeviceBase_Base; + typedef ::canvas::BufferedGraphicDeviceBase< ::canvas::BaseMutexHelper< WindowGraphicDeviceBase_Base >, + DeviceHelper, + ::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 + { + }; + + 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, + private UsageCounter< SpriteCanvas > + { + 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); + + 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; + typedef ::rtl::Reference< SpriteCanvas > DeviceRef; +} + +#endif diff --git a/canvas/source/null/null_spritecanvashelper.cxx b/canvas/source/null/null_spritecanvashelper.cxx new file mode 100644 index 000000000000..60a81726b196 --- /dev/null +++ b/canvas/source/null/null_spritecanvashelper.cxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * 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 <comphelper/scopeguard.hxx> + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <boost/cast.hpp> + +#include "null_spritecanvashelper.hxx" +#include "null_canvascustomsprite.hxx" + + +using namespace ::com::sun::star; + +namespace nullcanvas +{ + SpriteCanvasHelper::SpriteCanvasHelper() : + mpRedrawManager( NULL ) + { + } + + void SpriteCanvasHelper::init( ::canvas::SpriteRedrawManager& rManager, + SpriteCanvas& rDevice, + const ::basegfx::B2ISize& rSize, + bool bHasAlpha ) + { + mpRedrawManager = &rManager; + + CanvasHelper::init( rSize, rDevice, bHasAlpha ); + } + + void SpriteCanvasHelper::disposing() + { + mpRedrawManager = NULL; + + // forward to base + CanvasHelper::disposing(); + } + + uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromAnimation( + const uno::Reference< rendering::XAnimation >& /*animation*/ ) + { + 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, + mpDevice ) ); + } + + uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite( const uno::Reference< rendering::XSprite >& /*original*/ ) + { + return uno::Reference< rendering::XSprite >(); + } + + sal_Bool SpriteCanvasHelper::updateScreen( const ::basegfx::B2IRange& /*rCurrArea*/, + sal_Bool /*bUpdateAll*/, + bool& /*io_bSurfaceDirty*/ ) + { + // TODO + return sal_True; + } + + void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& /*rUpdateRect*/ ) + { + // TODO + } + + void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& /*rMoveStart*/, + const ::basegfx::B2DRange& /*rMoveEnd*/, + const ::canvas::SpriteRedrawManager::UpdateArea& /*rUpdateArea*/ ) + { + // TODO + } + + void SpriteCanvasHelper::opaqueUpdate( const ::canvas::SpriteRedrawManager::UpdateArea& /*rUpdateArea*/ ) + { + // TODO + } + + void SpriteCanvasHelper::genericUpdate( const ::canvas::SpriteRedrawManager::UpdateArea& /*rUpdateArea*/ ) + { + // TODO + } + +} diff --git a/canvas/source/null/null_spritecanvashelper.hxx b/canvas/source/null/null_spritecanvashelper.hxx new file mode 100644 index 000000000000..4fd7f6764779 --- /dev/null +++ b/canvas/source/null/null_spritecanvashelper.hxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_SPRITECANVASHELPER_HXX_ +#define _NULLCANVAS_SPRITECANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <canvas/spriteredrawmanager.hxx> + +#include "null_canvashelper.hxx" + +namespace basegfx +{ + class B2IRange; +} + +namespace nullcanvas +{ + class SpriteCanvas; + + class SpriteCanvasHelper : public CanvasHelper + { + public: + SpriteCanvasHelper(); + + void init( ::canvas::SpriteRedrawManager& rManager, + SpriteCanvas& rDevice, + const ::basegfx::B2ISize& rSize, + bool bHasAlpha ); + + /// 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 ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ); + + void genericUpdate( const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ); + + private: + /// Set from the SpriteCanvas: instance coordinating sprite redraw + ::canvas::SpriteRedrawManager* mpRedrawManager; + }; +} + +#endif /* _NULLCANVAS_SPRITECANVASHELPER_HXX_ */ + diff --git a/canvas/source/null/null_spritehelper.cxx b/canvas/source/null/null_spritehelper.cxx new file mode 100644 index 000000000000..94a4fa6b6578 --- /dev/null +++ b/canvas/source/null/null_spritehelper.cxx @@ -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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> +#include <canvas/verbosetrace.hxx> + +#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 "null_canvascustomsprite.hxx" +#include "null_spritehelper.hxx" + +#include <memory> + + +using namespace ::com::sun::star; + +namespace nullcanvas +{ + SpriteHelper::SpriteHelper() : + mpSpriteCanvas(), + 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::disposing() + { + mpSpriteCanvas.clear(); + + // forward to parent + CanvasCustomSpriteHelper::disposing(); + } + + void SpriteHelper::redraw( bool& /*io_bSurfaceDirty*/ ) const + { + // TODO + } + + ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const + { + return ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPoly ); + } +} diff --git a/canvas/source/null/null_spritehelper.hxx b/canvas/source/null/null_spritehelper.hxx new file mode 100644 index 000000000000..18585374ad9a --- /dev/null +++ b/canvas/source/null/null_spritehelper.hxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_SPRITEHELPER_HXX +#define _NULLCANVAS_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 "null_spritecanvas.hxx" + + +namespace nullcanvas +{ + /* 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(); + + // make CanvasCustomSpriteHelper::init visible for name lookup + using ::canvas::CanvasCustomSpriteHelper::init; + + /** 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(); + + /** Repaint sprite content via hardware to associated sprite + canvas + + @param io_bSurfaceDirty + Input/output parameter, whether the sprite content is + dirty or not. If texture was updated, set to false + */ + void redraw( bool& io_bSurfaceDirty ) const; + + private: + virtual ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >& xPoly ) const; + + + SpriteCanvasRef mpSpriteCanvas; + mutable bool mbTextureDirty; // when true, texture needs update + }; +} + +#endif /* _NULLCANVAS_SPRITEHELPER_HXX */ diff --git a/canvas/source/null/null_textlayout.cxx b/canvas/source/null/null_textlayout.cxx new file mode 100644 index 000000000000..991de3421958 --- /dev/null +++ b/canvas/source/null/null_textlayout.cxx @@ -0,0 +1,261 @@ +/************************************************************************* + * + * 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 <canvas/verbosetrace.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include "null_textlayout.hxx" +#include "null_spritecanvas.hxx" + + +using namespace ::com::sun::star; + +namespace nullcanvas +{ + TextLayout::TextLayout( const rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 /*nRandomSeed*/, + const CanvasFont::ImplRef& rFont ) : + TextLayout_Base( m_aMutex ), + maText( aText ), + maLogicalAdvancements(), + mpFont( rFont ), + mnTextDirection( nDirection ) + { + } + + TextLayout::~TextLayout() + { + } + + void SAL_CALL TextLayout::disposing() + { + mpFont.reset(); + } + + // 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 ); + + ENSURE_OR_THROW( mpFont.get(), + "TextLayout::queryTextBounds(): invalid font" ); + + // fake text bounds by either taking the advancement values, + // or assuming square glyph boxes (width similar to height) + const rendering::FontRequest& rFontRequest( mpFont->getFontRequest() ); + const double nFontSize( ::std::max( rFontRequest.CellSize, + rFontRequest.ReferenceAdvancement ) ); + if( maLogicalAdvancements.getLength() ) + { + return geometry::RealRectangle2D( 0, -nFontSize/2, + maLogicalAdvancements[ maLogicalAdvancements.getLength()-1 ], + nFontSize/2 ); + } + else + { + return geometry::RealRectangle2D( 0, -nFontSize/2, + nFontSize * maText.Length, + nFontSize/2 ); + } + } + + 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; + } + + bool TextLayout::draw( const rendering::ViewState& /*rViewState*/, + const rendering::RenderState& /*rRenderState*/, + const uno::Reference< rendering::XGraphicDevice >& /*xGraphicDevice*/ ) const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO + + return true; + } + + +#define SERVICE_NAME "com.sun.star.rendering.TextLayout" +#define IMPLEMENTATION_NAME "NullCanvas::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/null/null_textlayout.hxx b/canvas/source/null/null_textlayout.hxx new file mode 100644 index 000000000000..4e348b2f5fa8 --- /dev/null +++ b/canvas/source/null/null_textlayout.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_TEXTLAYOUT_HXX +#define _NULLCANVAS_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 <boost/utility.hpp> + +#include "null_canvasfont.hxx" +#include "null_usagecounter.hxx" + + +/* Definition of TextLayout class */ + +namespace nullcanvas +{ + typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XTextLayout, + ::com::sun::star::lang::XServiceInfo > TextLayout_Base; + + class TextLayout : public ::comphelper::OBaseMutex, + public TextLayout_Base, + private UsageCounter< TextLayout >, + private ::boost::noncopyable + { + public: + TextLayout( const ::com::sun::star::rendering::StringContext& aText, + sal_Int8 nDirection, + sal_Int64 nRandomSeed, + const CanvasFont::ImplRef& rFont ); + + /// 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( const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice ) 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::ImplRef mpFont; + sal_Int8 mnTextDirection; + }; + +} + +#endif /* _NULLCANVAS_TEXTLAYOUT_HXX */ diff --git a/canvas/source/null/null_usagecounter.hxx b/canvas/source/null/null_usagecounter.hxx new file mode 100644 index 000000000000..28e3c6b2c176 --- /dev/null +++ b/canvas/source/null/null_usagecounter.hxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * 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 _NULLCANVAS_USAGECOUNTER_HXX +#define _NULLCANVAS_USAGECOUNTER_HXX + +#include <osl/interlck.h> +#include <boost/current_function.hpp> + +namespace nullcanvas +{ + /** Little resource tracking counter. + + When using this object, a global use counter, specific to the + given type is incremented on object construction, and + decremented on object destruction. + */ + template< class Type > class UsageCounter + { + public: + UsageCounter() + { + OSL_TRACE( "%s, %d objects currently in use.\n", + BOOST_CURRENT_FUNCTION, + osl_incrementInterlockedCount( &s_nCount ) ); + } + + ~UsageCounter() + { + const sal_Int32 nCount( osl_decrementInterlockedCount( &s_nCount ) ); + + if( !nCount ) + { + OSL_TRACE( "%s, last instance deleted.\n", + BOOST_CURRENT_FUNCTION ); + } + else + { + OSL_TRACE( "%s, %d instances left.\n", + BOOST_CURRENT_FUNCTION, + nCount ); + } + } + + private: + static oslInterlockedCount s_nCount; + }; + + template< class Type > oslInterlockedCount UsageCounter<Type>::s_nCount = 0; +} + +#endif /* _NULLCANVAS_USAGECOUNTER_HXX */ diff --git a/canvas/source/null/sprite.hxx b/canvas/source/null/sprite.hxx new file mode 100644 index 000000000000..d34070848765 --- /dev/null +++ b/canvas/source/null/sprite.hxx @@ -0,0 +1,47 @@ +/************************************************************************* + * + * 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 INCLUDED_NULLCANVAS_SPRITE_HXX +#define INCLUDED_NULLCANVAS_SPRITE_HXX + +#include <canvas/base/sprite.hxx> + +namespace nullcanvas +{ + /** Specialization of ::canvas::Sprite interface, to also provide + redraw methods. + */ + class Sprite : public ::canvas::Sprite + { + public: + /** Redraw sprite + */ + virtual void redraw() const = 0; + }; +} + +#endif /* INCLUDED_NULLCANVAS_SPRITE_HXX */ diff --git a/canvas/source/simplecanvas/exports.dxp b/canvas/source/simplecanvas/exports.dxp new file mode 100644 index 000000000000..0cb5620a1603 --- /dev/null +++ b/canvas/source/simplecanvas/exports.dxp @@ -0,0 +1,2 @@ +component_getImplementationEnvironment +component_getFactory
\ No newline at end of file diff --git a/canvas/source/simplecanvas/makefile.mk b/canvas/source/simplecanvas/makefile.mk new file mode 100644 index 000000000000..8c3a9deede72 --- /dev/null +++ b/canvas/source/simplecanvas/makefile.mk @@ -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. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=canvas +TARGET=simplecanvas +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +DLLPRE = + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF +.IF "$(L10N_framework)"=="" +SLOFILES = $(SLO)$/simplecanvasimpl.obj + +SHL1TARGET=$(TARGET).uno + +SHL1STDLIBS= $(CPPULIB) $(SALLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) + +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)/simplecanvas.component + +$(MISC)/simplecanvas.component .ERRREMOVE : \ + $(SOLARENV)/bin/createcomponent.xslt simplecanvas.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt simplecanvas.component diff --git a/canvas/source/simplecanvas/simplecanvas.component b/canvas/source/simplecanvas/simplecanvas.component new file mode 100644 index 000000000000..3a00b407375e --- /dev/null +++ b/canvas/source/simplecanvas/simplecanvas.component @@ -0,0 +1,34 @@ +<?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.SimpleCanvas"> + <service name="com.sun.star.rendering.SimpleCanvas"/> + </implementation> +</component> diff --git a/canvas/source/simplecanvas/simplecanvasimpl.cxx b/canvas/source/simplecanvas/simplecanvasimpl.cxx new file mode 100644 index 000000000000..2c87eb6d5621 --- /dev/null +++ b/canvas/source/simplecanvas/simplecanvasimpl.cxx @@ -0,0 +1,400 @@ +/************************************************************************* + * + * 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 <com/sun/star/rendering/XSimpleCanvas.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/PanoseLetterForm.hpp> +#include <com/sun/star/rendering/PanoseWeight.hpp> +#include <com/sun/star/lang/XServiceName.hpp> + +#include <o3tl/lazy_update.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/compbase2.hxx> +#include <cppuhelper/basemutex.hxx> + +#include <comphelper/servicedecl.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include "canvas/canvastools.hxx" + +#include <boost/bind.hpp> + +#define SERVICE_NAME "com.sun.star.rendering.SimpleCanvas" + +using namespace ::com::sun::star; +using namespace canvas; + +namespace +{ + inline uno::Sequence< double > color2Sequence( sal_Int32 const& nColor ) + { + // TODO(F3): Color management + uno::Sequence< double > aRes( 4 ); + + aRes[0] = static_cast<sal_uInt8>( (nColor&0xFF000000U) >> 24U ) / 255.0; + aRes[1] = static_cast<sal_uInt8>( (nColor&0x00FF0000U) >> 16U ) / 255.0; + aRes[2] = static_cast<sal_uInt8>( (nColor&0x0000FF00U) >> 8U ) / 255.0; + aRes[3] = static_cast<sal_uInt8>( (nColor&0x000000FFU) ) / 255.0; + + return aRes; + } + + inline uno::Reference< rendering::XPolyPolygon2D > rect2Poly( uno::Reference<rendering::XGraphicDevice> const& xDevice, + geometry::RealRectangle2D const& rRect ) + { + uno::Sequence< geometry::RealPoint2D > rectSequence( 4 ); + geometry::RealPoint2D* pOutput = rectSequence.getArray(); + pOutput[0] = geometry::RealPoint2D( rRect.X1, rRect.Y1 ); + pOutput[1] = geometry::RealPoint2D( rRect.X2, rRect.Y1 ); + pOutput[2] = geometry::RealPoint2D( rRect.X2, rRect.Y2 ); + pOutput[3] = geometry::RealPoint2D( rRect.X1, rRect.Y2 ); + + uno::Sequence< uno::Sequence< geometry::RealPoint2D > > sequenceSequence( 1 ); + sequenceSequence[0] = rectSequence; + + uno::Reference< rendering::XPolyPolygon2D > xRes( + xDevice->createCompatibleLinePolyPolygon( sequenceSequence ), + uno::UNO_QUERY ); + if( xRes.is() ) + xRes->setClosed( 0, sal_True ); + return xRes; + } + + struct SimpleRenderState + { + o3tl::LazyUpdate<sal_Int32, + uno::Sequence<double>, + o3tl::LAZYUPDATE_FUNCTION_TAG > m_aPenColor; + o3tl::LazyUpdate<sal_Int32, + uno::Sequence<double>, + o3tl::LAZYUPDATE_FUNCTION_TAG > m_aFillColor; + o3tl::LazyUpdate<geometry::RealRectangle2D, + uno::Reference< rendering::XPolyPolygon2D >, + o3tl::LAZYUPDATE_FUNCTOR_TAG > m_aRectClip; + geometry::AffineMatrix2D m_aTransformation; + + explicit SimpleRenderState( uno::Reference<rendering::XGraphicDevice> const& xDevice ) : + m_aPenColor( &color2Sequence), + m_aFillColor( &color2Sequence ), + m_aRectClip( boost::bind( &rect2Poly, + xDevice, + _1 )), + m_aTransformation() + { + tools::setIdentityAffineMatrix2D( m_aTransformation ); + } + }; + + + typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XSimpleCanvas, + ::com::sun::star::lang::XServiceName > SimpleCanvasBase; + + class SimpleCanvasImpl : private cppu::BaseMutex, + public SimpleCanvasBase + { + private: + bool isStrokingEnabled() const + { + return maRenderState.m_aPenColor.getInValue() && sal_Int32(0xFF) != 0; + } + + rendering::RenderState createStrokingRenderState() const + { + return rendering::RenderState(maRenderState.m_aTransformation, + *maRenderState.m_aRectClip, + *maRenderState.m_aPenColor, + rendering::CompositeOperation::OVER); + } + + bool isFillingEnabled() const + { + return maRenderState.m_aFillColor.getInValue() && sal_Int32(0xFF) != 0; + } + + rendering::RenderState createFillingRenderState() const + { + return rendering::RenderState(maRenderState.m_aTransformation, + *maRenderState.m_aRectClip, + *maRenderState.m_aFillColor, + rendering::CompositeOperation::OVER); + } + + static uno::Reference<rendering::XCanvas> grabCanvas( uno::Sequence<uno::Any> const& rArgs ) + { + uno::Reference<rendering::XCanvas> xRet; + + // can't do much without an XCanvas, can't we? + if( rArgs.getLength() < 1 ) + throw lang::IllegalArgumentException(); + + xRet.set( rArgs[0], uno::UNO_QUERY ); + + // can't do much without an XCanvas, can't we? + if( !xRet.is() ) + throw lang::IllegalArgumentException(); + + return xRet; + } + + public: + SimpleCanvasImpl( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& ) : + SimpleCanvasBase( m_aMutex ), + mxCanvas( grabCanvas(aArguments) ), + maFont(boost::bind( &rendering::XCanvas::createFont, + boost::cref(mxCanvas), + _1, + uno::Sequence< beans::PropertyValue >(), + geometry::Matrix2D() )), + maViewState(), + maRenderState( mxCanvas->getDevice() ) + { + tools::initViewState(maViewState); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + private: + // Ifc XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICE_NAME ) ); + } + + // Ifc XSimpleCanvas + virtual void SAL_CALL selectFont( const ::rtl::OUString& sFontName, + double size, + ::sal_Bool bold, + ::sal_Bool italic ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + maFont->FontDescription.FamilyName = sFontName; + maFont->CellSize = size; + maFont->FontDescription.FontDescription.Weight = + bold ? rendering::PanoseWeight::BOLD : rendering::PanoseWeight::MEDIUM; + maFont->FontDescription.FontDescription.Letterform = + italic ? rendering::PanoseLetterForm::OBLIQUE_CONTACT : rendering::PanoseLetterForm::ANYTHING; + } + + virtual void SAL_CALL setPenColor( ::sal_Int32 nsRgbaColor ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + *(maRenderState.m_aPenColor) = nsRgbaColor; + } + + virtual void SAL_CALL setFillColor( ::sal_Int32 nsRgbaColor ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + *(maRenderState.m_aFillColor) = nsRgbaColor; + } + + virtual void SAL_CALL setRectClip( const geometry::RealRectangle2D& aRect ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + *(maRenderState.m_aRectClip) = aRect; + } + + virtual void SAL_CALL setTransformation( const geometry::AffineMatrix2D& aTransform ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + maRenderState.m_aTransformation = aTransform; + } + + virtual void SAL_CALL drawPixel( const geometry::RealPoint2D& aPoint ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + mxCanvas->drawPoint(aPoint, + maViewState, + createFillingRenderState()); + } + + virtual void SAL_CALL drawLine( const geometry::RealPoint2D& aStartPoint, + const geometry::RealPoint2D& aEndPoint ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + mxCanvas->drawLine(aStartPoint, + aEndPoint, + maViewState, + createStrokingRenderState()); + } + + virtual void SAL_CALL drawRect( const geometry::RealRectangle2D& aRect ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + uno::Reference< rendering::XPolyPolygon2D > xPoly( + rect2Poly( mxCanvas->getDevice(), + aRect)); + + if( isFillingEnabled() ) + mxCanvas->drawPolyPolygon(xPoly, + maViewState, + createFillingRenderState()); + if( isStrokingEnabled() ) + mxCanvas->drawPolyPolygon(xPoly, + maViewState, + createStrokingRenderState()); + } + + virtual void SAL_CALL drawPolyPolygon( const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if( isFillingEnabled() ) + mxCanvas->drawPolyPolygon(xPolyPolygon, + maViewState, + createFillingRenderState()); + if( isStrokingEnabled() ) + mxCanvas->drawPolyPolygon(xPolyPolygon, + maViewState, + createStrokingRenderState()); + } + + virtual void SAL_CALL drawText( const rendering::StringContext& aText, + const geometry::RealPoint2D& aOutPos, + ::sal_Int8 nTextDirection ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + const basegfx::B2DHomMatrix offsetTransform(basegfx::tools::createTranslateB2DHomMatrix(aOutPos.X,aOutPos.Y)); + rendering::RenderState aRenderState( createStrokingRenderState() ); + tools::appendToRenderState(aRenderState, offsetTransform); + + mxCanvas->drawText(aText, + maFont.getOutValue(), + maViewState, + aRenderState, + nTextDirection); + } + + virtual void SAL_CALL drawBitmap( const uno::Reference< rendering::XBitmap >& xBitmap, + const geometry::RealPoint2D& aLeftTop ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + const basegfx::B2DHomMatrix offsetTransform(basegfx::tools::createTranslateB2DHomMatrix(aLeftTop.X,aLeftTop.Y)); + rendering::RenderState aRenderState( createStrokingRenderState() ); + tools::appendToRenderState(aRenderState, offsetTransform); + + mxCanvas->drawBitmap(xBitmap,maViewState,aRenderState); + } + + virtual uno::Reference< rendering::XGraphicDevice > SAL_CALL getDevice( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return mxCanvas->getDevice(); + } + + virtual uno::Reference< rendering::XCanvas > SAL_CALL getCanvas( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return mxCanvas; + } + + virtual rendering::FontMetrics SAL_CALL getFontMetrics( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return maFont.getOutValue()->getFontMetrics(); + } + + virtual uno::Reference< rendering::XCanvasFont > SAL_CALL getCurrentFont( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return maFont.getOutValue(); + } + + virtual ::sal_Int32 SAL_CALL getCurrentPenColor( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return maRenderState.m_aPenColor.getInValue(); + } + + virtual ::sal_Int32 SAL_CALL getCurrentFillColor( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return maRenderState.m_aFillColor.getInValue(); + } + + virtual geometry::RealRectangle2D SAL_CALL getCurrentClipRect( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return maRenderState.m_aRectClip.getInValue(); + } + + virtual geometry::AffineMatrix2D SAL_CALL getCurrentTransformation( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return maRenderState.m_aTransformation; + } + + virtual rendering::ViewState SAL_CALL getCurrentViewState( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return maViewState; + } + + virtual rendering::RenderState SAL_CALL getCurrentRenderState( sal_Bool bUseFillColor ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if( bUseFillColor ) + return createFillingRenderState(); + else + return createStrokingRenderState(); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + typedef o3tl::LazyUpdate< + rendering::FontRequest, + uno::Reference< rendering::XCanvasFont >, + o3tl::LAZYUPDATE_FUNCTOR_TAG > SimpleFont; + + uno::Reference<rendering::XCanvas> mxCanvas; + SimpleFont maFont; + rendering::ViewState maViewState; + SimpleRenderState maRenderState; + }; + + namespace sdecl = comphelper::service_decl; +#if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3) + sdecl::class_<SimpleCanvasImpl, sdecl::with_args<true> > serviceImpl; + const sdecl::ServiceDecl simpleCanvasDecl( + serviceImpl, +#else + const sdecl::ServiceDecl simpleCanvasDecl( + sdecl::class_<SimpleCanvasImpl, sdecl::with_args<true> >(), +#endif + "com.sun.star.comp.rendering.SimpleCanvas", + SERVICE_NAME ); +} + +// The C shared lib entry points +COMPHELPER_SERVICEDECL_EXPORTS1(simpleCanvasDecl) diff --git a/canvas/source/tools/bitmap.cxx b/canvas/source/tools/bitmap.cxx new file mode 100644 index 000000000000..eb7732b9a8f6 --- /dev/null +++ b/canvas/source/tools/bitmap.cxx @@ -0,0 +1,838 @@ +/************************************************************************* + * + * 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 <canvas/rendering/bitmap.hxx> +#include <canvas/rendering/isurfaceproxy.hxx> +#include <basegfx/vector/b2isize.hxx> +#include "image.hxx" +#include <algorithm> +#include <iterator> + + +using namespace ::com::sun::star; + +namespace canvas +{ + class ImplBitmap + { + public: + ImplBitmap( const ::basegfx::B2IVector& rSize, + const ISurfaceProxyManagerSharedPtr& rMgr, + bool bWithAlpha ) : + mpImage(), + mpSurfaceProxy(), + mbIsSurfaceDirty( true ) + { + ENSURE_OR_THROW( rMgr, + "Bitmap::Bitmap(): Invalid surface proxy manager" ); + + Image::Description desc; + + desc.eFormat = bWithAlpha ? Image::FMT_A8R8G8B8 : Image::FMT_R8G8B8; + desc.nWidth = rSize.getX(); + desc.nHeight = rSize.getY(); + desc.nStride = 0; + desc.pBuffer = NULL; + + mpImage.reset( new Image(desc) ); + + // clear the surface [fill with opaque black] + mpImage->clear(0,255,255,255); + + // create a (possibly hardware accelerated) mirror surface. + mpSurfaceProxy = rMgr->createSurfaceProxy( mpImage ); + } + + bool hasAlpha() const + { + if( !mpImage ) + return false; + + return (mpImage->getDescription().eFormat == Image::FMT_A8R8G8B8); + } + + ::basegfx::B2IVector getSize() const + { + return ::basegfx::B2IVector( mpImage->getWidth(), + mpImage->getHeight() ); + } + + ::com::sun::star::uno::Sequence< sal_Int8 > getData( ::com::sun::star::rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ) + { + const IColorBuffer::Format format = mpImage->getFormat(); + const sal_uInt32 dwNumBytesPerPixel = getNumBytes(format); + const sal_uInt32 dwPitch = mpImage->getWidth()*dwNumBytesPerPixel; + + if(!(dwNumBytesPerPixel)) + return uno::Sequence< sal_Int8 >(); + + const sal_uInt32 dwWidth = rect.X2-rect.X1; + const sal_uInt32 dwHeight = rect.Y2-rect.Y1; + + uno::Sequence< sal_Int8 > aRes(dwWidth*dwHeight*4); + sal_uInt8 *pDst = reinterpret_cast<sal_uInt8 *>(aRes.getArray()); + + const sal_uInt8 *pSrc = mpImage->lock()+(rect.Y1*dwPitch)+(rect.X1*dwNumBytesPerPixel); + const sal_uInt32 dwSpanSizeInBytes = dwNumBytesPerPixel*dwWidth; + for(sal_uInt32 y=0; y<dwHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,dwSpanSizeInBytes); + pDst += dwSpanSizeInBytes; + pSrc += dwPitch; + } + mpImage->unlock(); + + return aRes; + } + + 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 ) + { + const IColorBuffer::Format format = mpImage->getFormat(); + const sal_uInt32 dwNumBytesPerPixel = getNumBytes(format); + const sal_uInt32 dwPitch = mpImage->getWidth()*dwNumBytesPerPixel; + + if(!(dwNumBytesPerPixel)) + return; + + const sal_uInt32 dwWidth = rect.X2-rect.X1; + const sal_uInt32 dwHeight = rect.Y2-rect.Y1; + const sal_uInt8 *pSrc = reinterpret_cast<const sal_uInt8 *>(data.getConstArray()); + + sal_uInt8 *pDst = mpImage->lock()+(rect.Y1*dwPitch)+(rect.X1*dwNumBytesPerPixel); + const sal_uInt32 dwSpanSizeInBytes = dwNumBytesPerPixel*dwWidth; + for(sal_uInt32 y=0; y<dwHeight; ++y) + { + rtl_copyMemory(pDst,pSrc,dwSpanSizeInBytes); + pSrc += dwSpanSizeInBytes; + pDst += dwPitch; + } + mpImage->unlock(); + } + + 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 ) + { + struct ARGBColor + { + sal_uInt8 a; + sal_uInt8 r; + sal_uInt8 g; + sal_uInt8 b; + }; + + union ARGB + { + ARGBColor Color; + sal_uInt32 color; + + inline ARGB( sal_uInt32 _color ) : color(_color) {} + }; + + ARGB argb(0xFFFFFFFF); + + if(color.getLength() > 2) + { + argb.Color.r = static_cast<sal_uInt8>(color[0]); + argb.Color.g = static_cast<sal_uInt8>(color[1]); + argb.Color.b = static_cast<sal_uInt8>(color[2]); + if(color.getLength() > 3) + argb.Color.a = static_cast<sal_uInt8>(255.0f*color[3]); + } + + const IColorBuffer::Format format = mpImage->getFormat(); + const sal_uInt32 dwNumBytesPerPixel = getNumBytes(format); + const sal_uInt32 dwPitch = mpImage->getWidth()*dwNumBytesPerPixel; + + if(!(dwNumBytesPerPixel)) + return; + + sal_uInt8 *pDst = mpImage->lock()+(pos.Y*dwPitch)+(pos.X*dwNumBytesPerPixel); + + switch(format) + { + case IColorBuffer::FMT_R8G8B8: + pDst[0] = argb.Color.r; + pDst[1] = argb.Color.g; + pDst[2] = argb.Color.b; + break; + case IColorBuffer::FMT_A8R8G8B8: + case IColorBuffer::FMT_X8R8G8B8: + pDst[0] = argb.Color.a; + pDst[1] = argb.Color.r; + pDst[2] = argb.Color.g; + pDst[3] = argb.Color.b; + break; + default: + break; + } + + mpImage->unlock(); + } + + uno::Sequence< sal_Int8 > getPixel( ::com::sun::star::rendering::IntegerBitmapLayout& /*bitmapLayout*/, + const ::com::sun::star::geometry::IntegerPoint2D& pos ) + { + const IColorBuffer::Format format = mpImage->getFormat(); + const sal_uInt32 dwNumBytesPerPixel = getNumBytes(format); + const sal_uInt32 dwPitch = mpImage->getWidth()*dwNumBytesPerPixel; + + if(!(dwNumBytesPerPixel)) + return uno::Sequence< sal_Int8 >(); + + uno::Sequence< sal_Int8 > aRet(dwNumBytesPerPixel); + const sal_uInt8 *pSrc = mpImage->lock()+(pos.Y*dwPitch)+(pos.X*dwNumBytesPerPixel); + + switch(format) + { + case IColorBuffer::FMT_R8G8B8: + aRet[0] = pSrc[0]; + aRet[1] = pSrc[1]; + aRet[2] = pSrc[2]; + break; + case IColorBuffer::FMT_A8R8G8B8: + case IColorBuffer::FMT_X8R8G8B8: + aRet[0] = pSrc[1]; + aRet[1] = pSrc[2]; + aRet[2] = pSrc[3]; + aRet[3] = pSrc[0]; + break; + default: + break; + } + + mpImage->unlock(); + + return aRet; + } + + // the IColorBuffer interface + // ========================== + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rTransform ); + } + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rArea, rTransform ); + } + + + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolyPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( mbIsSurfaceDirty ) + { + mpSurfaceProxy->setColorBufferDirty(); + mbIsSurfaceDirty = false; + } + + return mpSurfaceProxy->draw( fAlpha, rPos, rClipPoly, rTransform ); + } + + void clear( const uno::Sequence< double >& color ) + { + if(color.getLength() > 2) + { + mbIsSurfaceDirty = true; + + if(color.getLength() > 3) + { + mpImage->clear( static_cast<sal_uInt8>(255.0f*color[0]), + static_cast<sal_uInt8>(255.0f*color[1]), + static_cast<sal_uInt8>(255.0f*color[2]), + static_cast<sal_uInt8>(255.0f*color[3]) ); + } + else + { + mpImage->clear( static_cast<sal_uInt8>(255.0f*color[0]), + static_cast<sal_uInt8>(255.0f*color[1]), + static_cast<sal_uInt8>(255.0f*color[2]), + 255 ); + } + } + } + + void fillB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + mpImage->fillB2DPolyPolygon( rPolyPolygon, + viewState, + renderState ); + } + + + // the XCanvas-render interface + // ============================ + + void drawPoint( const geometry::RealPoint2D& aPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + mpImage->drawPoint( aPoint, viewState, renderState ); + } + + void drawLine( const geometry::RealPoint2D& aStartPoint, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + mpImage->drawLine( aStartPoint, aEndPoint, viewState, renderState ); + } + + void drawBezier( const geometry::RealBezierSegment2D& aBezierSegment, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + mpImage->drawBezier( aBezierSegment, aEndPoint, viewState, renderState ); + } + + ICachedPrimitiveSharedPtr drawPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + return setupCachedPrimitive( + mpImage->drawPolyPolygon( xPolyPolygon, viewState, renderState ) ); + } + + ICachedPrimitiveSharedPtr strokePolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::StrokeAttributes& strokeAttributes ) + { + mbIsSurfaceDirty = true; + + return setupCachedPrimitive( + mpImage->strokePolyPolygon( xPolyPolygon, + viewState, + renderState, + strokeAttributes ) ); + } + + ICachedPrimitiveSharedPtr strokeTexturedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations, + const rendering::StrokeAttributes& strokeAttributes ) + { + mbIsSurfaceDirty = true; + + ::std::vector< ImageSharedPtr > aTextureAnnotations; + convertTextureAnnotations( aTextureAnnotations, + textureAnnotations ); + + return setupCachedPrimitive( + mpImage->strokeTexturedPolyPolygon( xPolyPolygon, + viewState, + renderState, + textures, + aTextureAnnotations, + strokeAttributes ) ); + } + + ICachedPrimitiveSharedPtr strokeTextureMappedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations, + const uno::Reference< geometry::XMapping2D >& xMapping, + const rendering::StrokeAttributes& strokeAttributes ) + { + mbIsSurfaceDirty = true; + + ::std::vector< ImageSharedPtr > aTextureAnnotations; + convertTextureAnnotations( aTextureAnnotations, + textureAnnotations ); + + return setupCachedPrimitive( + mpImage->strokeTextureMappedPolyPolygon( xPolyPolygon, + viewState, + renderState, + textures, + aTextureAnnotations, + xMapping, + strokeAttributes ) ); + } + + + ICachedPrimitiveSharedPtr fillPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + return setupCachedPrimitive( + mpImage->fillPolyPolygon( xPolyPolygon, + viewState, + renderState ) ); + } + + ICachedPrimitiveSharedPtr fillTexturedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations ) + { + mbIsSurfaceDirty = true; + + ::std::vector< ImageSharedPtr > aTextureAnnotations; + convertTextureAnnotations( aTextureAnnotations, + textureAnnotations ); + + return setupCachedPrimitive( + mpImage->fillTexturedPolyPolygon( xPolyPolygon, + viewState, + renderState, + textures, + aTextureAnnotations ) ); + } + + + ICachedPrimitiveSharedPtr fillTextureMappedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations, + const uno::Reference< geometry::XMapping2D >& xMapping ) + { + mbIsSurfaceDirty = true; + + ::std::vector< ImageSharedPtr > aTextureAnnotations; + convertTextureAnnotations( aTextureAnnotations, + textureAnnotations ); + + return setupCachedPrimitive( + mpImage->fillTextureMappedPolyPolygon( xPolyPolygon, + viewState, + renderState, + textures, + aTextureAnnotations, + xMapping ) ); + } + + ICachedPrimitiveSharedPtr drawBitmap( + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + return setupCachedPrimitive( + mpImage->drawBitmap( xBitmap, + viewState, + renderState ) ); + } + + ICachedPrimitiveSharedPtr drawBitmap( + const ::boost::shared_ptr<Bitmap>& rImage, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + return setupCachedPrimitive( + mpImage->drawBitmap( rImage->mpImpl->mpImage, + viewState, + renderState ) ); + } + + ICachedPrimitiveSharedPtr drawBitmapModulated( + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + return setupCachedPrimitive( + mpImage->drawBitmapModulated( xBitmap, + viewState, + renderState ) ); + } + + + ICachedPrimitiveSharedPtr drawBitmapModulated( + const ::boost::shared_ptr<Bitmap>& rImage, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mbIsSurfaceDirty = true; + + return setupCachedPrimitive( + mpImage->drawBitmapModulated( rImage->mpImpl->mpImage, + viewState, + renderState ) ); + } + + private: + ICachedPrimitiveSharedPtr setupCachedPrimitive( + const ImageCachedPrimitiveSharedPtr& rCachedPrimitive ) const + { + if( rCachedPrimitive ) + rCachedPrimitive->setImage( mpImage ); + + return rCachedPrimitive; + } + + void convertTextureAnnotations( ::std::vector< ImageSharedPtr >& o_rTextureAnnotations, + const ::std::vector< BitmapSharedPtr >& textureAnnotations ) + { + ::std::vector< BitmapSharedPtr >::const_iterator aCurr( textureAnnotations.begin() ); + const ::std::vector< BitmapSharedPtr >::const_iterator aEnd( textureAnnotations.end() ); + while( aCurr != aEnd ) + { + if( aCurr->get() != NULL ) + o_rTextureAnnotations.push_back( (*aCurr)->mpImpl->mpImage ); + else + o_rTextureAnnotations.push_back( ImageSharedPtr() ); + + ++aCurr; + } + } + + sal_uInt32 getNumBytes( IColorBuffer::Format format ) + { + switch(format) + { + case IColorBuffer::FMT_R8G8B8: + return 3; + case IColorBuffer::FMT_A8R8G8B8: + case IColorBuffer::FMT_X8R8G8B8: + return 4; + default: + return 0; + } + } + + ImageSharedPtr mpImage; + ISurfaceProxySharedPtr mpSurfaceProxy; + bool mbIsSurfaceDirty; + }; + + + ///////////////////////////////////////////////////////////////// + // Actual Bitmap pimpl forwarding functions + ///////////////////////////////////////////////////////////////// + + Bitmap::Bitmap( const ::basegfx::B2IVector& rSize, + const ISurfaceProxyManagerSharedPtr& rMgr, + bool bWithAlpha ) : + mpImpl( new ImplBitmap( rSize, + rMgr, + bWithAlpha ) ) + { + } + + Bitmap::~Bitmap() + { + // outline destructor is _necessary_, because ImplBitmap is an + // incomplete type outside this file. + } + + // forward all methods to ImplBitmap + // ================================================== + + bool Bitmap::hasAlpha() const + { + return mpImpl->hasAlpha(); + } + + ::basegfx::B2IVector Bitmap::getSize() const + { + return mpImpl->getSize(); + } + + ::com::sun::star::uno::Sequence< sal_Int8 > Bitmap::getData( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ) + { + return mpImpl->getData(bitmapLayout,rect); + } + + void Bitmap::setData( + const ::com::sun::star::uno::Sequence< sal_Int8 >& data, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerRectangle2D& rect ) + { + mpImpl->setData(data,bitmapLayout,rect); + } + + void Bitmap::setPixel( + const ::com::sun::star::uno::Sequence< sal_Int8 >& color, + const ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ) + { + mpImpl->setPixel(color,bitmapLayout,pos); + } + + uno::Sequence< sal_Int8 > Bitmap::getPixel( + ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, + const ::com::sun::star::geometry::IntegerPoint2D& pos ) + { + return mpImpl->getPixel(bitmapLayout,pos); + } + + bool Bitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ) + { + return mpImpl->draw( fAlpha, rPos, rTransform ); + } + + bool Bitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ) + { + return mpImpl->draw( fAlpha, rPos, rArea, rTransform ); + } + + + bool Bitmap::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolyPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ) + { + return mpImpl->draw( fAlpha, rPos, rClipPoly, rTransform ); + } + + void Bitmap::clear( const uno::Sequence< double >& color ) + { + mpImpl->clear( color ); + } + + void Bitmap::fillB2DPolyPolygon( + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + mpImpl->fillB2DPolyPolygon( rPolyPolygon, viewState, renderState ); + } + + void Bitmap::drawPoint( const geometry::RealPoint2D& aPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->drawPoint( aPoint, viewState, renderState ); + } + + void Bitmap::drawLine( const geometry::RealPoint2D& aStartPoint, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->drawLine( aStartPoint, aEndPoint, viewState, renderState ); + } + + void Bitmap::drawBezier( const geometry::RealBezierSegment2D& aBezierSegment, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->drawBezier( aBezierSegment, aEndPoint, viewState, renderState ); + } + + ICachedPrimitiveSharedPtr Bitmap::drawPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->drawPolyPolygon( xPolyPolygon, viewState, renderState ); + } + + ICachedPrimitiveSharedPtr Bitmap::strokePolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::StrokeAttributes& strokeAttributes ) + { + return mpImpl->strokePolyPolygon( xPolyPolygon, viewState, renderState, strokeAttributes ); + } + + ICachedPrimitiveSharedPtr Bitmap::strokeTexturedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations, + const rendering::StrokeAttributes& strokeAttributes ) + { + return mpImpl->strokeTexturedPolyPolygon( xPolyPolygon, + viewState, + renderState, + textures, + textureAnnotations, + strokeAttributes ); + } + + ICachedPrimitiveSharedPtr Bitmap::strokeTextureMappedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations, + const uno::Reference< geometry::XMapping2D >& xMapping, + const rendering::StrokeAttributes& strokeAttributes ) + { + return mpImpl->strokeTextureMappedPolyPolygon( xPolyPolygon, + viewState, + renderState, + textures, + textureAnnotations, + xMapping, + strokeAttributes ); + } + + + ICachedPrimitiveSharedPtr Bitmap::fillPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->fillPolyPolygon( xPolyPolygon, + viewState, + renderState ); + } + + ICachedPrimitiveSharedPtr Bitmap::fillTexturedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations ) + { + return mpImpl->fillTexturedPolyPolygon( xPolyPolygon, + viewState, + renderState, + textures, + textureAnnotations ); + } + + ICachedPrimitiveSharedPtr Bitmap::fillTextureMappedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Bitmap> >& textureAnnotations, + const uno::Reference< geometry::XMapping2D >& xMapping ) + { + return mpImpl->fillTextureMappedPolyPolygon( xPolyPolygon, + viewState, + renderState, + textures, + textureAnnotations, + xMapping ); + } + + ICachedPrimitiveSharedPtr Bitmap::drawBitmap( + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->drawBitmap( xBitmap, + viewState, + renderState ); + } + + ICachedPrimitiveSharedPtr Bitmap::drawBitmap( + const ::boost::shared_ptr<Bitmap>& rImage, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->drawBitmap( rImage, + viewState, + renderState ); + } + + ICachedPrimitiveSharedPtr Bitmap::drawBitmapModulated( + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->drawBitmapModulated( xBitmap, + viewState, + renderState ); + } + + ICachedPrimitiveSharedPtr Bitmap::drawBitmapModulated( + const ::boost::shared_ptr<Bitmap>& rImage, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return mpImpl->drawBitmapModulated( rImage, + viewState, + renderState ); + } +} diff --git a/canvas/source/tools/cachedprimitivebase.cxx b/canvas/source/tools/cachedprimitivebase.cxx new file mode 100644 index 000000000000..0d850b842007 --- /dev/null +++ b/canvas/source/tools/cachedprimitivebase.cxx @@ -0,0 +1,112 @@ +/************************************************************************* + * + * 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/base/cachedprimitivebase.hxx> + +#include <com/sun/star/rendering/RepaintResult.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tools/canvastools.hxx> + + +using namespace ::com::sun::star; + +#define IMPLEMENTATION_NAME "canvas::CachedPrimitiveBase" +#define SERVICE_NAME "com.sun.star.rendering.CachedBitmap" + +namespace canvas +{ + CachedPrimitiveBase::CachedPrimitiveBase( const rendering::ViewState& rUsedViewState, + const uno::Reference< rendering::XCanvas >& rTarget, + bool bFailForChangedViewTransform ) : + CachedPrimitiveBase_Base( m_aMutex ), + maUsedViewState( rUsedViewState ), + mxTarget( rTarget ), + mbFailForChangedViewTransform( bFailForChangedViewTransform ) + { + } + + CachedPrimitiveBase::~CachedPrimitiveBase() + { + } + + void SAL_CALL CachedPrimitiveBase::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + maUsedViewState.Clip.clear(); + mxTarget.clear(); + } + + sal_Int8 SAL_CALL CachedPrimitiveBase::redraw( const rendering::ViewState& aState ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::basegfx::B2DHomMatrix aUsedTransformation; + ::basegfx::B2DHomMatrix aNewTransformation; + + ::basegfx::unotools::homMatrixFromAffineMatrix( aUsedTransformation, + maUsedViewState.AffineTransform ); + ::basegfx::unotools::homMatrixFromAffineMatrix( aNewTransformation, + aState.AffineTransform ); + + const bool bSameViewTransforms( aUsedTransformation == aNewTransformation ); + + if( mbFailForChangedViewTransform && + !bSameViewTransforms ) + { + // differing transformations, don't try to draft the + // output, just plain fail here. + return rendering::RepaintResult::FAILED; + } + + return doRedraw( aState, + maUsedViewState, + mxTarget, + bSameViewTransforms ); + } + + ::rtl::OUString SAL_CALL CachedPrimitiveBase::getImplementationName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL CachedPrimitiveBase::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL CachedPrimitiveBase::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/tools/canvascustomspritehelper.cxx b/canvas/source/tools/canvascustomspritehelper.cxx new file mode 100644 index 000000000000..f9d4f186d7a7 --- /dev/null +++ b/canvas/source/tools/canvascustomspritehelper.cxx @@ -0,0 +1,496 @@ +/************************************************************************* + * + * 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 <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> + +#include <rtl/math.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/base/canvascustomspritehelper.hxx> + +using namespace ::com::sun::star; + + +namespace canvas +{ + bool CanvasCustomSpriteHelper::updateClipState( const Sprite::Reference& rSprite ) + { + if( !mxClipPoly.is() ) + { + // empty clip polygon -> everything is visible now + maCurrClipBounds.reset(); + mbIsCurrClipRectangle = true; + } + else + { + const sal_Int32 nNumClipPolygons( mxClipPoly->getNumberOfPolygons() ); + + // clip is not empty - determine actual update area + ::basegfx::B2DPolyPolygon aClipPath( + polyPolygonFromXPolyPolygon2D( mxClipPoly ) ); + + // apply sprite transformation also to clip! + aClipPath.transform( maTransform ); + + // clip which is about to be set, expressed as a + // b2drectangle + const ::basegfx::B2DRectangle& rClipBounds( + ::basegfx::tools::getRange( aClipPath ) ); + + const ::basegfx::B2DRectangle aBounds( 0.0, 0.0, + maSize.getX(), + maSize.getY() ); + + // rectangular area which is actually covered by the sprite. + // coordinates are relative to the sprite origin. + ::basegfx::B2DRectangle aSpriteRectPixel; + ::canvas::tools::calcTransformedRectBounds( aSpriteRectPixel, + aBounds, + maTransform ); + + // aClipBoundsA = new clip bound rect, intersected + // with sprite area + ::basegfx::B2DRectangle aClipBoundsA(rClipBounds); + aClipBoundsA.intersect( aSpriteRectPixel ); + + if( nNumClipPolygons != 1 ) + { + // clip cannot be a single rectangle -> cannot + // optimize update + mbIsCurrClipRectangle = false; + maCurrClipBounds = aClipBoundsA; + } + else + { + // new clip could be a single rectangle - check + // that now: + const bool bNewClipIsRect( + ::basegfx::tools::isRectangle( aClipPath.getB2DPolygon(0) ) ); + + // both new and old clip are truly rectangles + // - can now take the optimized path + const bool bUseOptimizedUpdate( bNewClipIsRect && + mbIsCurrClipRectangle ); + + const ::basegfx::B2DRectangle aOldBounds( maCurrClipBounds ); + + // store new current clip type + maCurrClipBounds = aClipBoundsA; + mbIsCurrClipRectangle = bNewClipIsRect; + + if( mbActive && + bUseOptimizedUpdate ) + { + // aClipBoundsB = maCurrClipBounds, i.e. last + // clip, intersected with sprite area + typedef ::std::vector< ::basegfx::B2DRectangle > VectorOfRects; + VectorOfRects aClipDifferences; + + // get all rectangles covered by exactly one + // of the polygons (aka XOR) + ::basegfx::computeSetDifference(aClipDifferences, + aClipBoundsA, + aOldBounds); + + // aClipDifferences now contains the final + // update areas, coordinates are still relative + // to the sprite origin. before submitting + // this area to 'updateSprite()' we need to + // translate this area to the final position, + // coordinates need to be relative to the + // spritecanvas. + VectorOfRects::const_iterator aCurr( aClipDifferences.begin() ); + const VectorOfRects::const_iterator aEnd( aClipDifferences.end() ); + while( aCurr != aEnd ) + { + mpSpriteCanvas->updateSprite( + rSprite, + maPosition, + ::basegfx::B2DRectangle( + maPosition + aCurr->getMinimum(), + maPosition + aCurr->getMaximum() ) ); + ++aCurr; + } + + // update calls all done + return true; + } + } + } + + // caller needs to perform update calls + return false; + } + + CanvasCustomSpriteHelper::CanvasCustomSpriteHelper() : + mpSpriteCanvas(), + maCurrClipBounds(), + maPosition(), + maSize(), + maTransform(), + mxClipPoly(), + mfPriority(0.0), + mfAlpha(0.0), + mbActive(false), + mbIsCurrClipRectangle(true), + mbIsContentFullyOpaque( false ), + mbAlphaDirty( true ), + mbPositionDirty( true ), + mbTransformDirty( true ), + mbClipDirty( true ), + mbPrioDirty( true ), + mbVisibilityDirty( true ) + { + } + + void CanvasCustomSpriteHelper::init( const geometry::RealSize2D& rSpriteSize, + const SpriteSurface::Reference& rOwningSpriteCanvas ) + { + ENSURE_OR_THROW( rOwningSpriteCanvas.get(), + "CanvasCustomSpriteHelper::init(): Invalid owning sprite canvas" ); + + mpSpriteCanvas = rOwningSpriteCanvas; + maSize.setX( ::std::max( 1.0, + ceil( rSpriteSize.Width ) ) ); // round up to nearest int, + // enforce sprite to have at + // least (1,1) pixel size + maSize.setY( ::std::max( 1.0, + ceil( rSpriteSize.Height ) ) ); + } + + void CanvasCustomSpriteHelper::disposing() + { + mpSpriteCanvas.clear(); + } + + void CanvasCustomSpriteHelper::clearingContent( const Sprite::Reference& /*rSprite*/ ) + { + // about to clear content to fully transparent + mbIsContentFullyOpaque = false; + } + + void CanvasCustomSpriteHelper::checkDrawBitmap( const Sprite::Reference& rSprite, + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + // check whether bitmap is non-alpha, and whether its + // transformed size covers the whole sprite. + if( !xBitmap->hasAlpha() ) + { + const geometry::IntegerSize2D& rInputSize( + xBitmap->getSize() ); + const ::basegfx::B2DSize& rOurSize( + rSprite->getSizePixel() ); + + ::basegfx::B2DHomMatrix aTransform; + if( tools::isInside( + ::basegfx::B2DRectangle( 0.0,0.0, + rOurSize.getX(), + rOurSize.getY() ), + ::basegfx::B2DRectangle( 0.0,0.0, + rInputSize.Width, + rInputSize.Height ), + ::canvas::tools::mergeViewAndRenderTransform(aTransform, + viewState, + renderState) ) ) + { + // bitmap is opaque and will fully cover the sprite, + // set flag appropriately + mbIsContentFullyOpaque = true; + } + } + } + + void CanvasCustomSpriteHelper::setAlpha( const Sprite::Reference& rSprite, + double alpha ) + { + if( !mpSpriteCanvas.get() ) + return; // we're disposed + + if( alpha != mfAlpha ) + { + mfAlpha = alpha; + + if( mbActive ) + { + mpSpriteCanvas->updateSprite( rSprite, + maPosition, + getUpdateArea() ); + } + + mbAlphaDirty = true; + } + } + + void CanvasCustomSpriteHelper::move( const Sprite::Reference& rSprite, + const geometry::RealPoint2D& aNewPos, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( !mpSpriteCanvas.get() ) + return; // we're disposed + + ::basegfx::B2DHomMatrix aTransform; + ::canvas::tools::mergeViewAndRenderTransform(aTransform, + viewState, + renderState); + + // convert position to device pixel + ::basegfx::B2DPoint aPoint( + ::basegfx::unotools::b2DPointFromRealPoint2D(aNewPos) ); + aPoint *= aTransform; + + if( aPoint != maPosition ) + { + const ::basegfx::B2DRectangle& rBounds( getFullSpriteRect() ); + + if( mbActive ) + { + mpSpriteCanvas->moveSprite( rSprite, + rBounds.getMinimum(), + rBounds.getMinimum() - maPosition + aPoint, + rBounds.getRange() ); + } + + maPosition = aPoint; + mbPositionDirty = true; + } + } + + void CanvasCustomSpriteHelper::transform( const Sprite::Reference& rSprite, + const geometry::AffineMatrix2D& aTransformation ) + { + ::basegfx::B2DHomMatrix aMatrix; + ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix, + aTransformation); + + if( maTransform != aMatrix ) + { + // retrieve bounds before and after transformation change. + const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() ); + + maTransform = aMatrix; + + if( !updateClipState( rSprite ) && + mbActive ) + { + mpSpriteCanvas->updateSprite( rSprite, + maPosition, + rPrevBounds ); + mpSpriteCanvas->updateSprite( rSprite, + maPosition, + getUpdateArea() ); + } + + mbTransformDirty = true; + } + } + + void CanvasCustomSpriteHelper::clip( const Sprite::Reference& rSprite, + const uno::Reference< rendering::XPolyPolygon2D >& xClip ) + { + // NULL xClip explicitely allowed here (to clear clipping) + + // retrieve bounds before and after clip change. + const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() ); + + mxClipPoly = xClip; + + if( !updateClipState( rSprite ) && + mbActive ) + { + mpSpriteCanvas->updateSprite( rSprite, + maPosition, + rPrevBounds ); + mpSpriteCanvas->updateSprite( rSprite, + maPosition, + getUpdateArea() ); + } + + mbClipDirty = true; + } + + void CanvasCustomSpriteHelper::setPriority( const Sprite::Reference& rSprite, + double nPriority ) + { + if( !mpSpriteCanvas.get() ) + return; // we're disposed + + if( nPriority != mfPriority ) + { + mfPriority = nPriority; + + if( mbActive ) + { + mpSpriteCanvas->updateSprite( rSprite, + maPosition, + getUpdateArea() ); + } + + mbPrioDirty = true; + } + } + + void CanvasCustomSpriteHelper::show( const Sprite::Reference& rSprite ) + { + if( !mpSpriteCanvas.get() ) + return; // we're disposed + + if( !mbActive ) + { + mpSpriteCanvas->showSprite( rSprite ); + mbActive = true; + + // TODO(P1): if clip is the NULL clip (nothing visible), + // also save us the update call. + + if( mfAlpha != 0.0 ) + { + mpSpriteCanvas->updateSprite( rSprite, + maPosition, + getUpdateArea() ); + } + + mbVisibilityDirty = true; + } + } + + void CanvasCustomSpriteHelper::hide( const Sprite::Reference& rSprite ) + { + if( !mpSpriteCanvas.get() ) + return; // we're disposed + + if( mbActive ) + { + mpSpriteCanvas->hideSprite( rSprite ); + mbActive = false; + + // TODO(P1): if clip is the NULL clip (nothing visible), + // also save us the update call. + + if( mfAlpha != 0.0 ) + { + mpSpriteCanvas->updateSprite( rSprite, + maPosition, + getUpdateArea() ); + } + + mbVisibilityDirty = true; + } + } + + // Sprite interface + bool CanvasCustomSpriteHelper::isAreaUpdateOpaque( const ::basegfx::B2DRange& rUpdateArea ) const + { + if( !mbIsCurrClipRectangle || + !mbIsContentFullyOpaque || + !::rtl::math::approxEqual(mfAlpha, 1.0) ) + { + // sprite either transparent, or clip rect does not + // represent exact bounds -> update might not be fully + // opaque + return false; + } + else + { + // make sure sprite rect fully covers update area - + // although the update area originates from the sprite, + // it's by no means guaranteed that it's limited to this + // sprite's update area - after all, other sprites might + // have been merged, or this sprite is moving. + return getUpdateArea().isInside( rUpdateArea ); + } + } + + ::basegfx::B2DPoint CanvasCustomSpriteHelper::getPosPixel() const + { + return maPosition; + } + + ::basegfx::B2DVector CanvasCustomSpriteHelper::getSizePixel() const + { + return maSize; + } + + ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea( const ::basegfx::B2DRange& rBounds ) const + { + // Internal! Only call with locked object mutex! + ::basegfx::B2DHomMatrix aTransform( maTransform ); + aTransform.translate( maPosition.getX(), + maPosition.getY() ); + + // transform bounds at origin, as the sprite transformation is + // formulated that way + ::basegfx::B2DRectangle aTransformedBounds; + return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds, + rBounds, + aTransform ); + } + + ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea() const + { + // Internal! Only call with locked object mutex! + + // return effective sprite rect, i.e. take active clip into + // account + if( maCurrClipBounds.isEmpty() ) + return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0, + maSize.getX(), + maSize.getY() ) ); + else + return ::basegfx::B2DRectangle( + maPosition + maCurrClipBounds.getMinimum(), + maPosition + maCurrClipBounds.getMaximum() ); + } + + double CanvasCustomSpriteHelper::getPriority() const + { + return mfPriority; + } + + ::basegfx::B2DRange CanvasCustomSpriteHelper::getFullSpriteRect() const + { + // Internal! Only call with locked object mutex! + return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0, + maSize.getX(), + maSize.getY() ) ); + } +} diff --git a/canvas/source/tools/canvastools.cxx b/canvas/source/tools/canvastools.cxx new file mode 100755 index 000000000000..ad833cc3ca40 --- /dev/null +++ b/canvas/source/tools/canvastools.cxx @@ -0,0 +1,1044 @@ +/************************************************************************* + * + * 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 <com/sun/star/geometry/AffineMatrix2D.hpp> +#include <com/sun/star/geometry/Matrix2D.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/util/Endianness.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 <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/ViewState.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XColorSpace.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include <cppuhelper/compbase1.hxx> +#include <rtl/instance.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/window.hxx> +#include <vcl/canvastools.hxx> + +#include <canvas/canvastools.hxx> + +#include <limits> + + +using namespace ::com::sun::star; + +namespace com { namespace sun { namespace star { namespace rendering +{ + bool operator==( const RenderState& renderState1, + const RenderState& renderState2 ) + { + if( renderState1.Clip != renderState2.Clip ) + return false; + + if( renderState1.DeviceColor != renderState2.DeviceColor ) + return false; + + if( renderState1.CompositeOperation != renderState2.CompositeOperation ) + return false; + + ::basegfx::B2DHomMatrix mat1, mat2; + ::canvas::tools::getRenderStateTransform( mat1, renderState1 ); + ::canvas::tools::getRenderStateTransform( mat2, renderState2 ); + if( mat1 != mat2 ) + return false; + + return true; + } + + bool operator==( const ViewState& viewState1, + const ViewState& viewState2 ) + { + if( viewState1.Clip != viewState2.Clip ) + return false; + + ::basegfx::B2DHomMatrix mat1, mat2; + ::canvas::tools::getViewStateTransform( mat1, viewState1 ); + ::canvas::tools::getViewStateTransform( mat2, viewState2 ); + if( mat1 != mat2 ) + return false; + + return true; + } +}}}} + +namespace canvas +{ + namespace tools + { + geometry::RealSize2D createInfiniteSize2D() + { + return geometry::RealSize2D( + ::std::numeric_limits<double>::infinity(), + ::std::numeric_limits<double>::infinity() ); + } + + rendering::RenderState& initRenderState( rendering::RenderState& renderState ) + { + // setup identity transform + setIdentityAffineMatrix2D( renderState.AffineTransform ); + renderState.Clip = uno::Reference< rendering::XPolyPolygon2D >(); + renderState.DeviceColor = uno::Sequence< double >(); + renderState.CompositeOperation = rendering::CompositeOperation::OVER; + + return renderState; + } + + rendering::ViewState& initViewState( rendering::ViewState& viewState ) + { + // setup identity transform + setIdentityAffineMatrix2D( viewState.AffineTransform ); + viewState.Clip = uno::Reference< rendering::XPolyPolygon2D >(); + + return viewState; + } + + ::basegfx::B2DHomMatrix& getViewStateTransform( ::basegfx::B2DHomMatrix& transform, + const rendering::ViewState& viewState ) + { + return ::basegfx::unotools::homMatrixFromAffineMatrix( transform, viewState.AffineTransform ); + } + + rendering::ViewState& setViewStateTransform( rendering::ViewState& viewState, + const ::basegfx::B2DHomMatrix& transform ) + { + ::basegfx::unotools::affineMatrixFromHomMatrix( viewState.AffineTransform, transform ); + + return viewState; + } + + ::basegfx::B2DHomMatrix& getRenderStateTransform( ::basegfx::B2DHomMatrix& transform, + const rendering::RenderState& renderState ) + { + return ::basegfx::unotools::homMatrixFromAffineMatrix( transform, renderState.AffineTransform ); + } + + rendering::RenderState& setRenderStateTransform( rendering::RenderState& renderState, + const ::basegfx::B2DHomMatrix& transform ) + { + ::basegfx::unotools::affineMatrixFromHomMatrix( renderState.AffineTransform, transform ); + + return renderState; + } + + rendering::RenderState& appendToRenderState( rendering::RenderState& renderState, + const ::basegfx::B2DHomMatrix& rTransform ) + { + ::basegfx::B2DHomMatrix transform; + + getRenderStateTransform( transform, renderState ); + return setRenderStateTransform( renderState, transform * rTransform ); + } + + rendering::ViewState& appendToViewState( rendering::ViewState& viewState, + const ::basegfx::B2DHomMatrix& rTransform ) + { + ::basegfx::B2DHomMatrix transform; + + getViewStateTransform( transform, viewState ); + return setViewStateTransform( viewState, transform * rTransform ); + } + + rendering::RenderState& prependToRenderState( rendering::RenderState& renderState, + const ::basegfx::B2DHomMatrix& rTransform ) + { + ::basegfx::B2DHomMatrix transform; + + getRenderStateTransform( transform, renderState ); + return setRenderStateTransform( renderState, rTransform * transform ); + } + + rendering::ViewState& prependToViewState( rendering::ViewState& viewState, + const ::basegfx::B2DHomMatrix& rTransform ) + { + ::basegfx::B2DHomMatrix transform; + + getViewStateTransform( transform, viewState ); + return setViewStateTransform( viewState, rTransform * transform ); + } + + ::basegfx::B2DHomMatrix& mergeViewAndRenderTransform( ::basegfx::B2DHomMatrix& combinedTransform, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ::basegfx::B2DHomMatrix viewTransform; + + ::basegfx::unotools::homMatrixFromAffineMatrix( combinedTransform, renderState.AffineTransform ); + ::basegfx::unotools::homMatrixFromAffineMatrix( viewTransform, viewState.AffineTransform ); + + // this statement performs combinedTransform = viewTransform * combinedTransform + combinedTransform *= viewTransform; + + return combinedTransform; + } + + rendering::ViewState& mergeViewAndRenderState( rendering::ViewState& resultViewState, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Reference< rendering::XCanvas >& /*xCanvas*/ ) + { + ::basegfx::B2DHomMatrix aTmpMatrix; + geometry::AffineMatrix2D convertedMatrix; + + resultViewState.Clip = NULL; // TODO(F2): intersect clippings + + return setViewStateTransform( + resultViewState, + mergeViewAndRenderTransform( aTmpMatrix, + viewState, + renderState ) ); + } + + geometry::AffineMatrix2D& setIdentityAffineMatrix2D( geometry::AffineMatrix2D& matrix ) + { + matrix.m00 = 1.0; + matrix.m01 = 0.0; + matrix.m02 = 0.0; + matrix.m10 = 0.0; + matrix.m11 = 1.0; + matrix.m12 = 0.0; + + return matrix; + } + + geometry::Matrix2D& setIdentityMatrix2D( geometry::Matrix2D& matrix ) + { + matrix.m00 = 1.0; + matrix.m01 = 0.0; + matrix.m10 = 0.0; + matrix.m11 = 1.0; + + return matrix; + } + + namespace + { + class StandardColorSpace : 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 ) + { + *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]); + 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 ) + { + *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]); + 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[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]); + 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->Red; + *pColors++ = pIn->Green; + *pColors++ = pIn->Blue; + *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->Red; + *pColors++ = pIn->Green; + *pColors++ = pIn->Blue; + *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->Red/pIn->Alpha; + *pColors++ = pIn->Green/pIn->Alpha; + *pColors++ = pIn->Blue/pIn->Alpha; + *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<StandardColorSpace*>(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(255-*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<StandardColorSpace*>(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 ) + { + *pOut++ = rendering::RGBColor( + vcl::unotools::toDoubleColor(pIn[0]), + vcl::unotools::toDoubleColor(pIn[1]), + vcl::unotools::toDoubleColor(pIn[2])); + 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 ) + { + *pOut++ = rendering::ARGBColor( + vcl::unotools::toDoubleColor(255-pIn[3]), + vcl::unotools::toDoubleColor(pIn[0]), + vcl::unotools::toDoubleColor(pIn[1]), + vcl::unotools::toDoubleColor(pIn[2])); + 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 ) + { + const sal_Int8 nAlpha( 255-pIn[3] ); + *pOut++ = rendering::ARGBColor( + vcl::unotools::toDoubleColor(nAlpha), + vcl::unotools::toDoubleColor(nAlpha*pIn[0]), + vcl::unotools::toDoubleColor(nAlpha*pIn[1]), + vcl::unotools::toDoubleColor(nAlpha*pIn[2])); + 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->Red); + *pColors++ = vcl::unotools::toByteColor(pIn->Green); + *pColors++ = vcl::unotools::toByteColor(pIn->Blue); + *pColors++ = 0; + ++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 ) + { + *pColors++ = vcl::unotools::toByteColor(pIn->Red); + *pColors++ = vcl::unotools::toByteColor(pIn->Green); + *pColors++ = vcl::unotools::toByteColor(pIn->Blue); + *pColors++ = 255-vcl::unotools::toByteColor(pIn->Alpha); + ++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->Red/pIn->Alpha); + *pColors++ = vcl::unotools::toByteColor(pIn->Green/pIn->Alpha); + *pColors++ = vcl::unotools::toByteColor(pIn->Blue/pIn->Alpha); + *pColors++ = 255-vcl::unotools::toByteColor(pIn->Alpha); + ++pIn; + } + return aRes; + } + + public: + StandardColorSpace() : + maComponentTags(4), + maBitCounts(4) + { + sal_Int8* pTags = maComponentTags.getArray(); + sal_Int32* pBitCounts = maBitCounts.getArray(); + pTags[0] = rendering::ColorComponentTag::RGB_RED; + pTags[1] = rendering::ColorComponentTag::RGB_GREEN; + pTags[2] = rendering::ColorComponentTag::RGB_BLUE; + pTags[3] = rendering::ColorComponentTag::ALPHA; + + pBitCounts[0] = + pBitCounts[1] = + pBitCounts[2] = + pBitCounts[3] = 8; + } + }; + + struct StandardColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>, + StandardColorSpaceHolder> + { + uno::Reference<rendering::XIntegerBitmapColorSpace> operator()() + { + return new StandardColorSpace(); + } + }; + } + + uno::Reference<rendering::XIntegerBitmapColorSpace> getStdColorSpace() + { + return StandardColorSpaceHolder::get(); + } + + rendering::IntegerBitmapLayout getStdMemoryLayout( const geometry::IntegerSize2D& rBmpSize ) + { + rendering::IntegerBitmapLayout aLayout; + + aLayout.ScanLines = rBmpSize.Height; + aLayout.ScanLineBytes = rBmpSize.Width*4; + aLayout.ScanLineStride = aLayout.ScanLineBytes; + aLayout.PlaneStride = 0; + aLayout.ColorSpace = getStdColorSpace(); + aLayout.Palette.clear(); + aLayout.IsMsbFirst = sal_False; + + return aLayout; + } + + ::Color stdIntSequenceToColor( const uno::Sequence<sal_Int8>& rColor ) + { +#ifdef OSL_BIGENDIAN + const sal_Int8* pCols( rColor.getConstArray() ); + return ::Color( pCols[3], pCols[0], pCols[1], pCols[2] ); +#else + return ::Color( *reinterpret_cast< const ::ColorData* >(rColor.getConstArray()) ); +#endif + } + + uno::Sequence<sal_Int8> colorToStdIntSequence( const ::Color& rColor ) + { + uno::Sequence<sal_Int8> aRet(4); + sal_Int8* pCols( aRet.getArray() ); +#ifdef OSL_BIGENDIAN + pCols[0] = rColor.GetRed(); + pCols[1] = rColor.GetGreen(); + pCols[2] = rColor.GetBlue(); + pCols[3] = 255-rColor.GetTransparency(); +#else + *reinterpret_cast<sal_Int32*>(pCols) = rColor.GetColor(); +#endif + return aRet; + } + + // Create a corrected view transformation out of the give one, + // which ensures that the rectangle given by (0,0) and + // rSpriteSize is mapped with its left,top corner to (0,0) + // again. This is required to properly render sprite + // animations to buffer bitmaps. + ::basegfx::B2DHomMatrix& calcRectToOriginTransform( ::basegfx::B2DHomMatrix& o_transform, + const ::basegfx::B2DRange& i_srcRect, + const ::basegfx::B2DHomMatrix& i_transformation ) + { + if( i_srcRect.isEmpty() ) + return o_transform=i_transformation; + + // transform by given transformation + ::basegfx::B2DRectangle aTransformedRect; + + calcTransformedRectBounds( aTransformedRect, + i_srcRect, + i_transformation ); + + // now move resulting left,top point of bounds to (0,0) + const basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix( + -aTransformedRect.getMinX(), -aTransformedRect.getMinY())); + + // prepend to original transformation + o_transform = aCorrectedTransform * i_transformation; + + return o_transform; + } + + ::basegfx::B2DRange& calcTransformedRectBounds( ::basegfx::B2DRange& outRect, + const ::basegfx::B2DRange& inRect, + const ::basegfx::B2DHomMatrix& transformation ) + { + outRect.reset(); + + if( inRect.isEmpty() ) + return outRect; + + // transform all four extremal points of the rectangle, + // take bounding rect of those. + + // transform left-top point + outRect.expand( transformation * inRect.getMinimum() ); + + // transform bottom-right point + outRect.expand( transformation * inRect.getMaximum() ); + + ::basegfx::B2DPoint aPoint; + + // transform top-right point + aPoint.setX( inRect.getMaxX() ); + aPoint.setY( inRect.getMinY() ); + + aPoint *= transformation; + outRect.expand( aPoint ); + + // transform bottom-left point + aPoint.setX( inRect.getMinX() ); + aPoint.setY( inRect.getMaxY() ); + + aPoint *= transformation; + outRect.expand( aPoint ); + + // over and out. + return outRect; + } + + ::basegfx::B2DHomMatrix& calcRectToRectTransform( ::basegfx::B2DHomMatrix& o_transform, + const ::basegfx::B2DRange& destRect, + const ::basegfx::B2DRange& srcRect, + const ::basegfx::B2DHomMatrix& transformation ) + { + if( srcRect.isEmpty() || + destRect.isEmpty() ) + { + return o_transform=transformation; + } + + // transform inputRect by transformation + ::basegfx::B2DRectangle aTransformedRect; + calcTransformedRectBounds( aTransformedRect, + srcRect, + transformation ); + + // now move resulting left,top point of bounds to (0,0) + basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix( + -aTransformedRect.getMinX(), -aTransformedRect.getMinY())); + + // scale to match outRect + const double xDenom( aTransformedRect.getWidth() ); + const double yDenom( aTransformedRect.getHeight() ); + if( xDenom != 0.0 && yDenom != 0.0 ) + aCorrectedTransform.scale( destRect.getWidth() / xDenom, + destRect.getHeight() / yDenom ); + // TODO(E2): error handling + + // translate to final position + aCorrectedTransform.translate( destRect.getMinX(), + destRect.getMinY() ); + + ::basegfx::B2DHomMatrix transform( transformation ); + o_transform = aCorrectedTransform * transform; + + return o_transform; + } + + bool isInside( const ::basegfx::B2DRange& rContainedRect, + const ::basegfx::B2DRange& rTransformRect, + const ::basegfx::B2DHomMatrix& rTransformation ) + { + if( rContainedRect.isEmpty() || rTransformRect.isEmpty() ) + return false; + + ::basegfx::B2DPolygon aPoly( + ::basegfx::tools::createPolygonFromRect( rTransformRect ) ); + aPoly.transform( rTransformation ); + + return ::basegfx::tools::isInside( aPoly, + ::basegfx::tools::createPolygonFromRect( + rContainedRect ), + true ); + } + + namespace + { + bool clipAreaImpl( ::basegfx::B2IRange* o_pDestArea, + ::basegfx::B2IRange& io_rSourceArea, + ::basegfx::B2IPoint& io_rDestPoint, + const ::basegfx::B2IRange& rSourceBounds, + const ::basegfx::B2IRange& rDestBounds ) + { + const ::basegfx::B2IPoint aSourceTopLeft( + io_rSourceArea.getMinimum() ); + + ::basegfx::B2IRange aLocalSourceArea( io_rSourceArea ); + + // clip source area (which must be inside rSourceBounds) + aLocalSourceArea.intersect( rSourceBounds ); + + if( aLocalSourceArea.isEmpty() ) + return false; + + // calc relative new source area points (relative to orig + // source area) + const ::basegfx::B2IVector aUpperLeftOffset( + aLocalSourceArea.getMinimum()-aSourceTopLeft ); + const ::basegfx::B2IVector aLowerRightOffset( + aLocalSourceArea.getMaximum()-aSourceTopLeft ); + + ::basegfx::B2IRange aLocalDestArea( io_rDestPoint + aUpperLeftOffset, + io_rDestPoint + aLowerRightOffset ); + + // clip dest area (which must be inside rDestBounds) + aLocalDestArea.intersect( rDestBounds ); + + if( aLocalDestArea.isEmpty() ) + return false; + + // calc relative new dest area points (relative to orig + // source area) + const ::basegfx::B2IVector aDestUpperLeftOffset( + aLocalDestArea.getMinimum()-io_rDestPoint ); + const ::basegfx::B2IVector aDestLowerRightOffset( + aLocalDestArea.getMaximum()-io_rDestPoint ); + + io_rSourceArea = ::basegfx::B2IRange( aSourceTopLeft + aDestUpperLeftOffset, + aSourceTopLeft + aDestLowerRightOffset ); + io_rDestPoint = aLocalDestArea.getMinimum(); + + if( o_pDestArea ) + *o_pDestArea = aLocalDestArea; + + return true; + } + } + + bool clipScrollArea( ::basegfx::B2IRange& io_rSourceArea, + ::basegfx::B2IPoint& io_rDestPoint, + ::std::vector< ::basegfx::B2IRange >& o_ClippedAreas, + const ::basegfx::B2IRange& rBounds ) + { + ::basegfx::B2IRange aResultingDestArea; + + // compute full destination area (to determine uninitialized + // areas below) + const ::basegfx::B2I64Tuple& rRange( io_rSourceArea.getRange() ); + ::basegfx::B2IRange aInputDestArea( io_rDestPoint.getX(), + io_rDestPoint.getY(), + (io_rDestPoint.getX() + + static_cast<sal_Int32>(rRange.getX())), + (io_rDestPoint.getY() + + static_cast<sal_Int32>(rRange.getY())) ); + // limit to output area (no point updating outside of it) + aInputDestArea.intersect( rBounds ); + + // clip to rBounds + if( !clipAreaImpl( &aResultingDestArea, + io_rSourceArea, + io_rDestPoint, + rBounds, + rBounds ) ) + return false; + + // finally, compute all areas clipped off the total + // destination area. + ::basegfx::computeSetDifference( o_ClippedAreas, + aInputDestArea, + aResultingDestArea ); + + return true; + } + + bool clipBlit( ::basegfx::B2IRange& io_rSourceArea, + ::basegfx::B2IPoint& io_rDestPoint, + const ::basegfx::B2IRange& rSourceBounds, + const ::basegfx::B2IRange& rDestBounds ) + { + return clipAreaImpl( NULL, + io_rSourceArea, + io_rDestPoint, + rSourceBounds, + rDestBounds ); + } + + ::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange ) + { + if( rRange.isEmpty() ) + return ::basegfx::B2IRange(); + + const ::basegfx::B2IPoint aTopLeft( ::basegfx::fround( rRange.getMinX() ), + ::basegfx::fround( rRange.getMinY() ) ); + return ::basegfx::B2IRange( aTopLeft, + aTopLeft + ::basegfx::B2IPoint( + ::basegfx::fround( rRange.getWidth() ), + ::basegfx::fround( rRange.getHeight() ) ) ); + } + + uno::Sequence< uno::Any >& getDeviceInfo( const uno::Reference< rendering::XCanvas >& i_rxCanvas, + uno::Sequence< uno::Any >& o_rxParams ) + { + o_rxParams.realloc( 0 ); + + if( i_rxCanvas.is() ) + { + try + { + uno::Reference< rendering::XGraphicDevice > xDevice( i_rxCanvas->getDevice(), + uno::UNO_QUERY_THROW ); + + uno::Reference< lang::XServiceInfo > xServiceInfo( xDevice, + uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xPropSet( xDevice, + uno::UNO_QUERY_THROW ); + + o_rxParams.realloc( 2 ); + + o_rxParams[ 0 ] = uno::makeAny( xServiceInfo->getImplementationName() ); + o_rxParams[ 1 ] = uno::makeAny( xPropSet->getPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DeviceHandle") ) ) ); + } + catch( uno::Exception& ) + { + // ignore, but return empty sequence + } + } + + return o_rxParams; + } + + awt::Rectangle getAbsoluteWindowRect( const awt::Rectangle& rRect, + const uno::Reference< awt::XWindow2 >& xWin ) + { + awt::Rectangle aRetVal( rRect ); + + ::Window* pWindow = VCLUnoHelper::GetWindow(xWin); + if( pWindow ) + { + ::Point aPoint( aRetVal.X, + aRetVal.Y ); + + aPoint = pWindow->OutputToScreenPixel( aPoint ); + + aRetVal.X = aPoint.X(); + aRetVal.Y = aPoint.Y(); + } + + return aRetVal; + } + + ::basegfx::B2DPolyPolygon getBoundMarksPolyPolygon( const ::basegfx::B2DRange& rRange ) + { + ::basegfx::B2DPolyPolygon aPolyPoly; + ::basegfx::B2DPolygon aPoly; + + const double nX0( rRange.getMinX() ); + const double nY0( rRange.getMinY() ); + const double nX1( rRange.getMaxX() ); + const double nY1( rRange.getMaxY() ); + + aPoly.append( ::basegfx::B2DPoint( nX0+4, + nY0 ) ); + aPoly.append( ::basegfx::B2DPoint( nX0, + nY0 ) ); + aPoly.append( ::basegfx::B2DPoint( nX0, + nY0+4 ) ); + aPolyPoly.append( aPoly ); aPoly.clear(); + + aPoly.append( ::basegfx::B2DPoint( nX1-4, + nY0 ) ); + aPoly.append( ::basegfx::B2DPoint( nX1, + nY0 ) ); + aPoly.append( ::basegfx::B2DPoint( nX1, + nY0+4 ) ); + aPolyPoly.append( aPoly ); aPoly.clear(); + + aPoly.append( ::basegfx::B2DPoint( nX0+4, + nY1 ) ); + aPoly.append( ::basegfx::B2DPoint( nX0, + nY1 ) ); + aPoly.append( ::basegfx::B2DPoint( nX0, + nY1-4 ) ); + aPolyPoly.append( aPoly ); aPoly.clear(); + + aPoly.append( ::basegfx::B2DPoint( nX1-4, + nY1 ) ); + aPoly.append( ::basegfx::B2DPoint( nX1, + nY1 ) ); + aPoly.append( ::basegfx::B2DPoint( nX1, + nY1-4 ) ); + aPolyPoly.append( aPoly ); + + return aPolyPoly; + } + + int calcGradientStepCount( ::basegfx::B2DHomMatrix& rTotalTransform, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::Texture& texture, + int nColorSteps ) + { + // calculate overall texture transformation (directly from + // texture to device space). + ::basegfx::B2DHomMatrix aMatrix; + + rTotalTransform.identity(); + ::basegfx::unotools::homMatrixFromAffineMatrix( rTotalTransform, + texture.AffineTransform ); + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, + viewState, + renderState); + rTotalTransform *= aMatrix; // prepend total view/render transformation + + // determine size of gradient in device coordinate system + // (to e.g. determine sensible number of gradient steps) + ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 ); + ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 ); + ::basegfx::B2DPoint aRightTop( 1.0, 0.0 ); + ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 ); + + aLeftTop *= rTotalTransform; + aLeftBottom *= rTotalTransform; + aRightTop *= rTotalTransform; + aRightBottom*= rTotalTransform; + + // longest line in gradient bound rect + const int nGradientSize( + static_cast<int>( + ::std::max( + ::basegfx::B2DVector(aRightBottom-aLeftTop).getLength(), + ::basegfx::B2DVector(aRightTop-aLeftBottom).getLength() ) + 1.0 ) ); + + // typical number for pixel of the same color (strip size) + const int nStripSize( nGradientSize < 50 ? 2 : 4 ); + + // use at least three steps, and at utmost the number of color + // steps + return ::std::max( 3, + ::std::min( + nGradientSize / nStripSize, + nColorSteps ) ); + } + + } // namespace tools + +} // namespace canvas diff --git a/canvas/source/tools/canvastools.flt b/canvas/source/tools/canvastools.flt new file mode 100644 index 000000000000..a230939309da --- /dev/null +++ b/canvas/source/tools/canvastools.flt @@ -0,0 +1,4 @@ +__CT +__real +internal +agg
\ No newline at end of file diff --git a/canvas/source/tools/elapsedtime.cxx b/canvas/source/tools/elapsedtime.cxx new file mode 100644 index 000000000000..6c3d3284cb82 --- /dev/null +++ b/canvas/source/tools/elapsedtime.cxx @@ -0,0 +1,224 @@ +/************************************************************************* + * + * 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 "osl/time.h" +#include "osl/diagnose.h" +#include "canvas/elapsedtime.hxx" + +#if defined(WNT) + +#if defined _MSC_VER +#pragma warning(push,1) +#endif + +// TEMP!!! +// Awaiting corresponding functionality in OSL +// +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winbase.h> +#include <mmsystem.h> +#endif + +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include <algorithm> +#include <limits> + +namespace canvas { +namespace tools { + + +#if defined(WNT) +// TODO(Q2): is 0 okay for the failure case here? +double ElapsedTime::getSystemTime() +{ + // TEMP!!! + // Awaiting corresponding functionality in OSL + // + + // is there a performance counter available? + static bool bTimeSetupDone( false ); + static bool bPerfTimerAvailable( false ); + static LONGLONG nPerfCountFreq; + + // TODO(F1): This _might_ cause problems, as it prevents correct + // time handling for very long lifetimes of this class's + // surrounding component in memory. When the difference between + // current sys time and nInitialCount exceeds IEEE double's + // mantissa, time will start to run jerky. + static LONGLONG nInitialCount; + + if( !bTimeSetupDone ) + { + if( QueryPerformanceFrequency( + reinterpret_cast<LARGE_INTEGER *>(&nPerfCountFreq) ) ) + { + // read initial time: + QueryPerformanceCounter( + reinterpret_cast<LARGE_INTEGER *>(&nInitialCount) ); + bPerfTimerAvailable = true; + } + bTimeSetupDone = true; + } + + if( bPerfTimerAvailable ) + { + LONGLONG nCurrCount; + QueryPerformanceCounter( + reinterpret_cast<LARGE_INTEGER *>(&nCurrCount) ); + nCurrCount -= nInitialCount; + return double(nCurrCount) / nPerfCountFreq; + } + else + { + LONGLONG nCurrTime = timeGetTime(); + return double(nCurrTime) / 1000.0; + } +} + +#else // ! WNT + +// TODO(Q2): is 0 okay for the failure case here? +double ElapsedTime::getSystemTime() +{ + TimeValue aTimeVal; + if( osl_getSystemTime( &aTimeVal ) ) + return ((aTimeVal.Nanosec * 10e-10) + aTimeVal.Seconds); + else + return 0.0; +} + +#endif + +ElapsedTime::ElapsedTime() + : m_pTimeBase(), + m_fLastQueriedTime( 0.0 ), + m_fStartTime( getSystemTime() ), + m_fFrozenTime( 0.0 ), + m_bInPauseMode( false ), + m_bInHoldMode( false ) +{ +} + +ElapsedTime::ElapsedTime( + boost::shared_ptr<ElapsedTime> const & pTimeBase ) + : m_pTimeBase( pTimeBase ), + m_fLastQueriedTime( 0.0 ), + m_fStartTime( getCurrentTime() ), + m_fFrozenTime( 0.0 ), + m_bInPauseMode( false ), + m_bInHoldMode( false ) +{ +} + +boost::shared_ptr<ElapsedTime> const & ElapsedTime::getTimeBase() const +{ + return m_pTimeBase; +} + +void ElapsedTime::reset() +{ + m_fLastQueriedTime = 0.0; + m_fStartTime = getCurrentTime(); + m_fFrozenTime = 0.0; + m_bInPauseMode = false; + m_bInHoldMode = false; +} + +void ElapsedTime::adjustTimer( double fOffset, bool /*bLimitToLastQueriedTime*/ ) +{ + // to make getElapsedTime() become _larger_, have to reduce + // m_fStartTime. + m_fStartTime -= fOffset; + + // also adjust frozen time, this method must _always_ affect the + // value returned by getElapsedTime()! + if (m_bInHoldMode || m_bInPauseMode) + m_fFrozenTime += fOffset; +} + +double ElapsedTime::getCurrentTime() const +{ + return m_pTimeBase.get() == 0 + ? getSystemTime() : m_pTimeBase->getElapsedTimeImpl(); +} + +double ElapsedTime::getElapsedTime() const +{ + m_fLastQueriedTime = getElapsedTimeImpl(); + return m_fLastQueriedTime; +} + +double ElapsedTime::getElapsedTimeImpl() const +{ + if (m_bInHoldMode || m_bInPauseMode) + return m_fFrozenTime; + + return getCurrentTime() - m_fStartTime; +} + +void ElapsedTime::pauseTimer() +{ + m_fFrozenTime = getElapsedTimeImpl(); + m_bInPauseMode = true; +} + +void ElapsedTime::continueTimer() +{ + m_bInPauseMode = false; + + // stop pausing, time runs again. Note that + // getElapsedTimeImpl() honors hold mode, i.e. a + // continueTimer() in hold mode will preserve the latter + const double fPauseDuration( getElapsedTimeImpl() - m_fFrozenTime ); + + // adjust start time, such that subsequent getElapsedTime() calls + // will virtually start from m_fFrozenTime. + m_fStartTime += fPauseDuration; +} + +void ElapsedTime::holdTimer() +{ + // when called during hold mode (e.g. more than once per time + // object), the original hold time will be maintained. + m_fFrozenTime = getElapsedTimeImpl(); + m_bInHoldMode = true; +} + +void ElapsedTime::releaseTimer() +{ + m_bInHoldMode = false; +} + +} // namespace tools +} // namespace canvas diff --git a/canvas/source/tools/image.cxx b/canvas/source/tools/image.cxx new file mode 100644 index 000000000000..b6183e463e99 --- /dev/null +++ b/canvas/source/tools/image.cxx @@ -0,0 +1,2394 @@ +/************************************************************************* + * + * 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 <canvas/canvastools.hxx> +#include <canvas/parametricpolypolygon.hxx> + +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp> + +#include <vcl/canvastools.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygoncutandtouch.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> + +#include "image.hxx" + +#define CANVAS_IMAGE_CXX +#include "image_sysprereq.h" + +////////////////////////////////////////////////////////////////////////////////// +// platform-dependend includes [wrapped into their own namepsaces] +////////////////////////////////////////////////////////////////////////////////// + +#if defined(WNT) +# if defined _MSC_VER +# pragma warning(push,1) +# endif + + namespace win32 + { + #undef DECLARE_HANDLE + #undef WB_LEFT + #undef WB_RIGHT + #undef APIENTRY + #define WIN32_LEAN_AND_MEAN + #define NOMINMAX + #include <windows.h> + } + +# if defined _MSC_VER +# pragma warning(pop) +# endif +#elif defined(OS2) + namespace os2 + { + #include <svpm.h> + } +#else +#if !defined(QUARTZ) + namespace unx + { + #include <X11/Xlib.h> + } +#endif +#endif + +#include <algorithm> + +using namespace ::com::sun::star; + +namespace canvas { namespace +{ + ////////////////////////////////////////////////////////////////////////////////// + // TransAffineFromAffineMatrix + ////////////////////////////////////////////////////////////////////////////////// + + ::agg::trans_affine transAffineFromAffineMatrix( const geometry::AffineMatrix2D& m ) + { + return agg::trans_affine(m.m00, + m.m10, + m.m01, + m.m11, + m.m02, + m.m12); + } + + ////////////////////////////////////////////////////////////////////////////////// + // TransAffineFromB2DHomMatrix + ////////////////////////////////////////////////////////////////////////////////// + + ::agg::trans_affine transAffineFromB2DHomMatrix( const ::basegfx::B2DHomMatrix& m ) + { + return agg::trans_affine(m.get(0,0), + m.get(1,0), + m.get(0,1), + m.get(1,1), + m.get(0,2), + m.get(1,2)); + } + + ////////////////////////////////////////////////////////////////////////////////// + // ARGB + ////////////////////////////////////////////////////////////////////////////////// + + struct ARGBColor + { + sal_uInt8 a; + sal_uInt8 r; + sal_uInt8 g; + sal_uInt8 b; + }; + + /// ARGB color + union ARGB + { + ARGBColor Color; + sal_uInt32 color; + + ARGB() : + color(0) + { + } + + explicit ARGB( sal_uInt32 _color ) : + color(_color) + { + } + + ARGB( sal_uInt8 _a, + sal_uInt8 _r, + sal_uInt8 _g, + sal_uInt8 _b ) + { + Color.a = _a; + Color.r = _r; + Color.g = _g; + Color.b = _b; + } + + ARGB( sal_uInt32 default_color, + const ::com::sun::star::uno::Sequence< double >& sequence ) : + color(default_color) + { + if(sequence.getLength() > 2) + { + Color.r = static_cast<sal_uInt8>(255.0f*sequence[0]); + Color.g = static_cast<sal_uInt8>(255.0f*sequence[1]); + Color.b = static_cast<sal_uInt8>(255.0f*sequence[2]); + if(sequence.getLength() > 3) + Color.a = static_cast<sal_uInt8>(255.0f*sequence[3]); + } + } + + ARGB( const ARGB& rhs ) : + color( rhs.color ) + { + } + + ARGB &operator=( const ARGB &rhs ) + { + color=rhs.color; + return *this; + } + }; + + ////////////////////////////////////////////////////////////////////////////////// + // setupState + ////////////////////////////////////////////////////////////////////////////////// + + /// Calc common output state from XCanvas parameters + void setupState( ::basegfx::B2DHomMatrix& o_rViewTransform, + ::basegfx::B2DHomMatrix& o_rRenderTransform, + ::std::auto_ptr< ::basegfx::B2DPolyPolygon >& o_rViewClip, + ::std::auto_ptr< ::basegfx::B2DPolyPolygon >& o_rRenderClip, + ARGB& o_rRenderColor, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ::basegfx::unotools::homMatrixFromAffineMatrix(o_rRenderTransform, + renderState.AffineTransform); + ::basegfx::unotools::homMatrixFromAffineMatrix(o_rViewTransform, + viewState.AffineTransform); + + o_rRenderColor = ARGB(0xFFFFFFFF, + renderState.DeviceColor); + + // TODO(F3): handle compositing modes + + if( viewState.Clip.is() ) + { + ::basegfx::B2DPolyPolygon aViewClip( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( viewState.Clip )); + + if(aViewClip.areControlPointsUsed()) + aViewClip = ::basegfx::tools::adaptiveSubdivideByAngle(aViewClip); + + o_rViewClip.reset( new ::basegfx::B2DPolyPolygon( aViewClip ) ); + } + + if( renderState.Clip.is() ) + { + ::basegfx::B2DPolyPolygon aRenderClip( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( viewState.Clip ) ); + + if(aRenderClip.areControlPointsUsed()) + aRenderClip = ::basegfx::tools::adaptiveSubdivideByAngle(aRenderClip); + + o_rRenderClip.reset( new ::basegfx::B2DPolyPolygon( aRenderClip ) ); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // clipAndTransformPolygon + ////////////////////////////////////////////////////////////////////////////////// + + /** Clip and transform given polygon + + @param io_rClippee + Polygon to clip + + @param bIsFilledPolyPolygon + When true, the polygon is clipped as if it was to be rendered + with fill, when false, the polygon is clipped as if it was to + be rendered with stroking. + */ + void clipAndTransformPolygon( ::basegfx::B2DPolyPolygon& io_rClippee, + bool bIsFilledPolyPolygon, + const ::basegfx::B2DHomMatrix& rViewTransform, + const ::basegfx::B2DHomMatrix& rRenderTransform, + const ::basegfx::B2DPolyPolygon* pViewClip, + const ::basegfx::B2DPolyPolygon* pRenderClip ) + { + ::basegfx::B2DPolyPolygon aPolyPolygon(io_rClippee); + io_rClippee.clear(); + + // clip contour against renderclip + if( pRenderClip ) + { + // AW: Simplified + aPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aPolyPolygon, *pRenderClip, true, !bIsFilledPolyPolygon); + } + + if( !aPolyPolygon.count() ) + return; + + // transform result into view space + aPolyPolygon.transform(rRenderTransform); + + // clip contour against viewclip + if( pViewClip ) + { + // AW: Simplified + aPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aPolyPolygon, *pViewClip, true, !bIsFilledPolyPolygon); + } + + if(!(aPolyPolygon.count())) + return; + + // transform result into device space + aPolyPolygon.transform(rViewTransform); + + io_rClippee = aPolyPolygon; + } + + ////////////////////////////////////////////////////////////////////////////////// + // setupPolyPolygon + ////////////////////////////////////////////////////////////////////////////////// + + void setupPolyPolygon( ::basegfx::B2DPolyPolygon& io_rClippee, + bool bIsFilledPolyPolygon, + ARGB& o_rRenderColor, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ::basegfx::B2DHomMatrix aViewTransform; + ::basegfx::B2DHomMatrix aRenderTransform; + ::std::auto_ptr< ::basegfx::B2DPolyPolygon > pViewClip; + ::std::auto_ptr< ::basegfx::B2DPolyPolygon > pRenderClip; + + setupState( aViewTransform, + aRenderTransform, + pViewClip, + pRenderClip, + o_rRenderColor, + viewState, + renderState ); + + clipAndTransformPolygon( io_rClippee, + bIsFilledPolyPolygon, + aViewTransform, + aRenderTransform, + pViewClip.get(), + pRenderClip.get() ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // RawABGRBitmap + ////////////////////////////////////////////////////////////////////////////////// + + // Raw ABGR [AABBGGRR] 32bit continous + struct RawABGRBitmap + { + sal_Int32 mnWidth; + sal_Int32 mnHeight; + sal_uInt8* mpBitmapData; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // vclBitmapEx2Raw + ////////////////////////////////////////////////////////////////////////////////// + + void vclBitmapEx2Raw( const ::BitmapEx& rBmpEx, RawABGRBitmap& rBmpData ) + { + Bitmap aBitmap( rBmpEx.GetBitmap() ); + + ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), + aBitmap ); + + const sal_Int32 nWidth( rBmpData.mnWidth ); + const sal_Int32 nHeight( rBmpData.mnHeight ); + + ENSURE_OR_THROW( pReadAccess.get() != NULL, + "vclBitmapEx2Raw(): " + "Unable to acquire read acces to bitmap" ); + + if( rBmpEx.IsTransparent()) + { + if( rBmpEx.IsAlpha() ) + { + // 8bit alpha mask + Bitmap aAlpha( rBmpEx.GetAlpha().GetBitmap() ); + + ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.AcquireReadAccess(), + aAlpha ); + + // By convention, the access buffer always has + // one of the following formats: + // + // BMP_FORMAT_1BIT_MSB_PAL + // BMP_FORMAT_4BIT_MSN_PAL + // BMP_FORMAT_8BIT_PAL + // BMP_FORMAT_16BIT_TC_LSB_MASK + // BMP_FORMAT_24BIT_TC_BGR + // BMP_FORMAT_32BIT_TC_MASK + // + // and is always BMP_FORMAT_BOTTOM_UP + // + // This is the way + // WinSalBitmap::AcquireBuffer() sets up the + // buffer + + ENSURE_OR_THROW( pAlphaReadAccess.get() != NULL, + "vclBitmapEx2Raw(): " + "Unable to acquire read acces to alpha" ); + + ENSURE_OR_THROW( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL || + pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK, + "vclBitmapEx2Raw(): " + "Unsupported alpha scanline format" ); + + BitmapColor aCol; + sal_uInt8* pCurrOutput( rBmpData.mpBitmapData ); + int x, y; + + for( y=0; y<nHeight; ++y ) + { + switch( pReadAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + aCol = pReadAccess->GetPaletteColor( *pScan++ ); + + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + // store as RGBA + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + *pCurrOutput++ = *pScan++; + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + // TODO(P2): Might be advantageous + // to hand-formulate the following + // formats, too. + case BMP_FORMAT_1BIT_MSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_MSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_LSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_MASK: + { + Scanline pAScan = pAlphaReadAccess->GetScanline( y ); + + // using fallback for those + // seldom formats + for( x=0; x<nWidth; ++x ) + { + // yes. x and y are swapped on Get/SetPixel + aCol = pReadAccess->GetColor(y,x); + + *pCurrOutput++ = aCol.GetBlue(); + *pCurrOutput++ = aCol.GetGreen(); + *pCurrOutput++ = aCol.GetRed(); + + // out notion of alpha is + // different from the rest + // of the world's + *pCurrOutput++ = 255 - (BYTE)*pAScan++; + } + } + break; + + case BMP_FORMAT_1BIT_LSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_LSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_8BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_RGB: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_MSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ABGR: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ARGB: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_BGRA: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_RGBA: + // FALLTHROUGH intended + default: + ENSURE_OR_THROW( false, + "vclBitmapEx2Raw(): " + "Unexpected scanline format - has " + "WinSalBitmap::AcquireBuffer() changed?" ); + } + } + } + else + { + // 1bit alpha mask + Bitmap aMask( rBmpEx.GetMask() ); + + ScopedBitmapReadAccess pMaskReadAccess( aMask.AcquireReadAccess(), + aMask ); + + // By convention, the access buffer always has + // one of the following formats: + // + // BMP_FORMAT_1BIT_MSB_PAL + // BMP_FORMAT_4BIT_MSN_PAL + // BMP_FORMAT_8BIT_PAL + // BMP_FORMAT_16BIT_TC_LSB_MASK + // BMP_FORMAT_24BIT_TC_BGR + // BMP_FORMAT_32BIT_TC_MASK + // + // and is always BMP_FORMAT_BOTTOM_UP + // + // This is the way + // WinSalBitmap::AcquireBuffer() sets up the + // buffer + + ENSURE_OR_THROW( pMaskReadAccess.get() != NULL, + "vclBitmapEx2Raw(): " + "Unable to acquire read acces to mask" ); + + ENSURE_OR_THROW( pMaskReadAccess->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL, + "vclBitmapEx2Raw(): " + "Unsupported mask scanline format" ); + + BitmapColor aCol; + int nCurrBit; + const int nMask( 1L ); + const int nInitialBit(7); + sal_uInt32 *pBuffer = reinterpret_cast<sal_uInt32 *>(rBmpData.mpBitmapData); + int x, y; + + // mapping table, to get from mask index color to + // alpha value (which depends on the mask's palette) + sal_uInt8 aColorMap[2]; + + const BitmapColor& rCol0( pMaskReadAccess->GetPaletteColor( 0 ) ); + const BitmapColor& rCol1( pMaskReadAccess->GetPaletteColor( 1 ) ); + + // shortcut for true luminance calculation + // (assumes that palette is grey-level). Note the + // swapped the indices here, to account for the + // fact that VCL's notion of alpha is inverted to + // the rest of the world's. + aColorMap[0] = rCol1.GetRed(); + aColorMap[1] = rCol0.GetRed(); + + for( y=0; y<nHeight; ++y ) + { + switch( pReadAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + aCol = pReadAccess->GetPaletteColor( *pScan++ ); + + // RGB -> ABGR + unsigned int color = aCol.GetRed(); + color |= aCol.GetGreen()<<8; + color |= aCol.GetBlue()<<16; + color |= aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ]<<24; + *pBuffer++ = color; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pReadAccess->GetScanline( y ); + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + // BGR -> ABGR + unsigned int color = (*pScan++)<<16; + color |= (*pScan++)<<8; + color |= (*pScan++); + color |= (aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ])<<24; + *pBuffer++ = color; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + // TODO(P2): Might be advantageous + // to hand-formulate the following + // formats, too. + case BMP_FORMAT_1BIT_MSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_MSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_LSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_MASK: + { + Scanline pMScan = pMaskReadAccess->GetScanline( y ); + + // using fallback for those + // seldom formats + for( x=0, nCurrBit=nInitialBit; x<nWidth; ++x ) + { + // yes. x and y are swapped on Get/SetPixel + aCol = pReadAccess->GetColor(y,x); + + // -> ABGR + unsigned int color = aCol.GetBlue()<<16; + color |= aCol.GetGreen()<<8; + color |= aCol.GetRed(); + color |= (aColorMap[ (pMScan[ (x & ~7L) >> 3L ] >> nCurrBit ) & nMask ])<<24; + *pBuffer++ = color; + nCurrBit = ((nCurrBit - 1) % 8L) & 7L; + } + } + break; + + case BMP_FORMAT_1BIT_LSB_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_4BIT_LSN_PAL: + // FALLTHROUGH intended + case BMP_FORMAT_8BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_RGB: + // FALLTHROUGH intended + case BMP_FORMAT_24BIT_TC_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_16BIT_TC_MSB_MASK: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ABGR: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_ARGB: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_BGRA: + // FALLTHROUGH intended + case BMP_FORMAT_32BIT_TC_RGBA: + // FALLTHROUGH intended + default: + ENSURE_OR_THROW( false, + "vclBitmapEx2Raw(): " + "Unexpected scanline format - has " + "WinSalBitmap::AcquireBuffer() changed?" ); + } + } + } + } + else + { + // *no* alpha mask + ULONG nFormat = pReadAccess->GetScanlineFormat(); + BYTE *pBuffer = reinterpret_cast<BYTE *>(rBmpData.mpBitmapData); + + switch(nFormat) + { + case BMP_FORMAT_24BIT_TC_BGR: + + { + sal_Int32 height = pReadAccess->Height(); + for(sal_Int32 y=0; y<height; ++y) + { + BYTE *pScanline=pReadAccess->GetScanline(y); + sal_Int32 width = pReadAccess->Width(); + for(sal_Int32 x=0; x<width; ++x) + { + // BGR -> RGB + BYTE b(*pScanline++); + BYTE g(*pScanline++); + BYTE r(*pScanline++); + *pBuffer++ = r; + *pBuffer++ = g; + *pBuffer++ = b; + } + } + } + break; + + case BMP_FORMAT_24BIT_TC_RGB: + + { + sal_Int32 height = pReadAccess->Height(); + for(sal_Int32 y=0; y<height; ++y) + { + BYTE *pScanline=pReadAccess->GetScanline(y); + sal_Int32 width = pReadAccess->Width(); + for(sal_Int32 x=0; x<width; ++x) + { + // RGB -> RGB + BYTE r(*pScanline++); + BYTE g(*pScanline++); + BYTE b(*pScanline++); + *pBuffer++ = r; + *pBuffer++ = g; + *pBuffer++ = b; + } + } + } + break; + + case BMP_FORMAT_1BIT_MSB_PAL: + case BMP_FORMAT_1BIT_LSB_PAL: + case BMP_FORMAT_4BIT_MSN_PAL: + case BMP_FORMAT_4BIT_LSN_PAL: + case BMP_FORMAT_8BIT_PAL: + + { + sal_Int32 height = pReadAccess->Height(); + for(sal_Int32 y=0; y<height; ++y) + { + BYTE *pScanline=pReadAccess->GetScanline(y); + sal_Int32 width = pReadAccess->Width(); + for(sal_Int32 x=0; x<width; ++x) + { + BitmapColor aCol(pReadAccess->GetPaletteColor(*pScanline++)); + + *pBuffer++ = aCol.GetRed(); + *pBuffer++ = aCol.GetGreen(); + *pBuffer++ = aCol.GetBlue(); + } + } + } + break; + } + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // color_generator_linear + ////////////////////////////////////////////////////////////////////////////////// + + template<typename T> struct color_generator_linear + { + typedef typename T::value_type value_type; + + color_generator_linear( const T &c1, + const T &c2, + unsigned int aSteps ) : maSteps(aSteps), + maColor1(c1), + maColor2(c2) + { + } + + unsigned size() const { return maSteps; } + const T operator [] (unsigned v) const + { + const double w = double(v)/maSteps; + return T( static_cast<value_type>(maColor1.r+(maColor2.r-maColor1.r)*w), + static_cast<value_type>(maColor1.g+(maColor2.g-maColor1.g)*w), + static_cast<value_type>(maColor1.b+(maColor2.b-maColor1.b)*w), + static_cast<value_type>(maColor1.a+(maColor2.a-maColor1.a)*w)); + } + + unsigned int maSteps; + const T maColor1; + const T maColor2; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // color_generator_axial + ////////////////////////////////////////////////////////////////////////////////// + + template<typename T> struct color_generator_axial + { + typedef typename T::value_type value_type; + + color_generator_axial( const T &c1, + const T &c2, + unsigned int aSteps ) : maSteps(aSteps), + maColor1(c1), + maColor2(c2) + { + } + + unsigned size() const { return maSteps; } + const T operator [] (unsigned v) const + { + const double aHalfSteps = maSteps/2.0; + const double w = (v >= aHalfSteps) ? + 1.0-((double(v)-aHalfSteps)/aHalfSteps) : + (double(v)*2.0)/maSteps; + return T( static_cast<value_type>(maColor1.r+(maColor2.r-maColor1.r)*w), + static_cast<value_type>(maColor1.g+(maColor2.g-maColor1.g)*w), + static_cast<value_type>(maColor1.b+(maColor2.b-maColor1.b)*w), + static_cast<value_type>(maColor1.a+(maColor2.a-maColor1.a)*w)); + } + + unsigned int maSteps; + const T maColor1; + const T maColor2; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // color_generator_adaptor + ////////////////////////////////////////////////////////////////////////////////// + + template<typename T> struct color_generator_adaptor + { + color_generator_adaptor( const T &c1, + const T &c2, + unsigned int aSteps ) : linear_generator(c1,c2,aSteps), + axial_generator(c1,c2,aSteps), + mbLinear(true) {} + void set_linear( bool bLinear ) { mbLinear=bLinear; } + unsigned size() const { return mbLinear ? linear_generator.size() : axial_generator.size(); } + const T operator [] (unsigned v) const + { + return mbLinear ? + linear_generator.operator [] (v) : + axial_generator.operator [] (v); + } + + color_generator_linear<T> linear_generator; + color_generator_axial<T> axial_generator; + bool mbLinear; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // gradient_polymorphic_wrapper_base + ////////////////////////////////////////////////////////////////////////////////// + + struct gradient_polymorphic_wrapper_base + { + virtual int calculate(int x, int y, int) const = 0; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // gradient_polymorphic_wrapper + ////////////////////////////////////////////////////////////////////////////////// + + template<class GradientF> struct gradient_polymorphic_wrapper : + public gradient_polymorphic_wrapper_base + { + virtual int calculate(int x, int y, int d) const + { + return m_gradient.calculate(x, y, d); + } + GradientF m_gradient; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // gradient_rect + ////////////////////////////////////////////////////////////////////////////////// + + class gradient_rect + { + public: + + int width; + int height; + + inline int calculate(int x, int y, int d) const + { + int ax = abs(x); + int ay = abs(y); + int clamp_x = height>width ? 0 : (width-height); + int clamp_y = height>width ? (height-width) : 0; + int value_x = (ax-clamp_x)*d/(width-clamp_x); + int value_y = (ay-clamp_y)*d/(height-clamp_y); + if(ax < (clamp_x)) + value_x = 0; + if(ay < (clamp_y)) + value_y = 0; + return value_x > value_y ? value_x : value_y; + } + }; + + sal_uInt32 getBytesPerPixel( IColorBuffer::Format eFormat ) + { + switch(eFormat) + { + default: + OSL_ENSURE(false, "Unexpected pixel format"); + // FALLTHROUGH intended + case IColorBuffer::FMT_R8G8B8: + return 3L; + case IColorBuffer::FMT_A8R8G8B8: + return 4L; + } + } +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawLinePolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +template<class pixel_format> +void Image::drawLinePolyPolygonImpl( const ::basegfx::B2DPolyPolygon& rPolyPolygon, + double fStrokeWidth, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ + ::basegfx::B2DPolyPolygon aPolyPolygon( rPolyPolygon ); + ARGB aRenderColor; + + setupPolyPolygon( aPolyPolygon, false, aRenderColor, viewState, renderState ); + + if( !aPolyPolygon.count() ) + return; + + // Class template pixel_formats_rgb24 has full knowledge about this + // particular pixel format in memory. The only template parameter + // can be order_rgb24 or order_bgr24 that determines the order of color channels. + //typedef agg::pixfmt_rgba32 pixel_format; + pixel_format pixf(maRenderingBuffer); + + // There are two basic renderers with almost the same functionality: + // renderer_base and renderer_mclip. The first one is used most often + // and it performs low level clipping. + // This simply adds clipping to the graphics buffer, the clip rect + // will be initialized to the area of the framebuffer. + typedef agg::renderer_base<pixel_format> renderer_base; + agg::renderer_base<pixel_format> renb(pixf); + + // To draw Anti-Aliased primitives one shoud *rasterize* them first. + // The primary rasterization technique in AGG is scanline based. + // That is, a polygon is converted into a number of horizontal + // scanlines and then the scanlines are being rendered one by one. + // To transfer information from a rasterizer to the scanline renderer + // there scanline containers are used. A scanline consists of a + // number of horizontal, non-intersecting spans. All spans must be ordered by X. + // --> *packed* scanline container + agg::scanline_p8 sl; + + typedef agg::renderer_outline_aa<renderer_base> renderer_type; + typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type; + agg::line_profile_aa profile; + profile.width(fStrokeWidth); + renderer_type ren(renb, profile); + rasterizer_type ras(ren); + + const agg::rgba8 fillcolor(aRenderColor.Color.r, + aRenderColor.Color.g, + aRenderColor.Color.b, + aRenderColor.Color.a); + ren.color(fillcolor); + + agg::path_storage path; + agg::conv_curve<agg::path_storage> curve(path); + + for(sal_uInt32 nPolygon=0; nPolygon<aPolyPolygon.count(); ++nPolygon) + { + const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(nPolygon)); + const sal_uInt32 nPointCount(aPolygon.count()); + + if(nPointCount) + { + if(aPolygon.areControlPointsUsed()) + { + // prepare edge-based loop + basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0)); + const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount); + + // first vertex + path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY()); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + // access next point + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex)); + + // get control points + const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex)); + + // specify first cp, second cp, next vertex + path.curve4( + aControlNext.getX(), aControlNext.getY(), + aControlPrev.getX(), aControlPrev.getY(), + aNextPoint.getX(), aNextPoint.getY()); + + // prepare next step + aCurrentPoint = aNextPoint; + } + } + else + { + const basegfx::B2DPoint aStartPoint(aPolygon.getB2DPoint(0)); + ras.move_to_d(aStartPoint.getX(), aStartPoint.getY()); + + for(sal_uInt32 a(1); a < nPointCount; a++) + { + const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a)); + ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY()); + } + + ras.render(aPolygon.isClosed()); + } + } + } + + ras.add_path(curve); + ras.render(false); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawLinePolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +void Image::drawLinePolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, + double fStrokeWidth, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ + switch(maDesc.eFormat) + { + case FMT_R8G8B8: + drawLinePolyPolygonImpl<agg::pixfmt_rgb24>(rPoly,fStrokeWidth,viewState,renderState); + break; + case FMT_A8R8G8B8: + drawLinePolyPolygonImpl<agg::pixfmt_rgba32>(rPoly,fStrokeWidth,viewState,renderState); + break; + default: + OSL_ENSURE(false, "Unexpected pixel format"); + break; + } +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::implDrawBitmap +////////////////////////////////////////////////////////////////////////////////// + +/** internal utility function to draw one image into another one. + the source image will be drawn with respect to the given + transform and clip settings. + */ +ImageCachedPrimitiveSharedPtr Image::implDrawBitmap( + const Image& rBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ + ::basegfx::B2DPolyPolygon aPoly( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRange(0.0, 0.0, + rBitmap.maDesc.nWidth, + rBitmap.maDesc.nHeight ) ) ); + ARGB aFillColor; + + setupPolyPolygon( aPoly, true, aFillColor, viewState, renderState ); + + if( !aPoly.count() ) + return ImageCachedPrimitiveSharedPtr(); + + ::basegfx::B2DHomMatrix aViewTransform; + ::basegfx::B2DHomMatrix aRenderTransform; + ::basegfx::B2DHomMatrix aTextureTransform; + + ::basegfx::unotools::homMatrixFromAffineMatrix(aRenderTransform, + renderState.AffineTransform); + ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform, + viewState.AffineTransform); + aTextureTransform *= aRenderTransform; + + // TODO(F2): Fill in texture + rendering::Texture aTexture; + + return fillTexturedPolyPolygon( rBitmap, + aPoly, + aTextureTransform, + aViewTransform, + aTexture ); +} + +////////////////////////////////////////////////////////////////////////////////// +// cachedPrimitiveFTPP [cachedPrimitive for [F]ill[T]extured[P]oly[P]olygon] +////////////////////////////////////////////////////////////////////////////////// + +#if AGG_VERSION >= 2400 +template<class pixel_format_dst,class span_gen_type> +#else +template<class pixel_format,class span_gen_type> +#endif +class cachedPrimitiveFTPP : public ImageCachedPrimitive +{ + public: + + cachedPrimitiveFTPP( const ::basegfx::B2DHomMatrix &rTransform, + const ::basegfx::B2DHomMatrix &rViewTransform, + agg::rendering_buffer &dst, + const agg::rendering_buffer& src ) : + aTransform(rTransform), + inter(tm), + filter(filter_kernel), +#if AGG_VERSION >= 2400 + pixs(const_cast<agg::rendering_buffer&>(src)), + source(pixs), + sg(source,inter,filter), + pixd(dst), + rb(pixd), + ren(rb,sa,sg) +#else + sg(sa,src,inter,filter), + pixf(dst), + rb(pixf), + ren(rb,sg) +#endif + { + ::basegfx::B2DHomMatrix aFinalTransform(aTransform); + aFinalTransform *= rViewTransform; + tm = transAffineFromB2DHomMatrix(aFinalTransform); + tm.invert(); + } + + virtual void setImage( const ::boost::shared_ptr< class Image >& rTargetImage ) + { + pImage=rTargetImage; + } + + virtual sal_Int8 redraw( const ::com::sun::star::rendering::ViewState& aState ) const + { + ::basegfx::B2DHomMatrix aViewTransform; + ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform,aState.AffineTransform); + ::basegfx::B2DHomMatrix aFinalTransform(aTransform); + aFinalTransform *= aViewTransform; + tm = transAffineFromB2DHomMatrix(aFinalTransform); + tm.invert(); + redraw(); + return ::com::sun::star::rendering::RepaintResult::REDRAWN; + } + + inline void redraw() const { agg::render_scanlines(ras, sl, ren); } + + mutable agg::rasterizer_scanline_aa<> ras; + + private: + + typedef agg::span_interpolator_linear<> interpolator_type; +#if AGG_VERSION >= 2400 + typedef agg::renderer_base<pixel_format_dst> renderer_base; + typedef agg::span_allocator< typename span_gen_type::color_type > span_alloc_type; + typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type, span_gen_type> renderer_type; + typedef typename span_gen_type::source_type source_type; + typedef typename span_gen_type::source_type::pixfmt_type pixel_format_src; +#else + typedef agg::renderer_base<pixel_format> renderer_base; + typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> renderer_type; +#endif + + ::basegfx::B2DHomMatrix aTransform; + interpolator_type inter; + agg::image_filter_bilinear filter_kernel; + agg::image_filter_lut filter; +#if AGG_VERSION >= 2400 + span_alloc_type sa; + pixel_format_src pixs; + source_type source; +#else + agg::span_allocator< typename span_gen_type::color_type > sa; +#endif + span_gen_type sg; +#if AGG_VERSION >= 2400 + pixel_format_dst pixd; +#else + pixel_format pixf; +#endif + renderer_base rb; + mutable renderer_type ren; + mutable agg::scanline_p8 sl; + mutable agg::trans_affine tm; + ImageSharedPtr pImage; +}; + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillTexturedPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +template<class pixel_format,class span_gen_type> +ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygonImpl( + const Image& rTexture, + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::basegfx::B2DHomMatrix& rOverallTransform, + const ::basegfx::B2DHomMatrix& rViewTransform, + const rendering::Texture& ) +{ + // calculate final overall transform. + ::basegfx::B2DHomMatrix aOverallTransform(rOverallTransform); + aOverallTransform *= rViewTransform; + + // instead of always using the full-blown solution we + // first check to see if this is a simple rectangular + // 1-to-1 copy from source to destination image. + ::basegfx::B2DTuple aTranslate(aOverallTransform.get(0,2),aOverallTransform.get(1,2)); + ::basegfx::B2DTuple aSize(rTexture.maDesc.nWidth,rTexture.maDesc.nHeight); + ::basegfx::B2DRange aRange(aTranslate,aTranslate+aSize); + ::basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(aOverallTransform); + if(::basegfx::tools::isPolyPolygonEqualRectangle(aPolyPolygon,aRange)) + { + // yes, we can take the shortcut. + // but we need to clip the destination rectangle + // against the boundary of the destination image. + sal_Int32 dwSrcX(0); + sal_Int32 dwSrcY(0); + sal_Int32 dwDstX(static_cast<sal_Int32>(aTranslate.getX())); + sal_Int32 dwDstY(static_cast<sal_Int32>(aTranslate.getY())); + sal_Int32 dwWidth(rTexture.maDesc.nWidth); + sal_Int32 dwHeight(rTexture.maDesc.nHeight); + + // prevent fast copy if destination position is not an + // integer coordinate. otherwise we would most probably + // introduce visual glitches while combining this with + // high-accuracy rendering stuff. + if( ::basegfx::fTools::equalZero(aTranslate.getX()-dwDstX) && + ::basegfx::fTools::equalZero(aTranslate.getY()-dwDstY)) + { + // clip against destination boundary. shrink size if + // necessary, modify destination position if we need to. + if(dwDstX < 0) { dwWidth-=dwDstX; dwSrcX=-dwDstX; dwDstX=0; } + if(dwDstY < 0) { dwHeight-=dwDstY; dwSrcY=-dwDstY; dwDstY=0; } + const sal_Int32 dwRight(dwDstX+dwWidth); + const sal_Int32 dwBottom(dwDstY+dwHeight); + if(dwRight > dwWidth) + dwWidth -= dwRight-dwWidth; + if(dwBottom > dwHeight) + dwHeight -= dwBottom-dwHeight; + + // calculate source buffer + const Description &srcDesc = rTexture.maDesc; + const sal_uInt32 dwSrcBytesPerPixel(getBytesPerPixel(srcDesc.eFormat)); + const sal_uInt32 dwSrcPitch(srcDesc.nWidth*dwSrcBytesPerPixel+srcDesc.nStride); + sal_uInt8 *pSrcBuffer = rTexture.maDesc.pBuffer+(dwSrcPitch*dwSrcX)+(dwSrcBytesPerPixel*dwSrcY); + + // calculate destination buffer + const Description &dstDesc = maDesc; + const sal_uInt32 dwDstBytesPerPixel(getBytesPerPixel(dstDesc.eFormat)); + const sal_uInt32 dwDstPitch(dstDesc.nWidth*dwDstBytesPerPixel+dstDesc.nStride); + sal_uInt8 *pDstBuffer = maDesc.pBuffer+(dwDstPitch*dwDstY)+(dwDstBytesPerPixel*dwDstX); + + // if source and destination format match, we can simply + // copy whole scanlines. + if(srcDesc.eFormat == dstDesc.eFormat) + { + const sal_Size dwNumBytesPerScanline(dwSrcBytesPerPixel*dwWidth); + for(sal_Int32 y=0; y<dwHeight; ++y) + { + rtl_copyMemory(pDstBuffer,pSrcBuffer,dwNumBytesPerScanline); + pSrcBuffer += dwSrcPitch; + pDstBuffer += dwDstPitch; + } + } + else + { + // otherwise [formats do not match], we need to copy + // each pixel one by one and convert from source to destination format. + if(srcDesc.eFormat == FMT_A8R8G8B8 && dstDesc.eFormat == FMT_R8G8B8) + { + for(sal_Int32 y=0; y<dwHeight; ++y) + { + sal_uInt8 *pSrc=pSrcBuffer; + sal_uInt8 *pDst=pDstBuffer; + for(sal_Int32 x=0; x<dwWidth; ++x) + { + BYTE r(*pSrc++); + BYTE g(*pSrc++); + BYTE b(*pSrc++); + BYTE Alpha(*pSrc++); + BYTE OneMinusAlpha(0xFF-Alpha); + *pDst=(((r*Alpha)+((*pDst)*OneMinusAlpha))/0xFF); + ++pDst; + *pDst=(((g*Alpha)+((*pDst)*OneMinusAlpha))/0xFF); + ++pDst; + *pDst=(((b*Alpha)+((*pDst)*OneMinusAlpha))/0xFF); + ++pDst; + } + pSrcBuffer += dwSrcPitch; + pDstBuffer += dwDstPitch; + } + } + else if(srcDesc.eFormat == FMT_R8G8B8 && dstDesc.eFormat == FMT_A8R8G8B8) + { + for(sal_Int32 y=0; y<dwHeight; ++y) + { + sal_uInt8 *pSrc=pSrcBuffer; + sal_uInt8 *pDst=pDstBuffer; + for(sal_Int32 x=0; x<dwWidth; ++x) + { + BYTE r(*pSrc++); + BYTE g(*pSrc++); + BYTE b(*pSrc++); + *pDst++=r; + *pDst++=g; + *pDst++=b; + *pDst++=0xFF; + } + pSrcBuffer += dwSrcPitch; + pDstBuffer += dwDstPitch; + } + } + } + + return ImageCachedPrimitiveSharedPtr(); + } + } + + typedef cachedPrimitiveFTPP<pixel_format,span_gen_type> cachedPrimitive_t; + cachedPrimitive_t *pPrimitive = new cachedPrimitive_t( rOverallTransform, + rViewTransform, + maRenderingBuffer, + rTexture.maRenderingBuffer); + + agg::path_storage path; + agg::conv_curve<agg::path_storage> curve(path); + + for(sal_uInt32 nPolygon(0); nPolygon < rPolyPolygon.count(); nPolygon++) + { + const basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nPolygon)); + const sal_uInt32 nPointCount(aPolygon.count()); + + if(nPointCount) + { + if(aPolygon.areControlPointsUsed()) + { + // prepare edge-based loop + basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0)); + const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount); + + // first vertex + path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY()); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + // access next point + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex)); + + // get control points + const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex)); + + // specify first cp, second cp, next vertex + path.curve4( + aControlNext.getX(), aControlNext.getY(), + aControlPrev.getX(), aControlPrev.getY(), + aNextPoint.getX(), aNextPoint.getY()); + + // prepare next step + aCurrentPoint = aNextPoint; + } + } + else + { + const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0)); + pPrimitive->ras.move_to_d(aPoint.getX(), aPoint.getY()); + + for(sal_uInt32 a(1); a < nPointCount; a++) + { + const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a)); + pPrimitive->ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY()); + } + + if(aPolygon.isClosed()) + { + pPrimitive->ras.close_polygon(); + } + } + } + } + + pPrimitive->ras.add_path(curve); + pPrimitive->redraw(); + + return ImageCachedPrimitiveSharedPtr(pPrimitive); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillTexturedPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygon( + const Image& rTexture, + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::basegfx::B2DHomMatrix& rOverallTransform, + const ::basegfx::B2DHomMatrix& rViewTransform, + const rendering::Texture& texture ) +{ + typedef agg::wrap_mode_repeat wrap_x_type; + typedef agg::wrap_mode_repeat wrap_y_type; + typedef agg::pixfmt_rgb24 pixfmt_rgb24; + typedef agg::pixfmt_rgba32 pixfmt_rgba32; +#if AGG_VERSION >= 2400 + typedef agg::image_accessor_wrap< pixfmt_rgba32, wrap_x_type, wrap_y_type > img_source_type_rgba; + typedef agg::image_accessor_wrap< pixfmt_rgb24, wrap_x_type, wrap_y_type > img_source_type_rgb; + + typedef agg::span_image_resample_rgba_affine< img_source_type_rgba > span_gen_type_rgba; + typedef agg::span_image_resample_rgb_affine< img_source_type_rgb > span_gen_type_rgb; +#else + typedef agg::span_pattern_resample_rgba_affine< pixfmt_rgba32::color_type, + pixfmt_rgba32::order_type, + wrap_x_type, + wrap_y_type> span_gen_type_rgba; + typedef agg::span_pattern_resample_rgb_affine< pixfmt_rgb24::color_type, + pixfmt_rgb24::order_type, + wrap_x_type, + wrap_y_type> span_gen_type_rgb; +#endif + + const Format nDest = maDesc.eFormat; + const Format nSource = rTexture.maDesc.eFormat; + + if(nDest == FMT_R8G8B8 && nSource == FMT_R8G8B8) + { + return fillTexturedPolyPolygonImpl< agg::pixfmt_rgb24, + span_gen_type_rgb >( + rTexture, + rPolyPolygon, + rOverallTransform, + rViewTransform, + texture ); + } + else if(nDest == FMT_R8G8B8 && nSource == FMT_A8R8G8B8) + { + return fillTexturedPolyPolygonImpl< agg::pixfmt_rgb24, + span_gen_type_rgba >( + rTexture, + rPolyPolygon, + rOverallTransform, + rViewTransform, + texture ); + } + else if(nDest == FMT_A8R8G8B8 && nSource == FMT_R8G8B8) + { + return fillTexturedPolyPolygonImpl< agg::pixfmt_rgba32, + span_gen_type_rgb >( + rTexture, + rPolyPolygon, + rOverallTransform, + rViewTransform, + texture ); + } + else if(nDest == FMT_A8R8G8B8 && nSource == FMT_A8R8G8B8) + { + return fillTexturedPolyPolygonImpl< agg::pixfmt_rgba32, + span_gen_type_rgba >( + rTexture, + rPolyPolygon, + rOverallTransform, + rViewTransform, + texture ); + } + else + { + OSL_ENSURE(false, "Unexpected pixel format"); + } + + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillGradient +////////////////////////////////////////////////////////////////////////////////// + +template<class pixel_format> +void Image::fillGradientImpl( const ParametricPolyPolygon::Values& rValues, + const uno::Sequence< double >& rUnoColor1, + const uno::Sequence< double >& rUnoColor2, + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::basegfx::B2DHomMatrix& rOverallTransform, + const rendering::Texture& ) +{ + const ARGB aColor1(0xFFFFFFFF, + rUnoColor1); + const ARGB aColor2(0xFFFFFFFF, + rUnoColor2); + + // first of all we need to provide the framebuffer we want to render to. + // the properties of the framebuffer are + // 1) memory & layout [width, height, stride] + // 2) pixelformat + // 3) clipping + + // Class template pixel_formats_rgb24 has full knowledge about this + // particular pixel format in memory. The only template parameter + // can be order_rgb24 or order_bgr24 that determines the order of color channels. + pixel_format pixf(maRenderingBuffer); + + // There are two basic renderers with almost the same functionality: + // renderer_base and renderer_mclip. The first one is used most often + // and it performs low level clipping. + // This simply adds clipping to the graphics buffer, the clip rect + // will be initialized to the area of the framebuffer. + typedef agg::renderer_base<pixel_format> renderer_base; + renderer_base rb(pixf); + + // bounding rectangle of untransformed polypolygon + const ::basegfx::B2DRange& rBounds(::basegfx::tools::getRange(rPolyPolygon)); + + // the color generator produces a specific color from + // some given interpolation value. + // number of steps for color interpolation + typedef typename pixel_format::color_type color_type; + color_type color1(agg::rgba8(aColor1.Color.r, + aColor1.Color.g, + aColor1.Color.b, + 255)); + color_type color2(agg::rgba8(aColor2.Color.r, + aColor2.Color.g, + aColor2.Color.b, + 255)); + typedef color_generator_adaptor<color_type> color_generator_type; + unsigned int dwNumSteps = static_cast<unsigned int>(rBounds.getWidth()); + color_generator_type colors(color1,color2,dwNumSteps); + colors.set_linear(true); + + // color = f(x,y) + gradient_polymorphic_wrapper<agg::gradient_x> gf_x; + gradient_polymorphic_wrapper<agg::gradient_radial> gf_radial; + gradient_polymorphic_wrapper<gradient_rect> gf_rectangular; + gf_rectangular.m_gradient.width = static_cast<int>(rBounds.getWidth())<<4; + gf_rectangular.m_gradient.height = static_cast<int>(rBounds.getHeight())<<4; + const gradient_polymorphic_wrapper_base *gf[] = { &gf_x, // GRADIENT_LINEAR + &gf_x, // GRADIENT_AXIAL + &gf_radial, // GRADIENT_ELLIPTICAL + &gf_rectangular // GRADIENT_RECTANGULAR + }; + + // how do texture coordinates change when the pixel coordinate change? + typedef agg::span_interpolator_linear<> interpolator_type; + agg::trans_affine tm; + tm *= agg::trans_affine_scaling(1.0f/rBounds.getWidth(), + 1.0f/rBounds.getHeight()); + if(rValues.meType == ParametricPolyPolygon::GRADIENT_ELLIPTICAL || + rValues.meType == ParametricPolyPolygon::GRADIENT_RECTANGULAR) + { + //tm *= trans_affine_scaling(mnAspectRatio,+1.0f); + //const double fAspect = aBounds.getWidth()/aBounds.getHeight(); + //tm *= trans_affine_scaling(+0.5f,+0.5f*(1.0f/fAspect)); + //tm *= trans_affine_translation(+0.5f,+0.5f); + tm *= agg::trans_affine_scaling(+0.5f,+0.5f); + tm *= agg::trans_affine_translation(+0.5f,+0.5f); + } + tm *= transAffineFromB2DHomMatrix(rOverallTransform); + tm.invert(); + interpolator_type inter(tm); + + // spanline allocators reserve memory for the color values + // filled up by the spanline generators. + typedef agg::span_allocator<color_type> gradient_span_alloc; + gradient_span_alloc span_alloc; + + // scanline generators create the actual color values for + // some specific coordinate range of a scanline. + typedef agg::span_gradient<color_type, + interpolator_type, + gradient_polymorphic_wrapper_base, + color_generator_type > gradient_span_gen; +#if AGG_VERSION >= 2400 + gradient_span_gen span_gen(inter, + *gf[rValues.meType], + colors, + 0, + dwNumSteps); +#else + gradient_span_gen span_gen(span_alloc, + inter, + *gf[rValues.meType], + colors, + 0, + dwNumSteps); +#endif + + // To draw Anti-Aliased primitives one shoud *rasterize* them first. + // The primary rasterization technique in AGG is scanline based. + // That is, a polygon is converted into a number of horizontal + // scanlines and then the scanlines are being rendered one by one. + // To transfer information from a rasterizer to the scanline renderer + // there scanline containers are used. A scanline consists of a + // number of horizontal, non-intersecting spans. All spans must be ordered by X. + // --> packed scanline container + agg::scanline_p8 sl; + + // antialiased scanline renderer with pattern filling capability + // [in contrast to solid renderers, that is] + // the instance of this particular renderer combines the + // renderbuffer [i.e. destination] and the spanline generator [i.e. source] +#if AGG_VERSION >= 2400 + typedef agg::renderer_scanline_aa<renderer_base, gradient_span_alloc, gradient_span_gen> renderer_gradient; + renderer_gradient r1(rb, span_alloc, span_gen); +#else + typedef agg::renderer_scanline_aa<renderer_base, gradient_span_gen> renderer_gradient; + renderer_gradient r1(rb, span_gen); +#endif + + // instantiate the rasterizer and feed the incoming polypolygon. + agg::rasterizer_scanline_aa<> ras; + agg::path_storage path; + agg::conv_curve<agg::path_storage> curve(path); + + for(sal_uInt32 nPolygon(0); nPolygon < rPolyPolygon.count(); nPolygon++) + { + const basegfx::B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(nPolygon)); + const sal_uInt32 nPointCount(aPolygon.count()); + + if(nPointCount) + { + if(aPolygon.areControlPointsUsed()) + { + // prepare edge-based loop + basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0)); + const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount); + + // first vertex + path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY()); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + // access next point + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex)); + + // get control points + const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex)); + + // specify first cp, second cp, next vertex + path.curve4( + aControlNext.getX(), aControlNext.getY(), + aControlPrev.getX(), aControlPrev.getY(), + aNextPoint.getX(), aNextPoint.getY()); + + // prepare next step + aCurrentPoint = aNextPoint; + } + } + else + { + const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0)); + ras.move_to_d(aPoint.getX(), aPoint.getY()); + + for(sal_uInt32 a(1); a < nPointCount; a++) + { + const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a)); + ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY()); + } + + if(aPolygon.isClosed()) + { + ras.close_polygon(); + } + } + } + } + + // everything is up and running, go... + ras.add_path(curve); + render_scanlines(ras,sl,r1); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillGradient +////////////////////////////////////////////////////////////////////////////////// + +void Image::fillGradient( const ParametricPolyPolygon::Values& rValues, + const uno::Sequence< double >& rUnoColor1, + const uno::Sequence< double >& rUnoColor2, + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::basegfx::B2DHomMatrix& rOverallTransform, + const rendering::Texture& texture ) +{ + switch(maDesc.eFormat) + { + case FMT_R8G8B8: + fillGradientImpl<agg::pixfmt_rgb24>(rValues,rUnoColor1,rUnoColor2,rPolyPolygon,rOverallTransform,texture); + break; + case FMT_A8R8G8B8: + fillGradientImpl<agg::pixfmt_rgba32>(rValues,rUnoColor1,rUnoColor2,rPolyPolygon,rOverallTransform,texture); + break; + default: + OSL_ENSURE(false, "Unexpected pixel format"); + break; + } +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fromVCLBitmap +////////////////////////////////////////////////////////////////////////////////// + +bool Image::fromVCLBitmap( ::BitmapEx& rBmpEx ) +{ + const ::Size aBmpSize( rBmpEx.GetSizePixel() ); + Image::Description desc; + desc.eFormat = rBmpEx.IsTransparent() ? FMT_A8R8G8B8 : FMT_R8G8B8; + desc.nWidth = aBmpSize.Width(); + desc.nHeight = aBmpSize.Height(); + desc.nStride = 0; + const sal_uInt32 nPitch(desc.nWidth*getBytesPerPixel(desc.eFormat)+desc.nStride); + desc.pBuffer = new sal_uInt8 [nPitch*desc.nHeight]; + maDesc = desc; + mbBufferHasUserOwnership = false; + maRenderingBuffer.attach(static_cast<agg::int8u *>(desc.pBuffer), + desc.nWidth, + desc.nHeight, + nPitch); + RawABGRBitmap aBmpData; + aBmpData.mnWidth = aBmpSize.Width(); + aBmpData.mnHeight = aBmpSize.Height(); + aBmpData.mpBitmapData = static_cast<sal_uInt8 *>(desc.pBuffer); + vclBitmapEx2Raw(rBmpEx,aBmpData); + + return true; +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::Image +////////////////////////////////////////////////////////////////////////////////// + +Image::Image( const Description& rDesc ) : + maDesc( rDesc ), + maRenderingBuffer(), + mbBufferHasUserOwnership( rDesc.pBuffer != NULL ) +{ +#if defined(PROFILER) + for(int i=0; i<TIMER_MAX; ++i) + maElapsedTime[i]=0.0; +#endif + + // allocate own buffer memory, if not provided + sal_uInt8* pBuffer = maDesc.pBuffer; + const sal_uInt32 nWidth(maDesc.nWidth); + const sal_uInt32 nHeight(maDesc.nHeight); + const sal_uInt32 nStride(maDesc.nStride); + const sal_uInt32 nPitch(nWidth*getBytesPerPixel(maDesc.eFormat) + + nStride); + + if( !pBuffer ) + pBuffer = new sal_uInt8 [nPitch*nHeight]; + + maDesc.pBuffer = pBuffer; + + // attach graphics buffer + maRenderingBuffer.attach( + static_cast<agg::int8u *>(pBuffer), + nWidth, + nHeight, + nPitch ); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::Image +////////////////////////////////////////////////////////////////////////////////// + +Image::Image( const uno::Reference< rendering::XBitmap >& xBitmap ) : + maDesc(), + maRenderingBuffer(), + mbBufferHasUserOwnership( false ) +{ +#if defined(PROFILER) + for(int i=0; i<TIMER_MAX; ++i) + maElapsedTime[i]=0.0; +#endif + + // 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 ) + fromVCLBitmap(aBmpEx); + + // TODO(F2): Fallback to XIntegerBitmap interface for import + OSL_ENSURE(false, + "Image::Image(): Cannot retrieve bitmap data!" ); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::~Image +////////////////////////////////////////////////////////////////////////////////// + +Image::~Image() +{ +#if defined(PROFILER) + + double aAccumulatedTime(0.0); + for(int i=0; i<TIMER_MAX; ++i) + aAccumulatedTime += maElapsedTime[i]; + + OSL_TRACE("Image %d - %d %d %d %d %d\n",(int)(aAccumulatedTime*1000.0), + (int)(maElapsedTime[TIMER_FILLTEXTUREDPOLYPOLYGON]*1000.0), + (int)(maElapsedTime[TIMER_FILLB2DPOLYPOLYGON]*1000.0), + (int)(maElapsedTime[TIMER_DRAWPOLYPOLYGON]*1000.0), + (int)(maElapsedTime[TIMER_FILLPOLYPOLYGON]*1000.0), + (int)(maElapsedTime[TIMER_DRAWBITMAP]*1000.0)); + +#endif + + if( !mbBufferHasUserOwnership ) + delete [] maDesc.pBuffer; +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::clear +////////////////////////////////////////////////////////////////////////////////// + +template<class pixel_format> +void Image::clearImpl( sal_uInt8 a, + sal_uInt8 r, + sal_uInt8 g, + sal_uInt8 b ) +{ + pixel_format pixf(maRenderingBuffer); + agg::renderer_base<pixel_format> renb(pixf); + + renb.clear(agg::rgba8(r,g,b,a)); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::clear +////////////////////////////////////////////////////////////////////////////////// + +void Image::clear( sal_uInt8 a, + sal_uInt8 r, + sal_uInt8 g, + sal_uInt8 b ) +{ + switch(maDesc.eFormat) + { + case FMT_R8G8B8: + return clearImpl<agg::pixfmt_rgb24>(a,r,g,b); + case FMT_A8R8G8B8: + return clearImpl<agg::pixfmt_rgba32>(a,r,g,b); + default: + OSL_ENSURE(false, "Unexpected pixel format"); + break; + } +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillB2DPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +void Image::fillB2DPolyPolygon( + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ +#if defined(PROFILER) + ScopeTimer aTimer(TIMER_FILLB2DPOLYPOLYGON,this); +#endif + + switch(maDesc.eFormat) + { + case FMT_R8G8B8: + fillPolyPolygonImpl<agg::pixfmt_rgb24>(rPolyPolygon,viewState,renderState); + break; + case FMT_A8R8G8B8: + fillPolyPolygonImpl<agg::pixfmt_rgba32>(rPolyPolygon,viewState,renderState); + break; + default: + OSL_ENSURE(false, "Unexpected pixel format"); + break; + } +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::lock +////////////////////////////////////////////////////////////////////////////////// + +sal_uInt8* Image::lock() const +{ + return maDesc.pBuffer; +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::unlock +////////////////////////////////////////////////////////////////////////////////// + +void Image::unlock() const +{ +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::getWidth +////////////////////////////////////////////////////////////////////////////////// + +sal_uInt32 Image::getWidth() const +{ + return maDesc.nWidth; +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::getHeight +////////////////////////////////////////////////////////////////////////////////// + +sal_uInt32 Image::getHeight() const +{ + return maDesc.nHeight; +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::getStride +////////////////////////////////////////////////////////////////////////////////// + +sal_uInt32 Image::getStride() const +{ + return maDesc.nWidth*getBytesPerPixel(maDesc.eFormat)+maDesc.nStride; +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::getFormat +////////////////////////////////////////////////////////////////////////////////// + +IColorBuffer::Format Image::getFormat() const +{ + return maDesc.eFormat; +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawPoint +////////////////////////////////////////////////////////////////////////////////// + +void Image::drawPoint( const geometry::RealPoint2D& /*aPoint*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/ ) +{ + OSL_ENSURE(false, + "Image::drawPoint(): NYI" ); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawLine +////////////////////////////////////////////////////////////////////////////////// + +void Image::drawLine( const geometry::RealPoint2D& aStartPoint, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ + ::basegfx::B2DPolygon aLinePoly; + aLinePoly.append( + ::basegfx::unotools::b2DPointFromRealPoint2D( aStartPoint ) ); + aLinePoly.append( + ::basegfx::unotools::b2DPointFromRealPoint2D( aEndPoint ) ); + + drawLinePolyPolygon( ::basegfx::B2DPolyPolygon( aLinePoly ), + 1.0, + viewState, + renderState ); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawBezier +////////////////////////////////////////////////////////////////////////////////// + +void Image::drawBezier( const geometry::RealBezierSegment2D& aBezierSegment, + const geometry::RealPoint2D& aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ + basegfx::B2DPolygon aBezierPoly; + + aBezierPoly.append(basegfx::B2DPoint(aBezierSegment.Px, aBezierSegment.Py)); + aBezierPoly.appendBezierSegment( + basegfx::B2DPoint(aBezierSegment.C1x, aBezierSegment.C1y), + basegfx::B2DPoint(aBezierSegment.C2x, aBezierSegment.C2y), + basegfx::unotools::b2DPointFromRealPoint2D(aEndPoint)); + + drawLinePolyPolygon( ::basegfx::B2DPolyPolygon( aBezierPoly ), + 1.0, + viewState, + renderState ); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::drawPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ +#if defined(PROFILER) + ScopeTimer aTimer(TIMER_DRAWPOLYPOLYGON,this); +#endif + + if( !xPolyPolygon.is() ) + return ImageCachedPrimitiveSharedPtr(); + + drawLinePolyPolygon( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ), + 1.0, + viewState, + renderState ); + + // TODO(F2): Implement sensible ImageCachedPrimitive + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::strokePolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::strokePolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::StrokeAttributes& strokeAttributes ) +{ + if( !xPolyPolygon.is() ) + return ImageCachedPrimitiveSharedPtr(); + + drawLinePolyPolygon( ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ), + strokeAttributes.StrokeWidth, + viewState, + renderState ); + + // TODO(F2): Implement sensible ImageCachedPrimitive + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::strokeTexturedPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::strokeTexturedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const uno::Sequence< rendering::Texture >& /*textures*/, + const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/, + const rendering::StrokeAttributes& /*strokeAttributes*/ ) +{ + OSL_ENSURE(false, + "Image::strokeTexturedPolyPolygon(): NYI" ); + + // TODO(F2): Implement sensible ImageCachedPrimitive + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::strokeTextureMappedPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::strokeTextureMappedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const uno::Sequence< rendering::Texture >& /*textures*/, + const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/, + const uno::Reference< geometry::XMapping2D >& /*xMapping*/, + const rendering::StrokeAttributes& /*strokeAttributes*/ ) +{ + OSL_ENSURE(false, + "Image::strokeTextureMappedPolyPolygon(): NYI" ); + + // TODO(F2): Implement sensible ImageCachedPrimitive + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +template<class pixel_format> +ImageCachedPrimitiveSharedPtr Image::fillPolyPolygonImpl( + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ +#if defined(PROFILER) + ScopeTimer aTimer(TIMER_FILLPOLYPOLYGON,this); +#endif + + ARGB aFillColor; + + ::basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + setupPolyPolygon( aPolyPolygon, true, aFillColor, viewState, renderState ); + + if( !aPolyPolygon.count() ) + return ImageCachedPrimitiveSharedPtr(); + + pixel_format pixf(maRenderingBuffer); + agg::renderer_base<pixel_format> renb(pixf); + + // Scanline renderer for solid filling. + agg::renderer_scanline_aa_solid<agg::renderer_base<pixel_format> > ren(renb); + + // Rasterizer & scanline + agg::rasterizer_scanline_aa<> ras; + agg::scanline_p8 sl; + + agg::path_storage path; + agg::conv_curve<agg::path_storage> curve(path); + + for(sal_uInt32 nPolygon(0); nPolygon < aPolyPolygon.count(); nPolygon++) + { + const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(nPolygon)); + const sal_uInt32 nPointCount(aPolygon.count()); + + if(nPointCount) + { + if(aPolygon.areControlPointsUsed()) + { + // prepare edge-based loop + basegfx::B2DPoint aCurrentPoint(aPolygon.getB2DPoint(0)); + const sal_uInt32 nEdgeCount(aPolygon.isClosed() ? nPointCount - 1 : nPointCount); + + // first vertex + path.move_to(aCurrentPoint.getX(), aCurrentPoint.getY()); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + // access next point + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + const basegfx::B2DPoint aNextPoint(aPolygon.getB2DPoint(nNextIndex)); + + // get control points + const basegfx::B2DPoint aControlNext(aPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aControlPrev(aPolygon.getPrevControlPoint(nNextIndex)); + + // specify first cp, second cp, next vertex + path.curve4( + aControlNext.getX(), aControlNext.getY(), + aControlPrev.getX(), aControlPrev.getY(), + aNextPoint.getX(), aNextPoint.getY()); + + // prepare next step + aCurrentPoint = aNextPoint; + } + } + else + { + const basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(0)); + ras.move_to_d(aPoint.getX(), aPoint.getY()); + + for(sal_uInt32 a(1); a < nPointCount; a++) + { + const basegfx::B2DPoint aVertexPoint(aPolygon.getB2DPoint(a)); + ras.line_to_d(aVertexPoint.getX(), aVertexPoint.getY()); + } + + if(aPolygon.isClosed()) + { + ras.close_polygon(); + } + } + } + } + + ras.add_path(curve); + agg::rgba8 fillcolor(aFillColor.Color.r,aFillColor.Color.g,aFillColor.Color.b,aFillColor.Color.a); + ren.color(fillcolor); + agg::render_scanlines(ras, sl, ren); + + // TODO(F2): Implement sensible ImageCachedPrimitive + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::fillPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ + if( !xPolyPolygon.is() ) + return ImageCachedPrimitiveSharedPtr(); + + ::basegfx::B2DPolyPolygon aPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ) ); + + switch(maDesc.eFormat) + { + case FMT_R8G8B8: + return fillPolyPolygonImpl<agg::pixfmt_rgb24>(aPoly,viewState,renderState); + case FMT_A8R8G8B8: + return fillPolyPolygonImpl<agg::pixfmt_rgba32>(aPoly,viewState,renderState); + default: + OSL_ENSURE(false, "Unexpected pixel format"); + break; + } + + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillTexturedPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::fillTexturedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Sequence< rendering::Texture >& textures, + const ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations ) +{ +#if defined(PROFILER) + ScopeTimer aTimer(TIMER_FILLTEXTUREDPOLYPOLYGON,this); +#endif + + if( !xPolyPolygon.is() ) + return ImageCachedPrimitiveSharedPtr(); + + ::basegfx::B2DPolyPolygon aPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPolyPolygon ) ); + ARGB aFillColor; + + setupPolyPolygon( aPoly, true, aFillColor, viewState, renderState ); + + if( !aPoly.count() ) + return ImageCachedPrimitiveSharedPtr(); + + ::basegfx::B2DHomMatrix aViewTransform; + ::basegfx::B2DHomMatrix aRenderTransform; + ::basegfx::B2DHomMatrix aTextureTransform; + + ::basegfx::unotools::homMatrixFromAffineMatrix(aTextureTransform, + textures[0].AffineTransform); + ::basegfx::unotools::homMatrixFromAffineMatrix(aRenderTransform, + renderState.AffineTransform); + ::basegfx::unotools::homMatrixFromAffineMatrix(aViewTransform, + viewState.AffineTransform); + aTextureTransform *= aRenderTransform; + + // TODO(F1): Multi-texturing + if( textures[0].Gradient.is() ) + { + aTextureTransform *= aViewTransform; + + // try to cast XParametricPolyPolygon2D reference to + // our implementation class. + ::canvas::ParametricPolyPolygon* pGradient = + dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() ); + + if( pGradient ) + { + const ParametricPolyPolygon::Values& rValues( + pGradient->getValues() ); + + // TODO: use all the colors and place them on given positions/stops + // TODO(E1): Return value + // TODO(F1): FillRule + fillGradient( rValues, + rValues.maColors [0], + rValues.maColors [rValues.maColors.getLength () - 1], + aPoly, + aTextureTransform, + textures[0] ); + } + } + else if( textures[0].Bitmap.is() ) + { + ImageSharedPtr pTexture; + + if( textureAnnotations[0].get() != NULL ) + pTexture = textureAnnotations[0]; + else + pTexture.reset( new Image( textures[0].Bitmap ) ); + + const sal_uInt32 nWidth(pTexture->maDesc.nWidth); + const sal_uInt32 nHeight(pTexture->maDesc.nHeight); + + // scale texture into one-by-one unit rect. + aTextureTransform.scale(1.0f/nWidth, + 1.0f/nHeight); + + // TODO(E1): Return value + // TODO(F1): FillRule + return fillTexturedPolyPolygon( *pTexture, + aPoly, + aTextureTransform, + aViewTransform, + textures[0] ); + } + + // TODO(F2): Implement sensible ImageCachedPrimitive + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::fillTextureMappedPolyPolygon +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::fillTextureMappedPolyPolygon( + const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, + const rendering::ViewState& /*viewState*/, + const rendering::RenderState& /*renderState*/, + const uno::Sequence< rendering::Texture >& /*textures*/, + const ::std::vector< ::boost::shared_ptr<Image> >& /*textureAnnotations*/, + const uno::Reference< geometry::XMapping2D >& /*xMapping*/ ) +{ + OSL_ENSURE(false, + "Image::fillTextureMappedPolyPolygon(): NYI" ); + + // TODO(F2): Implement sensible ImageCachedPrimitive + return ImageCachedPrimitiveSharedPtr(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawBitmap +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::drawBitmap( + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ +#if defined(PROFILER) + ScopeTimer aTimer(TIMER_DRAWBITMAP,this); +#endif + + // TODO(P3): Implement bitmap caching + if( !xBitmap.is() ) + return ImageCachedPrimitiveSharedPtr(); +/* + XBitmapAccessor accessor( xBitmap ); + if(accessor.isValid()) + { + Image aImage( accessor.getDesc() ); + + implDrawBitmap( aImage, + viewState, + renderState ); + + // TODO(F2): Implement sensible ImageCachedPrimitive + return ImageCachedPrimitiveSharedPtr(); + } +*/ + Image aImage( xBitmap ); + + return implDrawBitmap( aImage,viewState,renderState ); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawBitmap +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::drawBitmap( + const ImageSharedPtr& rImage, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ +#if defined(PROFILER) + ScopeTimer aTimer(TIMER_DRAWBITMAP,this); +#endif + + // TODO(P3): Implement bitmap caching + if( !rImage ) + return ImageCachedPrimitiveSharedPtr(); + + return implDrawBitmap( *rImage, + viewState, + renderState ); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawBitmapModulated +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::drawBitmapModulated( + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ + // TODO(P3): Implement bitmap caching + if( !xBitmap.is() ) + return ImageCachedPrimitiveSharedPtr(); + + Image aImage( xBitmap ); + + // TODO(F2): Distinguish modulated and unmodulated bitmap output + return implDrawBitmap( aImage,viewState,renderState ); +} + +////////////////////////////////////////////////////////////////////////////////// +// Image::drawBitmapModulated +////////////////////////////////////////////////////////////////////////////////// + +ImageCachedPrimitiveSharedPtr Image::drawBitmapModulated( + const ImageSharedPtr& rImage, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) +{ + // TODO(P3): Implement bitmap caching + if( !rImage ) + return ImageCachedPrimitiveSharedPtr(); + + // TODO(F2): Distinguish modulated and unmodulated bitmap output + return implDrawBitmap( *rImage,viewState,renderState ); +} + +} diff --git a/canvas/source/tools/image.hxx b/canvas/source/tools/image.hxx new file mode 100644 index 000000000000..1c62c7d6276b --- /dev/null +++ b/canvas/source/tools/image.hxx @@ -0,0 +1,298 @@ +/************************************************************************* + * + * 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 INCLUDED_CANVAS_IMAGE_HXX +#define INCLUDED_CANVAS_IMAGE_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <canvas/rendering/icolorbuffer.hxx> +#include <canvas/parametricpolypolygon.hxx> +#include "imagecachedprimitive.hxx" + +#include <canvas/elapsedtime.hxx> + +#include "image_sysprereq.h" + +struct BitmapSystemData; +class BitmapEx; + +namespace canvas +{ + class Image : public IColorBuffer + { + public: + /// The description of the image + struct Description + { + IColorBuffer::Format eFormat; + sal_uInt32 nWidth; + sal_uInt32 nHeight; + sal_uInt32 nStride; + sal_uInt8* pBuffer; + }; + + /** Create a new image with the attributes passed as argument. + */ + explicit Image( const Description& desc ); + + /** Create a new image from the XBitmap passed as argument + */ + explicit Image( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& xBitmap ); + + + virtual ~Image(); + + /** Retrieve desciption of image layout + */ + const Description& getDescription() const { return maDesc; } + + /** Clear image with uniform color + */ + void clear( sal_uInt8 a, + sal_uInt8 r, + sal_uInt8 g, + sal_uInt8 b ); + + void fillB2DPolyPolygon( + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + + // IColorBuffer interface implementation + // ===================================== + + virtual sal_uInt8* lock() const; + virtual void unlock() const; + virtual sal_uInt32 getWidth() const; + virtual sal_uInt32 getHeight() const; + virtual sal_uInt32 getStride() const; + virtual Format getFormat() const; + + + // High-level drawing operations (from the XCanvas interface) + // ========================================================== + + void drawPoint( 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::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::geometry::RealBezierSegment2D& aBezierSegment, + const ::com::sun::star::geometry::RealPoint2D& aEndPoint, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + ImageCachedPrimitiveSharedPtr drawPolyPolygon( + 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 ); + + ImageCachedPrimitiveSharedPtr strokePolyPolygon( + 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 ); + ImageCachedPrimitiveSharedPtr strokeTexturedPolyPolygon( + 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 ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ImageCachedPrimitiveSharedPtr strokeTextureMappedPolyPolygon( + 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 ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations, + const ::com::sun::star::uno::Reference< + ::com::sun::star::geometry::XMapping2D >& xMapping, + const ::com::sun::star::rendering::StrokeAttributes& strokeAttributes ); + ImageCachedPrimitiveSharedPtr fillPolyPolygon( + 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 ); + ImageCachedPrimitiveSharedPtr fillTexturedPolyPolygon( + 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 ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations ); + ImageCachedPrimitiveSharedPtr fillTextureMappedPolyPolygon( + 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 ::std::vector< ::boost::shared_ptr<Image> >& textureAnnotations, + const ::com::sun::star::uno::Reference< + ::com::sun::star::geometry::XMapping2D >& xMapping ); + + ImageCachedPrimitiveSharedPtr drawBitmap( + 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 ); + ImageCachedPrimitiveSharedPtr drawBitmap( + const ::boost::shared_ptr<Image>& rImage, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + ImageCachedPrimitiveSharedPtr drawBitmapModulated( + 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 ); + ImageCachedPrimitiveSharedPtr drawBitmapModulated( + const ::boost::shared_ptr<Image>& rImage, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + private: + void drawLinePolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, + double fStrokeWidth, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + ImageCachedPrimitiveSharedPtr implDrawBitmap( + const Image& rBitmap, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + ImageCachedPrimitiveSharedPtr fillTexturedPolyPolygon( + const Image& rTexture, + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::basegfx::B2DHomMatrix& rOverallTransform, + const ::basegfx::B2DHomMatrix& rViewTransform, + const ::com::sun::star::rendering::Texture& texture ); + + void fillGradient( const ParametricPolyPolygon::Values& rValues, + const ::com::sun::star::uno::Sequence< double >& rColor1, + const ::com::sun::star::uno::Sequence< double >& rColor2, + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::basegfx::B2DHomMatrix& rOverallTransform, + const ::com::sun::star::rendering::Texture& texture ); + bool fromVCLBitmap( ::BitmapEx& rBmpEx ); + + template<class pixel_format> + void drawLinePolyPolygonImpl( const ::basegfx::B2DPolyPolygon& rPoly, + double fStrokeWidth, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + template<class pixel_format,class span_gen_type> + ImageCachedPrimitiveSharedPtr fillTexturedPolyPolygonImpl( + const Image& rTexture, + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::basegfx::B2DHomMatrix& rOverallTransform, + const ::basegfx::B2DHomMatrix& rViewTransform, + const ::com::sun::star::rendering::Texture& texture ); + + template<class pixel_format> + void fillGradientImpl( const ParametricPolyPolygon::Values& rValues, + const ::com::sun::star::uno::Sequence< double >& rUnoColor1, + const ::com::sun::star::uno::Sequence< double >& rUnoColor2, + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::basegfx::B2DHomMatrix& rOverallTransform, + const ::com::sun::star::rendering::Texture& texture ); + + template<class pixel_format> + ImageCachedPrimitiveSharedPtr fillPolyPolygonImpl( + const ::basegfx::B2DPolyPolygon& rPolyPolygon, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + template<class pixel_format> void clearImpl( sal_uInt8 a, + sal_uInt8 r, + sal_uInt8 g, + sal_uInt8 b ); + + /** Image description + */ + Description maDesc; + + /** the graphics buffer is a simple array + where each element points to the start + of a scanline in consecutive order. + */ + agg::rendering_buffer maRenderingBuffer; + + /// Whether maRenderingBuffer is owned by the client of this object + bool mbBufferHasUserOwnership; + +#if defined(PROFILER) + + enum constant + { + TIMER_FILLTEXTUREDPOLYPOLYGON, + TIMER_FILLB2DPOLYPOLYGON, + TIMER_DRAWPOLYPOLYGON, + TIMER_FILLPOLYPOLYGON, + TIMER_DRAWBITMAP, + TIMER_MAX + }; + + double maElapsedTime[TIMER_MAX]; + + struct ScopeTimer + { + ScopeTimer( constant aConstant, Image *pImage ) : + maConstant(aConstant),mpImage(pImage) + {} + + ~ScopeTimer() + { + mpImage->maElapsedTime[maConstant] += maTimer.getElapsedTime(); + } + + constant maConstant; + Image* mpImage; + ::canvas::tools::ElapsedTime maTimer; + }; + +#endif + }; + + typedef ::boost::shared_ptr< Image > ImageSharedPtr; + +} + +#endif /* INCLUDED_CANVAS_IMAGE_HXX */ diff --git a/canvas/source/tools/image_sysprereq.h b/canvas/source/tools/image_sysprereq.h new file mode 100644 index 000000000000..ad81259c75c7 --- /dev/null +++ b/canvas/source/tools/image_sysprereq.h @@ -0,0 +1,102 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#if defined __GNUC__ +#pragma GCC system_header +#elif defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +#include <agg2/agg_rendering_buffer.h> + +#ifdef CANVAS_IMAGE_CXX + +////////////////////////////////////////////////////////////////////////////////// +// includes from antigrain [i would love to write this stuff by myself] +////////////////////////////////////////////////////////////////////////////////// + +#include <agg2/agg_rendering_buffer.h> +#include <agg2/agg_pixfmt_rgb.h> +#include <agg2/agg_pixfmt_rgba.h> +#include <agg2/agg_renderer_base.h> +#include <agg2/agg_color_rgba.h> +#include <agg2/agg_rasterizer_outline_aa.h> +#include <agg2/agg_rasterizer_scanline_aa.h> +#include <agg2/agg_scanline_p.h> +#include <agg2/agg_scanline_u.h> +#include <agg2/agg_renderer_scanline.h> +#include <agg2/agg_renderer_outline_aa.h> +#include <agg2/agg_renderer_primitives.h> +#include <agg2/agg_path_storage.h> +#if AGG_VERSION == 2300 +#include <agg2/agg_span_pattern.h> +#endif +#include <agg2/agg_span_pattern_rgba.h> +#if AGG_VERSION >= 2400 +#include <agg2/agg_span_image_filter_rgb.h> +#include <agg2/agg_span_image_filter_rgba.h> +#else +#include <agg2/agg_span_pattern_resample_rgb.h> +#include <agg2/agg_span_pattern_resample_rgba.h> +#endif +#include <agg2/agg_span_interpolator_linear.h> +#include <agg2/agg_span_gradient.h> +#if AGG_VERSION == 2300 +#include <agg2/agg_span_image_resample_rgb.h> +#include <agg2/agg_span_image_resample_rgba.h> +#endif +#if AGG_VERSION >= 2400 +#include <agg2/agg_span_allocator.h> +#endif +#include <agg2/agg_image_filters.h> +#if AGG_VERSION >= 2400 +#include <agg2/agg_image_accessors.h> +#endif +#include <agg2/agg_dda_line.h> +#include <agg2/agg_scanline_storage_aa.h> +#include <agg2/agg_scanline_storage_bin.h> +#include <agg2/agg_scanline_bin.h> +#include <agg2/agg_path_storage_integer.h> +#include <agg2/agg_conv_contour.h> +#include <agg2/agg_conv_curve.h> +#include <agg2/agg_conv_stroke.h> +#include <agg2/agg_conv_transform.h> +#include <agg2/agg_trans_affine.h> +#include <agg2/agg_font_cache_manager.h> +#include <agg2/agg_bitset_iterator.h> +#include <agg2/agg_path_storage.h> + +#endif // CANVAS_IMAGE_CXX + +#if defined __SUNPRO_CC +#pragma enable_warn +#elif defined _MSC_VER +#pragma warning(pop) +#endif + diff --git a/canvas/source/tools/imagecachedprimitive.hxx b/canvas/source/tools/imagecachedprimitive.hxx new file mode 100644 index 000000000000..dfcf2bc6a831 --- /dev/null +++ b/canvas/source/tools/imagecachedprimitive.hxx @@ -0,0 +1,57 @@ +/************************************************************************* + * + * 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 INCLUDED_CANVAS_IMAGECACHEDPRIMITIVE_HXX +#define INCLUDED_CANVAS_IMAGECACHEDPRIMITIVE_HXX + +#include <canvas/rendering/icachedprimitive.hxx> + +#include <boost/shared_ptr.hpp> + + +namespace canvas +{ + /** Objects with this interface are returned from every Image + render operation. + + These objects can be used to implement the + rendering::XCachedPrimitive interface, which in turn caches + render state and objects to facilitate quick redraws. + + Derived from ICachedPrimitive, to add the setImage() method + (which, strictly speaking, is a technicality, because Image + cannot create objects with a shared_ptr to itself). + */ + struct ImageCachedPrimitive : public ICachedPrimitive + { + virtual void setImage( const ::boost::shared_ptr< class Image >& rTargetImage ) = 0; + }; + + typedef ::boost::shared_ptr< ImageCachedPrimitive > ImageCachedPrimitiveSharedPtr; +} + +#endif /* INCLUDED_CANVAS_IMAGECACHEDPRIMITIVE_HXX */ diff --git a/canvas/source/tools/makefile.mk b/canvas/source/tools/makefile.mk new file mode 100644 index 000000000000..9d9e5ba002bf --- /dev/null +++ b/canvas/source/tools/makefile.mk @@ -0,0 +1,101 @@ +#************************************************************************* +# +# 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=canvastools +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF +.IF "$(profiler)"!="" || "$(PROFILER)"!="" +CDEFS+= -DPROFILER +.ENDIF + +#CFLAGS +:= /Ox /Ot # THIS IS IMPORTANT + + +.IF "$(L10N_framework)"=="" +SLOFILES = \ + $(SLO)$/cachedprimitivebase.obj \ + $(SLO)$/canvascustomspritehelper.obj \ + $(SLO)$/canvastools.obj \ + $(SLO)$/elapsedtime.obj \ + $(SLO)$/parametricpolypolygon.obj \ + $(SLO)$/prioritybooster.obj \ + $(SLO)$/propertysethelper.obj \ + $(SLO)$/spriteredrawmanager.obj \ + $(SLO)$/surface.obj \ + $(SLO)$/surfaceproxy.obj \ + $(SLO)$/surfaceproxymanager.obj \ + $(SLO)$/pagemanager.obj \ + $(SLO)$/page.obj \ + $(SLO)$/verifyinput.obj + +SHL1TARGET= $(TARGET)$(DLLPOSTFIX) +SHL1IMPLIB= i$(TARGET) +SHL1STDLIBS= $(SALLIB) $(CPPULIB) $(BASEGFXLIB) $(CPPUHELPERLIB) $(COMPHELPERLIB) $(VCLLIB) $(TKLIB) $(TOOLSLIB) + +.IF "$(ENABLE_AGG)"=="YES" + SLOFILES += $(SLO)$/bitmap.obj \ + $(SLO)$/image.obj + + .IF "$(AGG_VERSION)"!="" + CDEFS += -DAGG_VERSION=$(AGG_VERSION) + .ENDIF + SHL1STDLIBS += $(AGGLIB) +.ENDIF + +SHL1LIBS= $(SLB)$/$(TARGET).lib + +SHL1DEF= $(MISC)$/$(SHL1TARGET).def +DEF1NAME =$(SHL1TARGET) +DEF1DEPN =$(MISC)$/$(SHL1TARGET).flt \ + $(LIB1TARGET) + +DEF1DES =Canvastools +DEFLIB1NAME =$(TARGET) + +.IF "$(GUI)" == "WNT" +SHL1STDLIBS += $(WINMMLIB) $(KERNEL32LIB) +.ENDIF +.ENDIF + +# ========================================================================== + +.INCLUDE : target.mk + +$(MISC)$/$(SHL1TARGET).flt : makefile.mk $(TARGET).flt + @$(TYPE) $(TARGET).flt > $@ diff --git a/canvas/source/tools/page.cxx b/canvas/source/tools/page.cxx new file mode 100644 index 000000000000..5035c0e81916 --- /dev/null +++ b/canvas/source/tools/page.cxx @@ -0,0 +1,152 @@ +/************************************************************************* + * + * 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 <boost/bind.hpp> +#include "page.hxx" + +namespace canvas +{ + Page::Page( const IRenderModuleSharedPtr &rRenderModule ) : + mpRenderModule(rRenderModule), + mpSurface(rRenderModule->createSurface(::basegfx::B2ISize())) + { + } + + void Page::validate() + { + if(!(isValid())) + { + ::std::for_each( mpFragments.begin(), + mpFragments.end(), + ::boost::mem_fn(&PageFragment::refresh)); + } + } + + bool Page::isValid() const + { + return mpSurface && mpSurface->isValid(); + } + + FragmentSharedPtr Page::allocateSpace( const ::basegfx::B2ISize& rSize ) + { + SurfaceRect rect(rSize); + if(insert(rect)) + { + FragmentSharedPtr pFragment(new PageFragment(rect,this)); + mpFragments.push_back(pFragment); + return pFragment; + } + + return FragmentSharedPtr(); + } + + bool Page::nakedFragment( const FragmentSharedPtr& pFragment ) + { + SurfaceRect rect(pFragment->getSize()); + if(insert(rect)) + { + pFragment->setPage(this); + mpFragments.push_back(pFragment); + return true; + } + + return false; + } + + void Page::free( const FragmentSharedPtr& pFragment ) + { + // the fragment passes as argument is no longer + // dedicated to this page. either it is about to + // be relocated to some other page or it will + // currently be deleted. in either case, simply + // remove the reference from our internal storage. + FragmentContainer_t::iterator it( + std::remove( + mpFragments.begin(),mpFragments.end(),pFragment)); + mpFragments.erase(it,mpFragments.end()); + } + + bool Page::insert( SurfaceRect& r ) + { + const FragmentContainer_t::const_iterator aEnd(mpFragments.end()); + FragmentContainer_t::const_iterator it(mpFragments.begin()); + while(it != aEnd) + { + const SurfaceRect &rect = (*it)->getRect(); + const sal_Int32 x = rect.maPos.getX(); + const sal_Int32 y = rect.maPos.getY(); + // to avoid interpolation artifacts from other textures, + // one pixel gap between them + const sal_Int32 w = rect.maSize.getX()+1; + const sal_Int32 h = rect.maSize.getY()+1; + + // probe location to the right + r.maPos.setX(x+w); + r.maPos.setY(y); + if(isValidLocation(r)) + return true; + + // probe location at bottom + r.maPos.setX(x); + r.maPos.setY(y+h); + if(isValidLocation(r)) + return true; + + ++it; + } + + r.maPos.setX(0); + r.maPos.setY(0); + + return isValidLocation(r); + } + + bool Page::isValidLocation( const SurfaceRect& r ) const + { + // the rectangle passed as argument has a valid + // location if and only if there's no intersection + // with existing areas. + SurfaceRect aBoundary(mpRenderModule->getPageSize()-basegfx::B2IVector(1,1)); + if( !r.inside(aBoundary) ) + return false; + + const FragmentContainer_t::const_iterator aEnd(mpFragments.end()); + FragmentContainer_t::const_iterator it(mpFragments.begin()); + while(it != aEnd) + { + if(r.intersection((*it)->getRect())) + return false; + + ++it; + } + + return true; + } +} diff --git a/canvas/source/tools/page.hxx b/canvas/source/tools/page.hxx new file mode 100644 index 000000000000..51b770ad4ade --- /dev/null +++ b/canvas/source/tools/page.hxx @@ -0,0 +1,157 @@ +/************************************************************************* + * + * 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 INCLUDED_CANVAS_PAGE_HXX +#define INCLUDED_CANVAS_PAGE_HXX + +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <canvas/rendering/icolorbuffer.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <canvas/rendering/isurface.hxx> + +#include <list> +#include <vector> +#include <boost/shared_ptr.hpp> +#include "surfacerect.hxx" + +namespace canvas +{ + class PageFragment; + + typedef ::boost::shared_ptr< PageFragment > FragmentSharedPtr; + + /** One page of IRenderModule-provided texture space + */ + class Page + { + public: + Page( const IRenderModuleSharedPtr& rRenderModule ); + + FragmentSharedPtr allocateSpace( const ::basegfx::B2ISize& rSize ); + bool nakedFragment( const FragmentSharedPtr& pFragment ); + void free( const FragmentSharedPtr& pFragment ); + const ISurfaceSharedPtr& getSurface() const { return mpSurface; } + bool isValid() const; + void validate(); + + private: + typedef std::list<FragmentSharedPtr> FragmentContainer_t; + + IRenderModuleSharedPtr mpRenderModule; + ISurfaceSharedPtr mpSurface; + FragmentContainer_t mpFragments; + + bool insert( SurfaceRect& r ); + bool isValidLocation( const SurfaceRect& r ) const; + }; + + typedef ::boost::shared_ptr< Page > PageSharedPtr; + + + /** A part of a page, which gets allocated to a surface + */ + class PageFragment + { + public: + PageFragment( const SurfaceRect& r, + Page* pPage ) : + mpPage(pPage), + maRect(r), + mpBuffer(), + maSourceOffset() + { + } + + /// Creates a 'naked' fragment. + PageFragment( const ::basegfx::B2ISize& rSize ) : + mpPage(NULL), + maRect(rSize), + mpBuffer(), + maSourceOffset() + { + } + + bool isNaked() const { return (mpPage == NULL); } + const SurfaceRect& getRect() const { return maRect; } + const ::basegfx::B2IPoint& getPos() const { return maRect.maPos; } + const ::basegfx::B2ISize& getSize() const { return maRect.maSize; } + void setColorBuffer( const IColorBufferSharedPtr& pColorBuffer ) { mpBuffer=pColorBuffer; } + void setSourceOffset( const ::basegfx::B2IPoint& rOffset ) { maSourceOffset=rOffset; } + void setPage( Page* pPage ) { mpPage=pPage; } + + void free( const FragmentSharedPtr& pFragment ) + { + if(mpPage) + mpPage->free(pFragment); + + mpPage=NULL; + } + + bool select( bool bRefresh ) + { + // request was made to select this fragment, + // but this fragment has not been located on any + // of the available pages, we need to hurry now. + if(!(mpPage)) + return false; + + ISurfaceSharedPtr pSurface(mpPage->getSurface()); + + // select this surface before wiping the contents + // since a specific implementation could trigger + // a rendering operation here... + if(!(pSurface->selectTexture())) + return false; + + // call refresh() if requested, otherwise we're up to date... + return bRefresh ? refresh() : true; + } + + bool refresh() + { + if(!(mpPage)) + return false; + + ISurfaceSharedPtr pSurface(mpPage->getSurface()); + + return pSurface->update( maRect.maPos, + ::basegfx::B2IRectangle( + maSourceOffset, + maSourceOffset + maRect.maSize ), + *mpBuffer ); + } + + private: + Page* mpPage; + SurfaceRect maRect; + IColorBufferSharedPtr mpBuffer; + ::basegfx::B2IPoint maSourceOffset; + }; +} + +#endif diff --git a/canvas/source/tools/pagemanager.cxx b/canvas/source/tools/pagemanager.cxx new file mode 100644 index 000000000000..b2a71bf86cd3 --- /dev/null +++ b/canvas/source/tools/pagemanager.cxx @@ -0,0 +1,222 @@ +/************************************************************************* + * + * 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 <boost/bind.hpp> +#include "pagemanager.hxx" + +namespace canvas +{ + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager + ////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager::allocateSpace + ////////////////////////////////////////////////////////////////////////////////// + + FragmentSharedPtr PageManager::allocateSpace( const ::basegfx::B2ISize& rSize ) + { + // we are asked to find a location for the requested size. + // first we try to satisfy the request from the + // remaining space in the existing pages. + const PageContainer_t::iterator aEnd(maPages.end()); + PageContainer_t::iterator it(maPages.begin()); + while(it != aEnd) + { + FragmentSharedPtr pFragment((*it)->allocateSpace(rSize)); + if(pFragment) + { + // the page created a new fragment, since we maybe want + // to consolidate sparse pages we keep a reference to + // the fragment. + maFragments.push_back(pFragment); + return pFragment; + } + + ++it; + } + + // otherwise try to create a new page and allocate space there... + PageSharedPtr pPage(new Page(mpRenderModule)); + if(pPage->isValid()) + { + maPages.push_back(pPage); + FragmentSharedPtr pFragment(pPage->allocateSpace(rSize)); + if (pFragment) + maFragments.push_back(pFragment); + return pFragment; + } + + // the rendermodule failed to create a new page [maybe out + // of videomemory], and all other pages could not take + // the new request. we decide to create a 'naked' fragment + // which will receive its location later. + FragmentSharedPtr pFragment(new PageFragment(rSize)); + maFragments.push_back(pFragment); + return pFragment; + } + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager::free + ////////////////////////////////////////////////////////////////////////////////// + + void PageManager::free( const FragmentSharedPtr& pFragment ) + { + // erase the reference to the given fragment from our + // internal container. + FragmentContainer_t::iterator it( + std::remove( + maFragments.begin(),maFragments.end(),pFragment)); + maFragments.erase(it,maFragments.end()); + + // let the fragment itself know about it... + // we need to pass 'this' as argument since the fragment + // needs to pass this to the page and can't create + // shared_ptr from itself... + pFragment->free(pFragment); + } + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager::nakedFragment + ////////////////////////////////////////////////////////////////////////////////// + + void PageManager::nakedFragment( const FragmentSharedPtr& pFragment ) + { + if(maPages.empty()) + return; + + // okay, one last chance is left, we try all available + // pages again. maybe some other fragment was deleted + // and we can exploit the space. + while(!(relocate(pFragment))) + { + // no way, we need to free up some space... + // TODO(F1): this is a heuristic, could + // be designed as a policy. + const FragmentContainer_t::const_iterator aEnd(maFragments.end()); + FragmentContainer_t::const_iterator candidate(maFragments.begin()); + while(candidate != aEnd) + { + if(*candidate && !((*candidate)->isNaked())) + break; + ++candidate; + } + + if (candidate != aEnd) + { + const ::basegfx::B2ISize& rSize((*candidate)->getSize()); + sal_uInt32 nMaxArea(rSize.getX()*rSize.getY()); + + FragmentContainer_t::const_iterator it(candidate); + while(it != aEnd) + { + if (*it && !((*it)->isNaked())) + { + const ::basegfx::B2ISize& rCandidateSize((*it)->getSize()); + const sal_uInt32 nArea(rCandidateSize.getX()*rCandidateSize.getY()); + if(nArea > nMaxArea) + { + candidate=it; + nMaxArea=nArea; + } + } + + ++it; + } + + // this does not erase the candidate, + // but makes it 'naked'... + (*candidate)->free(*candidate); + } + else + break; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager::relocate + ////////////////////////////////////////////////////////////////////////////////// + + bool PageManager::relocate( const FragmentSharedPtr& pFragment ) + { + // the fragment passed as argument is assumed to + // be naked, that is it is not located on any page. + // we try all available pages again, maybe some + // other fragment was deleted and we can exploit the space. + const PageContainer_t::iterator aEnd(maPages.end()); + PageContainer_t::iterator it(maPages.begin()); + while(it != aEnd) + { + // if the page at hand takes the fragment, we immediatelly + // call select() to pull the information from the associated + // image to the hardware surface. + if((*it)->nakedFragment(pFragment)) + { + // dirty, since newly allocated. + pFragment->select(true); + return true; + } + + ++it; + } + + return false; + } + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager::validatePages + ////////////////////////////////////////////////////////////////////////////////// + + void PageManager::validatePages() + { + ::std::for_each( maPages.begin(), + maPages.end(), + ::boost::mem_fn(&Page::validate)); + } + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager::getPageSize + ////////////////////////////////////////////////////////////////////////////////// + + ::basegfx::B2ISize PageManager::getPageSize() const + { + return mpRenderModule->getPageSize(); + } + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager::getRenderModule + ////////////////////////////////////////////////////////////////////////////////// + + canvas::IRenderModuleSharedPtr PageManager::getRenderModule() const + { + return mpRenderModule; + } +} diff --git a/canvas/source/tools/pagemanager.hxx b/canvas/source/tools/pagemanager.hxx new file mode 100644 index 000000000000..bf20b1d61e43 --- /dev/null +++ b/canvas/source/tools/pagemanager.hxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * 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 INCLUDED_CANVAS_PAGEMANAGER_HXX +#define INCLUDED_CANVAS_PAGEMANAGER_HXX + +#include <basegfx/vector/b2isize.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <canvas/rendering/isurface.hxx> + +#include "page.hxx" + +namespace canvas +{ + + ////////////////////////////////////////////////////////////////////////////////// + // PageManager + ////////////////////////////////////////////////////////////////////////////////// + + class PageManager + { + public: + PageManager( const canvas::IRenderModuleSharedPtr pRenderModule ) : + mpRenderModule(pRenderModule) + { + } + + // returns the maximum size of a hardware + // accelerated page, e.g. OpenGL texture. + ::basegfx::B2ISize getPageSize() const; + + canvas::IRenderModuleSharedPtr getRenderModule() const; + + FragmentSharedPtr allocateSpace( const ::basegfx::B2ISize& rSize ); + void free( const FragmentSharedPtr& pFragment ); + + void nakedFragment( const FragmentSharedPtr& pFragment ); + + void validatePages(); + + private: + // the pagemanager needs access to the rendermodule + // since we query for system resources from it. + canvas::IRenderModuleSharedPtr mpRenderModule; + + // here we collect all fragments that will be created + // since we need them for relocation purposes. + typedef std::list<FragmentSharedPtr> FragmentContainer_t; + FragmentContainer_t maFragments; + + // this is the container holding all created pages, + // behind the scenes these are real hardware surfaces. + typedef std::list<PageSharedPtr> PageContainer_t; + PageContainer_t maPages; + + bool relocate( const FragmentSharedPtr& pFragment ); + }; + + ////////////////////////////////////////////////////////////////////////////////// + // PageManagerSharedPtr + ////////////////////////////////////////////////////////////////////////////////// + + typedef ::boost::shared_ptr< PageManager > PageManagerSharedPtr; + + ////////////////////////////////////////////////////////////////////////////////// + // End of file + ////////////////////////////////////////////////////////////////////////////////// +} + +#endif diff --git a/canvas/source/tools/parametricpolypolygon.cxx b/canvas/source/tools/parametricpolypolygon.cxx new file mode 100644 index 000000000000..368f04a572e3 --- /dev/null +++ b/canvas/source/tools/parametricpolypolygon.cxx @@ -0,0 +1,290 @@ +/************************************************************************* + * + * 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 <rtl/math.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/tools/tools.hxx> + +#include <limits> + +#include <canvas/parametricpolypolygon.hxx> + + +using namespace ::com::sun::star; + +namespace canvas +{ + uno::Sequence<rtl::OUString> ParametricPolyPolygon::getAvailableServiceNames() + { + uno::Sequence<rtl::OUString> aRet(3); + aRet[0] = rtl::OUString::createFromAscii("LinearGradient"); + aRet[1] = rtl::OUString::createFromAscii("EllipticalGradient"); + aRet[2] = rtl::OUString::createFromAscii("RectangularGradient"); + + return aRet; + } + + ParametricPolyPolygon* ParametricPolyPolygon::create( + const uno::Reference< rendering::XGraphicDevice >& rDevice, + const ::rtl::OUString& rServiceName, + const uno::Sequence< uno::Any >& rArgs ) + { + uno::Sequence< uno::Sequence< double > > colorSequence(2); + uno::Sequence< double > colorStops(2); + double fAspectRatio=1.0; + + // defaults + uno::Sequence< rendering::RGBColor > rgbColors(1); + rgbColors[0] = rendering::RGBColor(0,0,0); + colorSequence[0] = rDevice->getDeviceColorSpace()->convertFromRGB(rgbColors); + rgbColors[0] = rendering::RGBColor(1,1,1); + colorSequence[1] = rDevice->getDeviceColorSpace()->convertFromRGB(rgbColors); + colorStops[0] = 0; + colorStops[1] = 1; + + // extract args + for( sal_Int32 i=0; i<rArgs.getLength(); ++i ) + { + beans::PropertyValue aProp; + if( (rArgs[i] >>= aProp) ) + { + if( aProp.Name.equalsAscii("Colors") ) + { + aProp.Value >>= colorSequence; + } + else if( aProp.Name.equalsAscii("Stops") ) + { + aProp.Value >>= colorStops; + } + else if( aProp.Name.equalsAscii("AspectRatio") ) + { + aProp.Value >>= fAspectRatio; + } + } + } + + if( rServiceName.equalsAscii("LinearGradient") ) + { + return createLinearHorizontalGradient(rDevice, colorSequence, colorStops); + } + else if( rServiceName.equalsAscii("EllipticalGradient") ) + { + return createEllipticalGradient(rDevice, colorSequence, colorStops, fAspectRatio); + } + else if( rServiceName.equalsAscii("RectangularGradient") ) + { + return createRectangularGradient(rDevice, colorSequence, colorStops, fAspectRatio); + } + else if( rServiceName.equalsAscii("VerticalLineHatch") ) + { + // TODO: NYI + } + else if( rServiceName.equalsAscii("OrthogonalLinesHatch") ) + { + // TODO: NYI + } + else if( rServiceName.equalsAscii("ThreeCrossingLinesHatch") ) + { + // TODO: NYI + } + else if( rServiceName.equalsAscii("FourCrossingLinesHatch") ) + { + // TODO: NYI + } + + return NULL; + } + + ParametricPolyPolygon* ParametricPolyPolygon::createLinearHorizontalGradient( + const uno::Reference< rendering::XGraphicDevice >& rDevice, + const uno::Sequence< uno::Sequence< double > >& colors, + const uno::Sequence< double >& stops ) + { + // TODO(P2): hold gradient brush statically, and only setup + // the colors + return new ParametricPolyPolygon( rDevice, GRADIENT_LINEAR, colors, stops ); + } + + ParametricPolyPolygon* ParametricPolyPolygon::createEllipticalGradient( + const uno::Reference< rendering::XGraphicDevice >& rDevice, + const uno::Sequence< uno::Sequence< double > >& colors, + const uno::Sequence< double >& stops, + double fAspectRatio ) + { + // TODO(P2): hold gradient polygon statically, and only setup + // the colors + return new ParametricPolyPolygon( + rDevice, + ::basegfx::tools::createPolygonFromCircle( + ::basegfx::B2DPoint(0,0), 1 ), + GRADIENT_ELLIPTICAL, + colors, stops, fAspectRatio ); + } + + ParametricPolyPolygon* ParametricPolyPolygon::createRectangularGradient( const uno::Reference< rendering::XGraphicDevice >& rDevice, + const uno::Sequence< uno::Sequence< double > >& colors, + const uno::Sequence< double >& stops, + double fAspectRatio ) + { + // TODO(P2): hold gradient polygon statically, and only setup + // the colors + return new ParametricPolyPolygon( + rDevice, + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( -1, -1, 1, 1 ) ), + GRADIENT_RECTANGULAR, + colors, stops, fAspectRatio ); + } + + void SAL_CALL ParametricPolyPolygon::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mxDevice.clear(); + } + + uno::Reference< rendering::XPolyPolygon2D > SAL_CALL ParametricPolyPolygon::getOutline( double /*t*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO(F1): outline NYI + return uno::Reference< rendering::XPolyPolygon2D >(); + } + + uno::Sequence< double > SAL_CALL ParametricPolyPolygon::getColor( double /*t*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO(F1): color NYI + return uno::Sequence< double >(); + } + + uno::Sequence< double > SAL_CALL ParametricPolyPolygon::getPointColor( const geometry::RealPoint2D& /*point*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // TODO(F1): point color NYI + return uno::Sequence< double >(); + } + + uno::Reference< rendering::XColorSpace > SAL_CALL ParametricPolyPolygon::getColorSpace() throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return mxDevice.is() ? mxDevice->getDeviceColorSpace() : uno::Reference< rendering::XColorSpace >(); + } + +#define IMPLEMENTATION_NAME "Canvas::ParametricPolyPolygon" +#define SERVICE_NAME "com.sun.star.rendering.ParametricPolyPolygon" + + ::rtl::OUString SAL_CALL ParametricPolyPolygon::getImplementationName( ) throw (uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) ); + } + + sal_Bool SAL_CALL ParametricPolyPolygon::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException) + { + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); + } + + uno::Sequence< ::rtl::OUString > SAL_CALL ParametricPolyPolygon::getSupportedServiceNames( ) throw (uno::RuntimeException) + { + uno::Sequence< ::rtl::OUString > aRet(1); + aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + + return aRet; + } + + ParametricPolyPolygon::~ParametricPolyPolygon() + { + } + + ParametricPolyPolygon::ParametricPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& rDevice, + const ::basegfx::B2DPolygon& rGradientPoly, + GradientType eType, + const uno::Sequence< uno::Sequence< double > >& rColors, + const uno::Sequence< double >& rStops ) : + ParametricPolyPolygon_Base( m_aMutex ), + mxDevice( rDevice ), + maValues( rGradientPoly, + rColors, + rStops, + 1.0, + eType ) + { + } + + ParametricPolyPolygon::ParametricPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& rDevice, + const ::basegfx::B2DPolygon& rGradientPoly, + GradientType eType, + const uno::Sequence< uno::Sequence< double > >& rColors, + const uno::Sequence< double >& rStops, + double nAspectRatio ) : + ParametricPolyPolygon_Base( m_aMutex ), + mxDevice( rDevice ), + maValues( rGradientPoly, + rColors, + rStops, + nAspectRatio, + eType ) + { + } + + ParametricPolyPolygon::ParametricPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& rDevice, + GradientType eType, + const uno::Sequence< uno::Sequence< double > >& rColors, + const uno::Sequence< double >& rStops ) : + ParametricPolyPolygon_Base( m_aMutex ), + mxDevice( rDevice ), + maValues( ::basegfx::B2DPolygon(), + rColors, + rStops, + 1.0, + eType ) + { + } + + ParametricPolyPolygon::Values ParametricPolyPolygon::getValues() const + { + ::osl::MutexGuard aGuard( m_aMutex ); + + return maValues; + } + +} diff --git a/canvas/source/tools/prioritybooster.cxx b/canvas/source/tools/prioritybooster.cxx new file mode 100644 index 000000000000..984003ebc984 --- /dev/null +++ b/canvas/source/tools/prioritybooster.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" + + +#ifdef WNT +# if defined _MSC_VER +# pragma warning(push,1) +# endif + +# include <windows.h> + +# if defined _MSC_VER +# pragma warning(pop) +# endif +#endif + +#include "osl/diagnose.h" +#include "canvas/prioritybooster.hxx" + + +namespace canvas +{ + namespace tools + { + struct PriorityBooster_Impl + { + int mnOldPriority; + }; + + PriorityBooster::PriorityBooster( sal_Int32 nDelta ) : + mpImpl( new PriorityBooster_Impl ) + { +#ifdef WNT + HANDLE aCurrThread = GetCurrentThread(); + mpImpl->mnOldPriority = GetThreadPriority( aCurrThread ); + + if ( 0 == SetThreadPriority( aCurrThread, mpImpl->mnOldPriority + nDelta ) ) + { + OSL_ENSURE( false, + "PriorityBooster::PriorityBooster(): Was not able to modify thread priority" ); + } +#else + nDelta = 0; // #i55991# placate gcc warning +#endif + } + + PriorityBooster::~PriorityBooster() + { +#ifdef WNT + SetThreadPriority( GetCurrentThread(), + mpImpl->mnOldPriority ); +#endif + } + } // namespace tools + +} // namespace canvas diff --git a/canvas/source/tools/propertysethelper.cxx b/canvas/source/tools/propertysethelper.cxx new file mode 100644 index 000000000000..c95eae045ee5 --- /dev/null +++ b/canvas/source/tools/propertysethelper.cxx @@ -0,0 +1,187 @@ +/************************************************************************* + * + * 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/propertysethelper.hxx> + +using namespace ::com::sun::star; + +namespace canvas +{ + namespace + { + void throwUnknown( const ::rtl::OUString& aPropertyName ) + { + throw beans::UnknownPropertyException( + ::rtl::OUString::createFromAscii("PropertySetHelper: property ") + + aPropertyName + + ::rtl::OUString::createFromAscii(" not found."), + uno::Reference< uno::XInterface >() + ); + } + + void throwVeto( const ::rtl::OUString& aPropertyName ) + { + throw beans::PropertyVetoException( + ::rtl::OUString::createFromAscii("PropertySetHelper: property ") + + aPropertyName + + ::rtl::OUString::createFromAscii(" access was vetoed."), + uno::Reference< uno::XInterface >() ); + } + + struct EntryComparator + { + bool operator()( const PropertySetHelper::MapType::MapEntry& rLHS, + const PropertySetHelper::MapType::MapEntry& rRHS ) + { + return strcmp( rLHS.maKey, + rRHS.maKey ) < 0; + } + }; + } + + PropertySetHelper::PropertySetHelper() : + mpMap(), + maMapEntries() + { + } + + PropertySetHelper::PropertySetHelper( const InputMap& rMap ) : + mpMap(), + maMapEntries() + { + initProperties(rMap); + } + + void PropertySetHelper::initProperties( const InputMap& rMap ) + { + mpMap.reset(); + maMapEntries = rMap; + + std::sort( maMapEntries.begin(), + maMapEntries.end(), + EntryComparator() ); + + if( !maMapEntries.empty() ) + mpMap.reset( new MapType(&maMapEntries[0], + maMapEntries.size(), + true) ); + } + + void PropertySetHelper::addProperties( const InputMap& rMap ) + { + InputMap aMerged( getPropertyMap() ); + aMerged.insert( aMerged.end(), + rMap.begin(), + rMap.end() ); + + initProperties( aMerged ); + } + + bool PropertySetHelper::isPropertyName( const ::rtl::OUString& aPropertyName ) const + { + if( !mpMap.get() ) + return false; + + Callbacks aDummy; + return mpMap->lookup( aPropertyName, + aDummy ); + } + + uno::Reference< beans::XPropertySetInfo > PropertySetHelper::getPropertySetInfo() const + { + // we're a stealth property set + return uno::Reference< beans::XPropertySetInfo >(); + } + + void PropertySetHelper::setPropertyValue( const ::rtl::OUString& aPropertyName, + const uno::Any& aValue ) + { + Callbacks aCallbacks; + if( !mpMap.get() || + !mpMap->lookup( aPropertyName, + aCallbacks ) ) + { + throwUnknown( aPropertyName ); + } + + if( aCallbacks.setter.empty() ) + throwVeto( aPropertyName ); + + aCallbacks.setter(aValue); + } + + uno::Any PropertySetHelper::getPropertyValue( const ::rtl::OUString& aPropertyName ) const + { + Callbacks aCallbacks; + if( !mpMap.get() || + !mpMap->lookup( aPropertyName, + aCallbacks ) ) + { + throwUnknown( aPropertyName ); + } + + if( !aCallbacks.getter.empty() ) + return aCallbacks.getter(); + + // TODO(Q1): subtlety, empty getter method silently returns + // the empty any + return uno::Any(); + } + + void PropertySetHelper::addPropertyChangeListener( const ::rtl::OUString& aPropertyName, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) + { + // check validity of property, but otherwise ignore the + // request + if( !isPropertyName( aPropertyName ) ) + throwUnknown( aPropertyName ); + } + + void PropertySetHelper::removePropertyChangeListener( const ::rtl::OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) + { + // ignore request, no listener added in the first place + } + + void PropertySetHelper::addVetoableChangeListener( const ::rtl::OUString& aPropertyName, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) + { + // check validity of property, but otherwise ignore the + // request + if( !isPropertyName( aPropertyName ) ) + throwUnknown( aPropertyName ); + } + + void PropertySetHelper::removeVetoableChangeListener( const ::rtl::OUString& /*aPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/ ) + { + // ignore request, no listener added in the first place + } +} diff --git a/canvas/source/tools/spriteredrawmanager.cxx b/canvas/source/tools/spriteredrawmanager.cxx new file mode 100644 index 000000000000..7027a9d263df --- /dev/null +++ b/canvas/source/tools/spriteredrawmanager.cxx @@ -0,0 +1,520 @@ +/************************************************************************* + * + * 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 <canvas/spriteredrawmanager.hxx> + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/range/rangeexpander.hxx> + +#include <algorithm> +#include <functional> +#include <boost/bind.hpp> + + +namespace canvas +{ + namespace + { + /** Helper class to condense sprite updates into a single action + + This class tracks the sprite changes over the recorded + change list, and generates a single update action from + that (note that per screen update, several moves, + visibility changes and content updates might happen) + */ + class SpriteTracer + { + public: + SpriteTracer( const Sprite::Reference& rAffectedSprite ) : + mpAffectedSprite(rAffectedSprite), + maMoveStartArea(), + maMoveEndArea(), + mbIsMove( false ), + mbIsGenericUpdate( false ) + { + } + + void operator()( const SpriteRedrawManager::SpriteChangeRecord& rSpriteRecord ) + { + // only deal with change events from the currently + // affected sprite + if( rSpriteRecord.mpAffectedSprite == mpAffectedSprite ) + { + switch( rSpriteRecord.meChangeType ) + { + case SpriteRedrawManager::SpriteChangeRecord::move: + if( !mbIsMove ) + { + // no move yet - this must be the first one + maMoveStartArea = ::basegfx::B2DRectangle( + rSpriteRecord.maOldPos, + rSpriteRecord.maOldPos + rSpriteRecord.maUpdateArea.getRange() ); + mbIsMove = true; + } + + maMoveEndArea = rSpriteRecord.maUpdateArea; + break; + + case SpriteRedrawManager::SpriteChangeRecord::update: + // update end update area of the + // sprite. Thus, every update() action + // _after_ the last move will correctly + // update the final repaint area. And this + // does not interfere with subsequent + // moves, because moves always perform a + // hard set of maMoveEndArea to their + // stored value + maMoveEndArea.expand( rSpriteRecord.maUpdateArea ); + mbIsGenericUpdate = true; + break; + + default: + ENSURE_OR_THROW( false, + "Unexpected case in SpriteUpdater::operator()" ); + break; + } + } + } + + void commit( SpriteRedrawManager::SpriteConnectedRanges& rUpdateCollector ) const + { + if( mbIsMove ) + { + if( !maMoveStartArea.isEmpty() || + !maMoveEndArea.isEmpty() ) + { + // if mbIsGenericUpdate is false, this is a + // pure move (i.e. no other update + // operations). Pass that information on to + // the SpriteInfo + const bool bIsPureMove( !mbIsGenericUpdate ); + + // ignore the case that start and end update + // area overlap - the b2dconnectedranges + // handle that, anyway. doing it this way + // ensures that we have both old and new area + // stored + + // round all given range up to enclosing + // integer rectangle - since the whole thing + // here is about + + // first, draw the new sprite position + rUpdateCollector.addRange( + ::basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange( maMoveEndArea ), + SpriteRedrawManager::SpriteInfo( + mpAffectedSprite, + maMoveEndArea, + true, + bIsPureMove ) ); + + // then, clear the old place (looks smoother + // this way) + rUpdateCollector.addRange( + ::basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange( maMoveStartArea ), + SpriteRedrawManager::SpriteInfo( + Sprite::Reference(), + maMoveStartArea, + true, + bIsPureMove ) ); + } + } + else if( mbIsGenericUpdate && + !maMoveEndArea.isEmpty() ) + { + rUpdateCollector.addRange( + ::basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange( maMoveEndArea ), + SpriteRedrawManager::SpriteInfo( + mpAffectedSprite, + maMoveEndArea, + true ) ); + } + } + + private: + Sprite::Reference mpAffectedSprite; + ::basegfx::B2DRectangle maMoveStartArea; + ::basegfx::B2DRectangle maMoveEndArea; + + /// True, if at least one move was encountered + bool mbIsMove; + + /// True, if at least one generic update was encountered + bool mbIsGenericUpdate; + }; + + + /** SpriteChecker functor, which for every sprite checks the + given update vector for necessary screen updates + */ + class SpriteUpdater + { + public: + /** Generate update area list + + @param rUpdater + Reference to an updater object, which will receive the + update areas. + + @param rChangeContainer + Container with all sprite change requests + + */ + SpriteUpdater( SpriteRedrawManager::SpriteConnectedRanges& rUpdater, + const SpriteRedrawManager::VectorOfChangeRecords& rChangeContainer ) : + mrUpdater( rUpdater ), + mrChangeContainer( rChangeContainer ) + { + } + + /** Call this method for every sprite on your screen + + This method scans the change container, collecting all + update info for the given sprite into one or two + update operations, which in turn are inserted into the + connected ranges processor. + + @param rSprite + Current sprite to collect update info for. + */ + void operator()( const Sprite::Reference& rSprite ) + { + const SpriteTracer aSpriteTracer( + ::std::for_each( mrChangeContainer.begin(), + mrChangeContainer.end(), + SpriteTracer( rSprite ) ) ); + + aSpriteTracer.commit( mrUpdater ); + } + + private: + SpriteRedrawManager::SpriteConnectedRanges& mrUpdater; + const SpriteRedrawManager::VectorOfChangeRecords& mrChangeContainer; + }; + } + + void SpriteRedrawManager::setupUpdateAreas( SpriteConnectedRanges& rUpdateAreas ) const + { + // TODO(T3): This is NOT thread safe at all. This only works + // under the assumption that NOBODY changes ANYTHING + // concurrently, while this method is on the stack. We should + // really rework the canvas::Sprite interface, in such a way + // that it dumps ALL its state with a single, atomic + // call. Then, we store that state locally. This prolly goes + // in line with the problem of having sprite state available + // for the frame before the last frame; plus, it avoids + // frequent locks of the object mutices + SpriteComparator aSpriteComparator; + + // put all sprites that have changed content into update areas + ListOfSprites::const_iterator aCurrSprite( maSprites.begin() ); + const ListOfSprites::const_iterator aEndSprite ( maSprites.end() ); + while( aCurrSprite != aEndSprite ) + { + if( (*aCurrSprite)->isContentChanged() ) + const_cast<SpriteRedrawManager*>(this)->updateSprite( *aCurrSprite, + (*aCurrSprite)->getPosPixel(), + (*aCurrSprite)->getUpdateArea() ); + ++aCurrSprite; + } + + // sort sprites after prio + VectorOfSprites aSortedSpriteVector; + ::std::copy( maSprites.begin(), + maSprites.end(), + ::std::back_insert_iterator< VectorOfSprites >(aSortedSpriteVector) ); + ::std::sort( aSortedSpriteVector.begin(), + aSortedSpriteVector.end(), + aSpriteComparator ); + + // extract all referenced sprites from the maChangeRecords + // (copy sprites, make the list unique, regarding the + // sprite pointer). This assumes that, until this scope + // ends, nobody changes the maChangeRecords vector! + VectorOfSprites aUpdatableSprites; + VectorOfChangeRecords::const_iterator aCurrRecord( maChangeRecords.begin() ); + const VectorOfChangeRecords::const_iterator aEndRecords( maChangeRecords.end() ); + while( aCurrRecord != aEndRecords ) + { + const Sprite::Reference& rSprite( aCurrRecord->getSprite() ); + if( rSprite.is() ) + aUpdatableSprites.push_back( rSprite ); + ++aCurrRecord; + } + + VectorOfSprites::iterator aBegin( aUpdatableSprites.begin() ); + VectorOfSprites::iterator aEnd ( aUpdatableSprites.end() ); + ::std::sort( aBegin, + aEnd, + aSpriteComparator ); + + aEnd = ::std::unique( aBegin, aEnd ); + + // for each unique sprite, check the change event vector, + // calculate the update operation from that, and add the + // result to the aUpdateArea. + ::std::for_each( aBegin, + aEnd, + SpriteUpdater( rUpdateAreas, + maChangeRecords) ); + + // TODO(P2): Implement your own output iterator adapter, to + // avoid that totally superfluous temp aUnchangedSprites + // vector. + + // add all sprites to rUpdateAreas, that are _not_ already + // contained in the uniquified vector of changed ones + // (i.e. the difference between aSortedSpriteVector and + // aUpdatableSprites). + VectorOfSprites aUnchangedSprites; + ::std::set_difference( aSortedSpriteVector.begin(), + aSortedSpriteVector.end(), + aBegin, aEnd, + ::std::back_insert_iterator< VectorOfSprites >(aUnchangedSprites) ); + + // add each remaining unchanged sprite to connected ranges, + // marked as "don't need update" + VectorOfSprites::const_iterator aCurr( aUnchangedSprites.begin() ); + const VectorOfSprites::const_iterator aEnd2( aUnchangedSprites.end() ); + while( aCurr != aEnd2 ) + { + const ::basegfx::B2DRange& rUpdateArea( (*aCurr)->getUpdateArea() ); + rUpdateAreas.addRange( + ::basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange( rUpdateArea ), + SpriteInfo(*aCurr, + rUpdateArea, + false) ); + ++aCurr; + } + } + +#if OSL_DEBUG_LEVEL > 0 + bool impIsEqualB2DRange(const basegfx::B2DRange& rRangeA, const basegfx::B2DRange& rRangeB, double fSmallValue) + { + return fabs(rRangeB.getMinX() - rRangeA.getMinX()) <= fSmallValue + && fabs(rRangeB.getMinY() - rRangeA.getMinY()) <= fSmallValue + && fabs(rRangeB.getMaxX() - rRangeA.getMaxX()) <= fSmallValue + && fabs(rRangeB.getMaxY() - rRangeA.getMaxY()) <= fSmallValue; + } + + bool impIsEqualB2DVector(const basegfx::B2DVector& rVecA, const basegfx::B2DVector& rVecB, double fSmallValue) + { + return fabs(rVecB.getX() - rVecA.getX()) <= fSmallValue + && fabs(rVecB.getY() - rVecA.getY()) <= fSmallValue; + } +#endif + + bool SpriteRedrawManager::isAreaUpdateScroll( ::basegfx::B2DRectangle& o_rMoveStart, + ::basegfx::B2DRectangle& o_rMoveEnd, + const UpdateArea& rUpdateArea, + ::std::size_t nNumSprites ) const + { + // check for a solitary move, which consists of exactly two + // pure-move entries, the first with valid, the second with + // invalid sprite (see SpriteTracer::commit()). Note that we + // cannot simply store some flag in SpriteTracer::commit() + // above and just check that here, since during the connected + // range calculations, other sprites might get merged into the + // same region (thus spoiling the scrolling move + // optimization). + if( nNumSprites != 2 ) + return false; + + const SpriteConnectedRanges::ComponentListType::const_iterator aFirst( + rUpdateArea.maComponentList.begin() ); + SpriteConnectedRanges::ComponentListType::const_iterator aSecond( + aFirst ); ++aSecond; + + if( !aFirst->second.isPureMove() || + !aSecond->second.isPureMove() || + !aFirst->second.getSprite().is() || + // use _true_ update area, not the rounded version + !aFirst->second.getSprite()->isAreaUpdateOpaque( aFirst->second.getUpdateArea() ) || + aSecond->second.getSprite().is() ) + { + // either no move update, or incorrect sprite, or sprite + // content not fully opaque over update region. + return false; + } + + o_rMoveStart = aSecond->second.getUpdateArea(); + o_rMoveEnd = aFirst->second.getUpdateArea(); + +#if OSL_DEBUG_LEVEL > 0 + ::basegfx::B2DRectangle aTotalBounds( o_rMoveStart ); + aTotalBounds.expand( o_rMoveEnd ); + + OSL_POSTCOND(impIsEqualB2DRange(rUpdateArea.maTotalBounds, basegfx::unotools::b2DSurroundingIntegerRangeFromB2DRange(aTotalBounds), 0.5), + "SpriteRedrawManager::isAreaUpdateScroll(): sprite area and total area mismatch"); + OSL_POSTCOND(impIsEqualB2DVector(o_rMoveStart.getRange(), o_rMoveEnd.getRange(), 0.5), + "SpriteRedrawManager::isAreaUpdateScroll(): scroll start and end area have mismatching size"); +#endif + + return true; + } + + bool SpriteRedrawManager::isAreaUpdateNotOpaque( const ::basegfx::B2DRectangle& rUpdateRect, + const AreaComponent& rComponent ) const + { + const Sprite::Reference& pAffectedSprite( rComponent.second.getSprite() ); + + if( !pAffectedSprite.is() ) + return true; // no sprite, no opaque update! + + return !pAffectedSprite->isAreaUpdateOpaque( rUpdateRect ); + } + + bool SpriteRedrawManager::isAreaUpdateOpaque( const UpdateArea& rUpdateArea, + ::std::size_t nNumSprites ) const + { + // check whether the sprites in the update area's list will + // fully cover the given area _and_ do that in an opaque way + // (i.e. no alpha, no non-rectangular sprite content). + + // TODO(P1): Come up with a smarter early-exit criterion here + // (though, I think, the case that _lots_ of sprites _fully_ + // cover a rectangular area _without_ any holes is extremely + // improbable) + + // avoid checking large number of sprites (and probably fail, + // anyway). Note: the case nNumSprites < 1 should normally not + // happen, as handleArea() calls backgroundPaint() then. + if( nNumSprites > 3 || nNumSprites < 1 ) + return false; + + const SpriteConnectedRanges::ComponentListType::const_iterator aBegin( + rUpdateArea.maComponentList.begin() ); + const SpriteConnectedRanges::ComponentListType::const_iterator aEnd( + rUpdateArea.maComponentList.end() ); + + // now, calc the _true_ update area, by merging all sprite's + // true update areas into one rectangle + ::basegfx::B2DRange aTrueArea( aBegin->second.getUpdateArea() ); + ::std::for_each( aBegin, + aEnd, + ::boost::bind( ::basegfx::B2DRangeExpander(aTrueArea), + ::boost::bind( &SpriteInfo::getUpdateArea, + ::boost::bind( ::std::select2nd<AreaComponent>(), + _1 ) ) ) ); + + // and check whether _any_ of the sprites tells that its area + // update will not be opaque. + return (::std::find_if( aBegin, + aEnd, + ::boost::bind( &SpriteRedrawManager::isAreaUpdateNotOpaque, + this, + ::boost::cref(aTrueArea), + _1 ) ) == aEnd ); + } + + bool SpriteRedrawManager::areSpritesChanged( const UpdateArea& rUpdateArea ) const + { + // check whether SpriteInfo::needsUpdate returns false for + // all elements of this area's contained sprites + // + // if not a single changed sprite found - just ignore this + // component (return false) + const SpriteConnectedRanges::ComponentListType::const_iterator aEnd( + rUpdateArea.maComponentList.end() ); + return (::std::find_if( rUpdateArea.maComponentList.begin(), + aEnd, + ::boost::bind( &SpriteInfo::needsUpdate, + ::boost::bind( + ::std::select2nd<SpriteConnectedRanges::ComponentType>(), + _1 ) ) ) != aEnd ); + } + + SpriteRedrawManager::SpriteRedrawManager() : + maSprites(), + maChangeRecords() + { + } + + void SpriteRedrawManager::disposing() + { + // drop all references + maChangeRecords.clear(); + + // dispose all sprites - the spritecanvas, and by delegation, + // this object, is the owner of the sprites. After all, a + // sprite without a canvas to render into makes not terribly + // much sense. + + // TODO(Q3): Once boost 1.33 is in, change back to for_each + // with ::boost::mem_fn. For the time being, explicit loop due + // to cdecl declaration of all UNO methods. + ListOfSprites::reverse_iterator aCurr( maSprites.rbegin() ); + ListOfSprites::reverse_iterator aEnd( maSprites.rend() ); + while( aCurr != aEnd ) + (*aCurr++)->dispose(); + + maSprites.clear(); + } + + void SpriteRedrawManager::clearChangeRecords() + { + maChangeRecords.clear(); + } + + void SpriteRedrawManager::showSprite( const Sprite::Reference& rSprite ) + { + maSprites.push_back( rSprite ); + } + + void SpriteRedrawManager::hideSprite( const Sprite::Reference& rSprite ) + { + maSprites.remove( rSprite ); + } + + void SpriteRedrawManager::moveSprite( const Sprite::Reference& rSprite, + const ::basegfx::B2DPoint& rOldPos, + const ::basegfx::B2DPoint& rNewPos, + const ::basegfx::B2DVector& rSpriteSize ) + { + maChangeRecords.push_back( SpriteChangeRecord( rSprite, + rOldPos, + rNewPos, + rSpriteSize ) ); + } + + void SpriteRedrawManager::updateSprite( const Sprite::Reference& rSprite, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rUpdateArea ) + { + maChangeRecords.push_back( SpriteChangeRecord( rSprite, + rPos, + rUpdateArea ) ); + } + +} diff --git a/canvas/source/tools/surface.cxx b/canvas/source/tools/surface.cxx new file mode 100644 index 000000000000..aaef28ba489f --- /dev/null +++ b/canvas/source/tools/surface.cxx @@ -0,0 +1,496 @@ +/************************************************************************* + * + * 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 "surface.hxx" +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <comphelper/scopeguard.hxx> +#include <boost/bind.hpp> + +namespace canvas +{ + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::Surface + ////////////////////////////////////////////////////////////////////////////////// + + Surface::Surface( const PageManagerSharedPtr& rPageManager, + const IColorBufferSharedPtr& rColorBuffer, + const ::basegfx::B2IPoint& rPos, + const ::basegfx::B2ISize& rSize ) : + mpColorBuffer(rColorBuffer), + mpPageManager(rPageManager), + mpFragment(), + maSourceOffset(rPos), + maSize(rSize), + mbIsDirty(true) + { + } + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::~Surface + ////////////////////////////////////////////////////////////////////////////////// + + Surface::~Surface() + { + if(mpFragment) + mpPageManager->free(mpFragment); + } + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::getUVCoords + ////////////////////////////////////////////////////////////////////////////////// + + void Surface::setColorBufferDirty() + { + mbIsDirty=true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::getUVCoords + ////////////////////////////////////////////////////////////////////////////////// + + basegfx::B2DRectangle Surface::getUVCoords() const + { + ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize()); + ::basegfx::B2IPoint aDestOffset; + if( mpFragment ) + aDestOffset = mpFragment->getPos(); + + const double pw( aPageSize.getX() ); + const double ph( aPageSize.getY() ); + const double ox( aDestOffset.getX() ); + const double oy( aDestOffset.getY() ); + const double sx( maSize.getX() ); + const double sy( maSize.getY() ); + + return ::basegfx::B2DRectangle( ox/pw, + oy/ph, + (ox+sx)/pw, + (oy+sy)/ph ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::getUVCoords + ////////////////////////////////////////////////////////////////////////////////// + + basegfx::B2DRectangle Surface::getUVCoords( const ::basegfx::B2IPoint& rPos, + const ::basegfx::B2ISize& rSize ) const + { + ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize()); + + const double pw( aPageSize.getX() ); + const double ph( aPageSize.getY() ); + const double ox( rPos.getX() ); + const double oy( rPos.getY() ); + const double sx( rSize.getX() ); + const double sy( rSize.getY() ); + + return ::basegfx::B2DRectangle( ox/pw, + oy/ph, + (ox+sx)/pw, + (oy+sy)/ph ); + } + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool Surface::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ) + { + IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule()); + + RenderModuleGuard aGuard( pRenderModule ); + + prepareRendering(); + + // convert size to normalized device coordinates + const ::basegfx::B2DRectangle& rUV( getUVCoords() ); + + const double u1(rUV.getMinX()); + const double v1(rUV.getMinY()); + const double u2(rUV.getMaxX()); + const double v2(rUV.getMaxY()); + + // concat transforms + // 1) offset of surface subarea + // 2) surface transform + // 3) translation to output position [rPos] + // 4) scale to normalized device coordinates + // 5) flip y-axis + // 6) translate to account for viewport transform + basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix( + maSourceOffset.getX(), maSourceOffset.getY())); + aTransform = aTransform * rTransform; + aTransform.translate(::basegfx::fround(rPos.getX()), + ::basegfx::fround(rPos.getY())); + + /* + ###################################### + ###################################### + ###################################### + + Y + ^+1 + | + 2 | 3 + x------------x + | | | + | | | + ------|-----O------|------>X + -1 | | | +1 + | | | + x------------x + 1 | 0 + | + |-1 + + ###################################### + ###################################### + ###################################### + */ + + const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(maSize.getX(),maSize.getY())); + const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0,maSize.getY())); + const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0,0.0)); + const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(maSize.getX(),0.0)); + + canvas::Vertex vertex; + vertex.r = 1.0f; + vertex.g = 1.0f; + vertex.b = 1.0f; + vertex.a = static_cast<float>(fAlpha); + vertex.z = 0.0f; + + { + pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD ); + + // issue an endPrimitive() when leaving the scope + const ::comphelper::ScopeGuard aScopeGuard( + boost::bind( &::canvas::IRenderModule::endPrimitive, + ::boost::ref(pRenderModule) ) ); + + vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2); + vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY()); + pRenderModule->pushVertex(vertex); + + vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2); + vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY()); + pRenderModule->pushVertex(vertex); + + vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1); + vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY()); + pRenderModule->pushVertex(vertex); + + vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1); + vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY()); + pRenderModule->pushVertex(vertex); + } + + return !(pRenderModule->isError()); + } + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::drawRectangularArea + ////////////////////////////////////////////////////////////////////////////////// + + bool Surface::drawRectangularArea( + double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRectangle& rArea, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( rArea.isEmpty() ) + return true; // immediate exit for empty area + + IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule()); + + RenderModuleGuard aGuard( pRenderModule ); + + prepareRendering(); + + // these positions are relative to the texture + ::basegfx::B2IPoint aPos1( + ::basegfx::fround(rArea.getMinimum().getX()), + ::basegfx::fround(rArea.getMinimum().getY())); + ::basegfx::B2IPoint aPos2( + ::basegfx::fround(rArea.getMaximum().getX()), + ::basegfx::fround(rArea.getMaximum().getY()) ); + + // clip the positions to the area this surface covers + aPos1.setX(::std::max(aPos1.getX(),maSourceOffset.getX())); + aPos1.setY(::std::max(aPos1.getY(),maSourceOffset.getY())); + aPos2.setX(::std::min(aPos2.getX(),maSourceOffset.getX()+maSize.getX())); + aPos2.setY(::std::min(aPos2.getY(),maSourceOffset.getY()+maSize.getY())); + + // if the resulting area is empty, return immediately + ::basegfx::B2IVector aSize(aPos2 - aPos1); + if(aSize.getX() <= 0 || aSize.getY() <= 0) + return true; + + ::basegfx::B2IPoint aDestOffset; + if( mpFragment ) + aDestOffset = mpFragment->getPos(); + + // convert size to normalized device coordinates + const ::basegfx::B2DRectangle& rUV( + getUVCoords(aPos1 - maSourceOffset + aDestOffset, + aSize) ); + const double u1(rUV.getMinX()); + const double v1(rUV.getMinY()); + const double u2(rUV.getMaxX()); + const double v2(rUV.getMaxY()); + + // concatenate transforms + // 1) offset of surface subarea + // 2) surface transform + // 3) translation to output position [rPos] + basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(aPos1.getX(), aPos1.getY())); + aTransform = aTransform * rTransform; + aTransform.translate(::basegfx::fround(rPos.getX()), + ::basegfx::fround(rPos.getY())); + + + /* + ###################################### + ###################################### + ###################################### + + Y + ^+1 + | + 2 | 3 + x------------x + | | | + | | | + ------|-----O------|------>X + -1 | | | +1 + | | | + x------------x + 1 | 0 + | + |-1 + + ###################################### + ###################################### + ###################################### + */ + + const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(aSize.getX(),aSize.getY())); + const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0, aSize.getY())); + const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0, 0.0)); + const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(aSize.getX(),0.0)); + + canvas::Vertex vertex; + vertex.r = 1.0f; + vertex.g = 1.0f; + vertex.b = 1.0f; + vertex.a = static_cast<float>(fAlpha); + vertex.z = 0.0f; + + { + pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD ); + + // issue an endPrimitive() when leaving the scope + const ::comphelper::ScopeGuard aScopeGuard( + boost::bind( &::canvas::IRenderModule::endPrimitive, + ::boost::ref(pRenderModule) ) ); + + vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2); + vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY()); + pRenderModule->pushVertex(vertex); + + vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2); + vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY()); + pRenderModule->pushVertex(vertex); + + vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1); + vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY()); + pRenderModule->pushVertex(vertex); + + vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1); + vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY()); + pRenderModule->pushVertex(vertex); + } + + return !(pRenderModule->isError()); + } + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::drawWithClip + ////////////////////////////////////////////////////////////////////////////////// + + bool Surface::drawWithClip( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ) + { + IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule()); + + RenderModuleGuard aGuard( pRenderModule ); + + prepareRendering(); + + // untransformed surface rectangle, relative to the whole + // image (note: this surface might actually only be a tile of + // the whole image, with non-zero maSourceOffset) + const double x1(maSourceOffset.getX()); + const double y1(maSourceOffset.getY()); + const double w(maSize.getX()); + const double h(maSize.getY()); + const double x2(x1+w); + const double y2(y1+h); + const ::basegfx::B2DRectangle aSurfaceClipRect(x1,y1,x2,y2); + + // concatenate transforms + // we use 'fround' here to avoid rounding errors. the vertices will + // be transformed by the overall transform and uv coordinates will + // be calculated from the result, and this is why we need to use + // integer coordinates here... + basegfx::B2DHomMatrix aTransform; + aTransform = aTransform * rTransform; + aTransform.translate(::basegfx::fround(rPos.getX()), + ::basegfx::fround(rPos.getY())); + + /* + ###################################### + ###################################### + ###################################### + + Y + ^+1 + | + 2 | 3 + x------------x + | | | + | | | + ------|-----O------|------>X + -1 | | | +1 + | | | + x------------x + 1 | 0 + | + |-1 + + ###################################### + ###################################### + ###################################### + */ + + // uv coordinates that map the surface rectangle + // to the destination rectangle. + const ::basegfx::B2DRectangle& rUV( getUVCoords() ); + + basegfx::B2DPolygon rTriangleList(basegfx::tools::clipTriangleListOnRange(rClipPoly, + aSurfaceClipRect)); + + // Push vertices to backend renderer + if(const sal_uInt32 nVertexCount = rTriangleList.count()) + { + canvas::Vertex vertex; + vertex.r = 1.0f; + vertex.g = 1.0f; + vertex.b = 1.0f; + vertex.a = static_cast<float>(fAlpha); + vertex.z = 0.0f; + +#if defined(TRIANGLE_LOG) && defined(DBG_UTIL) + OSL_TRACE( "Surface::draw(): numvertices %d numtriangles %d\n", + nVertexCount, + nVertexCount/3 ); +#endif + + pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_TRIANGLE ); + + // issue an endPrimitive() when leaving the scope + const ::comphelper::ScopeGuard aScopeGuard( + boost::bind( &::canvas::IRenderModule::endPrimitive, + ::boost::ref(pRenderModule) ) ); + + for(sal_uInt32 nIndex=0; nIndex<nVertexCount; ++nIndex) + { + const basegfx::B2DPoint &aPoint = rTriangleList.getB2DPoint(nIndex); + basegfx::B2DPoint aTransformedPoint(aTransform * aPoint); + const double tu(((aPoint.getX()-aSurfaceClipRect.getMinX())*rUV.getWidth()/w)+rUV.getMinX()); + const double tv(((aPoint.getY()-aSurfaceClipRect.getMinY())*rUV.getHeight()/h)+rUV.getMinY()); + vertex.u=static_cast<float>(tu); + vertex.v=static_cast<float>(tv); + vertex.x=static_cast<float>(aTransformedPoint.getX()); + vertex.y=static_cast<float>(aTransformedPoint.getY()); + pRenderModule->pushVertex(vertex); + } + } + + return !(pRenderModule->isError()); + } + + ////////////////////////////////////////////////////////////////////////////////// + // Surface::prepareRendering + ////////////////////////////////////////////////////////////////////////////////// + + void Surface::prepareRendering() + { + mpPageManager->validatePages(); + + // clients requested to draw from this surface, therefore one + // of the above implemented concrete rendering operations + // was triggered. we therefore need to ask the pagemanager + // to allocate some space for the fragment we're dedicated to. + if(!(mpFragment)) + { + mpFragment = mpPageManager->allocateSpace(maSize); + if( mpFragment ) + { + mpFragment->setColorBuffer(mpColorBuffer); + mpFragment->setSourceOffset(maSourceOffset); + } + } + + if( mpFragment ) + { + // now we need to 'select' the fragment, which will in turn + // pull informations from the image on demand. + // in case this fragment is still not located on any of the + // available pages ['naked'], we force the page manager to + // do it now, no way to defer this any longer... + if(!(mpFragment->select(mbIsDirty))) + mpPageManager->nakedFragment(mpFragment); + + } + mbIsDirty=false; + } + + ////////////////////////////////////////////////////////////////////////////////// + // End of file + ////////////////////////////////////////////////////////////////////////////////// +} + diff --git a/canvas/source/tools/surface.hxx b/canvas/source/tools/surface.hxx new file mode 100644 index 000000000000..9acda579803a --- /dev/null +++ b/canvas/source/tools/surface.hxx @@ -0,0 +1,162 @@ +/************************************************************************* + * + * 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 INCLUDED_CANVAS_SURFACE_HXX +#define INCLUDED_CANVAS_SURFACE_HXX + +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <canvas/rendering/irendermodule.hxx> +#include <canvas/rendering/icolorbuffer.hxx> +#include <canvas/rendering/isurface.hxx> + +#include "surfacerect.hxx" +#include "pagemanager.hxx" + +namespace canvas +{ + ////////////////////////////////////////////////////////////////////////////////// + // Surface + ////////////////////////////////////////////////////////////////////////////////// + + /** surfaces denote occupied areas withing pages. + + pages encapsulate the hardware buffers that + contain image data which can be used for texturing. + surfaces are areas within those pages. + */ + class Surface + { + public: + + Surface( const PageManagerSharedPtr& rPageManager, + const IColorBufferSharedPtr& rColorBuffer, + const ::basegfx::B2IPoint& rPos, + const ::basegfx::B2ISize& rSize ); + ~Surface(); + + void setColorBufferDirty(); + + /** Render the surface content to screen. + + @param fAlpha + Overall alpha for content + + @param rPos + Output position + + @param rTransform + Output transformation (does not affect output position) + */ + bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ); + + /** Render the surface content to screen. + + @param fAlpha + Overall alpha for content + + @param rPos + Output position + + @param rArea + Subset of the surface to render. Coordinate system are + surface area pixel, given area will be clipped to the + surface bounds. + + @param rTransform + Output transformation (does not affect output position) + */ + bool drawRectangularArea( + double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ); + + /** Render the surface content to screen. + + @param fAlpha + Overall alpha for content + + @param rPos + Output position + + @param rClipPoly + Clip polygon for the surface. The clip polygon is also + subject to the output transformation. + + @param rTransform + Output transformation (does not affect output position) + */ + bool drawWithClip( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ); + + // private attributes + private: + IColorBufferSharedPtr mpColorBuffer; + + // invoking any of the above defined 'draw' methods + // will forward primitive commands to the rendermodule. + PageManagerSharedPtr mpPageManager; + + FragmentSharedPtr mpFragment; + + // the offset of this surface with regard to the source + // image. if the source image had to be tiled into multiple + // surfaces, this offset denotes the relative pixel distance + // from the source image's upper, left corner + ::basegfx::B2IPoint maSourceOffset; + + // the size in pixels of this surface. please note that + // this size is likely to be smaller than the size of + // the colorbuffer we're associated with since we + // maybe represent only a part of it. + ::basegfx::B2ISize maSize; + + bool mbIsDirty; + + // private methods + private: + bool refresh( canvas::IColorBuffer& rBuffer ) const; + void prepareRendering(); + + basegfx::B2DRectangle getUVCoords() const; + basegfx::B2DRectangle getUVCoords( const ::basegfx::B2IPoint& rPos, + const ::basegfx::B2ISize& rSize ) const; + }; + + typedef ::boost::shared_ptr< Surface > SurfaceSharedPtr; +} + +#endif diff --git a/canvas/source/tools/surfaceproxy.cxx b/canvas/source/tools/surfaceproxy.cxx new file mode 100644 index 000000000000..f4c31d4a2dc6 --- /dev/null +++ b/canvas/source/tools/surfaceproxy.cxx @@ -0,0 +1,182 @@ +/************************************************************************* + * + * 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 <boost/bind.hpp> +#include <basegfx/polygon/b2dpolygoncutandtouch.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include "surfaceproxy.hxx" + +namespace canvas +{ + ////////////////////////////////////////////////////////////////////////////////// + // SurfaceProxy::SurfaceProxy + ////////////////////////////////////////////////////////////////////////////////// + + SurfaceProxy::SurfaceProxy( const canvas::IColorBufferSharedPtr& pBuffer, + const PageManagerSharedPtr& pPageManager ) : + mpPageManager( pPageManager ), + maSurfaceList(), + mpBuffer( pBuffer ) + { + const ::basegfx::B2ISize aImageSize(mpBuffer->getWidth(),mpBuffer->getHeight()); + const ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize()); + const sal_Int32 aPageSizeX(aPageSize.getX()); + const sal_Int32 aPageSizeY(aPageSize.getY()); + const sal_Int32 aImageSizeX(aImageSize.getX()); + const sal_Int32 aImageSizeY(aImageSize.getY()); + + // see if the size of the colorbuffer is larger than the size + // of a single page. if this is the case we divide the + // colorbuffer into as many surfaces as we need to get the + // whole area distributed. otherwise (the colorbuffer is + // smaller than the size of a single page) we search for free + // pages or create a new one. + // the incoming image is too large to fit into a single + // page. strategy: we split the image into rectangular + // areas that are as large as the maximum page size + // dictates and follow the strategy for fitting images. + size_t dwNumSurfaces(0); + for(sal_Int32 y=0; y<aImageSizeY; y+=aPageSizeY) + for(sal_Int32 x=0; x<aImageSizeX; x+=aPageSizeX) + ++dwNumSurfaces; + maSurfaceList.reserve(dwNumSurfaces); + + for(sal_Int32 y=0; y<aImageSizeY; y+=aPageSizeY) + { + for(sal_Int32 x=0; x<aImageSizeX; x+=aPageSizeX) + { + // the current surface is located at the position [x,y] + // and has the size [min(restx,pagesizex),min(resty,pagesizey) + ::basegfx::B2IPoint aOffset(x,y); + ::basegfx::B2ISize aSize( ::std::min( aImageSize.getX()-x, + aPageSize.getX() ), + ::std::min( aImageSize.getY()-y, + aPageSize.getY() ) ); + + maSurfaceList.push_back( + SurfaceSharedPtr( + new Surface( + mpPageManager, + mpBuffer, + aOffset, + aSize))); + } + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // SurfaceProxy::setColorBufferDirty + ////////////////////////////////////////////////////////////////////////////////// + + void SurfaceProxy::setColorBufferDirty() + { + ::std::for_each( maSurfaceList.begin(), + maSurfaceList.end(), + ::boost::mem_fn(&Surface::setColorBufferDirty)); + } + + ////////////////////////////////////////////////////////////////////////////////// + // SurfaceProxy::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool SurfaceProxy::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ) + { + ::std::for_each( maSurfaceList.begin(), + maSurfaceList.end(), + ::boost::bind( &Surface::draw, + _1, + fAlpha, + ::boost::cref(rPos), + ::boost::cref(rTransform))); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // SurfaceProxy::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool SurfaceProxy::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ) + { + ::std::for_each( maSurfaceList.begin(), + maSurfaceList.end(), + ::boost::bind(&Surface::drawRectangularArea, + _1, + fAlpha, + ::boost::cref(rPos), + ::boost::cref(rArea), + ::boost::cref(rTransform))); + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////// + // SurfaceProxy::draw + ////////////////////////////////////////////////////////////////////////////////// + + bool SurfaceProxy::draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolyPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ) + { + const ::basegfx::B2DPolygon& rTriangulatedPolygon( + ::basegfx::triangulator::triangulate(rClipPoly)); + +#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 + // dump polygons + OSL_TRACE( "Original clip polygon: %s\n" + "Triangulated polygon: %s\n", + rtl::OUStringToOString( + basegfx::tools::exportToSvgD( rClipPoly ), + RTL_TEXTENCODING_ASCII_US).getStr(), + rtl::OUStringToOString( + basegfx::tools::exportToSvgD( + basegfx::B2DPolyPolygon(rTriangulatedPolygon) ), + RTL_TEXTENCODING_ASCII_US).getStr() ); +#endif + + ::std::for_each( maSurfaceList.begin(), + maSurfaceList.end(), + ::boost::bind(&Surface::drawWithClip, + _1, + fAlpha, + ::boost::cref(rPos), + ::boost::cref(rTriangulatedPolygon), + ::boost::cref(rTransform))); + + return true; + } +} diff --git a/canvas/source/tools/surfaceproxy.hxx b/canvas/source/tools/surfaceproxy.hxx new file mode 100644 index 000000000000..7e42096c541b --- /dev/null +++ b/canvas/source/tools/surfaceproxy.hxx @@ -0,0 +1,134 @@ +/************************************************************************* + * + * 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 INCLUDED_CANVAS_SURFACEPROXY_HXX +#define INCLUDED_CANVAS_SURFACEPROXY_HXX + +#include <canvas/rendering/isurfaceproxy.hxx> +#include <canvas/rendering/icolorbuffer.hxx> + +#include "pagemanager.hxx" +#include "surface.hxx" + +namespace canvas +{ + + ////////////////////////////////////////////////////////////////////////////////// + // SurfaceProxy + ////////////////////////////////////////////////////////////////////////////////// + + /** Definition of the surface proxy class. + + Surface proxies are the connection between *one* source image + and *one or more* hardware surfaces (or textures). in a + logical structure surface proxies represent soley this + dependeny plus some simple cache management. + */ + class SurfaceProxy : public ISurfaceProxy + { + public: + + SurfaceProxy( const canvas::IColorBufferSharedPtr& pBuffer, + const PageManagerSharedPtr &pPageManager ); + + // ISurfaceProxy interface + virtual void setColorBufferDirty(); + + /** Render the surface content to screen. + + @param fAlpha + Overall alpha for content + + @param rPos + Output position + + @param rTransform + Output transformation (does not affect output position) + */ + virtual bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DHomMatrix& rTransform ); + + /** Render the surface content to screen. + + @param fAlpha + Overall alpha for content + + @param rPos + Output position + + @param rArea + Subset of the surface to render. Coordinate system are + surface area pixel, given area will be clipped to the + surface bounds. + + @param rTransform + Output transformation (does not affect output position) + */ + virtual bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DRange& rArea, + const ::basegfx::B2DHomMatrix& rTransform ); + + /** Render the surface content to screen. + + @param fAlpha + Overall alpha for content + + @param rPos + Output position + + @param rClipPoly + Clip polygon for the surface. The clip polygon is also + subject to the output transformation. + + @param rTransform + Output transformation (does not affect output position) + */ + virtual bool draw( double fAlpha, + const ::basegfx::B2DPoint& rPos, + const ::basegfx::B2DPolyPolygon& rClipPoly, + const ::basegfx::B2DHomMatrix& rTransform ); + + private: + PageManagerSharedPtr mpPageManager; + + // the pagemanager will distribute the image + // to one or more surfaces, this is why we + // need a list here. + std::vector<SurfaceSharedPtr> maSurfaceList; + + // pointer to the source of image data + // which always is stored in system memory, + // 32bit rgba and can have any size. + canvas::IColorBufferSharedPtr mpBuffer; + }; + + typedef ::boost::shared_ptr< SurfaceProxy > SurfaceProxySharedPtr; +} + +#endif diff --git a/canvas/source/tools/surfaceproxymanager.cxx b/canvas/source/tools/surfaceproxymanager.cxx new file mode 100644 index 000000000000..dcc2ff574b57 --- /dev/null +++ b/canvas/source/tools/surfaceproxymanager.cxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * 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/rendering/isurfaceproxymanager.hxx> +#include <canvas/rendering/isurfaceproxy.hxx> +#include "surfaceproxy.hxx" + +namespace canvas +{ + + ////////////////////////////////////////////////////////////////////////////////// + // SurfaceProxyManager + ////////////////////////////////////////////////////////////////////////////////// + + class SurfaceProxyManager : public ISurfaceProxyManager + { + public: + + SurfaceProxyManager( const IRenderModuleSharedPtr pRenderModule ) : + mpPageManager( new PageManager(pRenderModule) ) + { + } + + /** the whole idea is build around the concept that you create + some arbitrary buffer which contains the image data and + tell the texture manager about it. from there on you can + draw this image using any kind of graphics api you want. + in the technical sense we allocate some space in local + videomemory or AGP memory which will be filled on demand, + which means if there exists any rendering operation that + needs to read from this memory location. this method + creates a logical hardware surface object which uses the + given color buffer as the image source. internally this + texture may be distributed to several real hardware + surfaces. + */ + virtual ISurfaceProxySharedPtr createSurfaceProxy( const IColorBufferSharedPtr& pBuffer ) const + { + // not much to do for now, simply allocate a new surface + // proxy from our internal pool and initialize this thing + // properly. we *don't* create a hardware surface for now. + return SurfaceProxySharedPtr(new SurfaceProxy(pBuffer,mpPageManager)); + } + + private: + PageManagerSharedPtr mpPageManager; + }; + + ////////////////////////////////////////////////////////////////////////////////// + // createSurfaceProxyManager + ////////////////////////////////////////////////////////////////////////////////// + + ISurfaceProxyManagerSharedPtr createSurfaceProxyManager( const IRenderModuleSharedPtr& rRenderModule ) + { + return ISurfaceProxyManagerSharedPtr( + new SurfaceProxyManager( + rRenderModule)); + } +} diff --git a/canvas/source/tools/surfacerect.hxx b/canvas/source/tools/surfacerect.hxx new file mode 100644 index 000000000000..cbeaa5e144d7 --- /dev/null +++ b/canvas/source/tools/surfacerect.hxx @@ -0,0 +1,135 @@ +/************************************************************************* + * + * 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 INCLUDED_CANVAS_SURFACERECT_HXX +#define INCLUDED_CANVAS_SURFACERECT_HXX + +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/vector/b2isize.hxx> + +namespace canvas +{ + ////////////////////////////////////////////////////////////////////////////////// + // SurfaceRect + ////////////////////////////////////////////////////////////////////////////////// + + struct SurfaceRect + { + ::basegfx::B2IPoint maPos; + ::basegfx::B2ISize maSize; + ::basegfx::B2IPoint maBackup; + bool bEnabled; + + explicit SurfaceRect( const ::basegfx::B2ISize &rSize ) : + maPos(), + maSize(rSize), + maBackup(), + bEnabled(true) + { + } + + // coordinates contained in this rectangle are + // constrained to the following rules: + // 1) p.x >= pos.x + // 2) p.x <= pos.x+size.x + // 3) p.y >= pos.y + // 4) p.y <= pos.y+size.y + // in other words, 'size' means the number of pixels + // this rectangle encloses plus one. for example with pos[0,0] + // and size[512,512], p[512,512] would return inside. + // a size of [0,0] therefore denotes a one-by-one rectangle. + bool pointInside( sal_Int32 px, sal_Int32 py ) const + { + const sal_Int32 x1(maPos.getX()); + const sal_Int32 y1(maPos.getY()); + const sal_Int32 x2(maPos.getX()+maSize.getX()); + const sal_Int32 y2(maPos.getY()+maSize.getY()); + if(px < x1) return false; + if(px >= x2) return false; + if(py < y1) return false; + if(py >= y2) return false; + return true; + } + + // returns true if the horizontal line intersects the rect. + bool hLineIntersect( sal_Int32 lx1, sal_Int32 lx2, sal_Int32 ly ) const + { + const sal_Int32 x1(maPos.getX()); + const sal_Int32 y1(maPos.getY()); + const sal_Int32 x2(maPos.getX()+maSize.getX()); + const sal_Int32 y2(maPos.getY()+maSize.getY()); + if(ly < y1) return false; + if(ly >= y2) return false; + if((lx1 < x1) && (lx2 < x1)) return false; + if((lx1 >= x2) && (lx2 >= x2)) return false; + return true; + } + + //! Returns true if the vertical line intersects the rect. + bool vLineIntersect( sal_Int32 lx, sal_Int32 ly1, sal_Int32 ly2 ) const + { + const sal_Int32 x1(maPos.getX()); + const sal_Int32 y1(maPos.getY()); + const sal_Int32 x2(maPos.getX()+maSize.getX()); + const sal_Int32 y2(maPos.getY()+maSize.getY()); + if(lx < x1) return false; + if(lx >= x2) return false; + if((ly1 < y1) && (ly2 < y1)) return false; + if((ly1 >= y2) && (ly2 >= y2)) return false; + return true; + } + + // returns true if the passed rect intersects this one. + bool intersection( const SurfaceRect& r ) const + { + const sal_Int32 x1(maPos.getX()); + const sal_Int32 y1(maPos.getY()); + const sal_Int32 x2(maPos.getX()+maSize.getX()); + const sal_Int32 y2(maPos.getY()+maSize.getY()); + if(r.hLineIntersect(x1,x2,y1)) return true; + if(r.hLineIntersect(x1,x2,y2)) return true; + if(r.vLineIntersect(x1,y1,y2)) return true; + if(r.vLineIntersect(x2,y1,y2)) return true; + return false; + } + + bool inside( const SurfaceRect& r ) const + { + const sal_Int32 x1(maPos.getX()); + const sal_Int32 y1(maPos.getY()); + const sal_Int32 x2(maPos.getX()+maSize.getX()); + const sal_Int32 y2(maPos.getY()+maSize.getY()); + if(!(r.pointInside(x1,y1))) return false; + if(!(r.pointInside(x2,y1))) return false; + if(!(r.pointInside(x2,y2))) return false; + if(!(r.pointInside(x1,y2))) return false; + return true; + } + }; +} + +#endif diff --git a/canvas/source/tools/verifyinput.cxx b/canvas/source/tools/verifyinput.cxx new file mode 100644 index 000000000000..42ab1c7aee19 --- /dev/null +++ b/canvas/source/tools/verifyinput.cxx @@ -0,0 +1,926 @@ +/************************************************************************* + * + * 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 <com/sun/star/geometry/AffineMatrix2D.hpp> +#include <com/sun/star/geometry/Matrix2D.hpp> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/geometry/RealSize2D.hpp> +#include <com/sun/star/geometry/IntegerPoint2D.hpp> +#include <com/sun/star/geometry/IntegerSize2D.hpp> +#include <com/sun/star/geometry/RealRectangle2D.hpp> +#include <com/sun/star/geometry/RealBezierSegment2D.hpp> +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/ViewState.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/util/Endianness.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> +#include <com/sun/star/rendering/IntegerBitmapLayout.hpp> +#include <com/sun/star/rendering/FloatingPointBitmapFormat.hpp> +#include <com/sun/star/rendering/FloatingPointBitmapLayout.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> + +#include <canvas/verifyinput.hxx> +#include <canvas/canvastools.hxx> + + +using namespace ::com::sun::star; + +namespace canvas +{ + namespace tools + { + void verifyInput( const geometry::RealPoint2D& rPoint, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + (void)pStr; (void)xIf; (void)nArgPos; + +#if OSL_DEBUG_LEVEL > 0 + if( !::rtl::math::isFinite( rPoint.X ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): point X value contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rPoint.Y ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): point X value contains infinite or NAN"), + xIf, + nArgPos ); + } +#else + if( !::rtl::math::isFinite( rPoint.X ) || + !::rtl::math::isFinite( rPoint.Y ) ) + { + throw lang::IllegalArgumentException(); + } +#endif + } + + void verifyInput( const geometry::RealSize2D& rSize, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + (void)pStr; (void)xIf; (void)nArgPos; + +#if OSL_DEBUG_LEVEL > 0 + if( !::rtl::math::isFinite( rSize.Width ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): size.Width value contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rSize.Height ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): size.Height value contains infinite or NAN"), + xIf, + nArgPos ); + } +#else + if( !::rtl::math::isFinite( rSize.Width ) || + !::rtl::math::isFinite( rSize.Height ) ) + { + throw lang::IllegalArgumentException(); + } +#endif + } + + void verifyInput( const geometry::RealBezierSegment2D& rSegment, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + (void)pStr; (void)xIf; (void)nArgPos; + +#if OSL_DEBUG_LEVEL > 0 + if( !::rtl::math::isFinite( rSegment.Px ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's Px value contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rSegment.Py ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's Py value contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rSegment.C1x ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's C1x value contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rSegment.C1y ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's C1y value contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rSegment.C2x ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's C2x value contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rSegment.C2y ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bezier segment's C2y value contains infinite or NAN"), + xIf, + nArgPos ); + } +#else + if( !::rtl::math::isFinite( rSegment.Px ) || + !::rtl::math::isFinite( rSegment.Py ) || + !::rtl::math::isFinite( rSegment.C1x ) || + !::rtl::math::isFinite( rSegment.C1y ) || + !::rtl::math::isFinite( rSegment.C2x ) || + !::rtl::math::isFinite( rSegment.C2y ) ) + { + throw lang::IllegalArgumentException(); + } +#endif + } + + void verifyInput( const geometry::RealRectangle2D& rRect, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + (void)pStr; (void)xIf; (void)nArgPos; + +#if OSL_DEBUG_LEVEL > 0 + if( !::rtl::math::isFinite( rRect.X1 ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): rectangle point X1 contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rRect.Y1 ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): rectangle point Y1 contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rRect.X2 ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): rectangle point X2 contains infinite or NAN"), + xIf, + nArgPos ); + } + + if( !::rtl::math::isFinite( rRect.Y2 ) ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): rectangle point Y2 contains infinite or NAN"), + xIf, + nArgPos ); + } +#else + if( !::rtl::math::isFinite( rRect.X1 ) || + !::rtl::math::isFinite( rRect.Y1 ) || + !::rtl::math::isFinite( rRect.X2 ) || + !::rtl::math::isFinite( rRect.Y2 ) ) + { + throw lang::IllegalArgumentException(); + } +#endif + } + + void verifyInput( const geometry::AffineMatrix2D& matrix, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + (void)pStr; (void)xIf; (void)nArgPos; + +#if OSL_DEBUG_LEVEL > 0 + const sal_Int32 nBinaryState( + 100000 * !::rtl::math::isFinite( matrix.m00 ) + + 10000 * !::rtl::math::isFinite( matrix.m01 ) + + 1000 * !::rtl::math::isFinite( matrix.m02 ) + + 100 * !::rtl::math::isFinite( matrix.m10 ) + + 10 * !::rtl::math::isFinite( matrix.m11 ) + + 1 * !::rtl::math::isFinite( matrix.m12 ) ); + + if( nBinaryState ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): AffineMatrix2D contains infinite or NAN value(s) at the following positions (m00-m12): ") + + ::rtl::OUString::valueOf(nBinaryState), + xIf, + nArgPos ); + } +#else + if( !::rtl::math::isFinite( matrix.m00 ) || + !::rtl::math::isFinite( matrix.m01 ) || + !::rtl::math::isFinite( matrix.m02 ) || + !::rtl::math::isFinite( matrix.m10 ) || + !::rtl::math::isFinite( matrix.m11 ) || + !::rtl::math::isFinite( matrix.m12 ) ) + { + throw lang::IllegalArgumentException(); + } +#endif + } + + void verifyInput( const geometry::Matrix2D& matrix, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + (void)pStr; (void)xIf; (void)nArgPos; + +#if OSL_DEBUG_LEVEL > 0 + const sal_Int32 nBinaryState( + 1000 * !::rtl::math::isFinite( matrix.m00 ) + + 100 * !::rtl::math::isFinite( matrix.m01 ) + + 10 * !::rtl::math::isFinite( matrix.m10 ) + + 1 * !::rtl::math::isFinite( matrix.m11 ) ); + + if( nBinaryState ) + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): Matrix2D contains infinite or NAN value(s) at the following positions (m00-m11): ") + + ::rtl::OUString::valueOf(nBinaryState), + xIf, + nArgPos ); + } +#else + if( !::rtl::math::isFinite( matrix.m00 ) || + !::rtl::math::isFinite( matrix.m01 ) || + !::rtl::math::isFinite( matrix.m10 ) || + !::rtl::math::isFinite( matrix.m11 ) ) + { + throw lang::IllegalArgumentException(); + } +#endif + } + + void verifyInput( const rendering::ViewState& viewState, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + verifyInput( viewState.AffineTransform, + pStr, xIf, nArgPos ); + } + + void verifyInput( const rendering::RenderState& renderState, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos, + sal_Int32 nMinColorComponents ) + { + verifyInput( renderState.AffineTransform, + pStr, xIf, nArgPos ); + + if( renderState.DeviceColor.getLength() < nMinColorComponents ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): render state's device color has too few components (") + + ::rtl::OUString::valueOf(nMinColorComponents) + + ::rtl::OUString::createFromAscii(" expected, ") + + ::rtl::OUString::valueOf(renderState.DeviceColor.getLength()) + + ::rtl::OUString::createFromAscii(" provided)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( renderState.CompositeOperation < rendering::CompositeOperation::CLEAR || + renderState.CompositeOperation > rendering::CompositeOperation::SATURATE ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): render state's CompositeOperation value out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(renderState.CompositeOperation)) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + + void verifyInput( const rendering::Texture& texture, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + verifyInput( texture.AffineTransform, + pStr, xIf, nArgPos ); + + if( !::rtl::math::isFinite( texture.Alpha ) || + texture.Alpha < 0.0 || + texture.Alpha > 1.0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): textures' alpha value out of range (is ") + + ::rtl::OUString::valueOf(texture.Alpha) + + ::rtl::OUString::createFromAscii(")"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( texture.NumberOfHatchPolygons < 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): textures' NumberOfHatchPolygons is negative"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( texture.RepeatModeX < rendering::TexturingMode::NONE || + texture.RepeatModeX > rendering::TexturingMode::REPEAT ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): textures' RepeatModeX value is out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(texture.RepeatModeX)) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( texture.RepeatModeY < rendering::TexturingMode::NONE || + texture.RepeatModeY > rendering::TexturingMode::REPEAT ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): textures' RepeatModeY value is out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(texture.RepeatModeY)) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + + namespace + { + struct VerifyDashValue + { + VerifyDashValue( const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) : + mpStr( pStr ), + mrIf( xIf ), + mnArgPos( nArgPos ) + { + } + + void operator()( const double& rVal ) + { + if( !::rtl::math::isFinite( rVal ) || rVal < 0.0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(mpStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): one of stroke attributes' DashArray value out of range (is ") + + ::rtl::OUString::valueOf(rVal) + + ::rtl::OUString::createFromAscii(")"), + mrIf, + mnArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + + const char* mpStr; + const uno::Reference< uno::XInterface >& mrIf; + sal_Int16 mnArgPos; + }; + } + + void verifyInput( const rendering::StrokeAttributes& strokeAttributes, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + if( !::rtl::math::isFinite( strokeAttributes.StrokeWidth ) || + strokeAttributes.StrokeWidth < 0.0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' StrokeWidth value out of range (is ") + + ::rtl::OUString::valueOf(strokeAttributes.StrokeWidth) + + ::rtl::OUString::createFromAscii(")"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( !::rtl::math::isFinite( strokeAttributes.MiterLimit ) || + strokeAttributes.MiterLimit < 0.0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' MiterLimit value out of range (is ") + + ::rtl::OUString::valueOf(strokeAttributes.MiterLimit) + + ::rtl::OUString::createFromAscii(")"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + ::std::for_each( strokeAttributes.DashArray.getConstArray(), + strokeAttributes.DashArray.getConstArray() + strokeAttributes.DashArray.getLength(), + VerifyDashValue( pStr, xIf, nArgPos ) ); + + ::std::for_each( strokeAttributes.LineArray.getConstArray(), + strokeAttributes.LineArray.getConstArray() + strokeAttributes.LineArray.getLength(), + VerifyDashValue( pStr, xIf, nArgPos ) ); + + if( strokeAttributes.StartCapType < rendering::PathCapType::BUTT || + strokeAttributes.StartCapType > rendering::PathCapType::SQUARE ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' StartCapType value is out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(strokeAttributes.StartCapType)) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( strokeAttributes.EndCapType < rendering::PathCapType::BUTT || + strokeAttributes.EndCapType > rendering::PathCapType::SQUARE ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' StartCapType value is out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(strokeAttributes.EndCapType)) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( strokeAttributes.JoinType < rendering::PathJoinType::NONE || + strokeAttributes.JoinType > rendering::PathJoinType::BEVEL ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): stroke attributes' JoinType value is out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(strokeAttributes.JoinType)) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + + void verifyInput( const rendering::IntegerBitmapLayout& bitmapLayout, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + (void)pStr; (void)xIf; (void)nArgPos; + + if( bitmapLayout.ScanLines < 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ScanLines is negative"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( bitmapLayout.ScanLineBytes < 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ScanLineBytes is negative"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( !bitmapLayout.ColorSpace.is() ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ColorSpace is invalid"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + else + { + if( bitmapLayout.ColorSpace->getBitsPerPixel() < 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ColorSpace getBitsPerPixel() is negative"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( bitmapLayout.ColorSpace->getEndianness() < util::Endianness::LITTLE || + bitmapLayout.ColorSpace->getEndianness() > util::Endianness::BIG ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ColorSpace getEndianness() value is out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(bitmapLayout.ColorSpace->getEndianness())) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + } + + void verifyInput( const rendering::FloatingPointBitmapLayout& bitmapLayout, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + (void)pStr; (void)xIf; (void)nArgPos; + + if( bitmapLayout.ScanLines < 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ScanLines is negative"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( bitmapLayout.ScanLineBytes < 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ScanLineBytes is negative"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( !bitmapLayout.ColorSpace.is() ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's ColorSpace is invalid"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( bitmapLayout.NumComponents < 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's NumComponents is negative"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( bitmapLayout.Endianness < util::Endianness::LITTLE || + bitmapLayout.Endianness > util::Endianness::BIG ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's Endianness value is out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(bitmapLayout.Endianness)) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( bitmapLayout.Format < rendering::FloatingPointBitmapFormat::HALFFLOAT || + bitmapLayout.Format > rendering::FloatingPointBitmapFormat::DOUBLE ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): bitmap layout's Format value is out of range (") + + ::rtl::OUString::valueOf(sal::static_int_cast<sal_Int32>(bitmapLayout.Format)) + + ::rtl::OUString::createFromAscii(" not known)"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + + void verifyInput( const rendering::FontInfo& /*fontInfo*/, + const char* /*pStr*/, + const uno::Reference< uno::XInterface >& /*xIf*/, + ::sal_Int16 /*nArgPos*/ ) + { + // TODO(E3): Implement FontDescription checks, once the + // Panose stuff is ready. + } + + void verifyInput( const rendering::FontRequest& fontRequest, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf, + ::sal_Int16 nArgPos ) + { + verifyInput( fontRequest.FontDescription, + pStr, xIf, nArgPos ); + + if( !::rtl::math::isFinite( fontRequest.CellSize ) ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): font request's CellSize value contains infinite or NAN"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( !::rtl::math::isFinite( fontRequest.ReferenceAdvancement ) ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): font request's ReferenceAdvancement value contains infinite or NAN"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( fontRequest.CellSize != 0.0 && + fontRequest.ReferenceAdvancement != 0.0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyInput(): font request's CellSize and ReferenceAdvancement are mutually exclusive, one of them must be 0.0"), + xIf, + nArgPos ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + + void verifyIndexRange( const geometry::IntegerRectangle2D& rect, + const geometry::IntegerSize2D& size ) + { + const ::basegfx::B2IRange aRect( + ::basegfx::unotools::b2IRectangleFromIntegerRectangle2D( + rect ) ); + + if( aRect.getMinX() < 0 || + aRect.getMaxX() > size.Width || + aRect.getMinY() < 0 || + aRect.getMaxY() > size.Height ) + { + throw ::com::sun::star::lang::IndexOutOfBoundsException(); + } + } + + void verifyIndexRange( const geometry::IntegerPoint2D& pos, + const geometry::IntegerSize2D& size ) + { + if( pos.X < 0 || + pos.X > size.Width || + pos.Y < 0 || + pos.Y > size.Height ) + { + throw ::com::sun::star::lang::IndexOutOfBoundsException(); + } + } + + void verifyBitmapSize( const geometry::IntegerSize2D& size, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf ) + { + (void)pStr; (void)xIf; + + if( size.Width <= 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyBitmapSize(): size has 0 or negative width (value: ") + + ::rtl::OUString::valueOf(size.Width) + + ::rtl::OUString::createFromAscii(")"), + xIf, + 0 ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( size.Height <= 0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifyBitmapSize(): size has 0 or negative height (value: ") + + ::rtl::OUString::valueOf(size.Height) + + ::rtl::OUString::createFromAscii(")"), + xIf, + 0 ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + + void verifySpriteSize( const geometry::RealSize2D& size, + const char* pStr, + const uno::Reference< uno::XInterface >& xIf ) + { + (void)pStr; (void)xIf; + + if( size.Width <= 0.0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifySpriteSize(): size has 0 or negative width (value: ") + + ::rtl::OUString::valueOf(size.Width) + + ::rtl::OUString::createFromAscii(")"), + xIf, + 0 ); +#else + throw lang::IllegalArgumentException(); +#endif + } + + if( size.Height <= 0.0 ) + { +#if OSL_DEBUG_LEVEL > 0 + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii(pStr) + + ::rtl::OUString::createFromAscii(": verifySpriteSize(): size has 0 or negative height (value: ") + + ::rtl::OUString::valueOf(size.Height) + + ::rtl::OUString::createFromAscii(")"), + xIf, + 0 ); +#else + throw lang::IllegalArgumentException(); +#endif + } + } + + + } // namespace tools + +} // namespace canvas diff --git a/canvas/source/vcl/backbuffer.cxx b/canvas/source/vcl/backbuffer.cxx new file mode 100644 index 000000000000..3820c4e42657 --- /dev/null +++ b/canvas/source/vcl/backbuffer.cxx @@ -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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_canvas.hxx" + +#include "backbuffer.hxx" + + +namespace vclcanvas +{ + BackBuffer::BackBuffer( const OutputDevice& rRefDevice, + bool bMonochromeBuffer ) : + maVDev( new VirtualDevice( rRefDevice, + bMonochromeBuffer ) ) + { + if( !bMonochromeBuffer ) + { + // #i95645# +#if defined( QUARTZ ) + // use AA on VCLCanvas for Mac + maVDev->SetAntialiasing( ANTIALIASING_ENABLE_B2DDRAW | maVDev->GetAntialiasing() ); +#else + // switch off AA for WIN32 and UNIX, the VCLCanvas does not look good with it and + // is not required to do AA. It would need to be adapted to use it correctly + // (especially gradient painting). This will need extra work. + maVDev->SetAntialiasing( maVDev->GetAntialiasing() & !ANTIALIASING_ENABLE_B2DDRAW); +#endif + } + } + + OutputDevice& BackBuffer::getOutDev() + { + return maVDev.get(); + } + + const OutputDevice& BackBuffer::getOutDev() const + { + return maVDev.get(); + } + + void BackBuffer::setSize( const ::Size& rNewSize ) + { + maVDev->SetOutputSizePixel( rNewSize ); + } + +} diff --git a/canvas/source/vcl/backbuffer.hxx b/canvas/source/vcl/backbuffer.hxx new file mode 100644 index 000000000000..4f4dfa1f638c --- /dev/null +++ b/canvas/source/vcl/backbuffer.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 _VCLCANVAS_BACKBUFFER_HXX_ +#define _VCLCANVAS_BACKBUFFER_HXX_ + +#include <vcl/virdev.hxx> + +#include <canvas/vclwrapper.hxx> +#include "outdevprovider.hxx" + +#include <boost/shared_ptr.hpp> + + +namespace vclcanvas +{ + /// Background buffer abstraction + class BackBuffer : public OutDevProvider + { + public: + /** Create a backbuffer for given reference device + + @param bMonochromeBuffer + When false, default depth of reference device is + chosen. When true, the buffer will be monochrome, i.e. one + bit deep. + */ + BackBuffer( const OutputDevice& rRefDevice, + bool bMonochromeBuffer=false ); + + virtual OutputDevice& getOutDev(); + virtual const OutputDevice& getOutDev() const; + + void setSize( const ::Size& rNewSize ); + + private: + ::canvas::vcltools::VCLObject<VirtualDevice> maVDev; + }; + + typedef ::boost::shared_ptr< BackBuffer > BackBufferSharedPtr; +} + +#endif /* #ifndef _VCLCANVAS_BACKBUFFER_HXX_ */ diff --git a/canvas/source/vcl/bitmapbackbuffer.cxx b/canvas/source/vcl/bitmapbackbuffer.cxx new file mode 100644 index 000000000000..31c78283a128 --- /dev/null +++ b/canvas/source/vcl/bitmapbackbuffer.cxx @@ -0,0 +1,165 @@ +/************************************************************************* + * + * 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 "bitmapbackbuffer.hxx" + +#include <osl/mutex.hxx> +#include <vos/mutex.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> + + +namespace vclcanvas +{ + BitmapBackBuffer::BitmapBackBuffer( const BitmapEx& rBitmap, + const OutputDevice& rRefDevice ) : + maBitmap( rBitmap ), + mpVDev( NULL ), + mrRefDevice( rRefDevice ), + mbBitmapContentIsCurrent( false ), + mbVDevContentIsCurrent( false ) + { + } + + BitmapBackBuffer::~BitmapBackBuffer() + { + // make sure solar mutex is held on deletion (other methods + // are supposed to be called with already locked solar mutex) + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if( mpVDev ) + delete mpVDev; + } + + OutputDevice& BitmapBackBuffer::getOutDev() + { + createVDev(); + updateVDev(); + return *mpVDev; + } + + const OutputDevice& BitmapBackBuffer::getOutDev() const + { + createVDev(); + updateVDev(); + return *mpVDev; + } + + void BitmapBackBuffer::clear() + { + // force current content to bitmap, make all transparent white + getBitmapReference().Erase(COL_TRANSPARENT); + } + + BitmapEx& BitmapBackBuffer::getBitmapReference() + { + OSL_ENSURE( !mbBitmapContentIsCurrent || !mbVDevContentIsCurrent, + "BitmapBackBuffer::getBitmapReference(): Both bitmap and VDev are valid?!" ); + + if( mbVDevContentIsCurrent && mpVDev ) + { + // VDev content is more current than bitmap - copy contents before! + mpVDev->EnableMapMode( FALSE ); + const Point aEmptyPoint; + *maBitmap = mpVDev->GetBitmapEx( aEmptyPoint, + mpVDev->GetOutputSizePixel() ); + } + + // client queries bitmap, and will possibly alter content - + // next time, VDev needs to be updated + mbBitmapContentIsCurrent = true; + mbVDevContentIsCurrent = false; + + return *maBitmap; + } + + Size BitmapBackBuffer::getBitmapSizePixel() const + { + Size aSize = maBitmap->GetSizePixel(); + + if( mbVDevContentIsCurrent && mpVDev ) + { + mpVDev->EnableMapMode( FALSE ); + aSize = mpVDev->GetOutputSizePixel(); + } + + return aSize; + } + + void BitmapBackBuffer::createVDev() const + { + if( !mpVDev ) + { + // VDev not yet created, do it now. Create an alpha-VDev, + // if bitmap has transparency. + mpVDev = maBitmap->IsTransparent() ? + new VirtualDevice( mrRefDevice, 0, 0 ) : + new VirtualDevice( mrRefDevice ); + + OSL_ENSURE( mpVDev, + "BitmapBackBuffer::createVDev(): Unable to create VirtualDevice" ); + + mpVDev->SetOutputSizePixel( maBitmap->GetSizePixel() ); + + // #i95645# +#if defined( QUARTZ ) + // use AA on VCLCanvas for Mac + mpVDev->SetAntialiasing( ANTIALIASING_ENABLE_B2DDRAW | mpVDev->GetAntialiasing() ); +#else + // switch off AA for WIN32 and UNIX, the VCLCanvas does not look good with it and + // is not required to do AA. It would need to be adapted to use it correctly + // (especially gradient painting). This will need extra work. + mpVDev->SetAntialiasing(mpVDev->GetAntialiasing() & !ANTIALIASING_ENABLE_B2DDRAW); +#endif + } + } + + void BitmapBackBuffer::updateVDev() const + { + OSL_ENSURE( !mbBitmapContentIsCurrent || !mbVDevContentIsCurrent, + "BitmapBackBuffer::updateVDev(): Both bitmap and VDev are valid?!" ); + + if( mpVDev && mbBitmapContentIsCurrent ) + { + // fill with bitmap content + mpVDev->EnableMapMode( FALSE ); + const Point aEmptyPoint; + mpVDev->DrawBitmapEx( aEmptyPoint, *maBitmap ); + } + + // canvas queried the VDev, and will possibly paint into + // it. Next time, bitmap must be updated + mbBitmapContentIsCurrent = false; + mbVDevContentIsCurrent = true; + } +} + diff --git a/canvas/source/vcl/bitmapbackbuffer.hxx b/canvas/source/vcl/bitmapbackbuffer.hxx new file mode 100644 index 000000000000..96dd525b98a4 --- /dev/null +++ b/canvas/source/vcl/bitmapbackbuffer.hxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * 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_BITMAPBACKBUFFER_HXX_ +#define _VCLCANVAS_BITMAPBACKBUFFER_HXX_ + +#include <vcl/virdev.hxx> +#include <vcl/bitmapex.hxx> + +#include <canvas/vclwrapper.hxx> +#include "outdevprovider.hxx" + +#include <boost/shared_ptr.hpp> + + +namespace vclcanvas +{ + /** Backbuffer implementation for canvas bitmap. + + This class abstracts away the renderable bitmap for the bitmap + canvas. The actual VirtualDevice is only created when + necessary, which makes read-only bitmaps a lot smaller. + */ + class BitmapBackBuffer : public OutDevProvider + { + public: + /** Create a backbuffer for given reference device + */ + BitmapBackBuffer( const BitmapEx& rBitmap, + const OutputDevice& rRefDevice ); + + ~BitmapBackBuffer(); + + virtual OutputDevice& getOutDev(); + virtual const OutputDevice& getOutDev() const; + + /// Clear the underlying bitmap to white, all transparent + void clear(); + + /** Exposing our internal bitmap. Only to be used from + CanvasBitmapHelper + + @internal + */ + BitmapEx& getBitmapReference(); + Size getBitmapSizePixel() const; + + private: + void createVDev() const; + void updateVDev() const; + + ::canvas::vcltools::VCLObject<BitmapEx> maBitmap; + mutable VirtualDevice* mpVDev; // created only on demand + + const OutputDevice& mrRefDevice; + + /** When true, the bitmap contains the last valid + content. When false, and mbVDevContentIsCurrent is true, + the VDev contains the last valid content (which must be + copied back to the bitmap, when getBitmapReference() is + called). When both are false, this object is just + initialized. + */ + mutable bool mbBitmapContentIsCurrent; + + /** When true, and mpVDev is non-NULL, the VDev contains the + last valid content. When false, and + mbBitmapContentIsCurrent is true, the bitmap contains the + last valid content. When both are false, this object is + just initialized. + */ + mutable bool mbVDevContentIsCurrent; + }; + + typedef ::boost::shared_ptr< BitmapBackBuffer > BitmapBackBufferSharedPtr; + +} + +#endif /* #ifndef _VCLCANVAS_BITMAPBACKBUFFER_HXX_ */ + diff --git a/canvas/source/vcl/cachedbitmap.cxx b/canvas/source/vcl/cachedbitmap.cxx new file mode 100644 index 000000000000..70ca3a3e67ed --- /dev/null +++ b/canvas/source/vcl/cachedbitmap.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * 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 "cachedbitmap.hxx" +#include "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 ::com::sun::star; + +namespace vclcanvas +{ + CachedBitmap::CachedBitmap( const GraphicObjectSharedPtr& rGraphicObject, + const ::Point& rPoint, + const ::Size& rSize, + const GraphicAttr& rAttr, + const rendering::ViewState& rUsedViewState, + const rendering::RenderState& rUsedRenderState, + const uno::Reference< rendering::XCanvas >& rTarget ) : + CachedPrimitiveBase( rUsedViewState, rTarget, true ), + mpGraphicObject( rGraphicObject ), + maRenderState(rUsedRenderState), + maPoint( rPoint ), + maSize( rSize ), + maAttributes( rAttr ) + { + } + + void SAL_CALL CachedBitmap::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + mpGraphicObject.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)" ); + + // TODO(P1): Could adapt to modified clips as well + if( rNewState.Clip != rOldState.Clip ) + return rendering::RepaintResult::FAILED; + + RepaintTarget* pTarget = dynamic_cast< RepaintTarget* >(rTargetCanvas.get()); + + ENSURE_OR_THROW( pTarget, + "CachedBitmap::redraw(): cannot cast target to RepaintTarget" ); + + if( !pTarget->repaint( mpGraphicObject, + rNewState, + maRenderState, + maPoint, + maSize, + maAttributes ) ) + { + // target failed to repaint + return rendering::RepaintResult::FAILED; + } + + return rendering::RepaintResult::REDRAWN; + } +} diff --git a/canvas/source/vcl/cachedbitmap.hxx b/canvas/source/vcl/cachedbitmap.hxx new file mode 100644 index 000000000000..c45720c086c8 --- /dev/null +++ b/canvas/source/vcl/cachedbitmap.hxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * 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_CACHEDBITMAP_HXX +#define _VCLCANVAS_CACHEDBITMAP_HXX + +#include <canvas/base/cachedprimitivebase.hxx> + +#include <svtools/grfmgr.hxx> + +#include <boost/shared_ptr.hpp> + + +/* Definition of CachedBitmap class */ + +namespace vclcanvas +{ + typedef ::boost::shared_ptr< GraphicObject > GraphicObjectSharedPtr; + + class CachedBitmap : public ::canvas::CachedPrimitiveBase + { + public: + + /** Create an XCachedPrimitive for given GraphicObject + */ + CachedBitmap( const GraphicObjectSharedPtr& rGraphicObject, + const ::Point& rPoint, + const ::Size& rSize, + const GraphicAttr& rAttr, + 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 ); + + + GraphicObjectSharedPtr mpGraphicObject; + const ::com::sun::star::rendering::RenderState maRenderState; + const ::Point maPoint; + const ::Size maSize; + const GraphicAttr maAttributes; + }; +} + +#endif /* _VCLCANVAS_CACHEDBITMAP_HXX */ diff --git a/canvas/source/vcl/canvas.cxx b/canvas/source/vcl/canvas.cxx new file mode 100644 index 000000000000..837c064b4411 --- /dev/null +++ b/canvas/source/vcl/canvas.cxx @@ -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. + * + ************************************************************************/ + +// 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 <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <vcl/canvastools.hxx> +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> +#include <vcl/bitmapex.hxx> + +#include <basegfx/tools/canvastools.hxx> + +#include <algorithm> + +#include "canvas.hxx" +#include "windowoutdevholder.hxx" + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + namespace + { + class OutDevHolder : public OutDevProvider, + private ::boost::noncopyable + { + public: + explicit OutDevHolder( OutputDevice& rOutDev ) : + mrOutDev(rOutDev) + {} + + private: + virtual OutputDevice& getOutDev() { return mrOutDev; } + virtual const OutputDevice& getOutDev() const { return mrOutDev; } + + // TODO(Q2): Lifetime issue. This _only_ works reliably, + // if disposing the Canvas correctly disposes all + // entities which hold this pointer. + OutputDevice& mrOutDev; + }; + } + + 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 + */ + tools::LocalGuard aGuard; + + VERBOSE_TRACE( "VCLCanvas::initialize called" ); + + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 6 && + maArguments[0].getValueTypeClass() == uno::TypeClass_HYPER, + "Canvas::initialize: wrong number of arguments, or wrong types" ); + + sal_Int64 nPtr = 0; + maArguments[0] >>= nPtr; + + OutputDevice* pOutDev = reinterpret_cast<OutputDevice*>(nPtr); + if( !pOutDev ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Passed OutDev invalid!")), + NULL); + + OutDevProviderSharedPtr pOutdevProvider( new OutDevHolder(*pOutDev) ); + + // setup helper + maDeviceHelper.init( pOutdevProvider ); + maCanvasHelper.init( *this, + pOutdevProvider, + true, // OutDev state preservation + false ); // no alpha on surface + + maArguments.realloc(0); + } + + Canvas::~Canvas() + { + OSL_TRACE( "Canvas destroyed" ); + } + + void SAL_CALL Canvas::disposing() + { + tools::LocalGuard aGuard; + + mxComponentContext.clear(); + + // forward to parent + CanvasBaseT::disposing(); + } + + ::rtl::OUString SAL_CALL Canvas::getServiceName( ) throw (::com::sun::star::uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CANVAS_SERVICE_NAME ) ); + } + + bool Canvas::repaint( const GraphicObjectSharedPtr& rGrf, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const + { + tools::LocalGuard aGuard; + + return maCanvasHelper.repaint( rGrf, viewState, renderState, rPt, rSz, rAttr ); + } +} diff --git a/canvas/source/vcl/canvas.hxx b/canvas/source/vcl/canvas.hxx new file mode 100644 index 000000000000..adda8d8eea40 --- /dev/null +++ b/canvas/source/vcl/canvas.hxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * 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_CANVAS_HXX_ +#define _VCLCANVAS_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/XServiceName.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.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/basemutexhelper.hxx> +#include <canvas/base/integerbitmapbase.hxx> +#include <canvas/base/graphicdevicebase.hxx> + +#include "canvashelper.hxx" +#include "impltools.hxx" +#include "devicehelper.hxx" +#include "repainttarget.hxx" + +#define CANVAS_SERVICE_NAME "com.sun.star.rendering.Canvas.VCL" +#define CANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.Canvas.VCL" + +namespace vclcanvas +{ + 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, + tools::LocalGuard, + ::cppu::OWeakObject > CanvasBase_Base; + typedef ::canvas::IntegerBitmapBase< CanvasBase_Base, + CanvasHelper, + tools::LocalGuard, + ::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 GraphicObjectSharedPtr& rGrf, + const com::sun::star::rendering::ViewState& viewState, + const com::sun::star::rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const; + + 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/vcl/canvasbitmap.cxx b/canvas/source/vcl/canvasbitmap.cxx new file mode 100644 index 000000000000..38008e86ba87 --- /dev/null +++ b/canvas/source/vcl/canvasbitmap.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 <tools/diagnose_ex.h> +#include "canvasbitmap.hxx" + +#include <vcl/bmpacc.hxx> + +using namespace ::com::sun::star; + + +namespace vclcanvas +{ + // Currently, the only way to generate an XBitmap is from + // XGraphicDevice.getCompatibleBitmap(). Therefore, we don't even + // take a bitmap here, but a VDev directly. + CanvasBitmap::CanvasBitmap( const ::Size& rSize, + bool bAlphaBitmap, + rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDevProvider ) + { + // create bitmap for given reference device + // ======================================== + const USHORT nBitCount( (USHORT)24U ); + const BitmapPalette* pPalette = NULL; + + Bitmap aBitmap( rSize, nBitCount, pPalette ); + + // only create alpha channel bitmap, if factory requested + // that. Providing alpha-channeled bitmaps by default has, + // especially under VCL, a huge performance penalty (have to + // use alpha VDev, then). + if( bAlphaBitmap ) + { + AlphaMask aAlpha ( rSize ); + + maCanvasHelper.init( BitmapEx( aBitmap, aAlpha ), + rDevice, + rOutDevProvider ); + } + else + { + maCanvasHelper.init( BitmapEx( aBitmap ), + rDevice, + rOutDevProvider ); + } + } + + CanvasBitmap::CanvasBitmap( const BitmapEx& rBitmap, + rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDevProvider ) + { + maCanvasHelper.init( rBitmap, rDevice, rOutDevProvider ); + } + + void SAL_CALL CanvasBitmap::disposing() + { + // forward to base + CanvasBitmap_Base::disposing(); + } + +#define IMPLEMENTATION_NAME "VCLCanvas.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; + } + + BitmapEx CanvasBitmap::getBitmap() const + { + tools::LocalGuard aGuard; + + // TODO(T3): Rework to use shared_ptr all over the place for + // BmpEx. This is highly un-threadsafe + return maCanvasHelper.getBitmap(); + } + + bool CanvasBitmap::repaint( const GraphicObjectSharedPtr& rGrf, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const + { + tools::LocalGuard aGuard; + + mbSurfaceDirty = true; + + return maCanvasHelper.repaint( rGrf, viewState, renderState, rPt, rSz, rAttr ); + } + + uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle ) throw (uno::RuntimeException) + { + if( nHandle == 0 ) { + BitmapEx* pBitmapEx = new BitmapEx( getBitmap() ); + + return uno::Any( reinterpret_cast<sal_Int64>( pBitmapEx ) ); + } + + return uno::Any( sal_Int64(0) ); + } +} diff --git a/canvas/source/vcl/canvasbitmap.hxx b/canvas/source/vcl/canvasbitmap.hxx new file mode 100644 index 000000000000..6440b830c3ee --- /dev/null +++ b/canvas/source/vcl/canvasbitmap.hxx @@ -0,0 +1,129 @@ +/************************************************************************* + * + * 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_CANVASBITMAP_HXX +#define _VCLCANVAS_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 <vcl/virdev.hxx> +#include <vcl/bitmapex.hxx> + +#include <canvas/vclwrapper.hxx> + +#include <canvas/base/integerbitmapbase.hxx> +#include <canvasbitmaphelper.hxx> + +#include "impltools.hxx" +#include "repainttarget.hxx" +#include "spritecanvas.hxx" + + +/* Definition of CanvasBitmap class */ + +namespace vclcanvas +{ + 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; + typedef ::canvas::IntegerBitmapBase< ::canvas::BaseMutexHelper< CanvasBitmapBase_Base >, + CanvasBitmapHelper, + tools::LocalGuard, + ::cppu::OWeakObject > CanvasBitmap_Base; + + class CanvasBitmap : public CanvasBitmap_Base, + public RepaintTarget + { + public: + /** Must be called with locked Solar mutex + + @param rSize + Size in pixel of the bitmap to generate + + @param bAlphaBitmap + When true, bitmap will have an alpha channel + + @param rDevice + Reference device, with which bitmap should be compatible + */ + CanvasBitmap( const ::Size& rSize, + bool bAlphaBitmap, + ::com::sun::star::rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDevProvider ); + + /// Must be called with locked Solar mutex + CanvasBitmap( const BitmapEx& rBitmap, + ::com::sun::star::rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDevProvider ); + + // overridden because of mpDevice + virtual void SAL_CALL disposing(); + + // 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); + + // RepaintTarget interface + virtual bool repaint( const GraphicObjectSharedPtr& rGrf, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const; + + /// Not threadsafe! Returned object is shared! + BitmapEx getBitmap() const; + + // 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: + /** MUST hold here, too, since CanvasHelper only contains a + raw pointer (without refcounting) + */ + ::com::sun::star::uno::Reference<com::sun::star::rendering::XGraphicDevice> mxDevice; + }; +} + +#endif /* _VCLCANVAS_CANVASBITMAP_HXX */ diff --git a/canvas/source/vcl/canvasbitmaphelper.cxx b/canvas/source/vcl/canvasbitmaphelper.cxx new file mode 100644 index 000000000000..8fb5a872589d --- /dev/null +++ b/canvas/source/vcl/canvasbitmaphelper.cxx @@ -0,0 +1,567 @@ +/************************************************************************* + * + * 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 <com/sun/star/util/Endianness.hpp> + +#include <rtl/logfile.hxx> +#include <rtl/math.hxx> + +#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/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/canvastools.hxx> + +#include "canvasbitmap.hxx" +#include "canvasbitmaphelper.hxx" + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + CanvasBitmapHelper::CanvasBitmapHelper() : + mpBackBuffer(), + mpOutDevReference() + { + } + + void CanvasBitmapHelper::setBitmap( const BitmapEx& rBitmap ) + { + ENSURE_OR_THROW( mpOutDev, + "Invalid reference device" ); + + mpBackBuffer.reset( new BitmapBackBuffer( rBitmap, + mpOutDev->getOutDev() ) ); + + // tell canvas helper about the new target OutDev (don't + // protect state, it's our own VirDev, anyways) + setOutDev( mpBackBuffer, false ); + } + + void CanvasBitmapHelper::init( const BitmapEx& rBitmap, + rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDevReference ) + { + mpOutDevReference = rOutDevReference; + mpBackBuffer.reset( new BitmapBackBuffer( rBitmap, rOutDevReference->getOutDev() )); + + // forward new settings to base class (ref device, output + // surface, no protection (own backbuffer), alpha depends on + // whether BmpEx is transparent or not) + CanvasHelper::init( rDevice, + mpBackBuffer, + false, + rBitmap.IsTransparent() ); + } + + void CanvasBitmapHelper::disposing() + { + mpBackBuffer.reset(); + mpOutDevReference.reset(); + + // forward to base class + CanvasHelper::disposing(); + } + + geometry::IntegerSize2D CanvasBitmapHelper::getSize() + { + if( !mpBackBuffer ) + return geometry::IntegerSize2D(); + + return ::vcl::unotools::integerSize2DFromSize( mpBackBuffer->getBitmapSizePixel() ); + } + + void CanvasBitmapHelper::clear() + { + // are we disposed? + if( mpBackBuffer ) + mpBackBuffer->clear(); // alpha vdev needs special treatment + } + + uno::Reference< rendering::XBitmap > CanvasBitmapHelper::getScaledBitmap( const geometry::RealSize2D& newSize, + sal_Bool beFast ) + { + ENSURE_OR_THROW( mpDevice, + "disposed CanvasHelper" ); + + RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::CanvasBitmapHelper::getScaledBitmap()" ); + + if( !mpBackBuffer || mpDevice ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + BitmapEx aRes( mpBackBuffer->getBitmapReference() ); + + aRes.Scale( ::vcl::unotools::sizeFromRealSize2D(newSize), + beFast ? BMP_SCALE_FAST : BMP_SCALE_INTERPOLATE ); + + return uno::Reference< rendering::XBitmap >( + new CanvasBitmap( aRes, *mpDevice, mpOutDevReference ) ); + } + + uno::Sequence< sal_Int8 > CanvasBitmapHelper::getData( rendering::IntegerBitmapLayout& rLayout, + const geometry::IntegerRectangle2D& rect ) + { + RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::CanvasBitmapHelper::getData()" ); + + if( !mpBackBuffer ) + return uno::Sequence< sal_Int8 >(); // we're disposed + + rLayout = getMemoryLayout(); + Bitmap aBitmap( mpBackBuffer->getBitmapReference().GetBitmap() ); + Bitmap aAlpha( mpBackBuffer->getBitmapReference().GetAlpha().GetBitmap() ); + + ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), + aBitmap ); + ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.IsEmpty() ? + (BitmapReadAccess*)NULL : aAlpha.AcquireReadAccess(), + aAlpha ); + + ENSURE_OR_THROW( pReadAccess.get() != NULL, + "Could not acquire read access to bitmap" ); + + // TODO(F1): Support more formats. + const Size aBmpSize( aBitmap.GetSizePixel() ); + + rLayout.ScanLines = aBmpSize.Height(); + rLayout.ScanLineBytes = aBmpSize.Width()*4; + rLayout.ScanLineStride = rLayout.ScanLineBytes; + + // for the time being, always return as BGRA + uno::Sequence< sal_Int8 > aRes( 4*aBmpSize.Width()*aBmpSize.Height() ); + sal_Int8* pRes = aRes.getArray(); + + int nCurrPos(0); + for( int y=rect.Y1; + y<aBmpSize.Height() && y<rect.Y2; + ++y ) + { + if( pAlphaReadAccess.get() != NULL ) + { + for( int x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed(); + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen(); + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue(); + pRes[ nCurrPos++ ] = pAlphaReadAccess->GetPixel( y, x ).GetIndex(); + } + } + else + { + for( int x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed(); + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen(); + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue(); + pRes[ nCurrPos++ ] = sal_uInt8(255); + } + } + } + + return aRes; + } + + void CanvasBitmapHelper::setData( const uno::Sequence< sal_Int8 >& data, + const rendering::IntegerBitmapLayout& rLayout, + const geometry::IntegerRectangle2D& rect ) + { + RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::CanvasBitmapHelper::setData()" ); + + if( !mpBackBuffer ) + return; // we're disposed + + const rendering::IntegerBitmapLayout aRefLayout( getMemoryLayout() ); + ENSURE_ARG_OR_THROW( aRefLayout.PlaneStride != rLayout.PlaneStride || + aRefLayout.ColorSpace != rLayout.ColorSpace || + aRefLayout.Palette != rLayout.Palette || + aRefLayout.IsMsbFirst != rLayout.IsMsbFirst, + "Mismatching memory layout" ); + + // retrieve local copies from the BitmapEx, which are later + // stored back. Unfortunately, the BitmapEx does not permit + // in-place modifications, as they are necessary here. + Bitmap aBitmap( mpBackBuffer->getBitmapReference().GetBitmap() ); + Bitmap aAlpha( mpBackBuffer->getBitmapReference().GetAlpha().GetBitmap() ); + + bool bCopyBack( false ); // only copy something back, if we + // actually changed a pixel + + { + ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(), + aBitmap ); + ScopedBitmapWriteAccess pAlphaWriteAccess( aAlpha.IsEmpty() ? + (BitmapWriteAccess*)NULL : aAlpha.AcquireWriteAccess(), + aAlpha ); + + if( pAlphaWriteAccess.get() ) + { + DBG_ASSERT( pAlphaWriteAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL || + pAlphaWriteAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK, + "non-8bit alpha not supported!" ); + } + + ENSURE_OR_THROW( pWriteAccess.get() != NULL, + "Could not acquire write access to bitmap" ); + + // TODO(F1): Support more formats. + const Size aBmpSize( aBitmap.GetSizePixel() ); + + // for the time being, always read as BGRA + int x, y, nCurrPos(0); + for( y=rect.Y1; + y<aBmpSize.Height() && y<rect.Y2; + ++y ) + { + if( pAlphaWriteAccess.get() != NULL ) + { + switch( pWriteAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + Scanline pAScan = pAlphaWriteAccess->GetScanline( y ); + + for( x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + *pScan++ = (BYTE)pWriteAccess->GetBestPaletteIndex( + BitmapColor( data[ nCurrPos ], + data[ nCurrPos+1 ], + data[ nCurrPos+2 ] ) ); + + nCurrPos += 3; + + // cast to unsigned byte, for correct subtraction result + *pAScan++ = static_cast<BYTE>(255 - + static_cast<sal_uInt8>(data[ nCurrPos++ ])); + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + Scanline pAScan = pAlphaWriteAccess->GetScanline( y ); + + for( x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + *pScan++ = data[ nCurrPos+2 ]; + *pScan++ = data[ nCurrPos+1 ]; + *pScan++ = data[ nCurrPos ]; + + nCurrPos += 3; + + // cast to unsigned byte, for correct subtraction result + *pAScan++ = static_cast<BYTE>(255 - + static_cast<sal_uInt8>(data[ nCurrPos++ ])); + } + } + break; + + case BMP_FORMAT_24BIT_TC_RGB: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + Scanline pAScan = pAlphaWriteAccess->GetScanline( y ); + + for( x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + *pScan++ = data[ nCurrPos ]; + *pScan++ = data[ nCurrPos+1 ]; + *pScan++ = data[ nCurrPos+2 ]; + + nCurrPos += 3; + + // cast to unsigned byte, for correct subtraction result + *pAScan++ = static_cast<BYTE>(255 - + static_cast<sal_uInt8>(data[ nCurrPos++ ])); + } + } + break; + + default: + { + for( x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ], + data[ nCurrPos+1 ], + data[ nCurrPos+2 ] ) ); + nCurrPos += 3; + + // cast to unsigned byte, for correct subtraction result + pAlphaWriteAccess->SetPixel( y, x, + BitmapColor( + static_cast<BYTE>(255 - + static_cast<sal_uInt8>(data[ nCurrPos++ ])) ) ); + } + } + break; + } + } + else + { + // TODO(Q3): This is copy'n'pasted from + // canvashelper.cxx, unify! + switch( pWriteAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + + for( x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + *pScan++ = (BYTE)pWriteAccess->GetBestPaletteIndex( + BitmapColor( data[ nCurrPos ], + data[ nCurrPos+1 ], + data[ nCurrPos+2 ] ) ); + + nCurrPos += 4; // skip three colors, _plus_ alpha + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + + for( x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + *pScan++ = data[ nCurrPos+2 ]; + *pScan++ = data[ nCurrPos+1 ]; + *pScan++ = data[ nCurrPos ]; + + nCurrPos += 4; // skip three colors, _plus_ alpha + } + } + break; + + case BMP_FORMAT_24BIT_TC_RGB: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + + for( x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + *pScan++ = data[ nCurrPos ]; + *pScan++ = data[ nCurrPos+1 ]; + *pScan++ = data[ nCurrPos+2 ]; + + nCurrPos += 4; // skip three colors, _plus_ alpha + } + } + break; + + default: + { + for( x=rect.X1; + x<aBmpSize.Width() && x<rect.X2; + ++x ) + { + pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ], + data[ nCurrPos+1 ], + data[ nCurrPos+2 ] ) ); + nCurrPos += 4; // skip three colors, _plus_ alpha + } + } + break; + } + } + + bCopyBack = true; + } + } + + // copy back only here, since the BitmapAccessors must be + // destroyed beforehand + if( bCopyBack ) + { + if( aAlpha.IsEmpty() ) + setBitmap( BitmapEx( aBitmap ) ); + else + setBitmap( BitmapEx( aBitmap, + AlphaMask( aAlpha ) ) ); + } + } + + void CanvasBitmapHelper::setPixel( const uno::Sequence< sal_Int8 >& color, + const rendering::IntegerBitmapLayout& rLayout, + const geometry::IntegerPoint2D& pos ) + { + RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::CanvasBitmapHelper::setPixel()" ); + + if( !mpBackBuffer ) + return; // we're disposed + + const Size aBmpSize( mpBackBuffer->getBitmapReference().GetSizePixel() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aBmpSize.Width(), + "X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aBmpSize.Height(), + "Y coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( color.getLength() > 3, + "not enough color components" ); + + const rendering::IntegerBitmapLayout aRefLayout( getMemoryLayout() ); + ENSURE_ARG_OR_THROW( aRefLayout.PlaneStride != rLayout.PlaneStride || + aRefLayout.ColorSpace != rLayout.ColorSpace || + aRefLayout.Palette != rLayout.Palette || + aRefLayout.IsMsbFirst != rLayout.IsMsbFirst, + "Mismatching memory layout" ); + + // retrieve local copies from the BitmapEx, which are later + // stored back. Unfortunately, the BitmapEx does not permit + // in-place modifications, as they are necessary here. + Bitmap aBitmap( mpBackBuffer->getBitmapReference().GetBitmap() ); + Bitmap aAlpha( mpBackBuffer->getBitmapReference().GetAlpha().GetBitmap() ); + + bool bCopyBack( false ); // only copy something back, if we + // actually changed a pixel + + { + ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(), + aBitmap ); + ScopedBitmapWriteAccess pAlphaWriteAccess( aAlpha.IsEmpty() ? + (BitmapWriteAccess*)NULL : aAlpha.AcquireWriteAccess(), + aAlpha ); + + ENSURE_OR_THROW( pWriteAccess.get() != NULL, + "Could not acquire write access to bitmap" ); + + pWriteAccess->SetPixel( pos.Y, pos.X, BitmapColor( color[ 0 ], + color[ 1 ], + color[ 2 ] ) ); + + if( pAlphaWriteAccess.get() != NULL ) + pAlphaWriteAccess->SetPixel( pos.Y, pos.X, BitmapColor( 255 - color[ 3 ] ) ); + + bCopyBack = true; + } + + // copy back only here, since the BitmapAccessors must be + // destroyed beforehand + if( bCopyBack ) + { + if( aAlpha.IsEmpty() ) + setBitmap( BitmapEx( aBitmap ) ); + else + setBitmap( BitmapEx( aBitmap, + AlphaMask( aAlpha ) ) ); + } + } + + uno::Sequence< sal_Int8 > CanvasBitmapHelper::getPixel( rendering::IntegerBitmapLayout& rLayout, + const geometry::IntegerPoint2D& pos ) + { + RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::CanvasBitmapHelper::getPixel()" ); + + if( !mpBackBuffer ) + return uno::Sequence< sal_Int8 >(); // we're disposed + + rLayout = getMemoryLayout(); + rLayout.ScanLines = 1; + rLayout.ScanLineBytes = 4; + rLayout.ScanLineStride = rLayout.ScanLineBytes; + + const Size aBmpSize( mpBackBuffer->getBitmapReference().GetSizePixel() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aBmpSize.Width(), + "X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aBmpSize.Height(), + "Y coordinate out of bounds" ); + + Bitmap aBitmap( mpBackBuffer->getBitmapReference().GetBitmap() ); + Bitmap aAlpha( mpBackBuffer->getBitmapReference().GetAlpha().GetBitmap() ); + + ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), + aBitmap ); + ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.IsEmpty() ? + (BitmapReadAccess*)NULL : aAlpha.AcquireReadAccess(), + aAlpha ); + ENSURE_OR_THROW( pReadAccess.get() != NULL, + "Could not acquire read access to bitmap" ); + + uno::Sequence< sal_Int8 > aRes( 4 ); + sal_Int8* pRes = aRes.getArray(); + + const BitmapColor aColor( pReadAccess->GetColor( pos.Y, pos.X ) ); + pRes[ 0 ] = aColor.GetRed(); + pRes[ 1 ] = aColor.GetGreen(); + pRes[ 2 ] = aColor.GetBlue(); + + if( pAlphaReadAccess.get() != NULL ) + pRes[ 3 ] = pAlphaReadAccess->GetPixel( pos.Y, pos.X ).GetIndex(); + else + pRes[ 3 ] = sal_uInt8(255); + + return aRes; + } + + rendering::IntegerBitmapLayout CanvasBitmapHelper::getMemoryLayout() + { + if( !mpOutDev.get() ) + return rendering::IntegerBitmapLayout(); // we're disposed + + return ::canvas::tools::getStdMemoryLayout(getSize()); + } + + BitmapEx CanvasBitmapHelper::getBitmap() const + { + if( !mpBackBuffer ) + return BitmapEx(); // we're disposed + else + return mpBackBuffer->getBitmapReference(); + } + +} diff --git a/canvas/source/vcl/canvasbitmaphelper.hxx b/canvas/source/vcl/canvasbitmaphelper.hxx new file mode 100644 index 000000000000..196d53d7b58a --- /dev/null +++ b/canvas/source/vcl/canvasbitmaphelper.hxx @@ -0,0 +1,129 @@ +/************************************************************************* + * + * 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_CANVASBITMAPHELPER_HXX_ +#define _VCLCANVAS_CANVASBITMAPHELPER_HXX_ + +#include <canvashelper.hxx> +#include <canvas/vclwrapper.hxx> + +#include <vcl/bitmapex.hxx> + +#include "bitmapbackbuffer.hxx" +#include "spritecanvas.hxx" + + +namespace vclcanvas +{ + /** Helper class for basic canvasbitmap functionality. Extends + CanvasHelper with some CanvasBitmap specialities, such as alpha + support. + + Note that a plain CanvasHelper, although it does support the + XBitmap interface, has no provision for alpha channel on VCL + (at least no efficient one. If the alpha VDev one day gets + part of SAL, we might change that). + */ + class CanvasBitmapHelper : public CanvasHelper + { + public: + CanvasBitmapHelper(); + + /** Set a new bitmap on this helper. + + This method late-initializes the bitmap canvas helper, + providing it with the necessary device and output + objects. The internally stored bitmap representation is + updated from the given bitmap, including any size + changes. Note that the CanvasHelper does <em>not</em> take + ownership of the SpriteCanvas object, nor does it perform + any reference counting. Thus, to prevent reference counted + objects from deletion, the user of this class is + responsible for holding ref-counted references to those + objects! + + @param rBitmap + Content of this bitmap is used as our new content (our + internal size is adapted to the size of the bitmap given) + + @param rDevice + Reference device for this canvas bitmap + + @param rOutDevProvider + Reference output device. Used to create matching bitmap. + */ + void init( const BitmapEx& rBitmap, + ::com::sun::star::rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDevProvider ); + + + // Overridden CanvasHelper functionality + // ===================================== + + void disposing(); + + void clear(); + + ::com::sun::star::geometry::IntegerSize2D getSize(); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > queryBitmapCanvas(); + + ::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::rendering::IntegerBitmapLayout getMemoryLayout(); + + /// @internal + BitmapEx getBitmap() const; + + private: + + void setBitmap( const BitmapEx& rBitmap ); + + BitmapBackBufferSharedPtr mpBackBuffer; + OutDevProviderSharedPtr mpOutDevReference; + }; +} + +#endif /* _VCLCANVAS_CANVASBITMAPHELPER_HXX_ */ diff --git a/canvas/source/vcl/canvascustomsprite.cxx b/canvas/source/vcl/canvascustomsprite.cxx new file mode 100644 index 000000000000..a55109a9749f --- /dev/null +++ b/canvas/source/vcl/canvascustomsprite.cxx @@ -0,0 +1,197 @@ +/************************************************************************* + * + * 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 <canvas/verbosetrace.hxx> + +#include <rtl/math.hxx> + +#include <vcl/outdev.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/alpha.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/canvastools.hxx> + +#include "canvascustomsprite.hxx" + + +using namespace ::com::sun::star; + + +namespace vclcanvas +{ + + CanvasCustomSprite::CanvasCustomSprite( const geometry::RealSize2D& rSpriteSize, + rendering::XGraphicDevice& rDevice, + const ::canvas::SpriteSurface::Reference& rOwningSpriteCanvas, + const OutDevProviderSharedPtr& rOutDevProvider, + bool bShowSpriteBounds ) + { + ENSURE_OR_THROW( rOwningSpriteCanvas.get() && + rOutDevProvider, + "CanvasCustomSprite::CanvasCustomSprite(): Invalid sprite canvas" ); + + // setup back buffer + // ----------------- + + const ::Size aSize( + static_cast<sal_Int32>( ::std::max( 1.0, + ceil( rSpriteSize.Width ))), // round up to nearest int, + // enforce sprite to have at + // least (1,1) pixel size + static_cast<sal_Int32>( ::std::max( 1.0, + ceil( rSpriteSize.Height ))) ); + + // create content backbuffer in screen depth + BackBufferSharedPtr pBackBuffer( new BackBuffer( rOutDevProvider->getOutDev() ) ); + pBackBuffer->setSize( aSize ); + + // create mask backbuffer, with one bit color depth + BackBufferSharedPtr pBackBufferMask( new BackBuffer( rOutDevProvider->getOutDev(), + true ) ); + pBackBufferMask->setSize( aSize ); + + // TODO(F1): Implement alpha vdev (could prolly enable + // antialiasing again, then) + + // disable font antialiasing (causes ugly shadows otherwise) + pBackBuffer->getOutDev().SetAntialiasing( ANTIALIASING_DISABLE_TEXT ); + pBackBufferMask->getOutDev().SetAntialiasing( ANTIALIASING_DISABLE_TEXT ); + + // set mask vdev drawmode, such that everything is painted + // black. That leaves us with a binary image, white for + // background, black for painted content + pBackBufferMask->getOutDev().SetDrawMode( DRAWMODE_BLACKLINE | DRAWMODE_BLACKFILL | DRAWMODE_BLACKTEXT | + DRAWMODE_BLACKGRADIENT | DRAWMODE_BLACKBITMAP ); + + + // setup canvas helper + // ------------------- + + // always render into back buffer, don't preserve state (it's + // our private VDev, after all), have notion of alpha + maCanvasHelper.init( rDevice, + pBackBuffer, + false, + true ); + maCanvasHelper.setBackgroundOutDev( pBackBufferMask ); + + + // setup sprite helper + // ------------------- + + maSpriteHelper.init( rSpriteSize, + rOwningSpriteCanvas, + pBackBuffer, + pBackBufferMask, + bShowSpriteBounds ); + + // clear sprite to 100% transparent + maCanvasHelper.clear(); + } + + void SAL_CALL CanvasCustomSprite::disposing() + { + tools::LocalGuard aGuard; + + // forward to parent + CanvasCustomSpriteBaseT::disposing(); + } + +#define IMPLEMENTATION_NAME "VCLCanvas.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; + } + + // Sprite + void CanvasCustomSprite::redraw( OutputDevice& rOutDev, + bool bBufferedUpdate ) const + { + tools::LocalGuard aGuard; + + redraw( rOutDev, maSpriteHelper.getPosPixel(), bBufferedUpdate ); + } + + void CanvasCustomSprite::redraw( OutputDevice& rOutDev, + const ::basegfx::B2DPoint& rOrigOutputPos, + bool bBufferedUpdate ) const + { + tools::LocalGuard aGuard; + + maSpriteHelper.redraw( rOutDev, + rOrigOutputPos, + mbSurfaceDirty, + bBufferedUpdate ); + + mbSurfaceDirty = false; + } + + bool CanvasCustomSprite::repaint( const GraphicObjectSharedPtr& rGrf, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const + { + tools::LocalGuard aGuard; + + mbSurfaceDirty = true; + + return maCanvasHelper.repaint( rGrf, viewState, renderState, rPt, rSz, rAttr ); + } + +} diff --git a/canvas/source/vcl/canvascustomsprite.hxx b/canvas/source/vcl/canvascustomsprite.hxx new file mode 100644 index 000000000000..21202b75368d --- /dev/null +++ b/canvas/source/vcl/canvascustomsprite.hxx @@ -0,0 +1,133 @@ +/************************************************************************* + * + * 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_CANVASCUSTOMSPRITE_HXX +#define _VCLCANVAS_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 <vcl/virdev.hxx> + +#include <canvas/vclwrapper.hxx> +#include <canvas/base/basemutexhelper.hxx> +#include <canvas/base/spritesurface.hxx> +#include <canvas/base/canvascustomspritebase.hxx> + +#include "sprite.hxx" +#include "canvashelper.hxx" +#include "spritehelper.hxx" +#include "backbuffer.hxx" +#include "impltools.hxx" +#include "spritecanvas.hxx" +#include "repainttarget.hxx" + + +namespace vclcanvas +{ + 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 + { + }; + + typedef ::canvas::CanvasCustomSpriteBase< CanvasCustomSpriteSpriteBase_Base, + SpriteHelper, + CanvasHelper, + tools::LocalGuard, + ::cppu::OWeakObject > CanvasCustomSpriteBaseT; + + /* Definition of CanvasCustomSprite class */ + + class CanvasCustomSprite : public CanvasCustomSpriteBaseT, + public RepaintTarget + { + public: + CanvasCustomSprite( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + ::com::sun::star::rendering::XGraphicDevice& rDevice, + const ::canvas::SpriteSurface::Reference& rOwningSpriteCanvas, + const OutDevProviderSharedPtr& rOutDevProvider, + bool bShowSpriteBounds ); + + 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( OutputDevice& rOutDev, + bool bBufferedUpdate ) const; + virtual void redraw( OutputDevice& rOutDev, + const ::basegfx::B2DPoint& rPos, + bool bBufferedUpdate ) const; + + // RepaintTarget + virtual bool repaint( const GraphicObjectSharedPtr& rGrf, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const; + }; +} + +#endif /* _VCLCANVAS_CANVASCUSTOMSPRITE_HXX */ diff --git a/canvas/source/vcl/canvasfont.cxx b/canvas/source/vcl/canvasfont.cxx new file mode 100644 index 000000000000..e95a3f79f2b5 --- /dev/null +++ b/canvas/source/vcl/canvasfont.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 <rtl/math.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <i18npool/mslangid.hxx> +#include <vcl/metric.hxx> + +#include "canvasfont.hxx" +#include "textlayout.hxx" + +using namespace ::com::sun::star; + + +namespace vclcanvas +{ + CanvasFont::CanvasFont( const rendering::FontRequest& rFontRequest, + const uno::Sequence< beans::PropertyValue >& , + const geometry::Matrix2D& rFontMatrix, + rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDevProvider ) : + CanvasFont_Base( m_aMutex ), + maFont( Font( rFontRequest.FontDescription.FamilyName, + rFontRequest.FontDescription.StyleName, + Size( 0, ::basegfx::fround(rFontRequest.CellSize) ) ) ), + maFontRequest( rFontRequest ), + mpRefDevice( &rDevice ), + mpOutDevProvider( rOutDevProvider ) + { + 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& rOutDev( rOutDevProvider->getOutDev() ); + + const bool bOldMapState( rOutDev.IsMapModeEnabled() ); + rOutDev.EnableMapMode(FALSE); + + const Size aSize = rOutDev.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 ); + + rOutDev.EnableMapMode(bOldMapState); + } + } + + void SAL_CALL CanvasFont::disposing() + { + tools::LocalGuard aGuard; + + mpOutDevProvider.reset(); + mpRefDevice.clear(); + } + + uno::Reference< rendering::XTextLayout > SAL_CALL CanvasFont::createTextLayout( const rendering::StringContext& aText, sal_Int8 nDirection, sal_Int64 nRandomSeed ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + if( !mpRefDevice.is() ) + return uno::Reference< rendering::XTextLayout >(); // we're disposed + + return new TextLayout( aText, + nDirection, + nRandomSeed, + Reference( this ), + mpRefDevice, + mpOutDevProvider); + } + + rendering::FontRequest SAL_CALL CanvasFont::getFontRequest( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + return maFontRequest; + } + + rendering::FontMetrics SAL_CALL CanvasFont::getFontMetrics( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + OutputDevice& rOutDev = mpOutDevProvider->getOutDev(); + VirtualDevice aVDev( rOutDev ); + aVDev.SetFont(getVCLFont()); + const ::FontMetric& aMetric( aVDev.GetFontMetric() ); + + return rendering::FontMetrics( + aMetric.GetAscent(), + aMetric.GetDescent(), + aMetric.GetIntLeading(), + aMetric.GetExtLeading(), + 0, + aMetric.GetDescent() / 2.0, + aMetric.GetAscent() / 2.0); + } + + uno::Sequence< double > SAL_CALL CanvasFont::getAvailableSizes( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + // TODO(F1) + return uno::Sequence< double >(); + } + + uno::Sequence< beans::PropertyValue > SAL_CALL CanvasFont::getExtraFontProperties( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + // TODO(F1) + return uno::Sequence< beans::PropertyValue >(); + } + +#define IMPLEMENTATION_NAME "VCLCanvas::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/vcl/canvasfont.hxx b/canvas/source/vcl/canvasfont.hxx new file mode 100644 index 000000000000..e0c9a567a29a --- /dev/null +++ b/canvas/source/vcl/canvasfont.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * 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_CANVASFONT_HXX +#define _VCLCANVAS_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 <com/sun/star/rendering/XGraphicDevice.hpp> + +#include <vcl/font.hxx> + +#include <canvas/vclwrapper.hxx> + +#include "spritecanvas.hxx" +#include "impltools.hxx" + +#include <boost/utility.hpp> + + +/* Definition of CanvasFont class */ + +namespace vclcanvas +{ + 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, + ::com::sun::star::rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDevProvider ); + + /// 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; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice> mpRefDevice; + OutDevProviderSharedPtr mpOutDevProvider; + }; + +} + +#endif /* _VCLCANVAS_CANVASFONT_HXX */ diff --git a/canvas/source/vcl/canvashelper.cxx b/canvas/source/vcl/canvashelper.cxx new file mode 100644 index 000000000000..a83b260d52d5 --- /dev/null +++ b/canvas/source/vcl/canvashelper.cxx @@ -0,0 +1,1428 @@ +/************************************************************************* + * + * 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/math.hxx> + +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/util/Endianness.hpp> +#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 "textlayout.hxx" +#include "canvashelper.hxx" +#include "canvasbitmap.hxx" +#include "impltools.hxx" +#include "canvasfont.hxx" + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + namespace + { + basegfx::B2DLineJoin b2DJoineFromJoin( sal_Int8 nJoinType ) + { + switch( nJoinType ) + { + case rendering::PathJoinType::NONE: + return basegfx::B2DLINEJOIN_NONE; + + case rendering::PathJoinType::MITER: + return basegfx::B2DLINEJOIN_MITER; + + case rendering::PathJoinType::ROUND: + return basegfx::B2DLINEJOIN_ROUND; + + case rendering::PathJoinType::BEVEL: + return basegfx::B2DLINEJOIN_BEVEL; + + default: + ENSURE_OR_THROW( false, + "b2DJoineFromJoin(): Unexpected join type" ); + } + + return basegfx::B2DLINEJOIN_NONE; + } + } + + CanvasHelper::CanvasHelper() : + mpDevice(), + mpProtectedOutDev(), + mpOutDev(), + mp2ndOutDev(), + mbHaveAlpha( false ) + { + } + + void CanvasHelper::disposing() + { + mpDevice = NULL; + mpProtectedOutDev.reset(); + mpOutDev.reset(); + mp2ndOutDev.reset(); + } + + void CanvasHelper::init( rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDev, + bool bProtect, + bool bHaveAlpha ) + { + // cast away const, need to change refcount (as this is + // ~invisible to client code, still logically const) + mpDevice = &rDevice; + mbHaveAlpha = bHaveAlpha; + + setOutDev( rOutDev, bProtect ); + } + + void CanvasHelper::setOutDev( const OutDevProviderSharedPtr& rOutDev, + bool bProtect ) + { + if( bProtect ) + mpProtectedOutDev = rOutDev; + else + mpProtectedOutDev.reset(); + + mpOutDev = rOutDev; + } + + void CanvasHelper::setBackgroundOutDev( const OutDevProviderSharedPtr& rOutDev ) + { + mp2ndOutDev = rOutDev; + mp2ndOutDev->getOutDev().EnableMapMode( FALSE ); + } + + void CanvasHelper::clear() + { + // are we disposed? + if( mpOutDev ) + { + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + + rOutDev.EnableMapMode( FALSE ); + rOutDev.SetLineColor( COL_WHITE ); + rOutDev.SetFillColor( COL_WHITE ); + rOutDev.DrawRect( Rectangle( Point(), + rOutDev.GetOutputSizePixel()) ); + + if( mp2ndOutDev ) + { + OutputDevice& rOutDev2( mp2ndOutDev->getOutDev() ); + + rOutDev2.SetDrawMode( DRAWMODE_DEFAULT ); + rOutDev2.EnableMapMode( FALSE ); + rOutDev2.SetLineColor( COL_WHITE ); + rOutDev2.SetFillColor( COL_WHITE ); + rOutDev2.DrawRect( Rectangle( Point(), + rOutDev2.GetOutputSizePixel()) ); + rOutDev2.SetDrawMode( DRAWMODE_BLACKLINE | DRAWMODE_BLACKFILL | DRAWMODE_BLACKTEXT | + DRAWMODE_BLACKGRADIENT | DRAWMODE_BLACKBITMAP ); + } + } + } + + void CanvasHelper::drawPoint( const rendering::XCanvas* , + const geometry::RealPoint2D& aPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + // are we disposed? + if( mpOutDev ) + { + // nope, render + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + setupOutDevState( viewState, renderState, LINE_COLOR ); + + const Point aOutPoint( tools::mapRealPoint2D( aPoint, + viewState, renderState ) ); + // TODO(F1): alpha + mpOutDev->getOutDev().DrawPixel( aOutPoint ); + + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawPixel( aOutPoint ); + } + } + + void CanvasHelper::drawLine( const rendering::XCanvas* , + const geometry::RealPoint2D& aStartRealPoint2D, + const geometry::RealPoint2D& aEndRealPoint2D, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + // are we disposed? + if( mpOutDev ) + { + // nope, render + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + setupOutDevState( viewState, renderState, LINE_COLOR ); + + const Point aStartPoint( tools::mapRealPoint2D( aStartRealPoint2D, + viewState, renderState ) ); + const Point aEndPoint( tools::mapRealPoint2D( aEndRealPoint2D, + viewState, renderState ) ); + // TODO(F2): alpha + mpOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint ); + + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint ); + } + } + + void CanvasHelper::drawBezier( const rendering::XCanvas* , + const geometry::RealBezierSegment2D& aBezierSegment, + const geometry::RealPoint2D& _aEndPoint, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + if( mpOutDev ) + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + setupOutDevState( viewState, renderState, LINE_COLOR ); + + const Point& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.Px, + aBezierSegment.Py), + viewState, renderState ) ); + const Point& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C1x, + aBezierSegment.C1y), + viewState, renderState ) ); + const Point& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C2x, + aBezierSegment.C2y), + viewState, renderState ) ); + const Point& rEndPoint( tools::mapRealPoint2D( _aEndPoint, + viewState, renderState ) ); + + ::Polygon aPoly(4); + aPoly.SetPoint( rStartPoint, 0 ); + aPoly.SetFlags( 0, POLY_NORMAL ); + aPoly.SetPoint( rCtrlPoint1, 1 ); + aPoly.SetFlags( 1, POLY_CONTROL ); + aPoly.SetPoint( rCtrlPoint2, 2 ); + aPoly.SetFlags( 2, POLY_CONTROL ); + aPoly.SetPoint( rEndPoint, 3 ); + aPoly.SetFlags( 3, POLY_NORMAL ); + + // TODO(F2): alpha + mpOutDev->getOutDev().DrawPolygon( aPoly ); + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawPolygon( aPoly ); + } + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* , + const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_ARG_OR_THROW( xPolyPolygon.is(), + "polygon is NULL"); + + if( mpOutDev ) + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + setupOutDevState( viewState, renderState, LINE_COLOR ); + + const ::basegfx::B2DPolyPolygon& rPolyPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) ); + const PolyPolygon aPolyPoly( tools::mapPolyPolygon( rPolyPoly, viewState, renderState ) ); + + if( rPolyPoly.isClosed() ) + { + mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); + + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); + } + else + { + // mixed open/closed state. Cannot render open polygon + // via DrawPolyPolygon(), since that implicitley + // closed every polygon. OTOH, no need to distinguish + // further and render closed polygons via + // DrawPolygon(), and open ones via DrawPolyLine(): + // closed polygons will simply already contain the + // closing segment. + USHORT nSize( aPolyPoly.Count() ); + + for( USHORT i=0; i<nSize; ++i ) + { + mpOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] ); + + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] ); + } + } + } + + // TODO(P1): Provide caching here. + 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 ) + { + ENSURE_ARG_OR_THROW( xPolyPolygon.is(), + "polygon is NULL"); + + if( mpOutDev ) + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, viewState, renderState); + + ::basegfx::B2DSize aLinePixelSize(strokeAttributes.StrokeWidth, + strokeAttributes.StrokeWidth); + aLinePixelSize *= aMatrix; + + ::basegfx::B2DPolyPolygon aPolyPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) ); + + if( aPolyPoly.areControlPointsUsed() ) + { + // AW: Not needed for ApplyLineDashing anymore; should be removed + aPolyPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly); + } + + // apply dashing, if any + if( strokeAttributes.DashArray.getLength() ) + { + const ::std::vector<double>& aDashArray( + ::comphelper::sequenceToContainer< ::std::vector<double> >(strokeAttributes.DashArray) ); + + ::basegfx::B2DPolyPolygon aDashedPolyPoly; + + for( sal_uInt32 i=0; i<aPolyPoly.count(); ++i ) + { + // AW: new interface; You may also get gaps in the same run now + basegfx::tools::applyLineDashing(aPolyPoly.getB2DPolygon(i), aDashArray, &aDashedPolyPoly); + //aDashedPolyPoly.append( + // ::basegfx::tools::applyLineDashing( aPolyPoly.getB2DPolygon(i), + // aDashArray ) ); + } + + aPolyPoly = aDashedPolyPoly; + } + + ::basegfx::B2DPolyPolygon aStrokedPolyPoly; + if( aLinePixelSize.getLength() < 1.42 ) + { + // line width < 1.0 in device pixel, thus, output as a + // simple hairline poly-polygon + setupOutDevState( viewState, renderState, LINE_COLOR ); + + aStrokedPolyPoly = aPolyPoly; + } + else + { + // render as a 'thick' line + setupOutDevState( viewState, renderState, FILL_COLOR ); + + for( sal_uInt32 i=0; i<aPolyPoly.count(); ++i ) + { + // TODO(F2): Use MiterLimit from StrokeAttributes, + // need to convert it here to angle. + + // TODO(F2): Also use Cap settings from + // StrokeAttributes, the + // createAreaGeometryForLineStartEnd() method does not + // seem to fit very well here + + // AW: New interface, will create bezier polygons now + aStrokedPolyPoly.append(basegfx::tools::createAreaGeometry( + aPolyPoly.getB2DPolygon(i), strokeAttributes.StrokeWidth*0.5, b2DJoineFromJoin(strokeAttributes.JoinType))); + //aStrokedPolyPoly.append( + // ::basegfx::tools::createAreaGeometryForPolygon( aPolyPoly.getB2DPolygon(i), + // strokeAttributes.StrokeWidth*0.5, + // b2DJoineFromJoin(strokeAttributes.JoinType) ) ); + } + } + + // transform only _now_, all the StrokeAttributes are in + // user coordinates. + aStrokedPolyPoly.transform( aMatrix ); + + const PolyPolygon aVCLPolyPoly( aStrokedPolyPoly ); + + // TODO(F2): When using alpha here, must handle that via + // temporary surface or somesuch. + + // Note: the generated stroke poly-polygon is NOT free of + // self-intersections. Therefore, if we would render it + // via OutDev::DrawPolyPolygon(), on/off fill would + // generate off areas on those self-intersections. + USHORT nSize( aVCLPolyPoly.Count() ); + + for( USHORT i=0; i<nSize; ++i ) + { + if( aStrokedPolyPoly.getB2DPolygon( i ).isClosed() ) { + mpOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] ); + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] ); + } else { + const USHORT nPolySize = aVCLPolyPoly[i].GetSize(); + if( nPolySize ) { + Point rPrevPoint = aVCLPolyPoly[i].GetPoint( 0 ); + Point rPoint; + + for( USHORT j=1; j<nPolySize; j++ ) { + rPoint = aVCLPolyPoly[i].GetPoint( j ); + mpOutDev->getOutDev().DrawLine( rPrevPoint, rPoint ); + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawLine( rPrevPoint, rPoint ); + rPrevPoint = rPoint; + } + } + } + } + } + + // 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 >& , + const rendering::ViewState& , + const rendering::RenderState& , + const uno::Sequence< rendering::Texture >& , + const rendering::StrokeAttributes& ) + { + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* , + const uno::Reference< rendering::XPolyPolygon2D >& , + const rendering::ViewState& , + const rendering::RenderState& , + const uno::Sequence< rendering::Texture >& , + const uno::Reference< geometry::XMapping2D >& , + const rendering::StrokeAttributes& ) + { + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XPolyPolygon2D > CanvasHelper::queryStrokeShapes( const rendering::XCanvas* , + const uno::Reference< rendering::XPolyPolygon2D >& , + const rendering::ViewState& , + const rendering::RenderState& , + const rendering::StrokeAttributes& ) + { + 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 ) + { + ENSURE_ARG_OR_THROW( xPolyPolygon.is(), + "polygon is NULL"); + + if( mpOutDev ) + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + + const int nTransparency( setupOutDevState( viewState, renderState, FILL_COLOR ) ); + const int nTransPercent( (nTransparency * 100 + 128) / 255 ); // normal rounding, no truncation here + ::basegfx::B2DPolyPolygon aB2DPolyPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon)); + aB2DPolyPoly.setClosed(true); // ensure closed poly, otherwise VCL does not fill + const PolyPolygon aPolyPoly( tools::mapPolyPolygon( + aB2DPolyPoly, + viewState, renderState ) ); + const bool bSourceAlpha( renderState.CompositeOperation == rendering::CompositeOperation::SOURCE ); + if( !nTransparency || bSourceAlpha ) + { + mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); + } + else + { + mpOutDev->getOutDev().DrawTransparent( aPolyPoly, (USHORT)nTransPercent ); + } + + if( mp2ndOutDev ) + { + if( !nTransparency || bSourceAlpha ) + { + // HACK. Normally, CanvasHelper does not care + // about actually what mp2ndOutDev is... + if( bSourceAlpha && nTransparency == 255 ) + { + mp2ndOutDev->getOutDev().SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT | + DRAWMODE_WHITEGRADIENT | DRAWMODE_WHITEBITMAP ); + mp2ndOutDev->getOutDev().SetFillColor( COL_WHITE ); + mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); + mp2ndOutDev->getOutDev().SetDrawMode( DRAWMODE_BLACKLINE | DRAWMODE_BLACKFILL | DRAWMODE_BLACKTEXT | + DRAWMODE_BLACKGRADIENT | DRAWMODE_BLACKBITMAP ); + } + else + { + mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); + } + } + else + { + mp2ndOutDev->getOutDev().DrawTransparent( aPolyPoly, (USHORT)nTransPercent ); + } + } + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* , + const uno::Reference< rendering::XPolyPolygon2D >& , + const rendering::ViewState& , + const rendering::RenderState& , + const uno::Sequence< rendering::Texture >& , + const uno::Reference< geometry::XMapping2D >& ) + { + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* , + const rendering::FontRequest& fontRequest, + const uno::Sequence< beans::PropertyValue >& extraFontProperties, + const geometry::Matrix2D& fontMatrix ) + { + if( mpOutDev && mpDevice ) + { + // TODO(F2): font properties and font matrix + return uno::Reference< rendering::XCanvasFont >( + new CanvasFont(fontRequest, extraFontProperties, fontMatrix, + *mpDevice, mpOutDev) ); + } + + return uno::Reference< rendering::XCanvasFont >(); + } + + uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* , + const rendering::FontInfo& , + const uno::Sequence< beans::PropertyValue >& ) + { + // TODO(F2) + return uno::Sequence< rendering::FontInfo >(); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* , + const rendering::StringContext& text, + const uno::Reference< rendering::XCanvasFont >& xFont, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + sal_Int8 textDirection ) + { + ENSURE_ARG_OR_THROW( xFont.is(), + "font is NULL"); + + if( mpOutDev ) + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + + ::Point aOutpos; + if( !setupTextOutput( 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 + mpOutDev->getOutDev().SetLayoutMode( nLayoutMode ); + mpOutDev->getOutDev().DrawText( aOutpos, + text.Text, + ::canvas::tools::numeric_cast<USHORT>(text.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(text.Length) ); + + if( mp2ndOutDev ) + { + mp2ndOutDev->getOutDev().SetLayoutMode( nLayoutMode ); + mp2ndOutDev->getOutDev().DrawText( aOutpos, + text.Text, + ::canvas::tools::numeric_cast<USHORT>(text.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(text.Length) ); + } + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* , + const uno::Reference< rendering::XTextLayout >& xLayoutedText, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ENSURE_ARG_OR_THROW( xLayoutedText.is(), + "layout is NULL"); + + TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() ); + + if( pTextLayout ) + { + if( mpOutDev ) + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + + // 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( aOutpos, viewState, renderState, xLayoutedText->getFont() ) ) + return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary + + // TODO(F2): What about the offset scalings? + // TODO(F2): alpha + pTextLayout->draw( mpOutDev->getOutDev(), aOutpos, viewState, renderState ); + + if( mp2ndOutDev ) + pTextLayout->draw( mp2ndOutDev->getOutDev(), aOutpos, viewState, renderState ); + } + } + else + { + ENSURE_ARG_OR_THROW( false, + "TextLayout not compatible with this canvas" ); + } + + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::implDrawBitmap( const rendering::XCanvas* pCanvas, + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + bool bModulateColors ) + { + ENSURE_ARG_OR_THROW( xBitmap.is(), + "bitmap is NULL"); + + ::canvas::tools::verifyInput( renderState, + BOOST_CURRENT_FUNCTION, + mpDevice, + 4, + bModulateColors ? 3 : 0 ); + + if( mpOutDev ) + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + setupOutDevState( viewState, renderState, IGNORE_COLOR ); + + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, viewState, renderState); + + ::basegfx::B2DPoint aOutputPos( 0.0, 0.0 ); + aOutputPos *= aMatrix; + + BitmapEx aBmpEx( tools::bitmapExFromXBitmap(xBitmap) ); + + // TODO(F2): Implement modulation again for other color + // channels (currently, works only for alpha). Note: this + // is already implemented in transformBitmap() + if( bModulateColors && + renderState.DeviceColor.getLength() > 3 ) + { + // optimize away the case where alpha modulation value + // is 1.0 - we then simply switch off modulation at all + bModulateColors = !::rtl::math::approxEqual( + renderState.DeviceColor[3], 1.0); + } + + // check whether we can render bitmap as-is: must not + // modulate colors, matrix must either be the identity + // transform (that's clear), _or_ contain only + // translational components. + if( !bModulateColors && + (aMatrix.isIdentity() || + (::basegfx::fTools::equalZero( aMatrix.get(0,1) ) && + ::basegfx::fTools::equalZero( aMatrix.get(1,0) ) && + ::rtl::math::approxEqual(aMatrix.get(0,0), 1.0) && + ::rtl::math::approxEqual(aMatrix.get(1,1), 1.0)) ) ) + { + // optimized case: identity matrix, or only + // translational components. + mpOutDev->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos ), + aBmpEx ); + + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos ), + aBmpEx ); + + // Returning a cache object is not useful, the XBitmap + // itself serves this purpose + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + else + { + // Matrix contains non-trivial transformation (or + // color modulation is requested), decompose to check + // whether GraphicObject suffices + ::basegfx::B2DVector aScale; + double nRotate; + double nShearX; + aMatrix.decompose( aScale, aOutputPos, nRotate, nShearX ); + + GraphicAttr aGrfAttr; + GraphicObjectSharedPtr pGrfObj; + + ::Size aBmpSize( aBmpEx.GetSizePixel() ); + + // setup alpha modulation + if( bModulateColors ) + { + const double nAlphaModulation( renderState.DeviceColor[3] ); + + // TODO(F1): Note that the GraphicManager has a + // subtle difference in how it calculates the + // resulting alpha value: it's using the inverse + // alpha values (i.e. 'transparency'), and + // calculates transOrig + transModulate, instead + // of transOrig + transModulate - + // transOrig*transModulate (which would be + // equivalent to the origAlpha*modulateAlpha the + // DX canvas performs) + aGrfAttr.SetTransparency( + static_cast< BYTE >( + ::basegfx::fround( 255.0*( 1.0 - nAlphaModulation ) ) ) ); + } + + if( ::basegfx::fTools::equalZero( nShearX ) ) + { + // no shear, GraphicObject is enough (the + // GraphicObject only supports scaling, rotation + // and translation) + + // #i75339# don't apply mirror flags, having + // negative size values is enough to make + // GraphicObject flip the bitmap + + // The angle has to be mapped from radian to tenths of + // degress with the orientation reversed: [0,2Pi) -> + // (3600,0]. Note that the original angle may have + // values outside the [0,2Pi) interval. + const double nAngleInTenthOfDegrees (3600.0 - nRotate * 3600.0 / (2*M_PI)); + aGrfAttr.SetRotation( static_cast< USHORT >(::basegfx::fround(nAngleInTenthOfDegrees)) ); + + pGrfObj.reset( new GraphicObject( aBmpEx ) ); + } + else + { + // modify output position, to account for the fact + // that transformBitmap() always normalizes its output + // bitmap into the smallest enclosing box. + ::basegfx::B2DRectangle aDestRect; + ::canvas::tools::calcTransformedRectBounds( aDestRect, + ::basegfx::B2DRectangle(0, + 0, + aBmpSize.Width(), + aBmpSize.Height()), + aMatrix ); + + aOutputPos.setX( aDestRect.getMinX() ); + aOutputPos.setY( aDestRect.getMinY() ); + + // complex transformation, use generic affine bitmap + // transformation + aBmpEx = tools::transformBitmap( aBmpEx, + aMatrix, + renderState.DeviceColor, + tools::MODULATE_NONE ); + + pGrfObj.reset( new GraphicObject( aBmpEx ) ); + + // clear scale values, generated bitmap already + // contains scaling + aScale.setX( 1.0 ); aScale.setY( 1.0 ); + + // update bitmap size, bitmap has changed above. + aBmpSize = aBmpEx.GetSizePixel(); + } + + // output GraphicObject + const ::Point aPt( ::vcl::unotools::pointFromB2DPoint( aOutputPos ) ); + const ::Size aSz( ::basegfx::fround( aScale.getX() * aBmpSize.Width() ), + ::basegfx::fround( aScale.getY() * aBmpSize.Height() ) ); + + pGrfObj->Draw( &mpOutDev->getOutDev(), + aPt, + aSz, + &aGrfAttr ); + + if( mp2ndOutDev ) + pGrfObj->Draw( &mp2ndOutDev->getOutDev(), + aPt, + aSz, + &aGrfAttr ); + + // created GraphicObject, which possibly cached + // display bitmap - return cache object, to retain + // that information. + return uno::Reference< rendering::XCachedPrimitive >( + new CachedBitmap( pGrfObj, + aPt, + aSz, + aGrfAttr, + viewState, + renderState, + // cast away const, need to + // change refcount (as this is + // ~invisible to client code, + // still logically const) + const_cast< rendering::XCanvas* >(pCanvas)) ); + } + } + + // Nothing rendered + return 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 ) + { + return implDrawBitmap( pCanvas, + xBitmap, + viewState, + renderState, + false ); + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas, + const uno::Reference< rendering::XBitmap >& xBitmap, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + return implDrawBitmap( pCanvas, + xBitmap, + viewState, + renderState, + true ); + } + + uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice() + { + // cast away const, need to change refcount (as this is + // ~invisible to client code, still logically const) + return uno::Reference< rendering::XGraphicDevice >(mpDevice); + } + + void CanvasHelper::copyRect( const rendering::XCanvas* , + const uno::Reference< rendering::XBitmapCanvas >& , + const geometry::RealRectangle2D& , + const rendering::ViewState& , + const rendering::RenderState& , + const geometry::RealRectangle2D& , + const rendering::ViewState& , + const rendering::RenderState& ) + { + // TODO(F1) + } + + geometry::IntegerSize2D CanvasHelper::getSize() + { + if( !mpOutDev.get() ) + return geometry::IntegerSize2D(); // we're disposed + + return ::vcl::unotools::integerSize2DFromSize( mpOutDev->getOutDev().GetOutputSizePixel() ); + } + + uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D& newSize, + sal_Bool beFast ) + { + if( !mpOutDev.get() || !mpDevice ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + rOutDev.EnableMapMode( FALSE ); + + // TODO(F2): Support alpha vdev canvas here + const Point aEmptyPoint(0,0); + const Size aBmpSize( rOutDev.GetOutputSizePixel() ); + + Bitmap aBitmap( rOutDev.GetBitmap(aEmptyPoint, aBmpSize) ); + + aBitmap.Scale( ::vcl::unotools::sizeFromRealSize2D(newSize), + beFast ? BMP_SCALE_FAST : BMP_SCALE_INTERPOLATE ); + + return uno::Reference< rendering::XBitmap >( + new CanvasBitmap( aBitmap, *mpDevice, mpOutDev ) ); + } + + uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& rLayout, + const geometry::IntegerRectangle2D& rect ) + { + if( !mpOutDev.get() ) + return uno::Sequence< sal_Int8 >(); // we're disposed + + rLayout = getMemoryLayout(); + + // TODO(F2): Support alpha canvas here + const Rectangle aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect) ); + + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + rOutDev.EnableMapMode( FALSE ); + + Bitmap aBitmap( rOutDev.GetBitmap(aRect.TopLeft(), + aRect.GetSize()) ); + + ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), + aBitmap ); + + ENSURE_OR_THROW( pReadAccess.get() != NULL, + "Could not acquire read access to OutDev bitmap" ); + + const sal_Int32 nWidth( rect.X2 - rect.X1 ); + const sal_Int32 nHeight( rect.Y2 - rect.Y1 ); + + rLayout.ScanLines = nHeight; + rLayout.ScanLineBytes = nWidth*4; + rLayout.ScanLineStride = rLayout.ScanLineBytes; + + uno::Sequence< sal_Int8 > aRes( 4*nWidth*nHeight ); + sal_Int8* pRes = aRes.getArray(); + + int nCurrPos(0); + for( int y=0; y<nHeight; ++y ) + { + for( int x=0; x<nWidth; ++x ) + { + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed(); + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen(); + pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue(); + pRes[ nCurrPos++ ] = -1; + } + } + + return aRes; + } + + void CanvasHelper::setData( const uno::Sequence< sal_Int8 >& data, + const rendering::IntegerBitmapLayout& aLayout, + const geometry::IntegerRectangle2D& rect ) + { + if( !mpOutDev.get() ) + return; // we're disposed + + const rendering::IntegerBitmapLayout aRefLayout( getMemoryLayout() ); + ENSURE_ARG_OR_THROW( aRefLayout.PlaneStride != aLayout.PlaneStride || + aRefLayout.ColorSpace != aLayout.ColorSpace || + aRefLayout.Palette != aLayout.Palette || + aRefLayout.IsMsbFirst != aLayout.IsMsbFirst, + "Mismatching memory layout" ); + + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + rOutDev.EnableMapMode( FALSE ); + + const Rectangle aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect) ); + const USHORT nBitCount( ::std::min( (USHORT)24U, + (USHORT)rOutDev.GetBitCount() ) ); + const BitmapPalette* pPalette = NULL; + + if( nBitCount <= 8 ) + { + // TODO(Q1): Extract this to a common place, e.g. GraphicDevice + + // try to determine palette from output device (by + // extracting a 1,1 bitmap, and querying it) + const Point aEmptyPoint; + const Size aSize(1,1); + Bitmap aTmpBitmap( rOutDev.GetBitmap( aEmptyPoint, + aSize ) ); + + ScopedBitmapReadAccess pReadAccess( aTmpBitmap.AcquireReadAccess(), + aTmpBitmap ); + + pPalette = &pReadAccess->GetPalette(); + } + + // TODO(F2): Support alpha canvas here + Bitmap aBitmap( aRect.GetSize(), nBitCount, pPalette ); + + bool bCopyBack( false ); // only copy something back, if we + // actually changed some pixel + { + ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(), + aBitmap ); + + ENSURE_OR_THROW( pWriteAccess.get() != NULL, + "Could not acquire write access to OutDev bitmap" ); + + // for the time being, always read as RGB + const sal_Int32 nWidth( rect.X2 - rect.X1 ); + const sal_Int32 nHeight( rect.Y2 - rect.Y1 ); + int x, y, nCurrPos(0); + for( y=0; y<nHeight; ++y ) + { + switch( pWriteAccess->GetScanlineFormat() ) + { + case BMP_FORMAT_8BIT_PAL: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + *pScan++ = (BYTE)pWriteAccess->GetBestPaletteIndex( + BitmapColor( data[ nCurrPos ], + data[ nCurrPos+1 ], + data[ nCurrPos+2 ] ) ); + + nCurrPos += 4; + } + } + break; + + case BMP_FORMAT_24BIT_TC_BGR: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + *pScan++ = data[ nCurrPos+2 ]; + *pScan++ = data[ nCurrPos+1 ]; + *pScan++ = data[ nCurrPos ]; + + nCurrPos += 4; + } + } + break; + + case BMP_FORMAT_24BIT_TC_RGB: + { + Scanline pScan = pWriteAccess->GetScanline( y ); + + for( x=0; x<nWidth; ++x ) + { + *pScan++ = data[ nCurrPos ]; + *pScan++ = data[ nCurrPos+1 ]; + *pScan++ = data[ nCurrPos+2 ]; + + nCurrPos += 4; + } + } + break; + + default: + { + for( x=0; x<nWidth; ++x ) + { + pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ], + data[ nCurrPos+1 ], + data[ nCurrPos+2 ] ) ); + nCurrPos += 4; + } + } + break; + } + } + + bCopyBack = true; + } + + // copy back only here, since the BitmapAccessors must be + // destroyed beforehand + if( bCopyBack ) + { + // TODO(F2): Support alpha canvas here + rOutDev.DrawBitmap(aRect.TopLeft(), aBitmap); + } + } + + void CanvasHelper::setPixel( const uno::Sequence< sal_Int8 >& color, + const rendering::IntegerBitmapLayout& rLayout, + const geometry::IntegerPoint2D& pos ) + { + if( !mpOutDev.get() ) + return; // we're disposed + + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + rOutDev.EnableMapMode( FALSE ); + + const Size aBmpSize( rOutDev.GetOutputSizePixel() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aBmpSize.Width(), + "X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aBmpSize.Height(), + "Y coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( color.getLength() > 3, + "not enough color components" ); + + const rendering::IntegerBitmapLayout aRefLayout( getMemoryLayout() ); + ENSURE_ARG_OR_THROW( aRefLayout.PlaneStride != rLayout.PlaneStride || + aRefLayout.ColorSpace != rLayout.ColorSpace || + aRefLayout.Palette != rLayout.Palette || + aRefLayout.IsMsbFirst != rLayout.IsMsbFirst, + "Mismatching memory layout" ); + + // TODO(F2): Support alpha canvas here + rOutDev.DrawPixel( ::vcl::unotools::pointFromIntegerPoint2D( pos ), + ::canvas::tools::stdIntSequenceToColor( color )); + } + + uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout& rLayout, + const geometry::IntegerPoint2D& pos ) + { + if( !mpOutDev.get() ) + return uno::Sequence< sal_Int8 >(); // we're disposed + + rLayout = getMemoryLayout(); + rLayout.ScanLines = 1; + rLayout.ScanLineBytes = 4; + rLayout.ScanLineStride = rLayout.ScanLineBytes; + + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + rOutDev.EnableMapMode( FALSE ); + + const Size aBmpSize( rOutDev.GetOutputSizePixel() ); + + ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aBmpSize.Width(), + "X coordinate out of bounds" ); + ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aBmpSize.Height(), + "Y coordinate out of bounds" ); + + // TODO(F2): Support alpha canvas here + return ::canvas::tools::colorToStdIntSequence( + rOutDev.GetPixel( + ::vcl::unotools::pointFromIntegerPoint2D( pos ))); + } + + rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout() + { + if( !mpOutDev.get() ) + return rendering::IntegerBitmapLayout(); // we're disposed + + return ::canvas::tools::getStdMemoryLayout(getSize()); + } + + int CanvasHelper::setupOutDevState( const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + ColorType eColorType ) const + { + ENSURE_OR_THROW( mpOutDev.get(), + "outdev null. Are we disposed?" ); + + ::canvas::tools::verifyInput( renderState, + BOOST_CURRENT_FUNCTION, + mpDevice, + 2, + eColorType == IGNORE_COLOR ? 0 : 3 ); + + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + OutputDevice* p2ndOutDev = NULL; + + rOutDev.EnableMapMode( FALSE ); + + if( mp2ndOutDev ) + p2ndOutDev = &mp2ndOutDev->getOutDev(); + + 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( REGION_NULL ); + + 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 ) ); + } + else + { + // clip polygon is empty + aClipRegion.SetEmpty(); + } + } + + 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 ) ); + 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.IsNull() ) + { + rOutDev.SetClipRegion(); + + if( p2ndOutDev ) + p2ndOutDev->SetClipRegion(); + } + else + { + rOutDev.SetClipRegion( aClipRegion ); + + if( p2ndOutDev ) + p2ndOutDev->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(); + + if( p2ndOutDev ) + { + p2ndOutDev->SetLineColor( aColor ); + p2ndOutDev->SetFillColor(); + } + break; + + case FILL_COLOR: + rOutDev.SetFillColor( aColor ); + rOutDev.SetLineColor(); + + if( p2ndOutDev ) + { + p2ndOutDev->SetFillColor( aColor ); + p2ndOutDev->SetLineColor(); + } + break; + + case TEXT_COLOR: + rOutDev.SetTextColor( aColor ); + + if( p2ndOutDev ) + p2ndOutDev->SetTextColor( aColor ); + break; + + default: + ENSURE_OR_THROW( false, + "Unexpected color type"); + break; + } + } + + return nTransparency; + } + + bool CanvasHelper::setupTextOutput( ::Point& o_rOutPos, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const uno::Reference< rendering::XCanvasFont >& xFont ) const + { + ENSURE_OR_THROW( mpOutDev.get(), + "outdev null. Are we disposed?" ); + + setupOutDevState( viewState, renderState, TEXT_COLOR ); + + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + + ::Font aVCLFont; + + CanvasFont* pFont = dynamic_cast< CanvasFont* >( xFont.get() ); + + ENSURE_ARG_OR_THROW( pFont, + "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( !tools::setupFontTransform( o_rOutPos, aVCLFont, viewState, renderState, rOutDev ) ) + return false; + + rOutDev.SetFont( aVCLFont ); + + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().SetFont( aVCLFont ); + + return true; + } + + bool CanvasHelper::repaint( const GraphicObjectSharedPtr& rGrf, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const + { + ENSURE_OR_RETURN_FALSE( rGrf, + "Invalid Graphic" ); + + if( !mpOutDev ) + return false; // disposed + else + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + setupOutDevState( viewState, renderState, IGNORE_COLOR ); + + if( !rGrf->Draw( &mpOutDev->getOutDev(), rPt, rSz, &rAttr ) ) + return false; + + // #i80779# Redraw also into mask outdev + if( mp2ndOutDev ) + return rGrf->Draw( &mp2ndOutDev->getOutDev(), rPt, rSz, &rAttr ); + + return true; + } + } + + void CanvasHelper::flush() const + { + if( mpOutDev && mpOutDev->getOutDev().GetOutDevType() == OUTDEV_WINDOW ) + { + // TODO(Q3): Evil downcast. And what's more, Window::Flush is + // not even const. Wah. + static_cast<Window&>(mpOutDev->getOutDev()).Flush(); + } + + if( mp2ndOutDev && mp2ndOutDev->getOutDev().GetOutDevType() == OUTDEV_WINDOW ) + { + // TODO(Q3): Evil downcast. And what's more, Window::Flush is + // not even const. Wah. + static_cast<Window&>(mp2ndOutDev->getOutDev()).Flush(); + } + } + +} diff --git a/canvas/source/vcl/canvashelper.hxx b/canvas/source/vcl/canvashelper.hxx new file mode 100644 index 000000000000..ef5eafa0c9ef --- /dev/null +++ b/canvas/source/vcl/canvashelper.hxx @@ -0,0 +1,344 @@ +/************************************************************************* + * + * 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_CANVASHELPER_HXX_ +#define _VCLCANVAS_CANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <vcl/outdev.hxx> + +#include <canvas/vclwrapper.hxx> + +#include "cachedbitmap.hxx" +#include "outdevprovider.hxx" + +#include <boost/utility.hpp> + + +namespace vclcanvas +{ + class SpriteCanvas; + + /** Helper class for basic canvas functionality. Also offers + optional backbuffer painting, when providing it with a second + OutputDevice to render into. + */ + class CanvasHelper : private ::boost::noncopyable + { + public: + /** Create canvas helper + */ + CanvasHelper(); + + /// Release all references + void disposing(); + + /** Initialize canvas helper + + This method late-initializes the canvas helper, providing + it with the necessary device and output objects. 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 rDevice + Reference device this canvas is associated with + + @param rOutDev + Set primary output device for this canvas. That's where + all content is output to. + + @param bProtect + When true, all output operations preserve outdev + state. When false, outdev state might change at any time. + + @param bHaveAlpha + When true, hasAlpha() will always return true, otherwise, false. + */ + void init( ::com::sun::star::rendering::XGraphicDevice& rDevice, + const OutDevProviderSharedPtr& rOutDev, + bool bProtect, + bool bHaveAlpha ); + + /** Set primary output device + + This changes the primary output device, where rendering is + sent to. + */ + void setOutDev( const OutDevProviderSharedPtr& rOutDev, + bool bProtect); + + /** Set secondary output device + + Used for sprites, to generate mask bitmap. + */ + void setBackgroundOutDev( const OutDevProviderSharedPtr& rOutDev ); + + + // 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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 > + createFont( const ::com::sun::star::rendering::XCanvas* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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* rCanvas, + 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::XBitmapCanvas > queryBitmapCanvas(); + + ::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::rendering::IntegerBitmapLayout getMemoryLayout(); + + /// Repaint a cached bitmap + bool repaint( const GraphicObjectSharedPtr& rGrf, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const; + + /** Flush drawing queue. + + This only works for Window canvases, and ensures that all + pending render operations are flushed to the + driver/hardware. + */ + void flush() const; + + enum ColorType + { + LINE_COLOR, FILL_COLOR, TEXT_COLOR, IGNORE_COLOR + }; + + // returns transparency of color + int setupOutDevState( const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + ColorType eColorType ) const; + + /** Called from XCanvas base classes, to notify that content + is _about_ to change + */ + void modifying() {} + + bool hasAlpha() const { return mbHaveAlpha; } + + protected: + /** Phyical output device + + Deliberately not a refcounted reference, because of + potential circular references for spritecanvas. + */ + ::com::sun::star::rendering::XGraphicDevice* mpDevice; + + /// Rendering to this outdev preserves its state + OutDevProviderSharedPtr mpProtectedOutDev; + + /// Rendering to this outdev does not preserve its state + OutDevProviderSharedPtr mpOutDev; + + /// Rendering to this outdev does not preserve its state + OutDevProviderSharedPtr mp2ndOutDev; + + /// When true, content is able to represent alpha + bool mbHaveAlpha; + + private: + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCachedPrimitive > + implDrawBitmap( const ::com::sun::star::rendering::XCanvas* rCanvas, + 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, + bool bModulateColors ); + + bool setupTextOutput( ::Point& o_rOutPos, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont >& xFont ) const; + + }; +} + +#endif /* _VCLCANVAS_CANVASHELPER_HXX_ */ diff --git a/canvas/source/vcl/canvashelper_texturefill.cxx b/canvas/source/vcl/canvashelper_texturefill.cxx new file mode 100644 index 000000000000..c1e71ceb943f --- /dev/null +++ b/canvas/source/vcl/canvashelper_texturefill.cxx @@ -0,0 +1,1182 @@ +/************************************************************************* + * + * 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/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/virdev.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/tools.hxx> +#include <basegfx/tools/lerp.hxx> +#include <basegfx/tools/keystoplerp.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <comphelper/sequence.hxx> + +#include <canvas/canvastools.hxx> +#include <canvas/parametricpolypolygon.hxx> + +#include <boost/bind.hpp> +#include <boost/tuple/tuple.hpp> + +#include "spritecanvas.hxx" +#include "canvashelper.hxx" +#include "impltools.hxx" + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + 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; + } + + + /** Fill linear or axial gradient + + Since most of the code for linear and axial gradients are + the same, we've a unified method here + */ + void fillLinearGradient( OutputDevice& rOutDev, + const ::basegfx::B2DHomMatrix& rTextureTransform, + const ::Rectangle& rBounds, + unsigned int nStepCount, + const ::canvas::ParametricPolyPolygon::Values& rValues, + const std::vector< ::Color >& rColors ) + { + // determine general position of gradient in relation to + // the bound rect + // ===================================================== + + ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 ); + ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 ); + ::basegfx::B2DPoint aRightTop( 1.0, 0.0 ); + ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 ); + + aLeftTop *= rTextureTransform; + aLeftBottom *= rTextureTransform; + aRightTop *= rTextureTransform; + aRightBottom*= rTextureTransform; + + // calc length of bound rect diagonal + const ::basegfx::B2DVector aBoundRectDiagonal( + ::vcl::unotools::b2DPointFromPoint( rBounds.TopLeft() ) - + ::vcl::unotools::b2DPointFromPoint( rBounds.BottomRight() ) ); + const double nDiagonalLength( aBoundRectDiagonal.getLength() ); + + // create direction of gradient: + // _______ + // | | | + // -> | | | ... + // | | | + // ------- + ::basegfx::B2DVector aDirection( aRightTop - aLeftTop ); + aDirection.normalize(); + + // now, we potentially have to enlarge our gradient area + // atop and below the transformed [0,1]x[0,1] unit rect, + // for the gradient to fill the complete bound rect. + ::basegfx::tools::infiniteLineFromParallelogram( aLeftTop, + aLeftBottom, + aRightTop, + aRightBottom, + ::vcl::unotools::b2DRectangleFromRectangle( rBounds ) ); + + + // render gradient + // =============== + + // for linear gradients, it's easy to render + // non-overlapping polygons: just split the gradient into + // nStepCount small strips. Prepare the strip now. + + // For performance reasons, we create a temporary VCL + // polygon here, keep it all the way and only change the + // vertex values in the loop below (as ::Polygon is a + // pimpl class, creating one every loop turn would really + // stress the mem allocator) + ::Polygon aTempPoly( static_cast<USHORT>(5) ); + + OSL_ENSURE( nStepCount >= 3, + "fillLinearGradient(): stepcount smaller than 3" ); + + + // fill initial strip (extending two times the bound rect's + // diagonal to the 'left' + // ------------------------------------------------------ + + // calculate left edge, by moving left edge of the + // gradient rect two times the bound rect's diagonal to + // the 'left'. Since we postpone actual rendering into the + // loop below, we set the _right_ edge here, which will be + // readily copied into the left edge in the loop below + const ::basegfx::B2DPoint& rPoint1( aLeftTop - 2.0*nDiagonalLength*aDirection ); + aTempPoly[1] = ::Point( ::basegfx::fround( rPoint1.getX() ), + ::basegfx::fround( rPoint1.getY() ) ); + + const ::basegfx::B2DPoint& rPoint2( aLeftBottom - 2.0*nDiagonalLength*aDirection ); + aTempPoly[2] = ::Point( ::basegfx::fround( rPoint2.getX() ), + ::basegfx::fround( rPoint2.getY() ) ); + + + // iteratively render all other strips + // ----------------------------------- + + // ensure that nStepCount matches color stop parity, to + // have a well-defined middle color e.g. for axial + // gradients. + if( (rColors.size() % 2) != (nStepCount % 2) ) + ++nStepCount; + + basegfx::tools::KeyStopLerp aLerper(rValues.maStops); + + // only iterate nStepCount-1 steps, as the last strip is + // explicitely painted below + for( unsigned int i=0; i<nStepCount-1; ++i ) + { + std::ptrdiff_t nIndex; + double fAlpha; + boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(double(i)/nStepCount); + + rOutDev.SetFillColor( + Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)), + (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)), + (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) )); + + // copy right egde of polygon to left edge (and also + // copy the closing point) + aTempPoly[0] = aTempPoly[4] = aTempPoly[1]; + aTempPoly[3] = aTempPoly[2]; + + // calculate new right edge, from interpolating + // between start and end line. Note that i is + // increased by one, to account for the fact that we + // calculate the right border here (whereas the fill + // color is governed by the left edge) + const ::basegfx::B2DPoint& rPoint3( + (nStepCount - i-1)/double(nStepCount)*aLeftTop + + (i+1)/double(nStepCount)*aRightTop ); + aTempPoly[1] = ::Point( ::basegfx::fround( rPoint3.getX() ), + ::basegfx::fround( rPoint3.getY() ) ); + + const ::basegfx::B2DPoint& rPoint4( + (nStepCount - i-1)/double(nStepCount)*aLeftBottom + + (i+1)/double(nStepCount)*aRightBottom ); + aTempPoly[2] = ::Point( ::basegfx::fround( rPoint4.getX() ), + ::basegfx::fround( rPoint4.getY() ) ); + + rOutDev.DrawPolygon( aTempPoly ); + } + + // fill final strip (extending two times the bound rect's + // diagonal to the 'right' + // ------------------------------------------------------ + + // copy right egde of polygon to left edge (and also + // copy the closing point) + aTempPoly[0] = aTempPoly[4] = aTempPoly[1]; + aTempPoly[3] = aTempPoly[2]; + + // calculate new right edge, by moving right edge of the + // gradient rect two times the bound rect's diagonal to + // the 'right'. + const ::basegfx::B2DPoint& rPoint3( aRightTop + 2.0*nDiagonalLength*aDirection ); + aTempPoly[0] = aTempPoly[4] = ::Point( ::basegfx::fround( rPoint3.getX() ), + ::basegfx::fround( rPoint3.getY() ) ); + + const ::basegfx::B2DPoint& rPoint4( aRightBottom + 2.0*nDiagonalLength*aDirection ); + aTempPoly[3] = ::Point( ::basegfx::fround( rPoint4.getX() ), + ::basegfx::fround( rPoint4.getY() ) ); + + rOutDev.SetFillColor( rColors.back() ); + + rOutDev.DrawPolygon( aTempPoly ); + } + + void fillPolygonalGradient( OutputDevice& rOutDev, + const ::basegfx::B2DHomMatrix& rTextureTransform, + const ::Rectangle& rBounds, + unsigned int nStepCount, + bool bFillNonOverlapping, + const ::canvas::ParametricPolyPolygon::Values& rValues, + const std::vector< ::Color >& rColors ) + { + const ::basegfx::B2DPolygon& rGradientPoly( rValues.maGradientPoly ); + + ENSURE_OR_THROW( rGradientPoly.count() > 2, + "fillPolygonalGradient(): polygon without area given" ); + + // For performance reasons, we create a temporary VCL polygon + // here, keep it all the way and only change the vertex values + // in the loop below (as ::Polygon is a pimpl class, creating + // one every loop turn would really stress the mem allocator) + ::basegfx::B2DPolygon aOuterPoly( rGradientPoly ); + ::basegfx::B2DPolygon aInnerPoly; + + // subdivide polygon _before_ rendering, would otherwise have + // to be performed on every loop turn. + if( aOuterPoly.areControlPointsUsed() ) + aOuterPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aOuterPoly); + + aInnerPoly = aOuterPoly; + + // only transform outer polygon _after_ copying it into + // aInnerPoly, because inner polygon has to be scaled before + // the actual texture transformation takes place + aOuterPoly.transform( rTextureTransform ); + + // determine overall transformation for inner polygon (might + // have to be prefixed by anisotrophic scaling) + ::basegfx::B2DHomMatrix aInnerPolygonTransformMatrix; + + + // apply scaling (possibly anisotrophic) to inner polygon + // ------------------------------------------------------ + + // scale inner polygon according to aspect ratio: for + // wider-than-tall bounds (nAspectRatio > 1.0), the inner + // polygon, representing the gradient focus, must have + // non-zero width. Specifically, a bound rect twice as wide as + // tall has a focus polygon of half it's width. + const double nAspectRatio( rValues.mnAspectRatio ); + if( nAspectRatio > 1.0 ) + { + // width > height case + aInnerPolygonTransformMatrix.scale( 1.0 - 1.0/nAspectRatio, + 0.0 ); + } + else if( nAspectRatio < 1.0 ) + { + // width < height case + aInnerPolygonTransformMatrix.scale( 0.0, + 1.0 - nAspectRatio ); + } + else + { + // isotrophic case + aInnerPolygonTransformMatrix.scale( 0.0, 0.0 ); + } + + // and finally, add texture transform to it. + aInnerPolygonTransformMatrix *= rTextureTransform; + + // apply final matrix to polygon + aInnerPoly.transform( aInnerPolygonTransformMatrix ); + + + const sal_uInt32 nNumPoints( aOuterPoly.count() ); + ::Polygon aTempPoly( static_cast<USHORT>(nNumPoints+1) ); + + // increase number of steps by one: polygonal gradients have + // the outermost polygon rendered in rColor2, and the + // innermost in rColor1. The innermost polygon will never + // have zero area, thus, we must divide the interval into + // nStepCount+1 steps. For example, to create 3 steps: + // + // | | + // |-------|-------|-------| + // | | + // 3 2 1 0 + // + // This yields 4 tick marks, where 0 is never attained (since + // zero-area polygons typically don't display perceivable + // color). + ++nStepCount; + + basegfx::tools::KeyStopLerp aLerper(rValues.maStops); + + if( !bFillNonOverlapping ) + { + // fill background + rOutDev.SetFillColor( rColors.front() ); + rOutDev.DrawRect( rBounds ); + + // render polygon + // ============== + + for( unsigned int i=1,p; i<nStepCount; ++i ) + { + const double fT( i/double(nStepCount) ); + + std::ptrdiff_t nIndex; + double fAlpha; + boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT); + + // lerp color + rOutDev.SetFillColor( + Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)), + (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)), + (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) )); + + // scale and render polygon, by interpolating between + // outer and inner polygon. + + for( p=0; p<nNumPoints; ++p ) + { + const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) ); + const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.getB2DPoint(p) ); + + aTempPoly[(USHORT)p] = ::Point( + basegfx::fround( fT*rInnerPoint.getX() + (1-fT)*rOuterPoint.getX() ), + basegfx::fround( fT*rInnerPoint.getY() + (1-fT)*rOuterPoint.getY() ) ); + } + + // close polygon explicitely + aTempPoly[(USHORT)p] = aTempPoly[0]; + + // TODO(P1): compare with vcl/source/gdi/outdev4.cxx, + // OutputDevice::ImplDrawComplexGradient(), there's a note + // that on some VDev's, rendering disjunct poly-polygons + // is faster! + rOutDev.DrawPolygon( aTempPoly ); + } + } + else + { + // render polygon + // ============== + + // For performance reasons, we create a temporary VCL polygon + // here, keep it all the way and only change the vertex values + // in the loop below (as ::Polygon is a pimpl class, creating + // one every loop turn would really stress the mem allocator) + ::PolyPolygon aTempPolyPoly; + ::Polygon aTempPoly2( static_cast<USHORT>(nNumPoints+1) ); + + aTempPoly2[0] = rBounds.TopLeft(); + aTempPoly2[1] = rBounds.TopRight(); + aTempPoly2[2] = rBounds.BottomRight(); + aTempPoly2[3] = rBounds.BottomLeft(); + aTempPoly2[4] = rBounds.TopLeft(); + + aTempPolyPoly.Insert( aTempPoly ); + aTempPolyPoly.Insert( aTempPoly2 ); + + for( unsigned int i=0,p; i<nStepCount; ++i ) + { + const double fT( (i+1)/double(nStepCount) ); + + std::ptrdiff_t nIndex; + double fAlpha; + boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT); + + // lerp color + rOutDev.SetFillColor( + Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)), + (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)), + (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) )); + +#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 + if( i && !(i % 10) ) + rOutDev.SetFillColor( COL_RED ); +#endif + + // scale and render polygon. Note that here, we + // calculate the inner polygon, which is actually the + // start of the _next_ color strip. Thus, i+1 + + for( p=0; p<nNumPoints; ++p ) + { + const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) ); + const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.getB2DPoint(p) ); + + aTempPoly[(USHORT)p] = ::Point( + basegfx::fround( fT*rInnerPoint.getX() + (1-fT)*rOuterPoint.getX() ), + basegfx::fround( fT*rInnerPoint.getY() + (1-fT)*rOuterPoint.getY() ) ); + } + + // close polygon explicitely + aTempPoly[(USHORT)p] = aTempPoly[0]; + + // swap inner and outer polygon + aTempPolyPoly.Replace( aTempPolyPoly.GetObject( 1 ), 0 ); + + if( i+1<nStepCount ) + { + // assign new inner polygon. Note that with this + // formulation, the internal pimpl objects for both + // temp polygons and the polypolygon remain identical, + // minimizing heap accesses (only a Polygon wrapper + // object is freed and deleted twice during this swap). + aTempPolyPoly.Replace( aTempPoly, 1 ); + } + else + { + // last, i.e. inner strip. Now, the inner polygon + // has zero area anyway, and to not leave holes in + // the gradient, finally render a simple polygon: + aTempPolyPoly.Remove( 1 ); + } + + rOutDev.DrawPolyPolygon( aTempPolyPoly ); + } + } + } + + void doGradientFill( OutputDevice& rOutDev, + const ::canvas::ParametricPolyPolygon::Values& rValues, + const std::vector< ::Color >& rColors, + const ::basegfx::B2DHomMatrix& rTextureTransform, + const ::Rectangle& rBounds, + unsigned int nStepCount, + bool bFillNonOverlapping ) + { + switch( rValues.meType ) + { + case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR: + fillLinearGradient( rOutDev, + rTextureTransform, + rBounds, + nStepCount, + rValues, + rColors ); + break; + + case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL: + // FALLTHROUGH intended + case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR: + fillPolygonalGradient( rOutDev, + rTextureTransform, + rBounds, + nStepCount, + bFillNonOverlapping, + rValues, + rColors ); + break; + + default: + ENSURE_OR_THROW( false, + "CanvasHelper::doGradientFill(): Unexpected case" ); + } + } + + int numColorSteps( const ::Color& rColor1, const ::Color& rColor2 ) + { + return ::std::max( + labs( rColor1.GetRed() - rColor2.GetRed() ), + ::std::max( + labs( rColor1.GetGreen() - rColor2.GetGreen() ), + labs( rColor1.GetBlue() - rColor2.GetBlue() ) ) ); + } + + bool gradientFill( OutputDevice& rOutDev, + OutputDevice* p2ndOutDev, + const ::canvas::ParametricPolyPolygon::Values& rValues, + const std::vector< ::Color >& rColors, + const PolyPolygon& rPoly, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const rendering::Texture& texture, + int nTransparency ) + { + (void)nTransparency; + + // TODO(T2): It is maybe necessary to lock here, should + // maGradientPoly someday cease to be const. But then, beware of + // deadlocks, canvashelper calls this method with locked own + // mutex. + + // calc step size + // -------------- + int nColorSteps = 0; + for( size_t i=0; i<rColors.size()-1; ++i ) + nColorSteps += numColorSteps(rColors[i],rColors[i+1]); + + ::basegfx::B2DHomMatrix aTotalTransform; + const int nStepCount= + ::canvas::tools::calcGradientStepCount(aTotalTransform, + viewState, + renderState, + texture, + nColorSteps); + + rOutDev.SetLineColor(); + + // determine maximal bound rect of texture-filled + // polygon + const ::Rectangle aPolygonDeviceRectOrig( + rPoly.GetBoundRect() ); + + if( tools::isRectangle( rPoly ) ) + { + // use optimized output path + // ------------------------- + + // this distinction really looks like a + // micro-optimisation, but in fact greatly speeds up + // especially complex gradients. That's because when using + // clipping, we can output polygons instead of + // poly-polygons, and don't have to output the gradient + // twice for XOR + + rOutDev.Push( PUSH_CLIPREGION ); + rOutDev.IntersectClipRegion( aPolygonDeviceRectOrig ); + doGradientFill( rOutDev, + rValues, + rColors, + aTotalTransform, + aPolygonDeviceRectOrig, + nStepCount, + false ); + rOutDev.Pop(); + + if( p2ndOutDev ) + { + p2ndOutDev->Push( PUSH_CLIPREGION ); + p2ndOutDev->IntersectClipRegion( aPolygonDeviceRectOrig ); + doGradientFill( *p2ndOutDev, + rValues, + rColors, + aTotalTransform, + aPolygonDeviceRectOrig, + nStepCount, + false ); + p2ndOutDev->Pop(); + } + } + else +#if defined(QUARTZ) // TODO: other ports should avoid the XOR-trick too (implementation vs. interface!) + { + const Region aPolyClipRegion( rPoly ); + + rOutDev.Push( PUSH_CLIPREGION ); + rOutDev.SetClipRegion( aPolyClipRegion ); + + doGradientFill( rOutDev, + rValues, + rColors, + aTotalTransform, + aPolygonDeviceRectOrig, + nStepCount, + false ); + rOutDev.Pop(); + + if( p2ndOutDev ) + { + p2ndOutDev->Push( PUSH_CLIPREGION ); + p2ndOutDev->SetClipRegion( aPolyClipRegion ); + doGradientFill( *p2ndOutDev, + rValues, + rColors, + aTotalTransform, + aPolygonDeviceRectOrig, + nStepCount, + false ); + p2ndOutDev->Pop(); + } + } +#else // TODO: remove once doing the XOR-trick in the canvas-layer becomes redundant + { + // output gradient the hard way: XORing out the polygon + rOutDev.Push( PUSH_RASTEROP ); + rOutDev.SetRasterOp( ROP_XOR ); + doGradientFill( rOutDev, + rValues, + rColors, + aTotalTransform, + aPolygonDeviceRectOrig, + nStepCount, + true ); + rOutDev.SetFillColor( COL_BLACK ); + rOutDev.SetRasterOp( ROP_0 ); + rOutDev.DrawPolyPolygon( rPoly ); + rOutDev.SetRasterOp( ROP_XOR ); + doGradientFill( rOutDev, + rValues, + rColors, + aTotalTransform, + aPolygonDeviceRectOrig, + nStepCount, + true ); + rOutDev.Pop(); + + if( p2ndOutDev ) + { + p2ndOutDev->Push( PUSH_RASTEROP ); + p2ndOutDev->SetRasterOp( ROP_XOR ); + doGradientFill( *p2ndOutDev, + rValues, + rColors, + aTotalTransform, + aPolygonDeviceRectOrig, + nStepCount, + true ); + p2ndOutDev->SetFillColor( COL_BLACK ); + p2ndOutDev->SetRasterOp( ROP_0 ); + p2ndOutDev->DrawPolyPolygon( rPoly ); + p2ndOutDev->SetRasterOp( ROP_XOR ); + doGradientFill( *p2ndOutDev, + rValues, + rColors, + aTotalTransform, + aPolygonDeviceRectOrig, + nStepCount, + true ); + p2ndOutDev->Pop(); + } + } +#endif // complex-clipping vs. XOR-trick + +#if 0 //defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 + { + ::basegfx::B2DRectangle aRect(0.0, 0.0, 1.0, 1.0); + ::basegfx::B2DRectangle aTextureDeviceRect; + ::basegfx::B2DHomMatrix aTextureTransform; + ::canvas::tools::calcTransformedRectBounds( aTextureDeviceRect, + aRect, + aTextureTransform ); + rOutDev.SetLineColor( COL_RED ); + rOutDev.SetFillColor(); + rOutDev.DrawRect( ::vcl::unotools::rectangleFromB2DRectangle( aTextureDeviceRect ) ); + + rOutDev.SetLineColor( COL_BLUE ); + ::Polygon aPoly1( + ::vcl::unotools::rectangleFromB2DRectangle( aRect )); + ::basegfx::B2DPolygon aPoly2( aPoly1.getB2DPolygon() ); + aPoly2.transform( aTextureTransform ); + ::Polygon aPoly3( aPoly2 ); + rOutDev.DrawPolygon( aPoly3 ); + } +#endif + + return true; + } + } + + uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTexturedPolyPolygon( const rendering::XCanvas* pCanvas, + 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"); + + if( mpOutDev ) + { + tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); + + const int nTransparency( setupOutDevState( viewState, renderState, IGNORE_COLOR ) ); + PolyPolygon aPolyPoly( tools::mapPolyPolygon( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon), + viewState, renderState ) ); + + // TODO(F1): Multi-texturing + if( textures[0].Gradient.is() ) + { + // try to cast XParametricPolyPolygon2D reference to + // our implementation class. + ::canvas::ParametricPolyPolygon* pGradient = + dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() ); + + if( pGradient && pGradient->getValues().maColors.getLength() ) + { + // copy state from Gradient polypoly locally + // (given object might change!) + const ::canvas::ParametricPolyPolygon::Values& rValues( + pGradient->getValues() ); + + if( rValues.maColors.getLength() < 2 ) + { + rendering::RenderState aTempState=renderState; + aTempState.DeviceColor = rValues.maColors[0]; + fillPolyPolygon(pCanvas, xPolyPolygon, viewState, aTempState); + } + else + { + std::vector< ::Color > aColors(rValues.maColors.getLength()); + std::transform(&rValues.maColors[0], + &rValues.maColors[0]+rValues.maColors.getLength(), + aColors.begin(), + boost::bind( + &vcl::unotools::stdColorSpaceSequenceToColor, + _1)); + + // TODO(E1): Return value + // TODO(F1): FillRule + gradientFill( mpOutDev->getOutDev(), + mp2ndOutDev.get() ? &mp2ndOutDev->getOutDev() : (OutputDevice*)NULL, + rValues, + aColors, + aPolyPoly, + viewState, + renderState, + textures[0], + nTransparency ); + } + } + else + { + // TODO(F1): The generic case is missing here + ENSURE_OR_THROW( false, + "CanvasHelper::fillTexturedPolyPolygon(): unknown parametric polygon encountered" ); + } + } + else if( textures[0].Bitmap.is() ) + { + const geometry::IntegerSize2D aBmpSize( textures[0].Bitmap->getSize() ); + + ENSURE_ARG_OR_THROW( aBmpSize.Width != 0 && + aBmpSize.Height != 0, + "CanvasHelper::fillTexturedPolyPolygon(): zero-sized texture bitmap" ); + + // determine maximal bound rect of texture-filled + // polygon + const ::Rectangle aPolygonDeviceRect( + aPolyPoly.GetBoundRect() ); + + + // first of all, determine whether we have a + // drawBitmap() in disguise + // ========================================= + + const bool bRectangularPolygon( tools::isRectangle( aPolyPoly ) ); + + ::basegfx::B2DHomMatrix aTotalTransform; + ::canvas::tools::mergeViewAndRenderTransform(aTotalTransform, + viewState, + renderState); + ::basegfx::B2DHomMatrix aTextureTransform; + ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform, + textures[0].AffineTransform ); + + aTotalTransform *= aTextureTransform; + + const ::basegfx::B2DRectangle aRect(0.0, 0.0, 1.0, 1.0); + ::basegfx::B2DRectangle aTextureDeviceRect; + ::canvas::tools::calcTransformedRectBounds( aTextureDeviceRect, + aRect, + aTotalTransform ); + + const ::Rectangle aIntegerTextureDeviceRect( + ::vcl::unotools::rectangleFromB2DRectangle( aTextureDeviceRect ) ); + + if( bRectangularPolygon && + aIntegerTextureDeviceRect == aPolygonDeviceRect ) + { + rendering::RenderState aLocalState( renderState ); + ::canvas::tools::appendToRenderState(aLocalState, + aTextureTransform); + ::basegfx::B2DHomMatrix aScaleCorrection; + aScaleCorrection.scale( 1.0/aBmpSize.Width, + 1.0/aBmpSize.Height ); + ::canvas::tools::appendToRenderState(aLocalState, + aScaleCorrection); + + // need alpha modulation? + if( !::rtl::math::approxEqual( textures[0].Alpha, + 1.0 ) ) + { + // setup alpha modulation values + aLocalState.DeviceColor.realloc(4); + double* pColor = aLocalState.DeviceColor.getArray(); + pColor[0] = + pColor[1] = + pColor[2] = 0.0; + pColor[3] = textures[0].Alpha; + + return drawBitmapModulated( pCanvas, + textures[0].Bitmap, + viewState, + aLocalState ); + } + else + { + return drawBitmap( pCanvas, + textures[0].Bitmap, + viewState, + aLocalState ); + } + } + else + { + // No easy mapping to drawBitmap() - calculate + // texturing parameters + // =========================================== + + BitmapEx aBmpEx( tools::bitmapExFromXBitmap( textures[0].Bitmap ) ); + + // scale down bitmap to [0,1]x[0,1] rect, as required + // from the XCanvas interface. + ::basegfx::B2DHomMatrix aScaling; + ::basegfx::B2DHomMatrix aPureTotalTransform; // pure view*render*texture transform + aScaling.scale( 1.0/aBmpSize.Width, + 1.0/aBmpSize.Height ); + + aTotalTransform = aTextureTransform * aScaling; + aPureTotalTransform = aTextureTransform; + + // combine with view and render transform + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, viewState, renderState); + + // combine all three transformations into one + // global texture-to-device-space transformation + aTotalTransform *= aMatrix; + aPureTotalTransform *= aMatrix; + + // analyze transformation, and setup an + // appropriate GraphicObject + ::basegfx::B2DVector aScale; + ::basegfx::B2DPoint aOutputPos; + double nRotate; + double nShearX; + aTotalTransform.decompose( aScale, aOutputPos, nRotate, nShearX ); + + GraphicAttr aGrfAttr; + GraphicObjectSharedPtr pGrfObj; + + if( ::basegfx::fTools::equalZero( nShearX ) ) + { + // no shear, GraphicObject is enough (the + // GraphicObject only supports scaling, rotation + // and translation) + + // setup GraphicAttr + aGrfAttr.SetMirrorFlags( + ( aScale.getX() < 0.0 ? BMP_MIRROR_HORZ : 0 ) | + ( aScale.getY() < 0.0 ? BMP_MIRROR_VERT : 0 ) ); + aGrfAttr.SetRotation( static_cast< USHORT >(::basegfx::fround( nRotate*10.0 )) ); + + pGrfObj.reset( new GraphicObject( aBmpEx ) ); + } + else + { + // complex transformation, use generic affine bitmap + // transformation + aBmpEx = tools::transformBitmap( aBmpEx, + aTotalTransform, + uno::Sequence< double >(), + tools::MODULATE_NONE); + + pGrfObj.reset( new GraphicObject( aBmpEx ) ); + + // clear scale values, generated bitmap already + // contains scaling + aScale.setX( 0.0 ); aScale.setY( 0.0 ); + } + + + // render texture tiled into polygon + // ================================= + + // calc device space direction vectors. We employ + // the followin approach for tiled output: the + // texture bitmap is output in texture space + // x-major order, i.e. tile neighbors in texture + // space x direction are rendered back-to-back in + // device coordinate space (after the full device + // transformation). Thus, the aNextTile* vectors + // denote the output position updates in device + // space, to get from one tile to the next. + ::basegfx::B2DVector aNextTileX( 1.0, 0.0 ); + ::basegfx::B2DVector aNextTileY( 0.0, 1.0 ); + aNextTileX *= aPureTotalTransform; + aNextTileY *= aPureTotalTransform; + + ::basegfx::B2DHomMatrix aInverseTextureTransform( aPureTotalTransform ); + + ENSURE_ARG_OR_THROW( aInverseTextureTransform.isInvertible(), + "CanvasHelper::fillTexturedPolyPolygon(): singular texture matrix" ); + + aInverseTextureTransform.invert(); + + // calc bound rect of extended texture area in + // device coordinates. Therefore, we first calc + // the area of the polygon bound rect in texture + // space. To maintain texture phase, this bound + // rect is then extended to integer coordinates + // (extended, because shrinking might leave some + // inner polygon areas unfilled). + // Finally, the bound rect is transformed back to + // device coordinate space, were we determine the + // start point from it. + ::basegfx::B2DRectangle aTextureSpacePolygonRect; + ::canvas::tools::calcTransformedRectBounds( aTextureSpacePolygonRect, + ::vcl::unotools::b2DRectangleFromRectangle( + aPolygonDeviceRect ), + aInverseTextureTransform ); + + // calc left, top of extended polygon rect in + // texture space, create one-texture instance rect + // from it (i.e. rect from start point extending + // 1.0 units to the right and 1.0 units to the + // bottom). Note that the rounding employed here + // is a bit subtle, since we need to round up/down + // as _soon_ as any fractional amount is + // encountered. This is to ensure that the full + // polygon area is filled with texture tiles. + const sal_Int32 nX1( ::canvas::tools::roundDown( aTextureSpacePolygonRect.getMinX() ) ); + const sal_Int32 nY1( ::canvas::tools::roundDown( aTextureSpacePolygonRect.getMinY() ) ); + const sal_Int32 nX2( ::canvas::tools::roundUp( aTextureSpacePolygonRect.getMaxX() ) ); + const sal_Int32 nY2( ::canvas::tools::roundUp( aTextureSpacePolygonRect.getMaxY() ) ); + const ::basegfx::B2DRectangle aSingleTextureRect( + nX1, nY1, + nX1 + 1.0, + nY1 + 1.0 ); + + // and convert back to device space + ::basegfx::B2DRectangle aSingleDeviceTextureRect; + ::canvas::tools::calcTransformedRectBounds( aSingleDeviceTextureRect, + aSingleTextureRect, + aPureTotalTransform ); + + const ::Point aPtRepeat( ::vcl::unotools::pointFromB2DPoint( + aSingleDeviceTextureRect.getMinimum() ) ); + const ::Size aSz( ::basegfx::fround( aScale.getX() * aBmpSize.Width ), + ::basegfx::fround( aScale.getY() * aBmpSize.Height ) ); + const ::Size aIntegerNextTileX( ::vcl::unotools::sizeFromB2DSize(aNextTileX) ); + const ::Size aIntegerNextTileY( ::vcl::unotools::sizeFromB2DSize(aNextTileY) ); + + const ::Point aPt( textures[0].RepeatModeX == rendering::TexturingMode::NONE ? + ::basegfx::fround( aOutputPos.getX() ) : aPtRepeat.X(), + textures[0].RepeatModeY == rendering::TexturingMode::NONE ? + ::basegfx::fround( aOutputPos.getY() ) : aPtRepeat.Y() ); + const sal_Int32 nTilesX( textures[0].RepeatModeX == rendering::TexturingMode::NONE ? + 1 : nX2 - nX1 ); + const sal_Int32 nTilesY( textures[0].RepeatModeX == rendering::TexturingMode::NONE ? + 1 : nY2 - nY1 ); + + OutputDevice& rOutDev( mpOutDev->getOutDev() ); + + if( bRectangularPolygon ) + { + // use optimized output path + // ------------------------- + + // this distinction really looks like a + // micro-optimisation, but in fact greatly speeds up + // especially complex fills. That's because when using + // clipping, we can output polygons instead of + // poly-polygons, and don't have to output the gradient + // twice for XOR + + // setup alpha modulation + if( !::rtl::math::approxEqual( textures[0].Alpha, + 1.0 ) ) + { + // TODO(F1): Note that the GraphicManager has + // a subtle difference in how it calculates + // the resulting alpha value: it's using the + // inverse alpha values (i.e. 'transparency'), + // and calculates transOrig + transModulate, + // instead of transOrig + transModulate - + // transOrig*transModulate (which would be + // equivalent to the origAlpha*modulateAlpha + // the DX canvas performs) + aGrfAttr.SetTransparency( + static_cast< BYTE >( + ::basegfx::fround( 255.0*( 1.0 - textures[0].Alpha ) ) ) ); + } + + rOutDev.IntersectClipRegion( aPolygonDeviceRect ); + textureFill( rOutDev, + *pGrfObj, + aPt, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + + if( mp2ndOutDev ) + { + OutputDevice& r2ndOutDev( mp2ndOutDev->getOutDev() ); + r2ndOutDev.IntersectClipRegion( aPolygonDeviceRect ); + textureFill( r2ndOutDev, + *pGrfObj, + aPt, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + } + } + else + { + // output texture the hard way: XORing out the + // polygon + // =========================================== + + if( !::rtl::math::approxEqual( textures[0].Alpha, + 1.0 ) ) + { + // uh-oh. alpha blending is required, + // cannot do direct XOR, but have to + // prepare the filled polygon within a + // VDev + VirtualDevice aVDev( rOutDev ); + aVDev.SetOutputSizePixel( aPolygonDeviceRect.GetSize() ); + + // shift output to origin of VDev + const ::Point aOutPos( aPt - aPolygonDeviceRect.TopLeft() ); + aPolyPoly.Translate( ::Point( -aPolygonDeviceRect.Left(), + -aPolygonDeviceRect.Top() ) ); + + const Region aPolyClipRegion( aPolyPoly ); + + aVDev.SetClipRegion( aPolyClipRegion ); + textureFill( aVDev, + *pGrfObj, + aOutPos, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + + // output VDev content alpha-blended to + // target position. + const ::Point aEmptyPoint; + Bitmap aContentBmp( + aVDev.GetBitmap( aEmptyPoint, + aVDev.GetOutputSizePixel() ) ); + + BYTE nCol( static_cast< BYTE >( + ::basegfx::fround( 255.0*( 1.0 - textures[0].Alpha ) ) ) ); + AlphaMask aAlpha( aVDev.GetOutputSizePixel(), + &nCol ); + + BitmapEx aOutputBmpEx( aContentBmp, aAlpha ); + rOutDev.DrawBitmapEx( aPolygonDeviceRect.TopLeft(), + aOutputBmpEx ); + + if( mp2ndOutDev ) + mp2ndOutDev->getOutDev().DrawBitmapEx( aPolygonDeviceRect.TopLeft(), + aOutputBmpEx ); + } + else + { + const Region aPolyClipRegion( aPolyPoly ); + + rOutDev.Push( PUSH_CLIPREGION ); + rOutDev.SetClipRegion( aPolyClipRegion ); + + textureFill( rOutDev, + *pGrfObj, + aPt, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + rOutDev.Pop(); + + if( mp2ndOutDev ) + { + OutputDevice& r2ndOutDev( mp2ndOutDev->getOutDev() ); + r2ndOutDev.Push( PUSH_CLIPREGION ); + + r2ndOutDev.SetClipRegion( aPolyClipRegion ); + textureFill( r2ndOutDev, + *pGrfObj, + aPt, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + r2ndOutDev.Pop(); + } + } + } + } + } + } + + // TODO(P1): Provide caching here. + return uno::Reference< rendering::XCachedPrimitive >(NULL); + } + +} diff --git a/canvas/source/vcl/devicehelper.cxx b/canvas/source/vcl/devicehelper.cxx new file mode 100644 index 000000000000..9b7b9fac2857 --- /dev/null +++ b/canvas/source/vcl/devicehelper.cxx @@ -0,0 +1,242 @@ +/************************************************************************* + * + * 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 <canvas/canvastools.hxx> + +#include <rtl/instance.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/canvastools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/tools/unopolypolygon.hxx> + +#include "devicehelper.hxx" +#include "spritecanvas.hxx" +#include "spritecanvashelper.hxx" +#include "canvasbitmap.hxx" + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + DeviceHelper::DeviceHelper() : + mpOutDev() + {} + + void DeviceHelper::init( const OutDevProviderSharedPtr& rOutDev ) + { + mpOutDev = rOutDev; + } + + geometry::RealSize2D DeviceHelper::getPhysicalResolution() + { + if( !mpOutDev ) + return ::canvas::tools::createInfiniteSize2D(); // we're disposed + + // Map a one-by-one millimeter box to pixel + OutputDevice& rOutDev = mpOutDev->getOutDev(); + const MapMode aOldMapMode( rOutDev.GetMapMode() ); + rOutDev.SetMapMode( MapMode(MAP_MM) ); + const Size aPixelSize( rOutDev.LogicToPixel(Size(1,1)) ); + rOutDev.SetMapMode( aOldMapMode ); + + return ::vcl::unotools::size2DFromSize( aPixelSize ); + } + + geometry::RealSize2D DeviceHelper::getPhysicalSize() + { + if( !mpOutDev ) + return ::canvas::tools::createInfiniteSize2D(); // we're disposed + + // Map the pixel dimensions of the output window to millimeter + OutputDevice& rOutDev = mpOutDev->getOutDev(); + const MapMode aOldMapMode( rOutDev.GetMapMode() ); + rOutDev.SetMapMode( MapMode(MAP_MM) ); + const Size aLogSize( rOutDev.PixelToLogic(rOutDev.GetOutputSizePixel()) ); + rOutDev.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 ) + { + uno::Reference< rendering::XLinePolyPolygon2D > xPoly; + if( !mpOutDev ) + return xPoly; // we're disposed + + xPoly.set( new ::basegfx::unotools::UnoPolyPolygon( + ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points ) ) ); + // vcl only handles even_odd polygons + xPoly->setFillRule(rendering::FillRule_EVEN_ODD); + + return xPoly; + } + + uno::Reference< rendering::XBezierPolyPolygon2D > DeviceHelper::createCompatibleBezierPolyPolygon( + const uno::Reference< rendering::XGraphicDevice >& , + const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points ) + { + uno::Reference< rendering::XBezierPolyPolygon2D > xPoly; + if( !mpOutDev ) + return xPoly; // we're disposed + + xPoly.set( new ::basegfx::unotools::UnoPolyPolygon( + ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points ) ) ); + // vcl only handles even_odd polygons + xPoly->setFillRule(rendering::FillRule_EVEN_ODD); + + return xPoly; + } + + uno::Reference< rendering::XBitmap > DeviceHelper::createCompatibleBitmap( + const uno::Reference< rendering::XGraphicDevice >& rDevice, + const geometry::IntegerSize2D& size ) + { + if( !mpOutDev ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + return uno::Reference< rendering::XBitmap >( + new CanvasBitmap( ::vcl::unotools::sizeFromIntegerSize2D(size), + false, + *rDevice.get(), + mpOutDev ) ); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileBitmap( + const uno::Reference< rendering::XGraphicDevice >& , + const geometry::IntegerSize2D& ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + uno::Reference< rendering::XBitmap > DeviceHelper::createCompatibleAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& rDevice, + const geometry::IntegerSize2D& size ) + { + if( !mpOutDev ) + return uno::Reference< rendering::XBitmap >(); // we're disposed + + return uno::Reference< rendering::XBitmap >( + new CanvasBitmap( ::vcl::unotools::sizeFromIntegerSize2D(size), + true, + *rDevice.get(), + mpOutDev ) ); + } + + uno::Reference< rendering::XVolatileBitmap > DeviceHelper::createVolatileAlphaBitmap( + const uno::Reference< rendering::XGraphicDevice >& , + const geometry::IntegerSize2D& ) + { + return uno::Reference< rendering::XVolatileBitmap >(); + } + + sal_Bool DeviceHelper::hasFullScreenMode() + { + return false; + } + + sal_Bool DeviceHelper::enterFullScreenMode( sal_Bool bEnter ) + { + (void)bEnter; + return false; + } + + void DeviceHelper::disposing() + { + // release all references + mpOutDev.reset(); + } + + uno::Any DeviceHelper::isAccelerated() const + { + return ::com::sun::star::uno::makeAny(false); + } + + uno::Any DeviceHelper::getDeviceHandle() const + { + if( !mpOutDev ) + return uno::Any(); + + return uno::makeAny( + reinterpret_cast< sal_Int64 >(&mpOutDev->getOutDev()) ); + } + + uno::Any DeviceHelper::getSurfaceHandle() const + { + return getDeviceHandle(); + } + + 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( mpOutDev ) + { + String aFilename( String::CreateFromAscii("dbg_frontbuffer") ); + aFilename += String::CreateFromInt32(nFilePostfixCount); + aFilename += String::CreateFromAscii(".bmp"); + + SvFileStream aStream( aFilename, STREAM_STD_READWRITE ); + + const ::Point aEmptyPoint; + OutputDevice& rOutDev = mpOutDev->getOutDev(); + bool bOldMap( rOutDev.IsMapModeEnabled() ); + rOutDev.EnableMapMode( FALSE ); + aStream << rOutDev.GetBitmap(aEmptyPoint, + rOutDev.GetOutputSizePixel()); + rOutDev.EnableMapMode( bOldMap ); + + ++nFilePostfixCount; + } + } + +} diff --git a/canvas/source/vcl/devicehelper.hxx b/canvas/source/vcl/devicehelper.hxx new file mode 100644 index 000000000000..aa17e98b8070 --- /dev/null +++ b/canvas/source/vcl/devicehelper.hxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * 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_DEVICEHELPER_HXX +#define _VCLCANVAS_DEVICEHELPER_HXX + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> + +#include "outdevprovider.hxx" + +#include <boost/utility.hpp> + + +/* Definition of DeviceHelper class */ + +namespace vclcanvas +{ + class Canvas; + + class DeviceHelper : private ::boost::noncopyable + { + public: + DeviceHelper(); + + void init( const OutDevProviderSharedPtr& rOutDev ); + + /// 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; + + OutDevProviderSharedPtr getOutDev() const { return mpOutDev; } + + /** called when DumpScreenContent property is enabled on + XGraphicDevice, and writes out bitmaps of current screen. + */ + void dumpScreenContent() const; + + private: + /// For retrieving device info + OutDevProviderSharedPtr mpOutDev; + }; +} + +#endif /* _VCLCANVAS_DEVICEHELPER_HXX */ diff --git a/canvas/source/vcl/exports.dxp b/canvas/source/vcl/exports.dxp new file mode 100644 index 000000000000..0cb5620a1603 --- /dev/null +++ b/canvas/source/vcl/exports.dxp @@ -0,0 +1,2 @@ +component_getImplementationEnvironment +component_getFactory
\ No newline at end of file diff --git a/canvas/source/vcl/impltools.cxx b/canvas/source/vcl/impltools.cxx new file mode 100644 index 000000000000..b4c19aa5a028 --- /dev/null +++ b/canvas/source/vcl/impltools.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 <tools/diagnose_ex.h> + +#include <rtl/math.hxx> +#include <rtl/logfile.hxx> + +#include <com/sun/star/geometry/RealSize2D.hpp> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/geometry/RealRectangle2D.hpp> +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XBitmap.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> +#include <com/sun/star/geometry/RealBezierSegment2D.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <vcl/salbtype.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/metric.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/canvastools.hxx> + +#include "impltools.hxx" +#include "canvasbitmap.hxx" + +#include <numeric> + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + namespace tools + { + ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) + { + // TODO(F3): CanvasCustomSprite should also be tunnelled + // through (also implements XIntegerBitmap interface) + CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() ); + + if( pBitmapImpl ) + { + return pBitmapImpl->getBitmap(); + } + else + { + SpriteCanvas* pCanvasImpl = dynamic_cast< SpriteCanvas* >( xBitmap.get() ); + if( pCanvasImpl && pCanvasImpl->getBackBuffer() ) + { + // TODO(F3): mind the plain Canvas impl. Consolidate with CWS canvas05 + const ::OutputDevice& rDev( pCanvasImpl->getBackBuffer()->getOutDev() ); + const ::Point aEmptyPoint; + return rDev.GetBitmapEx( aEmptyPoint, + rDev.GetOutputSizePixel() ); + } + + // TODO(F2): 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 bitmap" ); + } + + return ::BitmapEx(); + } + + bool setupFontTransform( ::Point& o_rPoint, + ::Font& io_rVCLFont, + const rendering::ViewState& rViewState, + const rendering::RenderState& rRenderState, + ::OutputDevice& rOutDev ) + { + ::basegfx::B2DHomMatrix aMatrix; + + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, + rViewState, + rRenderState); + + ::basegfx::B2DTuple aScale; + ::basegfx::B2DTuple aTranslate; + double nRotate, nShearX; + + aMatrix.decompose( aScale, aTranslate, nRotate, nShearX ); + + // #i72417# detecting the 180 degree rotation case manually here. + if( aScale.getX() < 0.0 && + aScale.getY() < 0.0 && + basegfx::fTools::equalZero(nRotate) ) + { + aScale *= -1.0; + nRotate += M_PI; + } + + // 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; + } + + bool isRectangle( const PolyPolygon& rPolyPoly ) + { + // exclude some cheap cases first + if( rPolyPoly.Count() != 1 ) + return false; + + const ::Polygon& rPoly( rPolyPoly[0] ); + + USHORT nCount( rPoly.GetSize() ); + if( nCount < 4 ) + return false; + + // delegate to basegfx + return ::basegfx::tools::isRectangle( rPoly.getB2DPolygon() ); + } + + + // VCL-Canvas related + //--------------------------------------------------------------------- + + ::Point mapRealPoint2D( const geometry::RealPoint2D& rPoint, + const rendering::ViewState& rViewState, + const rendering::RenderState& rRenderState ) + { + ::basegfx::B2DPoint aPoint( ::basegfx::unotools::b2DPointFromRealPoint2D(rPoint) ); + + ::basegfx::B2DHomMatrix aMatrix; + aPoint *= ::canvas::tools::mergeViewAndRenderTransform(aMatrix, + rViewState, + rRenderState); + + return ::vcl::unotools::pointFromB2DPoint( aPoint ); + } + + ::PolyPolygon mapPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, + const rendering::ViewState& rViewState, + const rendering::RenderState& rRenderState ) + { + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, + rViewState, + rRenderState); + + ::basegfx::B2DPolyPolygon aTemp( rPoly ); + + aTemp.transform( aMatrix ); + + return ::PolyPolygon( aTemp ); + } + + ::BitmapEx transformBitmap( const BitmapEx& rBitmap, + const ::basegfx::B2DHomMatrix& rTransform, + const uno::Sequence< double >& rDeviceColor, + ModulationMode eModulationMode ) + { + RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::tools::transformBitmap()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::vclcanvas::tools::transformBitmap: 0x%X", &rBitmap ); + + // calc transformation and size of bitmap to be + // generated. Note, that the translational components are + // deleted from the transformation; this can be handled by + // an offset when painting the bitmap + const Size aBmpSize( rBitmap.GetSizePixel() ); + ::basegfx::B2DRectangle aDestRect; + + bool bCopyBack( false ); + + // calc effective transformation for bitmap + const ::basegfx::B2DRectangle aSrcRect( 0, 0, + aBmpSize.Width(), + aBmpSize.Height() ); + ::canvas::tools::calcTransformedRectBounds( aDestRect, + aSrcRect, + rTransform ); + + // re-center bitmap, such that it's left, top border is + // aligned with (0,0). The method takes the given + // rectangle, and calculates a transformation that maps + // this rectangle unscaled to the origin. + ::basegfx::B2DHomMatrix aLocalTransform; + ::canvas::tools::calcRectToOriginTransform( aLocalTransform, + aSrcRect, + rTransform ); + + const bool bModulateColors( eModulationMode == MODULATE_WITH_DEVICECOLOR && + rDeviceColor.getLength() > 2 ); + const double nRedModulation( bModulateColors ? rDeviceColor[0] : 1.0 ); + const double nGreenModulation( bModulateColors ? rDeviceColor[1] : 1.0 ); + const double nBlueModulation( bModulateColors ? rDeviceColor[2] : 1.0 ); + const double nAlphaModulation( bModulateColors && rDeviceColor.getLength() > 3 ? + rDeviceColor[3] : 1.0 ); + + Bitmap aSrcBitmap( rBitmap.GetBitmap() ); + Bitmap aSrcAlpha; + + // differentiate mask and alpha channel (on-off + // vs. multi-level transparency) + if( rBitmap.IsTransparent() ) + { + if( rBitmap.IsAlpha() ) + aSrcAlpha = rBitmap.GetAlpha().GetBitmap(); + else + aSrcAlpha = rBitmap.GetMask(); + } + + ScopedBitmapReadAccess pReadAccess( aSrcBitmap.AcquireReadAccess(), + aSrcBitmap ); + ScopedBitmapReadAccess pAlphaReadAccess( rBitmap.IsTransparent() ? + aSrcAlpha.AcquireReadAccess() : + (BitmapReadAccess*)NULL, + aSrcAlpha ); + + if( pReadAccess.get() == NULL || + (pAlphaReadAccess.get() == NULL && rBitmap.IsTransparent()) ) + { + // TODO(E2): Error handling! + ENSURE_OR_THROW( false, + "transformBitmap(): could not access source bitmap" ); + } + + // mapping table, to translate pAlphaReadAccess' pixel + // values into destination alpha values (needed e.g. for + // paletted 1-bit masks). + sal_uInt8 aAlphaMap[256]; + + if( rBitmap.IsTransparent() ) + { + if( rBitmap.IsAlpha() ) + { + // source already has alpha channel - 1:1 mapping, + // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255. + ::std::iota( aAlphaMap, &aAlphaMap[256], 0 ); + } + else + { + // mask transparency - determine used palette colors + const BitmapColor& rCol0( pAlphaReadAccess->GetPaletteColor( 0 ) ); + const BitmapColor& rCol1( pAlphaReadAccess->GetPaletteColor( 1 ) ); + + // shortcut for true luminance calculation + // (assumes that palette is grey-level) + aAlphaMap[0] = rCol0.GetRed(); + aAlphaMap[1] = rCol1.GetRed(); + } + } + // else: mapping table is not used + + const Size aDestBmpSize( ::basegfx::fround( aDestRect.getWidth() ), + ::basegfx::fround( aDestRect.getHeight() ) ); + + if( aDestBmpSize.Width() == 0 || aDestBmpSize.Height() == 0 ) + return BitmapEx(); + + Bitmap aDstBitmap( aDestBmpSize, aSrcBitmap.GetBitCount(), &pReadAccess->GetPalette() ); + Bitmap aDstAlpha( AlphaMask( aDestBmpSize ).GetBitmap() ); + + { + // just to be on the safe side: let the + // ScopedAccessors get destructed before + // copy-constructing the resulting bitmap. This will + // rule out the possibility that cached accessor data + // is not yet written back. + ScopedBitmapWriteAccess pWriteAccess( aDstBitmap.AcquireWriteAccess(), + aDstBitmap ); + ScopedBitmapWriteAccess pAlphaWriteAccess( aDstAlpha.AcquireWriteAccess(), + aDstAlpha ); + + + if( pWriteAccess.get() != NULL && + pAlphaWriteAccess.get() != NULL && + rTransform.isInvertible() ) + { + // we're doing inverse mapping here, i.e. mapping + // points from the destination bitmap back to the + // source + ::basegfx::B2DHomMatrix aTransform( aLocalTransform ); + aTransform.invert(); + + // for the time being, always read as ARGB + for( int y=0; y<aDestBmpSize.Height(); ++y ) + { + if( bModulateColors ) + { + // TODO(P2): Have different branches for + // alpha-only modulation (color + // modulations eq. 1.0) + + // modulate all color channels with given + // values + + // differentiate mask and alpha channel (on-off + // vs. multi-level transparency) + if( rBitmap.IsTransparent() ) + { + // Handling alpha and mask just the same... + for( int x=0; x<aDestBmpSize.Width(); ++x ) + { + ::basegfx::B2DPoint aPoint(x,y); + aPoint *= aTransform; + + const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); + const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); + if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || + nSrcY < 0 || nSrcY >= aBmpSize.Height() ) + { + pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); + } + else + { + // modulate alpha with + // nAlphaModulation. This is a + // little bit verbose, formula + // is 255 - (255-pixAlpha)*nAlphaModulation + // (invert 'alpha' pixel value, + // to get the standard alpha + // channel behaviour) + pAlphaWriteAccess->SetPixel( y, x, + BitmapColor( + 255U - + static_cast<BYTE>( + nAlphaModulation* + (255U + - aAlphaMap[ pAlphaReadAccess->GetPixel( + nSrcY, + nSrcX ).GetIndex() ] ) + .5 ) ) ); + + BitmapColor aColor( pReadAccess->GetPixel( nSrcY, + nSrcX ) ); + + aColor.SetRed( + static_cast<BYTE>( + nRedModulation * + aColor.GetRed() + .5 )); + aColor.SetGreen( + static_cast<BYTE>( + nGreenModulation * + aColor.GetGreen() + .5 )); + aColor.SetBlue( + static_cast<BYTE>( + nBlueModulation * + aColor.GetBlue() + .5 )); + + pWriteAccess->SetPixel( y, x, + aColor ); + } + } + } + else + { + for( int x=0; x<aDestBmpSize.Width(); ++x ) + { + ::basegfx::B2DPoint aPoint(x,y); + aPoint *= aTransform; + + const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); + const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); + if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || + nSrcY < 0 || nSrcY >= aBmpSize.Height() ) + { + pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); + } + else + { + // modulate alpha with + // nAlphaModulation. This is a + // little bit verbose, formula + // is 255 - 255*nAlphaModulation + // (invert 'alpha' pixel value, + // to get the standard alpha + // channel behaviour) + pAlphaWriteAccess->SetPixel( y, x, + BitmapColor( + 255U - + static_cast<BYTE>( + nAlphaModulation*255.0 + + .5 ) ) ); + + BitmapColor aColor( pReadAccess->GetPixel( nSrcY, + nSrcX ) ); + + aColor.SetRed( + static_cast<BYTE>( + nRedModulation * + aColor.GetRed() + .5 )); + aColor.SetGreen( + static_cast<BYTE>( + nGreenModulation * + aColor.GetGreen() + .5 )); + aColor.SetBlue( + static_cast<BYTE>( + nBlueModulation * + aColor.GetBlue() + .5 )); + + pWriteAccess->SetPixel( y, x, + aColor ); + } + } + } + } + else + { + // differentiate mask and alpha channel (on-off + // vs. multi-level transparency) + if( rBitmap.IsTransparent() ) + { + // Handling alpha and mask just the same... + for( int x=0; x<aDestBmpSize.Width(); ++x ) + { + ::basegfx::B2DPoint aPoint(x,y); + aPoint *= aTransform; + + const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); + const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); + if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || + nSrcY < 0 || nSrcY >= aBmpSize.Height() ) + { + pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); + } + else + { + pAlphaWriteAccess->SetPixel( y, x, + aAlphaMap[ + pAlphaReadAccess->GetPixel( nSrcY, + nSrcX ) ] ); + + pWriteAccess->SetPixel( y, x, pReadAccess->GetPixel( nSrcY, + nSrcX ) ); + } + } + } + else + { + for( int x=0; x<aDestBmpSize.Width(); ++x ) + { + ::basegfx::B2DPoint aPoint(x,y); + aPoint *= aTransform; + + const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); + const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); + if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || + nSrcY < 0 || nSrcY >= aBmpSize.Height() ) + { + pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); + } + else + { + pAlphaWriteAccess->SetPixel( y, x, BitmapColor(0) ); + pWriteAccess->SetPixel( y, x, pReadAccess->GetPixel( nSrcY, + nSrcX ) ); + } + } + } + } + } + + bCopyBack = true; + } + else + { + // TODO(E2): Error handling! + ENSURE_OR_THROW( false, + "transformBitmap(): could not access bitmap" ); + } + } + + if( bCopyBack ) + return BitmapEx( aDstBitmap, AlphaMask( aDstAlpha ) ); + else + return BitmapEx(); + } + } +} diff --git a/canvas/source/vcl/impltools.hxx b/canvas/source/vcl/impltools.hxx new file mode 100644 index 000000000000..8bedfc6de340 --- /dev/null +++ b/canvas/source/vcl/impltools.hxx @@ -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. + * + ************************************************************************/ + +#ifndef _VCLCANVAS_TOOLS_HXX +#define _VCLCANVAS_TOOLS_HXX + +#include <osl/mutex.hxx> +#include <vos/mutex.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/outdev.hxx> + +#include <basegfx/polygon/b2dpolypolygon.hxx> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <canvas/vclwrapper.hxx> +#include "outdevprovider.hxx" + + +class OutputDevice; +class Point; +class Size; + +namespace basegfx +{ + namespace matrix + { + class B2DHomMatrix; + } + namespace vector + { + class B2DVector; + } + namespace point + { + class B2DPoint; + } +} + +namespace com { namespace sun { namespace star { namespace awt +{ + struct Point; + struct Size; + struct Rectangle; +} } } } + +namespace com { namespace sun { namespace star { namespace drawing +{ + struct HomogenMatrix3; +} } } } + +namespace com { namespace sun { namespace star { namespace geometry +{ + struct RealPoint2D; + struct RealSize2D; + struct RealRectangle2D; +} } } } + +namespace com { namespace sun { namespace star { namespace rendering +{ + struct RenderState; + struct ViewState; + class XCanvas; + class XBitmap; + class XPolyPolygon2D; +} } } } + + +namespace vclcanvas +{ + namespace tools + { + ::BitmapEx + bitmapExFromXBitmap( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& ); + + /** Setup VCL font and output position + + @returns false, if no text output should happen + */ + bool setupFontTransform( ::Point& o_rPoint, + ::Font& io_rVCLFont, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + ::OutputDevice& rOutDev ); + + /** Predicate, to determine whether polygon is actually an axis-aligned rectangle + + @return true, if the polygon is a rectangle. + */ + bool isRectangle( const PolyPolygon& rPolyPoly ); + + + // 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; + }; + + class OutDevStateKeeper + { + public: + explicit OutDevStateKeeper( OutputDevice& rOutDev ) : + mpOutDev( &rOutDev ), + mbMappingWasEnabled( mpOutDev->IsMapModeEnabled() ) + { + init(); + } + + explicit OutDevStateKeeper( const OutDevProviderSharedPtr& rOutDev ) : + mpOutDev( rOutDev.get() ? &(rOutDev->getOutDev()) : NULL ), + mbMappingWasEnabled( mpOutDev ? mpOutDev->IsMapModeEnabled() : false ) + { + init(); + } + + ~OutDevStateKeeper() + { + if( mpOutDev ) + { + mpOutDev->EnableMapMode( mbMappingWasEnabled ); + mpOutDev->Pop(); + } + } + + private: + void init() + { + if( mpOutDev ) + { + mpOutDev->Push(); + mpOutDev->EnableMapMode(FALSE); + } + } + + OutputDevice* mpOutDev; + const bool mbMappingWasEnabled; + }; + + ::Point mapRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint, + const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState ); + + ::PolyPolygon mapPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, + const ::com::sun::star::rendering::ViewState& rViewState, + const ::com::sun::star::rendering::RenderState& rRenderState ); + + enum ModulationMode + { + MODULATE_NONE, + MODULATE_WITH_DEVICECOLOR + }; + + ::BitmapEx transformBitmap( const BitmapEx& rBitmap, + const ::basegfx::B2DHomMatrix& rTransform, + const ::com::sun::star::uno::Sequence< double >& rDeviceColor, + ModulationMode eModulationMode ); + + } +} + +#endif /* _VCLCANVAS_TOOLS_HXX */ diff --git a/canvas/source/vcl/makefile.mk b/canvas/source/vcl/makefile.mk new file mode 100644 index 000000000000..7d5f9658c829 --- /dev/null +++ b/canvas/source/vcl/makefile.mk @@ -0,0 +1,93 @@ +#************************************************************************* +# +# 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=vclcanvas +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +DLLPRE = + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF + +# Disable optimization for SunCC SPARC +.IF "$(OS)$(CPU)"=="SOLARISS" && "$(COM)"!="GCC" +NOOPTFILES = $(SLO)$/canvashelper_texturefill.obj +.ENDIF + +SLOFILES = $(SLO)$/backbuffer.obj \ + $(SLO)$/bitmapbackbuffer.obj \ + $(SLO)$/cachedbitmap.obj \ + $(SLO)$/canvas.obj \ + $(SLO)$/canvasbitmap.obj \ + $(SLO)$/canvasbitmaphelper.obj \ + $(SLO)$/canvascustomsprite.obj \ + $(SLO)$/canvasfont.obj \ + $(SLO)$/canvashelper.obj \ + $(SLO)$/canvashelper_texturefill.obj \ + $(SLO)$/devicehelper.obj \ + $(SLO)$/impltools.obj \ + $(SLO)$/services.obj \ + $(SLO)$/spritecanvas.obj \ + $(SLO)$/spritecanvashelper.obj \ + $(SLO)$/spritedevicehelper.obj \ + $(SLO)$/spritehelper.obj \ + $(SLO)$/textlayout.obj \ + $(SLO)$/windowoutdevholder.obj + +SHL1TARGET=$(TARGET).uno + +SHL1STDLIBS= $(TOOLSLIB) $(TKLIB) $(CPPULIB) $(SALLIB) $(VCLLIB) $(COMPHELPERLIB) $(CPPUHELPERLIB) $(BASEGFXLIB) $(CANVASTOOLSLIB) $(SVTOOLLIB) $(I18NISOLANGLIB) + +SHL1IMPLIB=i$(TARGET) +SHL1LIBS=$(SLB)$/$(TARGET).lib +SHL1DEF=$(MISC)$/$(SHL1TARGET).def + +SHL1VERSIONMAP=$(SOLARENV)/src/component.map + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=exports.dxp + +# ========================================================================== + +.INCLUDE : target.mk + +ALLTAR : $(MISC)/vclcanvas.component + +$(MISC)/vclcanvas.component .ERRREMOVE : $(SOLARENV)/bin/createcomponent.xslt \ + vclcanvas.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt vclcanvas.component diff --git a/canvas/source/vcl/outdevprovider.hxx b/canvas/source/vcl/outdevprovider.hxx new file mode 100644 index 000000000000..dd5f870c7d9c --- /dev/null +++ b/canvas/source/vcl/outdevprovider.hxx @@ -0,0 +1,61 @@ +/************************************************************************* + * + * 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_OUTDEVPROVIDER_HXX +#define _VCLCANVAS_OUTDEVPROVIDER_HXX + +#include <sal/types.h> +#include <boost/shared_ptr.hpp> + + +class OutputDevice; + +namespace vclcanvas +{ + /* Definition of OutDevProvider interface */ + + /** Implementers of this interface provide the CanvasHelper + with its OutputDevice. + + This additional level of indirection was necessary, as the + OutputDevice is not an interface. There had to be a mechanism + to detect the moment when an OutputDevice is rendered to + (e.g. for the BitmapBackBuffer). + */ + class OutDevProvider + { + public: + virtual ~OutDevProvider() {} + + virtual OutputDevice& getOutDev() = 0; + virtual const OutputDevice& getOutDev() const = 0; + }; + + typedef ::boost::shared_ptr< OutDevProvider > OutDevProviderSharedPtr; +} + +#endif /* _VCLCANVAS_OUTDEVPROVIDER_HXX */ diff --git a/canvas/source/vcl/repainttarget.hxx b/canvas/source/vcl/repainttarget.hxx new file mode 100644 index 000000000000..ce2037bf5b67 --- /dev/null +++ b/canvas/source/vcl/repainttarget.hxx @@ -0,0 +1,63 @@ +/************************************************************************* + * + * 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_REPAINTTARGET_HXX +#define _VCLCANVAS_REPAINTTARGET_HXX + +#include <rtl/ref.hxx> + +#include "cachedbitmap.hxx" + +class Point; +class Size; +class GraphicAttr; + +namespace vclcanvas +{ + /* 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 GraphicObjectSharedPtr& rGrf, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const = 0; + }; +} + +#endif /* _VCLCANVAS_REPAINTTARGET_HXX */ diff --git a/canvas/source/vcl/services.cxx b/canvas/source/vcl/services.cxx new file mode 100644 index 000000000000..e8cd2379a38f --- /dev/null +++ b/canvas/source/vcl/services.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 <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 <vcl/canvastools.hxx> +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> +#include <vcl/bitmapex.hxx> + +#include <basegfx/tools/canvastools.hxx> + +#include <algorithm> + +#include "canvas.hxx" +#include "spritecanvas.hxx" + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + namespace sdecl = comphelper::service_decl; + + static uno::Reference<uno::XInterface> initCanvas( Canvas* pCanvas ) + { + uno::Reference<uno::XInterface> xRet(static_cast<cppu::OWeakObject*>(pCanvas)); + pCanvas->initialize(); + return xRet; + } + + sdecl::class_<Canvas, sdecl::with_args<true> > serviceImpl1(&initCanvas); + const sdecl::ServiceDecl vclCanvasDecl( + 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; + } + + sdecl::class_<SpriteCanvas, sdecl::with_args<true> > serviceImpl2(&initSpriteCanvas); + const sdecl::ServiceDecl vclSpriteCanvasDecl( + serviceImpl2, + SPRITECANVAS_IMPLEMENTATION_NAME, + SPRITECANVAS_SERVICE_NAME ); +} + +// The C shared lib entry points +COMPHELPER_SERVICEDECL_EXPORTS2(vclcanvas::vclCanvasDecl, vclcanvas::vclSpriteCanvasDecl) diff --git a/canvas/source/vcl/sprite.hxx b/canvas/source/vcl/sprite.hxx new file mode 100644 index 000000000000..29ff80239e02 --- /dev/null +++ b/canvas/source/vcl/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 INCLUDED_VCLCANVAS_SPRITE_HXX +#define INCLUDED_VCLCANVAS_SPRITE_HXX + +#include <canvas/base/sprite.hxx> + +class OutputDevice; + +namespace vclcanvas +{ + /** 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( OutputDevice& rOutDev, + 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( OutputDevice& rOutDev, + const ::basegfx::B2DPoint& rPos, + bool bBufferedUpdate ) const = 0; + }; +} + +#endif /* INCLUDED_VCLCANVAS_SPRITE_HXX */ diff --git a/canvas/source/vcl/spritecanvas.cxx b/canvas/source/vcl/spritecanvas.cxx new file mode 100644 index 000000000000..c08529d3cb35 --- /dev/null +++ b/canvas/source/vcl/spritecanvas.cxx @@ -0,0 +1,178 @@ +/************************************************************************* + * + * 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 <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 <vcl/canvastools.hxx> +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> +#include <vcl/bitmapex.hxx> + +#include <basegfx/tools/canvastools.hxx> + +#include <algorithm> + +#include "spritecanvas.hxx" +#include "windowoutdevholder.hxx" + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + SpriteCanvas::SpriteCanvas( const uno::Sequence< uno::Any >& aArguments, + const uno::Reference< uno::XComponentContext >& rxContext ) : + maArguments(aArguments), + mxComponentContext( rxContext ) + { + } + + void SpriteCanvas::initialize() + { + tools::LocalGuard aGuard; + + // #i64742# Only call initialize when not in probe mode + if( maArguments.getLength() == 0 ) + return; + + OSL_TRACE( "SpriteCanvas created" ); + + // add our own property to GraphicDevice + maPropHelper.addProperties( + ::canvas::PropertySetHelper::MakeMap + ("UnsafeScrolling", + boost::bind(&SpriteCanvasHelper::isUnsafeScrolling, + boost::ref(maCanvasHelper)), + boost::bind(&SpriteCanvasHelper::enableUnsafeScrolling, + boost::ref(maCanvasHelper), + _1)) + ("SpriteBounds", + boost::bind(&SpriteCanvasHelper::isSpriteBounds, + boost::ref(maCanvasHelper)), + boost::bind(&SpriteCanvasHelper::enableSpriteBounds, + boost::ref(maCanvasHelper), + _1))); + + VERBOSE_TRACE( "VCLSpriteCanvas::initialize called" ); + + ENSURE_ARG_OR_THROW( maArguments.getLength() >= 1, + "VCLSpriteCanvas::initialize: wrong number of arguments" ); + + /* 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, + "VCLSpriteCanvas::initialize: wrong number of arguments, or wrong types" ); + + uno::Reference< awt::XWindow > xParentWindow; + maArguments[4] >>= xParentWindow; + + OutDevProviderSharedPtr pOutDev( new WindowOutDevHolder(xParentWindow) ); + + // setup helper + maDeviceHelper.init( pOutDev ); + setWindow(uno::Reference<awt::XWindow2>(xParentWindow, uno::UNO_QUERY_THROW)); + maCanvasHelper.init( maDeviceHelper.getBackBuffer(), + *this, + maRedrawManager, + false, // no OutDev state preservation + false ); // no alpha on surface + + maArguments.realloc(0); + } + + SpriteCanvas::~SpriteCanvas() + { + OSL_TRACE( "SpriteCanvas destroyed" ); + } + + + void SAL_CALL SpriteCanvas::disposing() + { + tools::LocalGuard aGuard; + + 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) + { + tools::LocalGuard aGuard; + + // 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(bUpdateAll, + mbSurfaceDirty); + } + + ::rtl::OUString SAL_CALL SpriteCanvas::getServiceName( ) throw (::com::sun::star::uno::RuntimeException) + { + return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SPRITECANVAS_SERVICE_NAME ) ); + } + + bool SpriteCanvas::repaint( const GraphicObjectSharedPtr& rGrf, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const + { + tools::LocalGuard aGuard; + + return maCanvasHelper.repaint( rGrf, viewState, renderState, rPt, rSz, rAttr ); + } +} diff --git a/canvas/source/vcl/spritecanvas.hxx b/canvas/source/vcl/spritecanvas.hxx new file mode 100644 index 000000000000..db4b05ddb9b2 --- /dev/null +++ b/canvas/source/vcl/spritecanvas.hxx @@ -0,0 +1,172 @@ +/************************************************************************* + * + * 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_SPRITECANVAS_HXX_ +#define _VCLCANVAS_SPRITECANVAS_HXX_ + +#include <rtl/ref.hxx> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/XPropertySet.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 "spritecanvashelper.hxx" +#include "impltools.hxx" +#include "spritedevicehelper.hxx" +#include "repainttarget.hxx" + + +#define SPRITECANVAS_SERVICE_NAME "com.sun.star.rendering.SpriteCanvas.VCL" +#define SPRITECANVAS_IMPLEMENTATION_NAME "com.sun.star.comp.rendering.SpriteCanvas.VCL" + +namespace vclcanvas +{ + 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, + tools::LocalGuard, + ::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 + { + }; + + typedef ::canvas::SpriteCanvasBase< SpriteCanvasBaseSpriteSurface_Base, + SpriteCanvasHelper, + tools::LocalGuard, + ::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(); + + /// For resource tracking + ~SpriteCanvas(); + +#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); + + // RepaintTarget + virtual bool repaint( const GraphicObjectSharedPtr& rGrf, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState, + const ::Point& rPt, + const ::Size& rSz, + const GraphicAttr& rAttr ) const; + + /// Get backbuffer for this canvas + OutDevProviderSharedPtr getFrontBuffer() const { return maDeviceHelper.getOutDev(); } + /// Get window for this canvas + BackBufferSharedPtr getBackBuffer() const { return maDeviceHelper.getBackBuffer(); } + + 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; + typedef ::rtl::Reference< SpriteCanvas > DeviceRef; + +} + +#endif diff --git a/canvas/source/vcl/spritecanvashelper.cxx b/canvas/source/vcl/spritecanvashelper.cxx new file mode 100644 index 000000000000..f2327a29c480 --- /dev/null +++ b/canvas/source/vcl/spritecanvashelper.cxx @@ -0,0 +1,718 @@ +/************************************************************************* + * + * 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 <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> + +#include <vcl/canvastools.hxx> +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> +#include <vcl/bitmapex.hxx> + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <boost/cast.hpp> + +#include "spritecanvashelper.hxx" +#include "canvascustomsprite.hxx" + + +using namespace ::com::sun::star; + +#define FPS_BOUNDS Rectangle(0,0,130,90) +#define INFO_COLOR COL_RED + +namespace vclcanvas +{ + namespace + { + /** Sprite redraw at original position + + Used to repaint the whole canvas (background and all + sprites) + */ + void spriteRedraw( OutputDevice& rOutDev, + const ::canvas::Sprite::Reference& rSprite ) + { + // downcast to derived vclcanvas::Sprite interface, which + // provides the actual redraw methods. + ::boost::polymorphic_downcast< Sprite* >(rSprite.get())->redraw(rOutDev, + true); + } + + double calcNumPixel( const ::canvas::Sprite::Reference& rSprite ) + { + const ::basegfx::B2DSize& rSize( + ::boost::polymorphic_downcast< Sprite* >(rSprite.get())->getSizePixel() ); + + return rSize.getX() * rSize.getY(); + } + + void repaintBackground( OutputDevice& rOutDev, + OutputDevice& rBackBuffer, + const ::basegfx::B2DRange& rArea ) + { + const ::Point& rPos( ::vcl::unotools::pointFromB2DPoint( rArea.getMinimum()) ); + const ::Size& rSize( ::vcl::unotools::sizeFromB2DSize( rArea.getRange()) ); + + rOutDev.DrawOutDev( rPos, rSize, rPos, rSize, rBackBuffer ); + } + + void opaqueUpdateSpriteArea( const ::canvas::Sprite::Reference& rSprite, + OutputDevice& rOutDev, + const ::basegfx::B2IRange& rArea ) + { + const Rectangle& rRequestedArea( + ::vcl::unotools::rectangleFromB2IRectangle( 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) + rOutDev.EnableMapMode( FALSE ); + rOutDev.SetClipRegion( rRequestedArea ); + + // repaint affected sprite directly to output device (at + // the actual screen output position) + ::boost::polymorphic_downcast< Sprite* >( + rSprite.get() )->redraw( rOutDev, + false ); // rendering + // directly to + // frontbuffer + } + + /** Repaint sprite at original position + + Used for opaque updates, which render directly to the + front buffer. + */ + void spriteRedrawStub( OutputDevice& rOutDev, + const ::canvas::Sprite::Reference& rSprite ) + { + if( rSprite.is() ) + { + ::boost::polymorphic_downcast< Sprite* >( + rSprite.get() )->redraw( rOutDev, + false ); + } + } + + /** Repaint sprite at given position + + Used for generic update, which renders into vdev of + adapted size. + */ + void spriteRedrawStub2( OutputDevice& rOutDev, + const ::basegfx::B2DPoint& rOutPos, + const ::canvas::Sprite::Reference& rSprite ) + { + if( rSprite.is() ) + { + Sprite* pSprite = ::boost::polymorphic_downcast< Sprite* >( + rSprite.get() ); + + // calc relative sprite position in rUpdateArea (which + // need not be the whole screen!) + const ::basegfx::B2DPoint& rSpriteScreenPos( pSprite->getPosPixel() ); + const ::basegfx::B2DPoint& rSpriteRenderPos( rSpriteScreenPos - rOutPos ); + + pSprite->redraw( rOutDev, rSpriteRenderPos, true ); + } + } + + /** Repaint sprite at original position + + Used for opaque updates from scrollUpdate(), which render + directly to the front buffer. + */ + void spriteRedrawStub3( OutputDevice& rOutDev, + const ::canvas::SpriteRedrawManager::AreaComponent& rComponent ) + { + const ::canvas::Sprite::Reference& rSprite( rComponent.second.getSprite() ); + + if( rSprite.is() ) + { + ::boost::polymorphic_downcast< Sprite* >( + rSprite.get() )->redraw( rOutDev, + false ); + } + } + + void renderInfoText( OutputDevice& rOutDev, + const ::rtl::OUString& rStr, + const Point& rPos ) + { + Font aVCLFont; + aVCLFont.SetHeight( 20 ); + aVCLFont.SetColor( Color( INFO_COLOR ) ); + + rOutDev.SetTextAlign(ALIGN_TOP); + rOutDev.SetTextColor( Color( INFO_COLOR ) ); + rOutDev.SetFont( aVCLFont ); + + rOutDev.DrawText( rPos, rStr ); + } + + } + + SpriteCanvasHelper::SpriteCanvasHelper() : + mpRedrawManager( NULL ), + mpOwningSpriteCanvas( NULL ), + maVDev(), + maLastUpdate(), + mbShowFrameInfo( false ), + mbShowSpriteBounds( false ), + mbIsUnsafeScrolling( false ) + { +#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 + // inverse defaults for verbose debug mode + mbShowSpriteBounds = mbShowFrameInfo = true; +#endif + } + + void SpriteCanvasHelper::init( const OutDevProviderSharedPtr& rOutDev, + SpriteCanvas& rOwningSpriteCanvas, + ::canvas::SpriteRedrawManager& rManager, + bool bProtect, + bool bHaveAlpha ) + { + mpOwningSpriteCanvas = &rOwningSpriteCanvas; + mpRedrawManager = &rManager; + + CanvasHelper::init(rOwningSpriteCanvas,rOutDev,bProtect,bHaveAlpha); + } + + void SpriteCanvasHelper::disposing() + { + mpRedrawManager = NULL; + mpOwningSpriteCanvas = 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 > >& , + sal_Int8 ) + { + return uno::Reference< rendering::XAnimatedSprite >(); + } + + uno::Reference< rendering::XCustomSprite > SpriteCanvasHelper::createCustomSprite( const geometry::RealSize2D& spriteSize ) + { + if( !mpRedrawManager || !mpDevice ) + return uno::Reference< rendering::XCustomSprite >(); // we're disposed + + return uno::Reference< rendering::XCustomSprite >( + new CanvasCustomSprite( spriteSize, + *mpDevice, + mpOwningSpriteCanvas, + mpOwningSpriteCanvas->getFrontBuffer(), + mbShowSpriteBounds ) ); + } + + uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite( const uno::Reference< rendering::XSprite >& ) + { + return uno::Reference< rendering::XSprite >(); + } + + sal_Bool SpriteCanvasHelper::updateScreen( sal_Bool bUpdateAll, + bool& io_bSurfaceDirty ) + { + if( !mpRedrawManager || + !mpOwningSpriteCanvas || + !mpOwningSpriteCanvas->getFrontBuffer() || + !mpOwningSpriteCanvas->getBackBuffer() ) + { + return sal_False; // disposed, or otherwise dysfunctional + } + + // commit to backbuffer + flush(); + + OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); + BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); + OutputDevice& rBackOutDev( pBackBuffer->getOutDev() ); + + // actual OutputDevice is a shared resource - restore its + // state when done. + tools::OutDevStateKeeper aStateKeeper( rOutDev ); + + const Size aOutDevSize( rBackOutDev.GetOutputSizePixel() ); + const Point aEmptyPoint(0,0); + + Window* pTargetWindow = NULL; + if( rOutDev.GetOutDevType() == OUTDEV_WINDOW ) + { + pTargetWindow = &static_cast<Window&>(rOutDev); // TODO(Q3): Evil downcast. + + // we're double-buffered, thus no need for paint area-limiting + // clips. besides that, will interfere with animations (as for + // Window-invalidate repaints, only parts of the window will + // be redrawn otherwise) + const Region aFullWindowRegion( Rectangle(aEmptyPoint, + aOutDevSize) ); + pTargetWindow->ExpandPaintClipRegion(aFullWindowRegion); + } + + // TODO(P1): Might be worthwile to track areas of background + // changes, too. + if( !bUpdateAll && !io_bSurfaceDirty ) + { + if( mbShowFrameInfo ) + { + // also repaint background below frame counter (fake + // that as a sprite vanishing in this area) + mpRedrawManager->updateSprite( ::canvas::Sprite::Reference(), + ::basegfx::B2DPoint(), + ::basegfx::B2DRectangle( 0.0, 0.0, + FPS_BOUNDS.Right(), + FPS_BOUNDS.Bottom() ) ); + } + + // 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 + { + // background has changed, so we currently have no choice + // but repaint everything (or caller requested that) + + maVDev->SetOutputSizePixel( aOutDevSize ); + maVDev->EnableMapMode( FALSE ); + maVDev->DrawOutDev( aEmptyPoint, aOutDevSize, + aEmptyPoint, aOutDevSize, + rBackOutDev ); + + // repaint all active sprites on top of background into + // VDev. + mpRedrawManager->forEachSprite( + ::boost::bind( + &spriteRedraw, + ::boost::ref( maVDev.get() ), + _1 ) ); + + // flush to screen + rOutDev.EnableMapMode( FALSE ); + rOutDev.SetClipRegion(); + rOutDev.DrawOutDev( aEmptyPoint, aOutDevSize, + aEmptyPoint, aOutDevSize, + *maVDev ); + } + + // change record vector must be cleared, for the next turn of + // rendering and sprite changing + mpRedrawManager->clearChangeRecords(); + + io_bSurfaceDirty = false; + + if( mbShowFrameInfo ) + { + renderFrameCounter( rOutDev ); + renderSpriteCount( rOutDev ); + renderMemUsage( rOutDev ); + } + +#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 + static ::canvas::tools::ElapsedTime aElapsedTime; + + // log time immediately after surface flip + OSL_TRACE( "SpriteCanvasHelper::updateScreen(): flip done at %f", + aElapsedTime.getElapsedTime() ); +#endif + + // sync output with screen, to ensure that we don't queue up + // render requests (calling code might rely on timing, + // i.e. assume that things are visible on screen after + // updateScreen() returns). + if( pTargetWindow ) + { + // commit to screen + pTargetWindow->Sync(); + } + + return sal_True; + } + + void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& rUpdateRect ) + { + ENSURE_OR_THROW( mpOwningSpriteCanvas && + mpOwningSpriteCanvas->getBackBuffer() && + mpOwningSpriteCanvas->getFrontBuffer(), + "SpriteCanvasHelper::backgroundPaint(): NULL device pointer " ); + + OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); + BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); + OutputDevice& rBackOutDev( pBackBuffer->getOutDev() ); + + repaintBackground( rOutDev, rBackOutDev, rUpdateRect ); + } + + void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& rMoveStart, + const ::basegfx::B2DRange& rMoveEnd, + const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea ) + { + ENSURE_OR_THROW( mpOwningSpriteCanvas && + mpOwningSpriteCanvas->getBackBuffer() && + mpOwningSpriteCanvas->getFrontBuffer(), + "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " ); + + OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); + BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); + OutputDevice& rBackOutDev( pBackBuffer->getOutDev() ); + + const Size& rTargetSizePixel( rOutDev.GetOutputSizePixel() ); + const ::basegfx::B2IRange aOutputBounds( 0,0, + rTargetSizePixel.Width(), + rTargetSizePixel.Height() ); + + // 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; + + // Since strictly speaking, this scroll algorithm is plain + // buggy, the scrolled area might actually lie _below_ another + // window - we've made this feature configurable via + // mbIsUnsafeScrolling. + + // clip to output bounds (cannot properly scroll stuff + // _outside_ our screen area) + if( !mbIsUnsafeScrolling || + !::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::ref( rOutDev ), + _1 ) ); + } + else + { + // scroll rOutDev content + rOutDev.CopyArea( ::vcl::unotools::pointFromB2IPoint( aDestPos ), + ::vcl::unotools::pointFromB2IPoint( aSourceRect.getMinimum() ), + // TODO(Q2): use numeric_cast to check range + ::Size( static_cast<sal_Int32>(aSourceRect.getRange().getX()), + static_cast<sal_Int32>(aSourceRect.getRange().getY()) ) ); + + 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 + rOutDev.Push( PUSH_CLIPREGION ); + ::std::for_each( aUnscrollableAreas.begin(), + aUnscrollableAreas.end(), + ::boost::bind( &opaqueUpdateSpriteArea, + ::boost::cref(aFirst->second.getSprite()), + ::boost::ref(rOutDev), + _1 ) ); + rOutDev.Pop(); + } + + // 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::ref(rOutDev), + ::boost::ref(rBackOutDev), + _1 ) ); + } + + void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange& rTotalArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) + { + (void)rTotalArea; + + ENSURE_OR_THROW( mpOwningSpriteCanvas && + mpOwningSpriteCanvas->getBackBuffer() && + mpOwningSpriteCanvas->getFrontBuffer(), + "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " ); + + OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); + + // no need to clip output to actual update region - there will + // always be ALL sprites contained in the rectangular update + // area containd in rTotalArea (that's the way + // B2DConnectedRanges work). If rTotalArea appears to be + // smaller than the sprite - then this sprite carries a clip, + // and the update will be constrained to that rect. + + // repaint all affected sprites directly to output device + ::std::for_each( rSortedUpdateSprites.begin(), + rSortedUpdateSprites.end(), + ::boost::bind( + &spriteRedrawStub, + ::boost::ref( rOutDev ), + _1 ) ); + } + + void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange& rRequestedArea, + const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites ) + { + ENSURE_OR_THROW( mpOwningSpriteCanvas && + mpOwningSpriteCanvas->getBackBuffer() && + mpOwningSpriteCanvas->getFrontBuffer(), + "SpriteCanvasHelper::genericUpdate(): NULL device pointer " ); + + OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() ); + BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); + OutputDevice& rBackOutDev( pBackBuffer->getOutDev() ); + + // limit size of update VDev to target outdev's size + const Size& rTargetSizePixel( rOutDev.GetOutputSizePixel() ); + + // 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 coverage of VDev to + // output device's area (i.e. not only to total size, but to + // cover _only_ the visible parts). + const ::Size aOutputSize( + ::std::max( sal_Int32( 0 ), + ::std::min( static_cast< sal_Int32 >(rTargetSizePixel.Width() - aOutputPosition.X()), + ::canvas::tools::roundUp( rRequestedArea.getMaxX() - aOutputPosition.X() ))), + ::std::max( sal_Int32( 0 ), + ::std::min( static_cast< sal_Int32 >(rTargetSizePixel.Height() - aOutputPosition.Y()), + ::canvas::tools::roundUp( rRequestedArea.getMaxY() - aOutputPosition.Y() )))); + + // early exit for empty output area. + if( aOutputSize.Width() == 0 && + aOutputSize.Height() == 0 ) + { + return; + } + + const Point aEmptyPoint(0,0); + const Size aCurrOutputSize( maVDev->GetOutputSizePixel() ); + + // adapt maVDev's size to the area that actually needs the + // repaint. + if( aCurrOutputSize.Width() < aOutputSize.Width() || + aCurrOutputSize.Height() < aOutputSize.Height() ) + { + // TODO(P1): Come up with a clever tactic to reduce maVDev + // from time to time. Reduction with threshold (say, if + // maVDev is more than twice too large) is not wise, as + // this might then toggle within the same updateScreen(), + // but for different disjunct sprite areas. + maVDev->SetOutputSizePixel( aOutputSize ); + } + + // paint background + maVDev->EnableMapMode( FALSE ); + maVDev->SetClipRegion(); + maVDev->DrawOutDev( aEmptyPoint, aOutputSize, + aOutputPosition, aOutputSize, + rBackOutDev ); + + // repaint all affected sprites on top of background into + // VDev. + ::std::for_each( rSortedUpdateSprites.begin(), + rSortedUpdateSprites.end(), + ::boost::bind( &spriteRedrawStub2, + ::boost::ref( maVDev.get() ), + ::boost::cref( + ::vcl::unotools::b2DPointFromPoint(aOutputPosition)), + _1 ) ); + + // flush to screen + rOutDev.EnableMapMode( FALSE ); + rOutDev.DrawOutDev( aOutputPosition, aOutputSize, + aEmptyPoint, aOutputSize, + *maVDev ); + } + + void SpriteCanvasHelper::renderFrameCounter( OutputDevice& rOutDev ) + { + const double denominator( maLastUpdate.getElapsedTime() ); + maLastUpdate.reset(); + + ::rtl::OUString text( ::rtl::math::doubleToUString( denominator == 0.0 ? 100.0 : 1.0/denominator, + rtl_math_StringFormat_F, + 2,'.',NULL,' ') ); + + // pad with leading space + while( text.getLength() < 6 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" fps")); + + renderInfoText( rOutDev, + text, + Point(0, 0) ); + } + + namespace + { + template< typename T > struct Adder + { + typedef void result_type; + + Adder( T& rAdderTarget, + T nIncrement ) : + mpTarget( &rAdderTarget ), + mnIncrement( nIncrement ) + { + } + + void operator()() { *mpTarget += mnIncrement; } + void operator()( const ::canvas::Sprite::Reference& ) { *mpTarget += mnIncrement; } + void operator()( T nIncrement ) { *mpTarget += nIncrement; } + + T* mpTarget; + T mnIncrement; + }; + + template< typename T> Adder<T> makeAdder( T& rAdderTarget, + T nIncrement ) + { + return Adder<T>(rAdderTarget, nIncrement); + } + } + + void SpriteCanvasHelper::renderSpriteCount( OutputDevice& rOutDev ) + { + if( mpRedrawManager ) + { + sal_Int32 nCount(0); + + mpRedrawManager->forEachSprite( makeAdder(nCount,sal_Int32(1)) ); + ::rtl::OUString text( + ::rtl::OUString::valueOf( + // disambiguate overload... + static_cast<sal_Int64>(nCount) ) ); + + // pad with leading space + while( text.getLength() < 3 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("Sprites: ")) + text; + + renderInfoText( rOutDev, + text, + Point(0, 30) ); + } + } + + void SpriteCanvasHelper::renderMemUsage( OutputDevice& rOutDev ) + { + BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() ); + + if( mpRedrawManager && + pBackBuffer ) + { + double nPixel(0.0); + + // accumulate pixel count for each sprite into fCount + mpRedrawManager->forEachSprite( ::boost::bind( + makeAdder(nPixel,1.0), + ::boost::bind( + &calcNumPixel, + _1 ) ) ); + + static const int NUM_VIRDEV(2); + static const int BYTES_PER_PIXEL(3); + + const Size& rVDevSize( maVDev->GetOutputSizePixel() ); + const Size& rBackBufferSize( pBackBuffer->getOutDev().GetOutputSizePixel() ); + + const double nMemUsage( nPixel * NUM_VIRDEV * BYTES_PER_PIXEL + + rVDevSize.Width()*rVDevSize.Height() * BYTES_PER_PIXEL + + rBackBufferSize.Width()*rBackBufferSize.Height() * BYTES_PER_PIXEL ); + + ::rtl::OUString text( ::rtl::math::doubleToUString( nMemUsage / 1048576.0, + rtl_math_StringFormat_F, + 2,'.',NULL,' ') ); + + // pad with leading space + while( text.getLength() < 4 ) + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text; + + text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("Mem: ")) + + text + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("MB")); + + renderInfoText( rOutDev, + text, + Point(0, 60) ); + } + } +} diff --git a/canvas/source/vcl/spritecanvashelper.hxx b/canvas/source/vcl/spritecanvashelper.hxx new file mode 100644 index 000000000000..bc80f4359e5b --- /dev/null +++ b/canvas/source/vcl/spritecanvashelper.hxx @@ -0,0 +1,179 @@ +/************************************************************************* + * + * 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_SPRITECANVASHELPER_HXX_ +#define _VCLCANVAS_SPRITECANVASHELPER_HXX_ + +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XIntegerBitmap.hpp> + +#include <vcl/virdev.hxx> + +#include <canvas/spriteredrawmanager.hxx> +#include <canvas/elapsedtime.hxx> +#include <canvas/vclwrapper.hxx> +#include "canvashelper.hxx" +#include "impltools.hxx" + + +namespace vclcanvas +{ + class RedrawManager; + class SpriteCanvas; + + class SpriteCanvasHelper : public CanvasHelper + { + public: + SpriteCanvasHelper(); + + void init( const OutDevProviderSharedPtr& rOutDev, + SpriteCanvas& rOwningSpriteCanvas, + ::canvas::SpriteRedrawManager& rManager, + bool bProtect, + bool bHaveAlpha ); + + /// 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 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( 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 ); + + ::com::sun::star::uno::Any isUnsafeScrolling() const + { + return ::com::sun::star::uno::makeAny(mbIsUnsafeScrolling); + } + void enableUnsafeScrolling( const ::com::sun::star::uno::Any& rAny ) + { + mbIsUnsafeScrolling = rAny.get<bool>(); + } + + ::com::sun::star::uno::Any isSpriteBounds() const + { + return ::com::sun::star::uno::makeAny(mbShowSpriteBounds); + } + void enableSpriteBounds( const ::com::sun::star::uno::Any& rAny ) + { + mbShowSpriteBounds = rAny.get<bool>(); + } + + private: + void renderFrameCounter( OutputDevice& rOutDev ); + void renderSpriteCount( OutputDevice& rOutDev ); + void renderMemUsage( OutputDevice& rOutDev ); + + /// Set from the SpriteCanvas: instance coordinating sprite redraw + ::canvas::SpriteRedrawManager* mpRedrawManager; + + /// Set from the init method. used to generate sprites + SpriteCanvas* mpOwningSpriteCanvas; + + /** Background compositing surface. + + Typically, sprites will be composited in the background, + before pushing them to screen. This happens here. + */ + ::canvas::vcltools::VCLObject< VirtualDevice > maVDev; + + /// For the frame counter timings + ::canvas::tools::ElapsedTime maLastUpdate; + + /// When true, canvas displays debug info on each frame + bool mbShowFrameInfo; + + /// When true, canvas creates all new sprites with red lines in the corners + bool mbShowSpriteBounds; + + /// When true, canvas uses the scroll optimization (direct scrolls in front buffer) + bool mbIsUnsafeScrolling; + }; +} + +#endif /* _VCLCANVAS_SPRITECANVASHELPER_HXX_ */ + diff --git a/canvas/source/vcl/spritedevicehelper.cxx b/canvas/source/vcl/spritedevicehelper.cxx new file mode 100644 index 000000000000..4c0ea4fd6d3b --- /dev/null +++ b/canvas/source/vcl/spritedevicehelper.cxx @@ -0,0 +1,158 @@ +/************************************************************************* + * + * 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 <toolkit/helper/vclunohelper.hxx> +#include <vcl/canvastools.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include "spritedevicehelper.hxx" +#include "spritecanvas.hxx" +#include "spritecanvashelper.hxx" +#include "canvasbitmap.hxx" + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + SpriteDeviceHelper::SpriteDeviceHelper() : + mpBackBuffer() + { + } + + void SpriteDeviceHelper::init( const OutDevProviderSharedPtr& pOutDev ) + { + DeviceHelper::init(pOutDev); + + // setup back buffer + OutputDevice& rOutDev( pOutDev->getOutDev() ); + mpBackBuffer.reset( new BackBuffer( rOutDev )); + mpBackBuffer->setSize( rOutDev.GetOutputSizePixel() ); + + // #i95645# +#if defined( QUARTZ ) + // use AA on VCLCanvas for Mac + mpBackBuffer->getOutDev().SetAntialiasing( ANTIALIASING_ENABLE_B2DDRAW | mpBackBuffer->getOutDev().GetAntialiasing() ); +#else + // switch off AA for WIN32 and UNIX, the VCLCanvas does not look good with it and + // is not required to do AA. It would need to be adapted to use it correctly + // (especially gradient painting). This will need extra work. + mpBackBuffer->getOutDev().SetAntialiasing(mpBackBuffer->getOutDev().GetAntialiasing() & !ANTIALIASING_ENABLE_B2DDRAW); +#endif + } + + ::sal_Int32 SpriteDeviceHelper::createBuffers( ::sal_Int32 nBuffers ) + { + (void)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; + } + + void SpriteDeviceHelper::disposing() + { + // release all references + mpBackBuffer.reset(); + + DeviceHelper::disposing(); + } + + uno::Any SpriteDeviceHelper::isAccelerated() const + { + return DeviceHelper::isAccelerated(); + } + + uno::Any SpriteDeviceHelper::getDeviceHandle() const + { + return DeviceHelper::getDeviceHandle(); + } + + uno::Any SpriteDeviceHelper::getSurfaceHandle() const + { + if( !mpBackBuffer ) + return uno::Any(); + + return uno::makeAny( + reinterpret_cast< sal_Int64 >(&mpBackBuffer->getOutDev()) ); + } + + void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds ) + { + if( mpBackBuffer ) + mpBackBuffer->setSize( ::Size(rBounds.Width, + rBounds.Height) ); + } + + void SpriteDeviceHelper::dumpScreenContent() const + { + DeviceHelper::dumpScreenContent(); + + static sal_uInt32 nFilePostfixCount(0); + + if( mpBackBuffer ) + { + String aFilename( String::CreateFromAscii("dbg_backbuffer") ); + aFilename += String::CreateFromInt32(nFilePostfixCount); + aFilename += String::CreateFromAscii(".bmp"); + + SvFileStream aStream( aFilename, STREAM_STD_READWRITE ); + + const ::Point aEmptyPoint; + mpBackBuffer->getOutDev().EnableMapMode( FALSE ); + aStream << mpBackBuffer->getOutDev().GetBitmap(aEmptyPoint, + mpBackBuffer->getOutDev().GetOutputSizePixel()); + } + + ++nFilePostfixCount; + } + +} diff --git a/canvas/source/vcl/spritedevicehelper.hxx b/canvas/source/vcl/spritedevicehelper.hxx new file mode 100644 index 000000000000..eaedbc8ca5ac --- /dev/null +++ b/canvas/source/vcl/spritedevicehelper.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 _VCLCANVAS_SPRITEDEVICEHELPER_HXX +#define _VCLCANVAS_SPRITEDEVICEHELPER_HXX + +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XBufferController.hpp> + +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> + +#include "backbuffer.hxx" +#include "devicehelper.hxx" + +#include <boost/utility.hpp> + + +/* Definition of DeviceHelper class */ + +namespace vclcanvas +{ + class SpriteCanvas; + class SpriteCanvasHelper; + + class SpriteDeviceHelper : public DeviceHelper + { + public: + SpriteDeviceHelper(); + + void init( const OutDevProviderSharedPtr& rOutDev ); + + /// Dispose all internal references + void disposing(); + + ::sal_Int32 createBuffers( ::sal_Int32 nBuffers ); + void destroyBuffers( ); + ::sal_Bool showBuffer( bool bWindowVisible, ::sal_Bool bUpdateAll ); + ::sal_Bool switchBuffer( bool bWindowVisible, ::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 dumpScreenContent() const; + BackBufferSharedPtr getBackBuffer() const { return mpBackBuffer; } + + void notifySizeUpdate( const ::com::sun::star::awt::Rectangle& rBounds ); + + private: + /// This buffer holds the background content for all associated canvases + BackBufferSharedPtr mpBackBuffer; + }; +} + +#endif /* _VCLCANVAS_SPRITEDEVICEHELPER_HXX */ diff --git a/canvas/source/vcl/spritehelper.cxx b/canvas/source/vcl/spritehelper.cxx new file mode 100644 index 000000000000..a09905e006a8 --- /dev/null +++ b/canvas/source/vcl/spritehelper.cxx @@ -0,0 +1,443 @@ +/************************************************************************* + * + * 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 <canvas/verbosetrace.hxx> + +#include <rtl/math.hxx> + +#include <vcl/outdev.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/alpha.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygoncutandtouch.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/canvastools.hxx> + +#include "spritehelper.hxx" + +using namespace ::com::sun::star; + + +namespace vclcanvas +{ + SpriteHelper::SpriteHelper() : + mpBackBuffer(), + mpBackBufferMask(), + maContent(), + mbShowSpriteBounds(false) + { + } + + void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize, + const ::canvas::SpriteSurface::Reference& rOwningSpriteCanvas, + const BackBufferSharedPtr& rBackBuffer, + const BackBufferSharedPtr& rBackBufferMask, + bool bShowSpriteBounds ) + { + ENSURE_OR_THROW( rOwningSpriteCanvas.get() && rBackBuffer && rBackBufferMask, + "SpriteHelper::init(): Invalid sprite canvas or back buffer" ); + + mpBackBuffer = rBackBuffer; + mpBackBufferMask = rBackBufferMask; + mbShowSpriteBounds = bShowSpriteBounds; + + init( rSpriteSize, rOwningSpriteCanvas ); + } + + void SpriteHelper::disposing() + { + mpBackBuffer.reset(); + mpBackBufferMask.reset(); + + // forward to parent + CanvasCustomSpriteHelper::disposing(); + } + + void SpriteHelper::redraw( OutputDevice& rTargetSurface, + const ::basegfx::B2DPoint& rPos, + bool& io_bSurfacesDirty, + bool bBufferedUpdate ) const + { + (void)bBufferedUpdate; // not used on every platform + + if( !mpBackBuffer || + !mpBackBufferMask ) + { + return; // we're disposed + } + + // log output pos in device pixel + VERBOSE_TRACE( "SpriteHelper::redraw(): output pos is (%f, %f)", + rPos.getX(), + rPos.getY() ); + + const double fAlpha( getAlpha() ); + + if( isActive() && + !::basegfx::fTools::equalZero( fAlpha ) ) + { + const Point aEmptyPoint; + const ::basegfx::B2DVector& rOrigOutputSize( getSizePixel() ); + + // might get changed below (e.g. adapted for + // transformations). IMPORTANT: both position and size are + // rounded to integer values. From now on, only those + // rounded values are used, to keep clip and content in + // sync. + ::Size aOutputSize( ::vcl::unotools::sizeFromB2DSize( rOrigOutputSize ) ); + ::Point aOutPos( ::vcl::unotools::pointFromB2DPoint( rPos ) ); + + + // TODO(F3): Support for alpha-VDev + + // Do we have to update our bitmaps (necessary if virdev + // was painted to, or transformation changed)? + const bool bNeedBitmapUpdate( io_bSurfacesDirty || + hasTransformChanged() || + maContent->IsEmpty() ); + + // updating content of sprite cache - surface is no + // longer dirty in relation to our cache + io_bSurfacesDirty = false; + transformUpdated(); + + if( bNeedBitmapUpdate ) + { + Bitmap aBmp( mpBackBuffer->getOutDev().GetBitmap( aEmptyPoint, + aOutputSize ) ); + + if( isContentFullyOpaque() ) + { + // optimized case: content canvas is fully + // opaque. Note: since we retrieved aBmp directly + // from an OutDev, it's already a 'display bitmap' + // on windows. + maContent = BitmapEx( aBmp ); + } + else + { + // sprite content might contain alpha, create + // BmpEx, then. + Bitmap aMask( mpBackBufferMask->getOutDev().GetBitmap( aEmptyPoint, + aOutputSize ) ); + + // bitmasks are much faster than alphamasks on some platforms + // so convert to bitmask if useful +#ifndef QUARTZ + if( aMask.GetBitCount() != 1 ) + { + OSL_ENSURE(false, + "CanvasCustomSprite::redraw(): Mask bitmap is not " + "monochrome (performance!)"); + aMask.MakeMono(255); + } +#endif + + // Note: since we retrieved aBmp and aMask + // directly from an OutDev, it's already a + // 'display bitmap' on windows. + maContent = BitmapEx( aBmp, aMask ); + } + } + + ::basegfx::B2DHomMatrix aTransform( getTransformation() ); + + // check whether matrix is "easy" to handle - pure + // translations or scales are handled by OutputDevice + // alone + const bool bIdentityTransform( aTransform.isIdentity() ); + + // make transformation absolute (put sprite to final + // output position). Need to happen here, as we also have + // to translate the clip polygon + aTransform.translate( aOutPos.X(), + aOutPos.Y() ); + + if( !bIdentityTransform ) + { + if( !::basegfx::fTools::equalZero( aTransform.get(0,1) ) || + !::basegfx::fTools::equalZero( aTransform.get(1,0) ) ) + { + // "complex" transformation, employ affine + // transformator + + // modify output position, to account for the fact + // that transformBitmap() always normalizes its output + // bitmap into the smallest enclosing box. + ::basegfx::B2DRectangle aDestRect; + ::canvas::tools::calcTransformedRectBounds( aDestRect, + ::basegfx::B2DRectangle(0, + 0, + rOrigOutputSize.getX(), + rOrigOutputSize.getY()), + aTransform ); + + aOutPos.X() = ::basegfx::fround( aDestRect.getMinX() ); + aOutPos.Y() = ::basegfx::fround( aDestRect.getMinY() ); + + // TODO(P3): Use optimized bitmap transformation here. + + // actually re-create the bitmap ONLY if necessary + if( bNeedBitmapUpdate ) + maContent = tools::transformBitmap( *maContent, + aTransform, + uno::Sequence<double>(), + tools::MODULATE_NONE ); + + aOutputSize = maContent->GetSizePixel(); + } + else + { + // relatively 'simplistic' transformation - + // retrieve scale and translational offset + aOutputSize.setWidth ( + ::basegfx::fround( rOrigOutputSize.getX() * aTransform.get(0,0) ) ); + aOutputSize.setHeight( + ::basegfx::fround( rOrigOutputSize.getY() * aTransform.get(1,1) ) ); + + aOutPos.X() = ::basegfx::fround( aTransform.get(0,2) ); + aOutPos.Y() = ::basegfx::fround( aTransform.get(1,2) ); + } + } + + // transformBitmap() might return empty bitmaps, for tiny + // scales. + if( !!(*maContent) ) + { + // when true, fast path for slide transition has + // already redrawn the sprite. + bool bSpriteRedrawn( false ); + + rTargetSurface.Push( PUSH_CLIPREGION ); + + // apply clip (if any) + if( getClip().is() ) + { + ::basegfx::B2DPolyPolygon aClipPoly( + ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( + getClip() )); + + if( aClipPoly.count() ) + { + // aTransform already contains the + // translational component, moving the clip to + // the final sprite output position. + aClipPoly.transform( aTransform ); + +#if ! defined WNT && ! defined QUARTZ + // non-Windows only - bAtLeastOnePolygon is + // only used in non-WNT code below + + // check whether maybe the clip consists + // solely out of rectangular polygons. If this + // is the case, enforce using the triangle + // clip region setup - non-optimized X11 + // drivers tend to perform abyssmally on + // XPolygonRegion, which is used internally, + // when filling complex polypolygons. + bool bAtLeastOnePolygon( false ); + const sal_Int32 nPolygons( aClipPoly.count() ); + + for( sal_Int32 i=0; i<nPolygons; ++i ) + { + if( !::basegfx::tools::isRectangle( + aClipPoly.getB2DPolygon(i)) ) + { + bAtLeastOnePolygon = true; + break; + } + } +#endif + + if( mbShowSpriteBounds ) + { + // Paint green sprite clip area + rTargetSurface.SetLineColor( Color( 0,255,0 ) ); + rTargetSurface.SetFillColor(); + + rTargetSurface.DrawPolyPolygon(PolyPolygon(aClipPoly)); // #i76339# + } + +#if ! defined WNT && ! defined QUARTZ + // as a matter of fact, this fast path only + // performs well for X11 - under Windows, the + // clip via SetTriangleClipRegion is faster. + if( bAtLeastOnePolygon && + bBufferedUpdate && + ::rtl::math::approxEqual(fAlpha, 1.0) && + !maContent->IsTransparent() ) + { + // fast path for slide transitions + // (buffered, no alpha, no mask (because + // full slide is contained in the sprite)) + + // XOR bitmap onto backbuffer, clear area + // that should be _visible_ with black, + // XOR bitmap again on top of that - + // result: XOR cancels out where no black + // has been rendered, and yields the + // original bitmap, where black is + // underneath. + rTargetSurface.Push( PUSH_RASTEROP ); + rTargetSurface.SetRasterOp( ROP_XOR ); + rTargetSurface.DrawBitmap( aOutPos, + aOutputSize, + maContent->GetBitmap() ); + + rTargetSurface.SetLineColor(); + rTargetSurface.SetFillColor( COL_BLACK ); + rTargetSurface.SetRasterOp( ROP_0 ); + rTargetSurface.DrawPolyPolygon(PolyPolygon(aClipPoly)); // #i76339# + + rTargetSurface.SetRasterOp( ROP_XOR ); + rTargetSurface.DrawBitmap( aOutPos, + aOutputSize, + maContent->GetBitmap() ); + + rTargetSurface.Pop(); + + bSpriteRedrawn = true; + } + else +#endif + { + // redraw is direcly on the front buffer, + // or using alpha blending - cannot use + // XOR, thus, employing the still somewhat + // speedier triangle clip method + ::basegfx::B2DPolygon aTriangulatedClip(::basegfx::triangulator::triangulate(aClipPoly)); + + // restrict the clipping area to the visible portion of the output device. + Size aSize(rTargetSurface.GetOutputSizePixel()); + ::basegfx::B2DRange aOutputRect(::basegfx::B2DPoint(0,0),::basegfx::B2DPoint(aSize.Width(),aSize.Height())); + ::basegfx::B2DPolygon aClippedClip(::basegfx::tools::clipTriangleListOnRange(aTriangulatedClip,aOutputRect)); + + // #i76339# + const Polygon aPoly(aClippedClip); + const PolyPolygon aPolyPoly(aPoly); + rTargetSurface.SetTriangleClipRegion(aPolyPoly); + } + } + } + + if( !bSpriteRedrawn ) + { + if( ::rtl::math::approxEqual(fAlpha, 1.0) ) + { + // no alpha modulation -> just copy to output + if( maContent->IsTransparent() ) + rTargetSurface.DrawBitmapEx( aOutPos, aOutputSize, *maContent ); + else + rTargetSurface.DrawBitmap( aOutPos, aOutputSize, maContent->GetBitmap() ); + } + else + { + // TODO(P3): Switch to OutputDevice::DrawTransparent() + // here + + // draw semi-transparent + BYTE nColor( static_cast<UINT8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) ); + AlphaMask aAlpha( maContent->GetSizePixel(), + &nColor ); + + // mask out fully transparent areas + if( maContent->IsTransparent() ) + aAlpha.Replace( maContent->GetMask(), 255 ); + + // alpha-blend to output + rTargetSurface.DrawBitmapEx( aOutPos, aOutputSize, + BitmapEx( maContent->GetBitmap(), + aAlpha ) ); + } + } + + rTargetSurface.Pop(); + + if( mbShowSpriteBounds ) + { + ::PolyPolygon aMarkerPoly( + ::canvas::tools::getBoundMarksPolyPolygon( + ::basegfx::B2DRectangle(aOutPos.X(), + aOutPos.Y(), + aOutPos.X() + aOutputSize.Width()-1, + aOutPos.Y() + aOutputSize.Height()-1) ) ); + + // Paint little red sprite area markers + rTargetSurface.SetLineColor( COL_RED ); + rTargetSurface.SetFillColor(); + + for( int i=0; i<aMarkerPoly.Count(); ++i ) + { + rTargetSurface.DrawPolyLine( aMarkerPoly.GetObject((USHORT)i) ); + } + + // paint sprite prio + Font aVCLFont; + aVCLFont.SetHeight( std::min(long(20),aOutputSize.Height()) ); + aVCLFont.SetColor( COL_RED ); + + rTargetSurface.SetTextAlign(ALIGN_TOP); + rTargetSurface.SetTextColor( COL_RED ); + rTargetSurface.SetFont( aVCLFont ); + + ::rtl::OUString text( ::rtl::math::doubleToUString( getPriority(), + rtl_math_StringFormat_F, + 2,'.',NULL,' ') ); + + rTargetSurface.DrawText( aOutPos+Point(2,2), text ); + +#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 + OSL_TRACE( "SpriteHelper::redraw(): sprite %X has prio %f\n", + this, getPriority() ); +#endif + } + } + } + } + + ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const + { + return ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D( xPoly ); + } + +} diff --git a/canvas/source/vcl/spritehelper.hxx b/canvas/source/vcl/spritehelper.hxx new file mode 100644 index 000000000000..67aa588dff6e --- /dev/null +++ b/canvas/source/vcl/spritehelper.hxx @@ -0,0 +1,121 @@ +/************************************************************************* + * + * 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_SPRITEHELPER_HXX +#define _VCLCANVAS_SPRITEHELPER_HXX + +#include <com/sun/star/rendering/XCustomSprite.hpp> + +#include <vcl/virdev.hxx> + +#include <canvas/base/canvascustomspritehelper.hxx> +#include <canvas/base/spritesurface.hxx> +#include <canvas/vclwrapper.hxx> + +#include "backbuffer.hxx" +#include "impltools.hxx" +#include "spritecanvas.hxx" + + +namespace vclcanvas +{ + /* 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: + SpriteHelper(); + + // make CanvasCustomSpriteHelper::init visible for name lookup + using ::canvas::CanvasCustomSpriteHelper::init; + + /** 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 rBackBuffer + Buffer of the sprite content (non-alpha part) + + @param rBackBufferMask + Buffer of the sprite content (alpha part) + */ + void init( const ::com::sun::star::geometry::RealSize2D& rSpriteSize, + const ::canvas::SpriteSurface::Reference& rOwningSpriteCanvas, + const BackBufferSharedPtr& rBackBuffer, + const BackBufferSharedPtr& rBackBufferMask, + bool bShowSpriteBounds ); + + void disposing(); + + /** 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( OutputDevice& rOutDev, + 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; + + // for the redraw + BackBufferSharedPtr mpBackBuffer; + BackBufferSharedPtr mpBackBufferMask; + + /// Cached bitmap for the current sprite content + mutable ::canvas::vcltools::VCLObject<BitmapEx> maContent; + + /// When true, line sprite corners in red + bool mbShowSpriteBounds; + + }; +} + +#endif /* _VCLCANVAS_SPRITEHELPER_HXX */ diff --git a/canvas/source/vcl/textlayout.cxx b/canvas/source/vcl/textlayout.cxx new file mode 100644 index 000000000000..a2fd331fa66f --- /dev/null +++ b/canvas/source/vcl/textlayout.cxx @@ -0,0 +1,496 @@ +/************************************************************************* + * + * 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 <canvas/canvastools.hxx> + +#include <com/sun/star/rendering/CompositeOperation.hpp> +#include <com/sun/star/rendering/TextDirection.hpp> + +#include <vcl/metric.hxx> +#include <vcl/virdev.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include "impltools.hxx" +#include "textlayout.hxx" + +#include <boost/scoped_array.hpp> + + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + 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 uno::Reference<rendering::XGraphicDevice>& xDevice, + const OutDevProviderSharedPtr& rOutDev ) : + TextLayout_Base( m_aMutex ), + maText( aText ), + maLogicalAdvancements(), + mpFont( rFont ), + mxDevice( xDevice ), + mpOutDevProvider( rOutDev ), + mnTextDirection( nDirection ) + { + (void)nRandomSeed; + } + + void SAL_CALL TextLayout::disposing() + { + tools::LocalGuard aGuard; + + mpOutDevProvider.reset(); + mxDevice.clear(); + mpFont.reset(); + } + + // XTextLayout + uno::Sequence< uno::Reference< rendering::XPolyPolygon2D > > SAL_CALL TextLayout::queryTextShapes( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + OutputDevice& rOutDev = mpOutDevProvider->getOutDev(); + VirtualDevice aVDev( rOutDev ); + aVDev.SetFont( mpFont->getVCLFont() ); + + setupLayoutMode( aVDev, mnTextDirection ); + + const rendering::ViewState aViewState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + NULL); + + rendering::RenderState aRenderState ( + geometry::AffineMatrix2D(1,0,0,0,1,0), + NULL, + uno::Sequence<double>(4), + rendering::CompositeOperation::SOURCE); + + ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[maLogicalAdvancements.getLength()]); + setupTextOffsets(aOffsets.get(), maLogicalAdvancements, aViewState, aRenderState); + + uno::Sequence< uno::Reference< rendering::XPolyPolygon2D> > aOutlineSequence; + ::basegfx::B2DPolyPolygonVector aOutlines; + if (aVDev.GetTextOutlines( + aOutlines, + maText.Text, + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.Length), + FALSE, + 0, + aOffsets.get())) + { + aOutlineSequence.realloc(aOutlines.size()); + sal_Int32 nIndex (0); + for (::basegfx::B2DPolyPolygonVector::const_iterator + iOutline(aOutlines.begin()), + iEnd(aOutlines.end()); + iOutline!=iEnd; + ++iOutline) + { + aOutlineSequence[nIndex++] = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxDevice, + *iOutline); + } + } + + return aOutlineSequence; + } + + uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryInkMeasures( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + + OutputDevice& rOutDev = mpOutDevProvider->getOutDev(); + VirtualDevice aVDev( rOutDev ); + aVDev.SetFont( mpFont->getVCLFont() ); + + setupLayoutMode( aVDev, mnTextDirection ); + + const rendering::ViewState aViewState( + geometry::AffineMatrix2D(1,0,0, 0,1,0), + NULL); + + rendering::RenderState aRenderState ( + geometry::AffineMatrix2D(1,0,0,0,1,0), + NULL, + uno::Sequence<double>(4), + rendering::CompositeOperation::SOURCE); + + ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[maLogicalAdvancements.getLength()]); + setupTextOffsets(aOffsets.get(), maLogicalAdvancements, aViewState, aRenderState); + + MetricVector aMetricVector; + uno::Sequence<geometry::RealRectangle2D> aBoundingBoxes; + if (aVDev.GetGlyphBoundRects( + Point(0,0), + maText.Text, + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.Length), + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + aMetricVector)) + { + aBoundingBoxes.realloc(aMetricVector.size()); + sal_Int32 nIndex (0); + for (MetricVector::const_iterator + iMetric(aMetricVector.begin()), + iEnd(aMetricVector.end()); + iMetric!=iEnd; + ++iMetric) + { + aBoundingBoxes[nIndex++] = geometry::RealRectangle2D( + iMetric->getX(), + iMetric->getY(), + iMetric->getX() + iMetric->getWidth(), + iMetric->getY() + iMetric->getHeight()); + } + } + return aBoundingBoxes; + } + + uno::Sequence< geometry::RealRectangle2D > SAL_CALL TextLayout::queryMeasures( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + // TODO(F1) + return uno::Sequence< geometry::RealRectangle2D >(); + } + + uno::Sequence< double > SAL_CALL TextLayout::queryLogicalAdvancements( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + return maLogicalAdvancements; + } + + void SAL_CALL TextLayout::applyLogicalAdvancements( const uno::Sequence< double >& aAdvancements ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + tools::LocalGuard aGuard; + + ENSURE_ARG_OR_THROW( aAdvancements.getLength() == maText.Length, + "TextLayout::applyLogicalAdvancements(): mismatching number of advancements" ); + + maLogicalAdvancements = aAdvancements; + } + + geometry::RealRectangle2D SAL_CALL TextLayout::queryTextBounds( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + if( !mpOutDevProvider ) + return geometry::RealRectangle2D(); + + OutputDevice& rOutDev = mpOutDevProvider->getOutDev(); + + VirtualDevice aVDev( rOutDev ); + 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) + { + tools::LocalGuard aGuard; + + (void)nSize; + + // TODO(F1) + return 0.0; + } + + double SAL_CALL TextLayout::combinedJustify( const uno::Sequence< uno::Reference< rendering::XTextLayout > >& aNextLayouts, + double nSize ) throw (lang::IllegalArgumentException, uno::RuntimeException) + { + tools::LocalGuard aGuard; + + (void)aNextLayouts; + (void)nSize; + + // TODO(F1) + return 0.0; + } + + rendering::TextHit SAL_CALL TextLayout::getTextHit( const geometry::RealPoint2D& aHitPoint ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + (void)aHitPoint; + + // TODO(F1) + return rendering::TextHit(); + } + + rendering::Caret SAL_CALL TextLayout::getCaret( sal_Int32 nInsertionIndex, sal_Bool bExcludeLigatures ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + tools::LocalGuard aGuard; + + (void)nInsertionIndex; + (void)bExcludeLigatures; + + // TODO(F1) + return rendering::Caret(); + } + + sal_Int32 SAL_CALL TextLayout::getNextInsertionIndex( sal_Int32 nStartIndex, sal_Int32 nCaretAdvancement, sal_Bool bExcludeLigatures ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + tools::LocalGuard aGuard; + + (void)nStartIndex; + (void)nCaretAdvancement; + (void)bExcludeLigatures; + + // TODO(F1) + return 0; + } + + uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryVisualHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + tools::LocalGuard aGuard; + + (void)nStartIndex; + (void)nEndIndex; + + // TODO(F1) + return uno::Reference< rendering::XPolyPolygon2D >(); + } + + uno::Reference< rendering::XPolyPolygon2D > SAL_CALL TextLayout::queryLogicalHighlighting( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + tools::LocalGuard aGuard; + + (void)nStartIndex; + (void)nEndIndex; + + // TODO(F1) + return uno::Reference< rendering::XPolyPolygon2D >(); + } + + double SAL_CALL TextLayout::getBaselineOffset( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + // TODO(F1) + return 0.0; + } + + sal_Int8 SAL_CALL TextLayout::getMainTextDirection( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + return mnTextDirection; + } + + uno::Reference< rendering::XCanvasFont > SAL_CALL TextLayout::getFont( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + return mpFont.getRef(); + } + + rendering::StringContext SAL_CALL TextLayout::getText( ) throw (uno::RuntimeException) + { + tools::LocalGuard aGuard; + + return maText; + } + + bool TextLayout::draw( OutputDevice& rOutDev, + const Point& rOutpos, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) const + { + tools::LocalGuard aGuard; + + setupLayoutMode( rOutDev, mnTextDirection ); + + if( maLogicalAdvancements.getLength() ) + { + // TODO(P2): cache that + ::boost::scoped_array< sal_Int32 > aOffsets(new sal_Int32[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) + + rOutDev.DrawTextArray( rOutpos, + maText.Text, + aOffsets.get(), + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.Length) ); + } + else + { + rOutDev.DrawText( rOutpos, + maText.Text, + ::canvas::tools::numeric_cast<USHORT>(maText.StartPosition), + ::canvas::tools::numeric_cast<USHORT>(maText.Length) ); + } + + 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 IMPLEMENTATION_NAME "VCLCanvas::TextLayout" +#define SERVICE_NAME "com.sun.star.rendering.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/vcl/textlayout.hxx b/canvas/source/vcl/textlayout.hxx new file mode 100644 index 000000000000..ad443ae76376 --- /dev/null +++ b/canvas/source/vcl/textlayout.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 _VCLCANVAS_TEXTLAYOUT_HXX +#define _VCLCANVAS_TEXTLAYOUT_HXX + +#include <cppuhelper/compbase2.hxx> +#include <comphelper/broadcasthelper.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/StringContext.hpp> +#include <com/sun/star/rendering/XTextLayout.hpp> + +#include <canvas/vclwrapper.hxx> + +#include "canvasfont.hxx" +#include "impltools.hxx" + +#include <boost/utility.hpp> + + +/* Definition of TextLayout class */ + +namespace vclcanvas +{ + 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 ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice>& xDevice, + const OutDevProviderSharedPtr& rOutDev ); + + /// 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( OutputDevice& rOutDev, + const Point& rOutpos, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ) const; + + private: + 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; + + ::com::sun::star::rendering::StringContext maText; + ::com::sun::star::uno::Sequence< double > maLogicalAdvancements; + CanvasFont::Reference mpFont; + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice> mxDevice; + OutDevProviderSharedPtr mpOutDevProvider; + sal_Int8 mnTextDirection; + }; + +} + +#endif /* _VCLCANVAS_TEXTLAYOUT_HXX */ diff --git a/canvas/source/vcl/vclcanvas.component b/canvas/source/vcl/vclcanvas.component new file mode 100644 index 000000000000..f7e0bb8c0266 --- /dev/null +++ b/canvas/source/vcl/vclcanvas.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.VCL"> + <service name="com.sun.star.rendering.Canvas.VCL"/> + </implementation> + <implementation name="com.sun.star.comp.rendering.SpriteCanvas.VCL"> + <service name="com.sun.star.rendering.SpriteCanvas.VCL"/> + </implementation> +</component> diff --git a/canvas/source/vcl/windowoutdevholder.cxx b/canvas/source/vcl/windowoutdevholder.cxx new file mode 100644 index 000000000000..9515912a1d93 --- /dev/null +++ b/canvas/source/vcl/windowoutdevholder.cxx @@ -0,0 +1,57 @@ +/************************************************************************* + * + * 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 <com/sun/star/lang/NoSupportException.hpp> + +#include "windowoutdevholder.hxx" +#include <toolkit/helper/vclunohelper.hxx> + +using namespace ::com::sun::star; + +namespace vclcanvas +{ + namespace + { + Window& windowFromXWin( const uno::Reference<awt::XWindow>& xWin ) + { + Window* pWindow = VCLUnoHelper::GetWindow(xWin); + if( !pWindow ) + throw lang::NoSupportException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "Parent window not VCL window, or canvas out-of-process!")), + NULL); + return *pWindow; + } + } + + WindowOutDevHolder::WindowOutDevHolder( const uno::Reference<awt::XWindow>& xWin ) : + mrOutputWindow( windowFromXWin(xWin) ) + {} +} diff --git a/canvas/source/vcl/windowoutdevholder.hxx b/canvas/source/vcl/windowoutdevholder.hxx new file mode 100644 index 000000000000..ae20a49462e1 --- /dev/null +++ b/canvas/source/vcl/windowoutdevholder.hxx @@ -0,0 +1,66 @@ +/************************************************************************* + * + * 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_WINDOWOUTDEVHOLDER_HXX +#define _VCLCANVAS_WINDOWOUTDEVHOLDER_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/awt/XWindow.hpp> +#include <vcl/window.hxx> + +#include "outdevprovider.hxx" + +#include <boost/utility.hpp> + +namespace vclcanvas +{ + class WindowOutDevHolder : public OutDevProvider, + private ::boost::noncopyable + { + public: + explicit WindowOutDevHolder( const ::com::sun::star::uno::Reference< + ::com::sun::star::awt::XWindow>& xWin ); + + private: + virtual OutputDevice& getOutDev() { return mrOutputWindow; } + virtual const OutputDevice& getOutDev() const { return mrOutputWindow; } + + // TODO(Q2): Lifetime issue. Though WindowGraphicDeviceBase + // now listenes to the window component, I still consider + // holding a naked reference unsafe here (especially as we + // pass it around via getOutDev). This _only_ works reliably, + // if disposing the SpriteCanvas correctly disposes all + // entities which hold this pointer. + // So: as soon as the protocol inside + // vcl/source/window/window.cxx is broken, that disposes the + // canvas during window deletion, we're riding a dead horse + // here + Window& mrOutputWindow; + }; +} + +#endif /* _VCLCANVAS_WINDOWOUTDEVHOLDER_HXX */ |