diff options
Diffstat (limited to 'canvas/source/vcl')
42 files changed, 9973 insertions, 0 deletions
diff --git a/canvas/source/vcl/backbuffer.cxx b/canvas/source/vcl/backbuffer.cxx new file mode 100644 index 000000000000..5e08204681d3 --- /dev/null +++ b/canvas/source/vcl/backbuffer.cxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: backbuffer.cxx,v $ + * $Revision: 1.9 $ + * + * 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..2f9a387b3d1e --- /dev/null +++ b/canvas/source/vcl/backbuffer.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: backbuffer.hxx,v $ + * $Revision: 1.7 $ + * + * 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..1cc97351d9c0 --- /dev/null +++ b/canvas/source/vcl/bitmapbackbuffer.cxx @@ -0,0 +1,168 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: bitmapbackbuffer.cxx,v $ + * $Revision: 1.9 $ + * + * 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..7668aaaaf6b2 --- /dev/null +++ b/canvas/source/vcl/bitmapbackbuffer.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: bitmapbackbuffer.hxx,v $ + * $Revision: 1.7 $ + * + * 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..96bee5a12a89 --- /dev/null +++ b/canvas/source/vcl/cachedbitmap.cxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: cachedbitmap.cxx,v $ + * $Revision: 1.9 $ + * + * 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..8f60f1661a9b --- /dev/null +++ b/canvas/source/vcl/cachedbitmap.hxx @@ -0,0 +1,81 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: cachedbitmap.hxx,v $ + * $Revision: 1.6 $ + * + * 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 <goodies/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..9cc81cd08e57 --- /dev/null +++ b/canvas/source/vcl/canvas.cxx @@ -0,0 +1,164 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvas.cxx,v $ + * $Revision: 1.3 $ + * + * 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..2279f817a406 --- /dev/null +++ b/canvas/source/vcl/canvas.hxx @@ -0,0 +1,135 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvas.hxx,v $ + * $Revision: 1.2 $ + * + * 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 <com/sun/star/rendering/XParametricPolyPolygon2DFactory.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::rendering::XParametricPolyPolygon2DFactory, + ::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..7185ac56f894 --- /dev/null +++ b/canvas/source/vcl/canvasbitmap.cxx @@ -0,0 +1,147 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvasbitmap.cxx,v $ + * $Revision: 1.11 $ + * + * 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..fa795c63a8d1 --- /dev/null +++ b/canvas/source/vcl/canvasbitmap.hxx @@ -0,0 +1,132 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvasbitmap.hxx,v $ + * $Revision: 1.10 $ + * + * 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..5d5aa0dc8179 --- /dev/null +++ b/canvas/source/vcl/canvasbitmaphelper.cxx @@ -0,0 +1,570 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvasbitmaphelper.cxx,v $ + * $Revision: 1.13 $ + * + * 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..9cd3f3718920 --- /dev/null +++ b/canvas/source/vcl/canvasbitmaphelper.hxx @@ -0,0 +1,132 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvasbitmaphelper.hxx,v $ + * $Revision: 1.7 $ + * + * 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..2413bab0de5c --- /dev/null +++ b/canvas/source/vcl/canvascustomsprite.cxx @@ -0,0 +1,200 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvascustomsprite.cxx,v $ + * $Revision: 1.15 $ + * + * 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..de35bdea1587 --- /dev/null +++ b/canvas/source/vcl/canvascustomsprite.hxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvascustomsprite.hxx,v $ + * $Revision: 1.12 $ + * + * 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..d5b276901594 --- /dev/null +++ b/canvas/source/vcl/canvasfont.cxx @@ -0,0 +1,186 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvasfont.cxx,v $ + * $Revision: 1.10 $ + * + * 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..7c979e4e7b17 --- /dev/null +++ b/canvas/source/vcl/canvasfont.hxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvasfont.hxx,v $ + * $Revision: 1.8 $ + * + * 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..20b489144d0e --- /dev/null +++ b/canvas/source/vcl/canvashelper.cxx @@ -0,0 +1,1431 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvashelper.cxx,v $ + * $Revision: 1.19 $ + * + * 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( 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..a4319daeae1d --- /dev/null +++ b/canvas/source/vcl/canvashelper.hxx @@ -0,0 +1,347 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvashelper.hxx,v $ + * $Revision: 1.11 $ + * + * 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..571a8c4fc5a3 --- /dev/null +++ b/canvas/source/vcl/canvashelper_texturefill.cxx @@ -0,0 +1,1362 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: canvashelper_texturefill.cxx,v $ + * $Revision: 1.13 $ + * + * 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/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <comphelper/sequence.hxx> + +#include <canvas/canvastools.hxx> +#include <canvas/parametricpolypolygon.hxx> + +#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 fillGeneralLinearGradient( OutputDevice& rOutDev, + const ::basegfx::B2DHomMatrix& rTextureTransform, + const ::Rectangle& rBounds, + int nStepCount, + const ::Color& rColor1, + const ::Color& rColor2, + bool bFillNonOverlapping, + bool bAxialGradient ) + { + (void)bFillNonOverlapping; + + // 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 is odd, to have a well-defined + // middle index for axial gradients. + if( bAxialGradient && !(nStepCount % 2) ) + ++nStepCount; + + const int nStepCountHalved( nStepCount / 2 ); + + // only iterate nStepCount-1 steps, as the last strip is + // explicitely painted below + for( int i=0; i<nStepCount-1; ++i ) + { + // lerp color + if( bAxialGradient ) + { + // axial gradient has a triangle-like interpolation function + const int iPrime( i<=nStepCountHalved ? i : nStepCount-i-1); + + rOutDev.SetFillColor( + Color( (UINT8)(((nStepCountHalved - iPrime)*rColor1.GetRed() + iPrime*rColor2.GetRed())/nStepCountHalved), + (UINT8)(((nStepCountHalved - iPrime)*rColor1.GetGreen() + iPrime*rColor2.GetGreen())/nStepCountHalved), + (UINT8)(((nStepCountHalved - iPrime)*rColor1.GetBlue() + iPrime*rColor2.GetBlue())/nStepCountHalved) ) ); + } + else + { + // linear gradient has a plain lerp between start and end color + rOutDev.SetFillColor( + Color( (UINT8)(((nStepCount - i)*rColor1.GetRed() + i*rColor2.GetRed())/nStepCount), + (UINT8)(((nStepCount - i)*rColor1.GetGreen() + i*rColor2.GetGreen())/nStepCount), + (UINT8)(((nStepCount - i)*rColor1.GetBlue() + i*rColor2.GetBlue())/nStepCount) ) ); + } + + // 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() ) ); + + if( bAxialGradient ) + rOutDev.SetFillColor( rColor1 ); + else + rOutDev.SetFillColor( rColor2 ); + + rOutDev.DrawPolygon( aTempPoly ); + } + + + inline void fillLinearGradient( OutputDevice& rOutDev, + const ::Color& rColor1, + const ::Color& rColor2, + const ::basegfx::B2DHomMatrix& rTextureTransform, + const ::Rectangle& rBounds, + int nStepCount, + bool bFillNonOverlapping ) + { + fillGeneralLinearGradient( rOutDev, + rTextureTransform, + rBounds, + nStepCount, + rColor1, + rColor2, + bFillNonOverlapping, + false ); + } + + inline void fillAxialGradient( OutputDevice& rOutDev, + const ::Color& rColor1, + const ::Color& rColor2, + const ::basegfx::B2DHomMatrix& rTextureTransform, + const ::Rectangle& rBounds, + int nStepCount, + bool bFillNonOverlapping ) + { + fillGeneralLinearGradient( rOutDev, + rTextureTransform, + rBounds, + nStepCount, + rColor1, + rColor2, + bFillNonOverlapping, + true ); + } + + void fillPolygonalGradient( OutputDevice& rOutDev, + const ::canvas::ParametricPolyPolygon::Values& rValues, + const ::Color& rColor1, + const ::Color& rColor2, + const ::basegfx::B2DHomMatrix& rTextureTransform, + const ::Rectangle& rBounds, + int nStepCount, + bool bFillNonOverlapping ) + { + 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 + // ------------------------------------------------------ + + // move center of scaling to origin + aInnerPolygonTransformMatrix.translate( -0.5, -0.5 ); + + // 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 ); + } + + // move origin back to former center of polygon + aInnerPolygonTransformMatrix.translate( 0.5, 0.5 ); + + // and finally, add texture transform to it. + aInnerPolygonTransformMatrix *= rTextureTransform; + + // apply final matrix to polygon + aInnerPoly.transform( aInnerPolygonTransformMatrix ); + + + const sal_Int32 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; + + if( !bFillNonOverlapping ) + { + // fill background + rOutDev.SetFillColor( rColor1 ); + rOutDev.DrawRect( rBounds ); + + // render polygon + // ============== + + for( int i=1,p; i<nStepCount; ++i ) + { + // lerp color + rOutDev.SetFillColor( + Color( (UINT8)(((nStepCount - i)*rColor1.GetRed() + i*rColor2.GetRed())/nStepCount), + (UINT8)(((nStepCount - i)*rColor1.GetGreen() + i*rColor2.GetGreen())/nStepCount), + (UINT8)(((nStepCount - i)*rColor1.GetBlue() + i*rColor2.GetBlue())/nStepCount) ) ); + + // scale and render polygon, by interpolating between + // outer and inner polygon. + + // calc interpolation parameter in [0,1] range + const double nT( (nStepCount-i)/double(nStepCount) ); + + 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( (1.0-nT)*rInnerPoint.getX() + nT*rOuterPoint.getX() ), + basegfx::fround( (1.0-nT)*rInnerPoint.getY() + nT*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( int i=0,p; i<nStepCount; ++i ) + { + // lerp color + rOutDev.SetFillColor( + Color( (UINT8)(((nStepCount - i)*rColor1.GetRed() + i*rColor2.GetRed())/nStepCount), + (UINT8)(((nStepCount - i)*rColor1.GetGreen() + i*rColor2.GetGreen())/nStepCount), + (UINT8)(((nStepCount - i)*rColor1.GetBlue() + i*rColor2.GetBlue())/nStepCount) ) ); + +#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 + + // calc interpolation parameter in [0,1] range + const double nT( (nStepCount-i-1)/double(nStepCount) ); + + 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( (1.0-nT)*rInnerPoint.getX() + nT*rOuterPoint.getX() ), + basegfx::fround( (1.0-nT)*rInnerPoint.getY() + nT*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 ::Color& rColor1, + const ::Color& rColor2, + const ::basegfx::B2DHomMatrix& rTextureTransform, + const ::Rectangle& rBounds, + int nStepCount, + bool bFillNonOverlapping ) + { + switch( rValues.meType ) + { + case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR: + fillLinearGradient( rOutDev, + rColor1, + rColor2, + rTextureTransform, + rBounds, + nStepCount, + bFillNonOverlapping ); + break; + + case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL: + fillAxialGradient( rOutDev, + rColor1, + rColor2, + rTextureTransform, + rBounds, + nStepCount, + bFillNonOverlapping ); + break; + + case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL: + // FALLTHROUGH intended + case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR: + fillPolygonalGradient( rOutDev, + rValues, + rColor1, + rColor2, + rTextureTransform, + rBounds, + nStepCount, + bFillNonOverlapping ); + break; + + default: + ENSURE_OR_THROW( false, + "CanvasHelper::doGradientFill(): Unexpected case" ); + } + } + + bool gradientFill( OutputDevice& rOutDev, + OutputDevice* p2ndOutDev, + const ::canvas::ParametricPolyPolygon::Values& rValues, + const ::Color& rColor1, + const ::Color& rColor2, + 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. + + // calculate overall texture transformation (directly from + // texture to device space). + ::basegfx::B2DHomMatrix aMatrix; + ::basegfx::B2DHomMatrix aTextureTransform; + + ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform, + texture.AffineTransform ); + ::canvas::tools::mergeViewAndRenderTransform(aMatrix, + viewState, + renderState); + aTextureTransform *= aMatrix; // prepend total view/render transformation + + // determine maximal bound rect of gradient-filled polygon + const ::Rectangle aPolygonDeviceRectOrig( + rPoly.GetBoundRect() ); + + // 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 *= aTextureTransform; + aLeftBottom *= aTextureTransform; + aRightTop *= aTextureTransform; + aRightBottom*= aTextureTransform; + + + // calc step size + // -------------- + const int nColorSteps( + ::std::max( + labs( rColor1.GetRed() - rColor2.GetRed() ), + ::std::max( + labs( rColor1.GetGreen() - rColor2.GetGreen() ), + labs( rColor1.GetBlue() - rColor2.GetBlue() ) ) ) ); + + // 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 + const int nStepCount( + ::std::max( + 3, + ::std::min( + nGradientSize / nStripSize, + nColorSteps ) ) ); + + rOutDev.SetLineColor(); + + 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, + rColor1, + rColor2, + aTextureTransform, + aPolygonDeviceRectOrig, + nStepCount, + false ); + rOutDev.Pop(); + + if( p2ndOutDev ) + { + p2ndOutDev->Push( PUSH_CLIPREGION ); + p2ndOutDev->IntersectClipRegion( aPolygonDeviceRectOrig ); + doGradientFill( *p2ndOutDev, + rValues, + rColor1, + rColor2, + aTextureTransform, + 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, + rColor1, + rColor2, + aTextureTransform, + aPolygonDeviceRectOrig, + nStepCount, + false ); + rOutDev.Pop(); + + if( p2ndOutDev ) + { + p2ndOutDev->Push( PUSH_CLIPREGION ); + p2ndOutDev->SetClipRegion( aPolyClipRegion ); + doGradientFill( *p2ndOutDev, + rValues, + rColor1, + rColor2, + aTextureTransform, + 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, + rColor1, + rColor2, + aTextureTransform, + aPolygonDeviceRectOrig, + nStepCount, + true ); + rOutDev.SetFillColor( COL_BLACK ); + rOutDev.SetRasterOp( ROP_0 ); + rOutDev.DrawPolyPolygon( rPoly ); + rOutDev.SetRasterOp( ROP_XOR ); + doGradientFill( rOutDev, + rValues, + rColor1, + rColor2, + aTextureTransform, + aPolygonDeviceRectOrig, + nStepCount, + true ); + rOutDev.Pop(); + + if( p2ndOutDev ) + { + p2ndOutDev->Push( PUSH_RASTEROP ); + p2ndOutDev->SetRasterOp( ROP_XOR ); + doGradientFill( *p2ndOutDev, + rValues, + rColor1, + rColor2, + aTextureTransform, + aPolygonDeviceRectOrig, + nStepCount, + true ); + p2ndOutDev->SetFillColor( COL_BLACK ); + p2ndOutDev->SetRasterOp( ROP_0 ); + p2ndOutDev->DrawPolyPolygon( rPoly ); + p2ndOutDev->SetRasterOp( ROP_XOR ); + doGradientFill( *p2ndOutDev, + rValues, + rColor1, + rColor2, + aTextureTransform, + aPolygonDeviceRectOrig, + nStepCount, + true ); + p2ndOutDev->Pop(); + } + } +#endif // complex-clipping vs. XOR-trick + +#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 + { + ::basegfx::B2DRectangle aRect(0.0, 0.0, 1.0, 1.0); + ::basegfx::B2DRectangle aTextureDeviceRect; + ::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 ) + { + // copy state from Gradient polypoly locally + // (given object might change!) + const ::canvas::ParametricPolyPolygon::Values& rValues( + pGradient->getValues() ); + + // TODO: use all the colors and place them on given positions/stops + const ::Color aColor1( + ::vcl::unotools::stdColorSpaceSequenceToColor( + rValues.maColors [0] ) ); + const ::Color aColor2( + ::vcl::unotools::stdColorSpaceSequenceToColor( + rValues.maColors [rValues.maColors.getLength () - 1] ) ); + + // TODO(E1): Return value + // TODO(F1): FillRule + gradientFill( mpOutDev->getOutDev(), + mp2ndOutDev.get() ? &mp2ndOutDev->getOutDev() : (OutputDevice*)NULL, + rValues, + aColor1, + aColor2, + 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() ) + { +// OSL_ENSURE( textures[0].RepeatModeX == rendering::TexturingMode::REPEAT && +// textures[0].RepeatModeY == rendering::TexturingMode::REPEAT, +// "CanvasHelper::fillTexturedPolyPolygon(): VCL canvas cannot currently clamp textures." ); + + 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 if ( textures[0].RepeatModeX == rendering::TexturingMode::CLAMP &&
+ textures[0].RepeatModeY == rendering::TexturingMode::CLAMP )
+ {
+ 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);
+
+ 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 aPt( ::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 sal_Int32 nTilesX( nX2 - nX1 ); + const sal_Int32 nTilesY( 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() ) ); + + aVDev.SetRasterOp( ROP_XOR ); + textureFill( aVDev, + *pGrfObj, + aOutPos, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + aVDev.SetFillColor( COL_BLACK ); + aVDev.SetRasterOp( ROP_0 ); + aVDev.DrawPolyPolygon( aPolyPoly ); + aVDev.SetRasterOp( ROP_XOR ); + 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 +#if defined(QUARTZ) // TODO: other ports should avoid the XOR-trick too (implementation vs. interface!) + { + 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(); + } + } +#else // TODO: remove once doing the XOR-trick in the canvas-layer becomes redundant + { + // output via repeated XORing + rOutDev.Push( PUSH_RASTEROP ); + rOutDev.SetRasterOp( ROP_XOR ); + textureFill( rOutDev, + *pGrfObj, + aPt, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + rOutDev.SetFillColor( COL_BLACK ); + rOutDev.SetRasterOp( ROP_0 ); + rOutDev.DrawPolyPolygon( aPolyPoly ); + rOutDev.SetRasterOp( ROP_XOR ); + textureFill( rOutDev, + *pGrfObj, + aPt, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + rOutDev.Pop(); + + if( mp2ndOutDev ) + { + OutputDevice& r2ndOutDev( mp2ndOutDev->getOutDev() ); + r2ndOutDev.Push( PUSH_RASTEROP ); + r2ndOutDev.SetRasterOp( ROP_XOR ); + textureFill( r2ndOutDev, + *pGrfObj, + aPt, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + r2ndOutDev.SetFillColor( COL_BLACK ); + r2ndOutDev.SetRasterOp( ROP_0 ); + r2ndOutDev.DrawPolyPolygon( aPolyPoly ); + r2ndOutDev.SetRasterOp( ROP_XOR ); + textureFill( r2ndOutDev, + *pGrfObj, + aPt, + aIntegerNextTileX, + aIntegerNextTileY, + nTilesX, + nTilesY, + aSz, + aGrfAttr ); + r2ndOutDev.Pop(); + } + } +#endif // complex-clipping vs. XOR-trick + } + } + } + } + + // 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..853ae52c32c8 --- /dev/null +++ b/canvas/source/vcl/devicehelper.cxx @@ -0,0 +1,245 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: devicehelper.cxx,v $ + * $Revision: 1.8 $ + * + * 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..87d5d31ebffc --- /dev/null +++ b/canvas/source/vcl/devicehelper.hxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: devicehelper.hxx,v $ + * $Revision: 1.5 $ + * + * 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..0c2e3e7cddd7 --- /dev/null +++ b/canvas/source/vcl/exports.dxp @@ -0,0 +1,3 @@ +component_getImplementationEnvironment +component_writeInfo +component_getFactory
\ No newline at end of file diff --git a/canvas/source/vcl/exports.map b/canvas/source/vcl/exports.map new file mode 100644 index 000000000000..4101b0d761a9 --- /dev/null +++ b/canvas/source/vcl/exports.map @@ -0,0 +1,8 @@ +CAN_1_0 { + global: + component_getImplementationEnvironment; + component_writeInfo; + component_getFactory; + local: + *; +}; diff --git a/canvas/source/vcl/impltools.cxx b/canvas/source/vcl/impltools.cxx new file mode 100644 index 000000000000..aadd2521d488 --- /dev/null +++ b/canvas/source/vcl/impltools.cxx @@ -0,0 +1,547 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: impltools.cxx,v $ + * $Revision: 1.14 $ + * + * 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..62b18d7526e0 --- /dev/null +++ b/canvas/source/vcl/impltools.hxx @@ -0,0 +1,204 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: impltools.hxx,v $ + * $Revision: 1.8 $ + * + * 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..fdfdd62d16b8 --- /dev/null +++ b/canvas/source/vcl/makefile.mk @@ -0,0 +1,89 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.10 $ +# +# 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) $(GOODIESLIB) $(I18NISOLANGLIB) + +SHL1IMPLIB=i$(TARGET) +SHL1LIBS=$(SLB)$/$(TARGET).lib +SHL1DEF=$(MISC)$/$(SHL1TARGET).def + +SHL1VERSIONMAP=exports.map + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=exports.dxp + +# ========================================================================== + +.INCLUDE : target.mk diff --git a/canvas/source/vcl/outdevprovider.hxx b/canvas/source/vcl/outdevprovider.hxx new file mode 100644 index 000000000000..ca2c4556f003 --- /dev/null +++ b/canvas/source/vcl/outdevprovider.hxx @@ -0,0 +1,64 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outdevprovider.hxx,v $ + * $Revision: 1.6 $ + * + * 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..6317ec4d3ce0 --- /dev/null +++ b/canvas/source/vcl/repainttarget.hxx @@ -0,0 +1,66 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: repainttarget.hxx,v $ + * $Revision: 1.5 $ + * + * 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..138dc2f433ac --- /dev/null +++ b/canvas/source/vcl/services.cxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: services.cxx,v $ + * $Revision: 1.2 $ + * + * 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..059447cee05c --- /dev/null +++ b/canvas/source/vcl/sprite.hxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sprite.hxx,v $ + * $Revision: 1.8 $ + * + * 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..69bd4786b4c8 --- /dev/null +++ b/canvas/source/vcl/spritecanvas.cxx @@ -0,0 +1,181 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritecanvas.cxx,v $ + * $Revision: 1.16 $ + * + * 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..545eeeed4577 --- /dev/null +++ b/canvas/source/vcl/spritecanvas.hxx @@ -0,0 +1,176 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritecanvas.hxx,v $ + * $Revision: 1.13 $ + * + * 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 <com/sun/star/rendering/XParametricPolyPolygon2DFactory.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::rendering::XParametricPolyPolygon2DFactory, + ::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..89d3896d0a16 --- /dev/null +++ b/canvas/source/vcl/spritecanvashelper.cxx @@ -0,0 +1,721 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritecanvashelper.cxx,v $ + * $Revision: 1.12 $ + * + * 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..3a91753240e7 --- /dev/null +++ b/canvas/source/vcl/spritecanvashelper.hxx @@ -0,0 +1,182 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritecanvashelper.hxx,v $ + * $Revision: 1.4 $ + * + * 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..755f1ce9cfdc --- /dev/null +++ b/canvas/source/vcl/spritedevicehelper.cxx @@ -0,0 +1,161 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritedevicehelper.cxx,v $ + * $Revision: 1.3 $ + * + * 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..14bdc63a4303 --- /dev/null +++ b/canvas/source/vcl/spritedevicehelper.hxx @@ -0,0 +1,85 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritedevicehelper.hxx,v $ + * $Revision: 1.3 $ + * + * 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..123fe1002332 --- /dev/null +++ b/canvas/source/vcl/spritehelper.cxx @@ -0,0 +1,446 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritehelper.cxx,v $ + * $Revision: 1.13 $ + * + * 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..64b35d6f0703 --- /dev/null +++ b/canvas/source/vcl/spritehelper.hxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritehelper.hxx,v $ + * $Revision: 1.6 $ + * + * 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..5787f32cf4bf --- /dev/null +++ b/canvas/source/vcl/textlayout.cxx @@ -0,0 +1,499 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textlayout.cxx,v $ + * $Revision: 1.10 $ + * + * 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..7abe06ea7af0 --- /dev/null +++ b/canvas/source/vcl/textlayout.hxx @@ -0,0 +1,118 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textlayout.hxx,v $ + * $Revision: 1.7 $ + * + * 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/windowoutdevholder.cxx b/canvas/source/vcl/windowoutdevholder.cxx new file mode 100644 index 000000000000..23889b0c690d --- /dev/null +++ b/canvas/source/vcl/windowoutdevholder.cxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: windowoutdevholder.cxx,v $ + * $Revision: 1.2 $ + * + * 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..6108f5ff5536 --- /dev/null +++ b/canvas/source/vcl/windowoutdevholder.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: windowoutdevholder.hxx,v $ + * $Revision: 1.2 $ + * + * 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 */ |