diff options
Diffstat (limited to 'cppcanvas/source')
49 files changed, 12871 insertions, 0 deletions
diff --git a/cppcanvas/source/inc/action.hxx b/cppcanvas/source/inc/action.hxx new file mode 100644 index 000000000000..ec59f77960a6 --- /dev/null +++ b/cppcanvas/source/inc/action.hxx @@ -0,0 +1,167 @@ +/************************************************************************* + * + * 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: action.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 _CPPCANVAS_ACTION_HXX +#define _CPPCANVAS_ACTION_HXX + +#include <sal/types.h> + +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif + +namespace basegfx +{ + class B2DHomMatrix; + class B2DRange; +} + + +/* Definition of Action interface */ + +namespace cppcanvas +{ + namespace internal + { + /** Interface for internal render actions + + This interface is implemented by all objects generated + from the metafile renderer, and corresponds roughly to the + VCL meta action. + */ + class Action + { + public: + /** Used for rendering action subsets + + There are several cases where an Action might have + subsettable content, e.g. text, or referenced + metafiles, like the transparent action. + + Generally, at the metafile renderer, all actions are + 'flattened' out, i.e. a meta action rendering the + string "Hello" counts five indices, and a transparent + action containing a metafile with 100 actions counts + at least 100 indices (contained transparency or text + actions recursively add to this value). From the + outside, the subset to render is referenced via this + flat index range + */ + struct Subset + { + /** Denotes start of the subset. + + The index given here specifies the first subaction + to render. + */ + sal_Int32 mnSubsetBegin; + + /** Denotes end of the subset + + The index given here specifies the first subaction + <em>not<em> to render, i.e. one action behind the + subset to be rendered + */ + sal_Int32 mnSubsetEnd; + }; + + virtual ~Action() {} + + /** Render this action to the associated canvas + + @param rTransformation + Transformation matrix to apply before rendering + + @return true, if rendering was successful. If + rendering failed, false is returned. + */ + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const = 0; + + /** Render the given part of the action to the associated + canvas. + + @param rTransformation + Transformation matrix to apply before rendering + + @param rSubset + Subset of the action to render. See Subset description + for index semantics. + + @return true, if rendering was successful. If the + specified subset is invalid for this action, or if + rendering failed for other reasons, false is returned. + */ + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const = 0; + + /** Query bounds of this action on the associated canvas + + @param rTransformation + Transformation matrix to apply + + @return the bounds for this action in device + coordinate space. + */ + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const = 0; + + /** Query bounds for the given part of the action on the + associated canvas. + + @param rTransformation + Transformation matrix to apply. + + @param rSubset + Subset of the action to query. See Subset description + for index semantics. + + @return the bounds for the given subset in device + coordinate space. + */ + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const = 0; + + /** Query action count. + + This method returns the number of subset actions + contained in this action. The render( Subset ) method + must accept subset ranges up to the value returned + here. + + @return the number of subset actions + */ + virtual sal_Int32 getActionCount() const = 0; + }; + + typedef ::boost::shared_ptr< Action > ActionSharedPtr; + + } +} + +#endif /* _CPPCANVAS_ACTION_HXX */ diff --git a/cppcanvas/source/inc/canvasgraphichelper.hxx b/cppcanvas/source/inc/canvasgraphichelper.hxx new file mode 100644 index 000000000000..edc16b46a09e --- /dev/null +++ b/cppcanvas/source/inc/canvasgraphichelper.hxx @@ -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: canvasgraphichelper.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 _CPPCANVAS_CANVASGRAPHICHELPER_HXX +#define _CPPCANVAS_CANVASGRAPHICHELPER_HXX + +#include <com/sun/star/rendering/RenderState.hpp> +#include <basegfx/polygon/b2dpolypolygon.hxx> + +#include <cppcanvas/canvasgraphic.hxx> + +#include <boost/optional.hpp> + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XGraphicDevice; +} } } } + + +/* Definition of CanvasGraphicHelper class */ + +namespace cppcanvas +{ + + namespace internal + { + + class CanvasGraphicHelper : public virtual CanvasGraphic + { + public: + CanvasGraphicHelper( const CanvasSharedPtr& rParentCanvas ); + + // CanvasGraphic implementation + virtual void setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ); + virtual ::basegfx::B2DHomMatrix getTransformation() const; + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ); + virtual void setClip(); + virtual ::basegfx::B2DPolyPolygon const* getClip() const; + virtual void setRGBAColor( Color::IntSRGBA ); + virtual Color::IntSRGBA getRGBAColor() const; + virtual void setCompositeOp( CompositeOp aOp ); + virtual CompositeOp getCompositeOp() const; + + protected: + // for our clients + // =============== + CanvasSharedPtr getCanvas() const; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > getGraphicDevice() const; + const ::com::sun::star::rendering::RenderState& getRenderState() const; + + private: + mutable ::com::sun::star::rendering::RenderState maRenderState; + + boost::optional<basegfx::B2DPolyPolygon> maClipPolyPolygon; + CanvasSharedPtr mpCanvas; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > mxGraphicDevice; + }; + + } +} + +#endif /* _CPPCANVAS_CANVASGRAPHICHELPER_HXX */ diff --git a/cppcanvas/source/inc/implrenderer.hxx b/cppcanvas/source/inc/implrenderer.hxx new file mode 100644 index 000000000000..46f025b40b48 --- /dev/null +++ b/cppcanvas/source/inc/implrenderer.hxx @@ -0,0 +1,190 @@ +/************************************************************************* + * + * 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: implrenderer.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 _CPPCANVAS_IMPLRENDERER_HXX +#define _CPPCANVAS_IMPLRENDERER_HXX + +#include <sal/types.h> + +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif +#include <cppcanvas/renderer.hxx> +#include <cppcanvas/canvas.hxx> + +#include <canvasgraphichelper.hxx> +#include <action.hxx> + +#include <vector> + +class GDIMetaFile; +class VirtualDevice; +class Gradient; +class BitmapEx; +class MapMode; +class Size; + +namespace basegfx { + class B2DPolyPolygon; + class B2DPolygon; +} + +namespace cppcanvas +{ + + namespace internal + { + struct OutDevState; + struct ActionFactoryParameters; + + // state stack of OutputDevice, to correctly handle + // push/pop actions + typedef ::std::vector< OutDevState > VectorOfOutDevStates; + + class ImplRenderer : public virtual Renderer, protected CanvasGraphicHelper + { + public: + ImplRenderer( const CanvasSharedPtr& rCanvas, + const GDIMetaFile& rMtf, + const Parameters& rParms ); + ImplRenderer( const CanvasSharedPtr& rCanvas, + const BitmapEx& rBmpEx, + const Parameters& rParms ); + + virtual ~ImplRenderer(); + + virtual bool draw() const; + virtual bool drawSubset( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const; + virtual ::basegfx::B2DRange getSubsetArea( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const; + + + // element of the Renderer's action vector. Need to be + // public, since some functors need it, too. + struct MtfAction + { + MtfAction( const ActionSharedPtr& rAction, + sal_Int32 nOrigIndex ) : + mpAction( rAction ), + mnOrigIndex( nOrigIndex ) + { + } + + ActionSharedPtr mpAction; + sal_Int32 mnOrigIndex; + }; + + // prefetched and prepared canvas actions + // (externally not visible) + typedef ::std::vector< MtfAction > ActionVector; + + + private: + // default: disabled copy/assignment + ImplRenderer(const ImplRenderer&); + ImplRenderer& operator=( const ImplRenderer& ); + + void updateClipping( const ::basegfx::B2DPolyPolygon& rClipPoly, + const ActionFactoryParameters& rParms, + bool bIntersect ); + + void updateClipping( const ::Rectangle& rClipRect, + const ActionFactoryParameters& rParms, + bool bIntersect ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont > createFont( double& o_rFontRotation, + const ::Font& rFont, + const ActionFactoryParameters& rParms ) const; + bool createActions( GDIMetaFile& rMtf, + const ActionFactoryParameters& rParms, + bool bSubsettableActions ); + bool createFillAndStroke( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const ActionFactoryParameters& rParms ); + bool createFillAndStroke( const ::basegfx::B2DPolygon& rPoly, + const ActionFactoryParameters& rParms ); + void skipContent( GDIMetaFile& rMtf, + const char* pCommentString, + sal_Int32& io_rCurrActionIndex ) const; + + bool isActionContained( GDIMetaFile& rMtf, + const char* pCommentString, + USHORT nType ) const; + + void createGradientAction( const ::PolyPolygon& rPoly, + const ::Gradient& rGradient, + const ActionFactoryParameters& rParms, + bool bIsPolygonRectangle, + bool bSubsettableActions ); + + void createTextAction( const ::Point& rStartPoint, + const String rString, + int nIndex, + int nLength, + const sal_Int32* pCharWidths, + const ActionFactoryParameters& rParms, + bool bSubsettable ); + + bool getSubsetIndices( sal_Int32& io_rStartIndex, + sal_Int32& io_rEndIndex, + ActionVector::const_iterator& o_rRangeBegin, + ActionVector::const_iterator& o_rRangeEnd ) const; + + + ActionVector maActions; + }; + + + /// Common parameters when creating actions + struct ActionFactoryParameters + { + ActionFactoryParameters( VectorOfOutDevStates& rStates, + const CanvasSharedPtr& rCanvas, + ::VirtualDevice& rVDev, + const Renderer::Parameters& rParms, + sal_Int32& io_rCurrActionIndex ) : + mrStates(rStates), + mrCanvas(rCanvas), + mrVDev(rVDev), + mrParms(rParms), + mrCurrActionIndex(io_rCurrActionIndex) + {} + + VectorOfOutDevStates& mrStates; + const CanvasSharedPtr& mrCanvas; + ::VirtualDevice& mrVDev; + const Renderer::Parameters& mrParms; + sal_Int32& mrCurrActionIndex; + }; + } +} + +#endif /* _CPPCANVAS_IMPLRENDERER_HXX */ diff --git a/cppcanvas/source/inc/tools.hxx b/cppcanvas/source/inc/tools.hxx new file mode 100644 index 000000000000..1f709861428b --- /dev/null +++ b/cppcanvas/source/inc/tools.hxx @@ -0,0 +1,59 @@ +/************************************************************************* + * + * 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: tools.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 _CPPCANVAS_TOOLS_HXX +#define _CPPCANVAS_TOOLS_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <cppcanvas/color.hxx> + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XGraphicDevice; +} } } } + + +namespace cppcanvas +{ + namespace tools + { + ::com::sun::star::uno::Sequence< double > + intSRGBAToDoubleSequence( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >&, + Color::IntSRGBA ); + + Color::IntSRGBA doubleSequenceToIntSRGBA( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >& rDevice, + const ::com::sun::star::uno::Sequence< double >& rColor ); + } +} + +#endif /* _CPPCANVAS_TOOLS_HXX */ diff --git a/cppcanvas/source/mtfrenderer/bitmapaction.cxx b/cppcanvas/source/mtfrenderer/bitmapaction.cxx new file mode 100644 index 000000000000..355dd336e2c5 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/bitmapaction.cxx @@ -0,0 +1,250 @@ +/************************************************************************* + * + * 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: bitmapaction.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_cppcanvas.hxx" + +#include <rtl/logfile.hxx> +#include <com/sun/star/rendering/XBitmap.hpp> +#include <com/sun/star/rendering/RepaintResult.hpp> +#include <com/sun/star/rendering/XCachedPrimitive.hpp> + +#include <vcl/bitmapex.hxx> +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> + +#include <canvas/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <boost/utility.hpp> + +#include "cachedprimitivebase.hxx" +#include "bitmapaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + + class BitmapAction : public CachedPrimitiveBase + { + public: + BitmapAction( const ::BitmapEx&, + const ::basegfx::B2DPoint& rDstPoint, + const CanvasSharedPtr&, + const OutDevState& ); + BitmapAction( const ::BitmapEx&, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr&, + const OutDevState& ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + uno::Reference< rendering::XBitmap > mxBitmap; + CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + }; + + + BitmapAction::BitmapAction( const ::BitmapEx& rBmpEx, + const ::basegfx::B2DPoint& rDstPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + CachedPrimitiveBase( rCanvas, true ), + mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(), + rBmpEx ) ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + + // Setup transformation such that the next render call is + // moved rPoint away. + ::basegfx::B2DHomMatrix aLocalTransformation; + aLocalTransformation.translate( rDstPoint.getX(), + rDstPoint.getY() ); + ::canvas::tools::appendToRenderState( maState, + aLocalTransformation ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, + rState, + rCanvas, + rDstPoint, + NULL, + NULL ); + } + + BitmapAction::BitmapAction( const ::BitmapEx& rBmpEx, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + CachedPrimitiveBase( rCanvas, true ), + mxBitmap( ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(), + rBmpEx ) ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + + // Setup transformation such that the next render call is + // moved rPoint away, and scaled according to the ratio + // given by src and dst size. + const ::Size aBmpSize( rBmpEx.GetSizePixel() ); + ::basegfx::B2DHomMatrix aLocalTransformation; + + const ::basegfx::B2DVector aScale( rDstSize.getX() / aBmpSize.Width(), + rDstSize.getY() / aBmpSize.Height() ); + aLocalTransformation.scale( aScale.getX(), aScale.getY() ); + aLocalTransformation.translate( rDstPoint.getX(), + rDstPoint.getY() ); + ::canvas::tools::appendToRenderState( maState, + aLocalTransformation ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, + rState, + rCanvas, + rDstPoint, + &aScale, + NULL ); + } + + bool BitmapAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::BitmapAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::BitmapAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + rCachedPrimitive = mpCanvas->getUNOCanvas()->drawBitmap( mxBitmap, + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + bool BitmapAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // bitmap only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange BitmapAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + const geometry::IntegerSize2D aSize( mxBitmap->getSize() ); + + return tools::calcDevicePixelBounds( ::basegfx::B2DRange( 0,0, + aSize.Width, + aSize.Height ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange BitmapAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // bitmap only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 BitmapAction::getActionCount() const + { + return 1; + } + } + + ActionSharedPtr BitmapActionFactory::createBitmapAction( const ::BitmapEx& rBmpEx, + const ::basegfx::B2DPoint& rDstPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new BitmapAction(rBmpEx, + rDstPoint, + rCanvas, + rState ) ); + } + + ActionSharedPtr BitmapActionFactory::createBitmapAction( const ::BitmapEx& rBmpEx, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new BitmapAction(rBmpEx, + rDstPoint, + rDstSize, + rCanvas, + rState ) ); + } + } +} diff --git a/cppcanvas/source/mtfrenderer/bitmapaction.hxx b/cppcanvas/source/mtfrenderer/bitmapaction.hxx new file mode 100644 index 000000000000..662b585acd66 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/bitmapaction.hxx @@ -0,0 +1,84 @@ +/************************************************************************* + * + * 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: bitmapaction.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 _CPPCANVAS_BITMAPACTION_HXX +#define _CPPCANVAS_BITMAPACTION_HXX + +#include <cppcanvas/canvas.hxx> +#include <action.hxx> + +namespace basegfx { + class B2DPoint; + class B2DVector; +} +class BitmapEx; + +/* Definition of internal::BitmapActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class BitmapActionFactory + { + public: + /// Unscaled bitmap action, only references destination point + static ActionSharedPtr createBitmapAction( const ::BitmapEx&, + const ::basegfx::B2DPoint& rDstPoint, + const CanvasSharedPtr&, + const OutDevState& ); + + /// Scaled bitmap action, dest point and dest size + static ActionSharedPtr createBitmapAction( const ::BitmapEx&, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr&, + const OutDevState& ); + + private: + // static factory, disable big four + BitmapActionFactory(); + ~BitmapActionFactory(); + BitmapActionFactory(const BitmapActionFactory&); + BitmapActionFactory& operator=( const BitmapActionFactory& ); + }; + } +} + +#endif /*_CPPCANVAS_BITMAPACTION_HXX */ diff --git a/cppcanvas/source/mtfrenderer/cachedprimitivebase.cxx b/cppcanvas/source/mtfrenderer/cachedprimitivebase.cxx new file mode 100644 index 000000000000..68c1b0ad2c16 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/cachedprimitivebase.cxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * 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: cachedprimitivebase.cxx,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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_cppcanvas.hxx" + +#include <rtl/logfile.hxx> + +#include <com/sun/star/rendering/RepaintResult.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <canvas/canvastools.hxx> +#include <cppcanvas/canvas.hxx> + +#include "cachedprimitivebase.hxx" + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + CachedPrimitiveBase::CachedPrimitiveBase( const CanvasSharedPtr& rCanvas, + bool bOnlyRedrawWithSameTransform ) : + mpCanvas( rCanvas ), + mxCachedPrimitive(), + maLastTransformation(), + mbOnlyRedrawWithSameTransform( bOnlyRedrawWithSameTransform ) + { + // TODO(F2): also store last view transform, and refuse to + // redraw if changed. + } + + bool CachedPrimitiveBase::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::CachedPrimitiveBase::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::CachedPrimitiveBase: 0x%X", this ); + + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + ::basegfx::B2DHomMatrix aTotalTransform; + + ::canvas::tools::getViewStateTransform( aTotalTransform, + rViewState ); + aTotalTransform *= rTransformation; + + // can we use the cached primitive? For that, it must be + // present in the first place, and, if + // mbOnlyRedrawWithSameTransform is true, the overall + // transformation must be the same. + if( mxCachedPrimitive.is() && + (!mbOnlyRedrawWithSameTransform || + maLastTransformation == aTotalTransform) ) + { + if( mxCachedPrimitive->redraw( rViewState ) == + rendering::RepaintResult::REDRAWN ) + { + // cached repaint succeeded, done. + return true; + } + } + + maLastTransformation = aTotalTransform; + + // delegate rendering to derived classes + return render( mxCachedPrimitive, + rTransformation ); + } + } +} diff --git a/cppcanvas/source/mtfrenderer/cachedprimitivebase.hxx b/cppcanvas/source/mtfrenderer/cachedprimitivebase.hxx new file mode 100644 index 000000000000..6bb0348cc570 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/cachedprimitivebase.hxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * 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: cachedprimitivebase.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 _CPPCANVAS_CACHEDPRIMITIVEBASE_HXX +#define _CPPCANVAS_CACHEDPRIMITIVEBASE_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <cppcanvas/canvas.hxx> +#include <boost/utility.hpp> + +#include "action.hxx" + +namespace basegfx { class B2DHomMatrix; } + + +/* Definition of internal::CachedPrimitiveBase class */ + +namespace cppcanvas +{ + namespace internal + { + /** Base class providing cached re-rendering, if XCanvas + returns XCachedPrimitive + + Derive from this class and implement private render() + method to perform the actual primitive rendering. Return + cached primitive into given reference. Next time this + class' public render() method gets called, the cached + representation is taken. + */ + class CachedPrimitiveBase : public Action, + private ::boost::noncopyable + { + public: + /** Constructor + + @param rCanvas + Canvas on which this primitive is to appear + + @param bOnlyRedrawWithSameTransform + When true, this class only reuses the cached + primitive, if the overall transformation stays the + same. Otherwise, repaints are always performed via the + cached primitive. + */ + CachedPrimitiveBase( const CanvasSharedPtr& rCanvas, + bool bOnlyRedrawWithSameTransform ); + virtual ~CachedPrimitiveBase() {} + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + + protected: + using Action::render; + + private: + virtual bool render( ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const = 0; + + CanvasSharedPtr mpCanvas; + mutable ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCachedPrimitive > mxCachedPrimitive; + mutable ::basegfx::B2DHomMatrix maLastTransformation; + const bool mbOnlyRedrawWithSameTransform; + }; + } +} + +#endif /*_CPPCANVAS_CACHEDPRIMITIVEBASE_HXX */ diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx new file mode 100644 index 000000000000..c6f9a295b332 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx @@ -0,0 +1,3261 @@ +/************************************************************************* + * + * 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: implrenderer.cxx,v $ + * $Revision: 1.25.4.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_cppcanvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> +#include <canvas/verbosetrace.hxx> + +#include <osl/mutex.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> + +#include <rtl/logfile.hxx> + +#include <comphelper/sequence.hxx> +#include <comphelper/anytostring.hxx> +#include <cppuhelper/exc_hlp.hxx> + +#include <cppcanvas/canvas.hxx> + +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/geometry/RealPoint2D.hpp> +#include <com/sun/star/rendering/ViewState.hpp> +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> + +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> + +#include <canvas/canvastools.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/salbtype.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/metaact.hxx> +#include <vcl/virdev.hxx> +#include <vcl/metric.hxx> +#include <vcl/graphictools.hxx> +#include <tools/poly.hxx> +#include <i18npool/mslangid.hxx> + +#include <implrenderer.hxx> +#include <tools.hxx> +#include <outdevstate.hxx> + +#include <action.hxx> +#include <bitmapaction.hxx> +#include <lineaction.hxx> +#include <pointaction.hxx> +#include <polypolyaction.hxx> +#include <textaction.hxx> +#include <transparencygroupaction.hxx> + +#include <vector> +#include <algorithm> +#include <iterator> + +#include <boost/scoped_array.hpp> + +#include "mtftools.hxx" +#include "outdevstate.hxx" + + +using namespace ::com::sun::star; + + +// free support functions +// ====================== +namespace +{ + template < class MetaActionType > void setStateColor( MetaActionType* pAct, + bool& rIsColorSet, + uno::Sequence< double >& rColorSequence, + const cppcanvas::CanvasSharedPtr& rCanvas ) + { + // set rIsColorSet and check for true at the same time + if( (rIsColorSet=pAct->IsSetting()) != false ) + { + ::Color aColor( pAct->GetColor() ); + + // force alpha part of color to + // opaque. transparent painting is done + // explicitely via META_TRANSPARENT_ACTION + aColor.SetTransparency(0); + //aColor.SetTransparency(128); + + rColorSequence = ::vcl::unotools::colorToDoubleSequence( + aColor, + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + } + } + + + // state stack manipulators + // ------------------------ + void clearStateStack( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) + { + rStates.clear(); + const ::cppcanvas::internal::OutDevState aDefaultState; + rStates.push_back( aDefaultState ); + } + + ::cppcanvas::internal::OutDevState& getState( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) + { + return rStates.back(); + } + + const ::cppcanvas::internal::OutDevState& getState( const ::cppcanvas::internal::VectorOfOutDevStates& rStates ) + { + return rStates.back(); + } + + void pushState( ::cppcanvas::internal::VectorOfOutDevStates& rStates, + USHORT nFlags ) + { + rStates.push_back( getState( rStates ) ); + getState( rStates ).pushFlags = nFlags; + } + + void popState( ::cppcanvas::internal::VectorOfOutDevStates& rStates ) + { + if( getState( rStates ).pushFlags != PUSH_ALL ) + { + // a state is pushed which is incomplete, i.e. does not + // restore everything to the previous stack level when + // popped. + // That means, we take the old state, and restore every + // OutDevState member whose flag is set, from the new to the + // old state. Then the new state gets overwritten by the + // calculated state + + // preset to-be-calculated new state with old state + ::cppcanvas::internal::OutDevState aCalculatedNewState( getState( rStates ) ); + + // selectively copy to-be-restored content over saved old + // state + rStates.pop_back(); + + const ::cppcanvas::internal::OutDevState& rNewState( getState( rStates ) ); + + if( (aCalculatedNewState.pushFlags & PUSH_LINECOLOR) ) + { + aCalculatedNewState.lineColor = rNewState.lineColor; + aCalculatedNewState.isLineColorSet = rNewState.isLineColorSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_FILLCOLOR) ) + { + aCalculatedNewState.fillColor = rNewState.fillColor; + aCalculatedNewState.isFillColorSet = rNewState.isFillColorSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_FONT) ) + { + aCalculatedNewState.xFont = rNewState.xFont; + aCalculatedNewState.fontRotation = rNewState.fontRotation; + aCalculatedNewState.textReliefStyle = rNewState.textReliefStyle; + aCalculatedNewState.textOverlineStyle = rNewState.textOverlineStyle; + aCalculatedNewState.textUnderlineStyle = rNewState.textUnderlineStyle; + aCalculatedNewState.textStrikeoutStyle = rNewState.textStrikeoutStyle; + aCalculatedNewState.textEmphasisMarkStyle = rNewState.textEmphasisMarkStyle; + aCalculatedNewState.isTextEffectShadowSet = rNewState.isTextEffectShadowSet; + aCalculatedNewState.isTextWordUnderlineSet = rNewState.isTextWordUnderlineSet; + aCalculatedNewState.isTextOutlineModeSet = rNewState.isTextOutlineModeSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTCOLOR) ) + { + aCalculatedNewState.textColor = rNewState.textColor; + } + + if( (aCalculatedNewState.pushFlags & PUSH_MAPMODE) ) + { + aCalculatedNewState.mapModeTransform = rNewState.mapModeTransform; + } + + if( (aCalculatedNewState.pushFlags & PUSH_CLIPREGION) ) + { + aCalculatedNewState.clip = rNewState.clip; + aCalculatedNewState.clipRect = rNewState.clipRect; + aCalculatedNewState.xClipPoly = rNewState.xClipPoly; + } + + // TODO(F2): Raster ops NYI + // if( (aCalculatedNewState.pushFlags & PUSH_RASTEROP) ) + // { + // } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTFILLCOLOR) ) + { + aCalculatedNewState.textFillColor = rNewState.textFillColor; + aCalculatedNewState.isTextFillColorSet = rNewState.isTextFillColorSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTALIGN) ) + { + aCalculatedNewState.textReferencePoint = rNewState.textReferencePoint; + } + + // TODO(F1): Refpoint handling NYI + // if( (aCalculatedNewState.pushFlags & PUSH_REFPOINT) ) + // { + // } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTLINECOLOR) ) + { + aCalculatedNewState.textLineColor = rNewState.textLineColor; + aCalculatedNewState.isTextLineColorSet = rNewState.isTextLineColorSet; + } + + if( (aCalculatedNewState.pushFlags & PUSH_TEXTLAYOUTMODE) ) + { + aCalculatedNewState.textAlignment = rNewState.textAlignment; + aCalculatedNewState.textDirection = rNewState.textDirection; + } + + // TODO(F2): Text language handling NYI + // if( (aCalculatedNewState.pushFlags & PUSH_TEXTLANGUAGE) ) + // { + // } + + // always copy push mode + aCalculatedNewState.pushFlags = rNewState.pushFlags; + + // flush to stack + getState( rStates ) = aCalculatedNewState; + } + else + { + rStates.pop_back(); + } + } + + void setupStrokeAttributes( rendering::StrokeAttributes& o_rStrokeAttributes, + const ::cppcanvas::internal::ActionFactoryParameters& rParms, + const LineInfo& rLineInfo ) + { + const ::basegfx::B2DSize aWidth( rLineInfo.GetWidth(), 0 ); + o_rStrokeAttributes.StrokeWidth = + (getState( rParms.mrStates ).mapModeTransform * aWidth).getX(); + + // setup reasonable defaults + o_rStrokeAttributes.MiterLimit = 1.0; + o_rStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; + o_rStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; + o_rStrokeAttributes.JoinType = rendering::PathJoinType::MITER; + + if( LINE_DASH == rLineInfo.GetStyle() ) + { + const ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); + + // TODO(F1): Interpret OutDev::GetRefPoint() for the start of the dashing. + + // interpret dash info only if explicitely enabled as + // style + const ::basegfx::B2DSize aDistance( rLineInfo.GetDistance(), 0 ); + const double nDistance( (rState.mapModeTransform * aDistance).getX() ); + + const ::basegfx::B2DSize aDashLen( rLineInfo.GetDashLen(), 0 ); + const double nDashLen( (rState.mapModeTransform * aDashLen).getX() ); + + const ::basegfx::B2DSize aDotLen( rLineInfo.GetDotLen(), 0 ); + const double nDotLen( (rState.mapModeTransform * aDotLen).getX() ); + + const sal_Int32 nNumArryEntries( 2*rLineInfo.GetDashCount() + + 2*rLineInfo.GetDotCount() ); + + o_rStrokeAttributes.DashArray.realloc( nNumArryEntries ); + double* pDashArray = o_rStrokeAttributes.DashArray.getArray(); + + + // iteratively fill dash array, first with dashs, then + // with dots. + // =================================================== + + sal_Int32 nCurrEntry=0; + + for( sal_Int32 i=0; i<rLineInfo.GetDashCount(); ++i ) + { + pDashArray[nCurrEntry++] = nDashLen; + pDashArray[nCurrEntry++] = nDistance; + } + for( sal_Int32 i=0; i<rLineInfo.GetDotCount(); ++i ) + { + pDashArray[nCurrEntry++] = nDotLen; + pDashArray[nCurrEntry++] = nDistance; + } + } + } + + + /** Create masked BitmapEx, where the white areas of rBitmap are + transparent, and the other appear in rMaskColor. + */ + BitmapEx createMaskBmpEx( const Bitmap& rBitmap, + const ::Color& rMaskColor ) + { + const ::Color aWhite( COL_WHITE ); + BitmapPalette aBiLevelPalette(2); + aBiLevelPalette[0] = aWhite; + aBiLevelPalette[1] = rMaskColor; + + Bitmap aMask( rBitmap.CreateMask( aWhite )); + Bitmap aSolid( rBitmap.GetSizePixel(), + 1, + &aBiLevelPalette ); + aSolid.Erase( rMaskColor ); + + return BitmapEx( aSolid, aMask ); + } + + /** Shameless rip from vcl/source/gdi/outdev3.cxx + + Should consolidate, into something like basetxt... + */ + sal_Unicode getLocalizedChar( sal_Unicode nChar, LanguageType eLang ) + { + // currently only conversion from ASCII digits is interesting + if( (nChar < '0') || ('9' < nChar) ) + return nChar; + + sal_Unicode nOffset(0); + // eLang & LANGUAGE_MASK_PRIMARY catches language independent of region. + // CAVEAT! To some like Mongolian MS assigned the same primary language + // although the script type is different! + switch( eLang & LANGUAGE_MASK_PRIMARY ) + { + default: + break; + + case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY: + case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY: + case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //??? + nOffset = 0x0660 - '0'; // arabic/persian/urdu + break; + case LANGUAGE_BENGALI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x09E6 - '0'; // bengali + break; + case LANGUAGE_BURMESE & LANGUAGE_MASK_PRIMARY: + nOffset = 0x1040 - '0'; // burmese + break; + case LANGUAGE_HINDI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0966 - '0'; // devanagari + break; + case LANGUAGE_GUJARATI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0AE6 - '0'; // gujarati + break; + case LANGUAGE_KANNADA & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0CE6 - '0'; // kannada + break; + case LANGUAGE_KHMER & LANGUAGE_MASK_PRIMARY: + nOffset = 0x17E0 - '0'; // khmer + break; + case LANGUAGE_LAO & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0ED0 - '0'; // lao + break; + case LANGUAGE_MALAYALAM & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0D66 - '0'; // malayalam + break; + case LANGUAGE_MONGOLIAN & LANGUAGE_MASK_PRIMARY: + if (eLang == LANGUAGE_MONGOLIAN_MONGOLIAN) + nOffset = 0x1810 - '0'; // mongolian + else + nOffset = 0; // mongolian cyrillic + break; + case LANGUAGE_ORIYA & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0B66 - '0'; // oriya + break; + case LANGUAGE_TAMIL & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0BE7 - '0'; // tamil + break; + case LANGUAGE_TELUGU & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0C66 - '0'; // telugu + break; + case LANGUAGE_THAI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0E50 - '0'; // thai + break; + case LANGUAGE_TIBETAN & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0F20 - '0'; // tibetan + break; + } + + nChar = sal::static_int_cast<sal_Unicode>(nChar + nOffset); + return nChar; + } + + void convertToLocalizedNumerals( XubString& rStr, + LanguageType eTextLanguage ) + { + const sal_Unicode* pBase = rStr.GetBuffer(); + const sal_Unicode* pBegin = pBase + 0; + const xub_StrLen nEndIndex = rStr.Len(); + const sal_Unicode* pEnd = pBase + nEndIndex; + + for( ; pBegin < pEnd; ++pBegin ) + { + // TODO: are there non-digit localizations? + if( (*pBegin >= '0') && (*pBegin <= '9') ) + { + // translate characters to local preference + sal_Unicode cChar = getLocalizedChar( *pBegin, eTextLanguage ); + if( cChar != *pBegin ) + rStr.SetChar( sal::static_int_cast<USHORT>(pBegin - pBase), cChar ); + } + } + } +} + + +namespace cppcanvas +{ + namespace internal + { + bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const ActionFactoryParameters& rParms ) + { + const OutDevState& rState( getState( rParms.mrStates ) ); + if( (!rState.isLineColorSet && + !rState.isFillColorSet) || + (rState.lineColor.getLength() == 0 && + rState.fillColor.getLength() == 0) ) + { + return false; + } + + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + rPolyPoly, rParms.mrCanvas, rState ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + rParms.mrCurrActionIndex ) ); + + rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; + } + + return true; + } + + bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolygon& rPoly, + const ActionFactoryParameters& rParms ) + { + return createFillAndStroke( ::basegfx::B2DPolyPolygon( rPoly ), + rParms ); + } + + void ImplRenderer::skipContent( GDIMetaFile& rMtf, + const char* pCommentString, + sal_Int32& io_rCurrActionIndex ) const + { + ENSURE_OR_THROW( pCommentString, + "ImplRenderer::skipContent(): NULL string given" ); + + MetaAction* pCurrAct; + while( (pCurrAct=rMtf.NextAction()) != NULL ) + { + // increment action index, we've skipped an action. + ++io_rCurrActionIndex; + + if( pCurrAct->GetType() == META_COMMENT_ACTION && + static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( + pCommentString ) == COMPARE_EQUAL ) + { + // requested comment found, done + return; + } + } + + // EOF + return; + } + + bool ImplRenderer::isActionContained( GDIMetaFile& rMtf, + const char* pCommentString, + USHORT nType ) const + { + ENSURE_OR_THROW( pCommentString, + "ImplRenderer::isActionContained(): NULL string given" ); + + bool bRet( false ); + + // at least _one_ call to GDIMetaFile::NextAction() is + // executed + ULONG nPos( 1 ); + + MetaAction* pCurrAct; + while( (pCurrAct=rMtf.NextAction()) != NULL ) + { + if( pCurrAct->GetType() == nType ) + { + bRet = true; // action type found + break; + } + + if( pCurrAct->GetType() == META_COMMENT_ACTION && + static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( + pCommentString ) == COMPARE_EQUAL ) + { + // delimiting end comment found, done + bRet = false; // not yet found + break; + } + + ++nPos; + } + + // rewind metafile to previous position (this method must + // not change the current metaaction) + while( nPos-- ) + rMtf.WindPrev(); + + if( !pCurrAct ) + { + // EOF, and not yet found + bRet = false; + } + + return bRet; + } + + void ImplRenderer::createGradientAction( const ::PolyPolygon& rPoly, + const ::Gradient& rGradient, + const ActionFactoryParameters& rParms, + bool bIsPolygonRectangle, + bool bSubsettableActions ) + { + DBG_TESTSOLARMUTEX(); + + ::basegfx::B2DPolyPolygon aDevicePoly( rPoly.getB2DPolyPolygon() ); + aDevicePoly.transform( getState( rParms.mrStates ).mapModeTransform ); + + // decide, whether this gradient can be rendered natively + // by the canvas, or must be emulated via VCL gradient + // action extraction. + const USHORT nSteps( rGradient.GetSteps() ); + + if( // step count is infinite, can use native canvas + // gradients here + nSteps == 0 || + // step count is sufficiently high, such that no + // discernible difference should be visible. + nSteps > 64 ) + { + uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory( + rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() ); + + if( xFactory.is() ) + { + ::basegfx::B2DHomMatrix aTextureTransformation; + rendering::Texture aTexture; + + aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; + aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; + aTexture.Alpha = 1.0; + + + // setup start/end color values + // ---------------------------- + + // scale color coefficients with gradient intensities + const USHORT nStartIntensity( rGradient.GetStartIntensity() ); + ::Color aVCLStartColor( rGradient.GetStartColor() ); + aVCLStartColor.SetRed( (UINT8)(aVCLStartColor.GetRed() * nStartIntensity / 100) ); + aVCLStartColor.SetGreen( (UINT8)(aVCLStartColor.GetGreen() * nStartIntensity / 100) ); + aVCLStartColor.SetBlue( (UINT8)(aVCLStartColor.GetBlue() * nStartIntensity / 100) ); + + const USHORT nEndIntensity( rGradient.GetEndIntensity() ); + ::Color aVCLEndColor( rGradient.GetEndColor() ); + aVCLEndColor.SetRed( (UINT8)(aVCLEndColor.GetRed() * nEndIntensity / 100) ); + aVCLEndColor.SetGreen( (UINT8)(aVCLEndColor.GetGreen() * nEndIntensity / 100) ); + aVCLEndColor.SetBlue( (UINT8)(aVCLEndColor.GetBlue() * nEndIntensity / 100) ); + + uno::Reference<rendering::XColorSpace> xColorSpace( + rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()); + const uno::Sequence< double > aStartColor( + ::vcl::unotools::colorToDoubleSequence( aVCLStartColor, + xColorSpace )); + const uno::Sequence< double > aEndColor( + ::vcl::unotools::colorToDoubleSequence( aVCLEndColor, + xColorSpace )); + + uno::Sequence< uno::Sequence < double > > aColors(2); + uno::Sequence< double > aStops(2); + + aStops[0] = 0.0; + aStops[1] = 1.0; + + aColors[0] = aStartColor; + aColors[1] = aEndColor; + + + // Setup texture transformation + // ---------------------------- + + const ::basegfx::B2DRectangle aBounds( + ::basegfx::tools::getRange(aDevicePoly) ); + + // setup rotation angle. VCL rotates + // counter-clockwise, while canvas transformation + // rotates clockwise + double nRotation( -rGradient.GetAngle() * M_PI / 1800.0 ); + + switch( rGradient.GetStyle() ) + { + case GRADIENT_LINEAR: + // FALLTHROUGH intended + case GRADIENT_AXIAL: + { + // standard orientation for VCL linear + // gradient is vertical, thus, rotate 90 + // degrees + nRotation += M_PI/2.0; + + const double nBorder( + ::basegfx::pruneScaleValue( + (1.0 - rGradient.GetBorder() / 100.0) ) ); + + // shrink texture, to account for border + // (only in x direction, linear gradient + // is constant in y direction, anyway) + aTextureTransformation.scale( nBorder, + 1.0 ); + + // linear gradients don't respect offsets + // (they are implicitely assumed to be + // 50%). linear gradients don't have + // border on both sides, only on the + // startColor side, axial gradients have + // border on both sides. As both gradients + // are invariant in y direction: leave y + // offset alone. + double nOffsetX( rGradient.GetBorder() / 200.0 ); + + // determine type of gradient (and necessary + // transformation matrix, should it be emulated by a + // generic gradient) + switch( rGradient.GetStyle() ) + { + case GRADIENT_LINEAR: + nOffsetX = rGradient.GetBorder() / 100.0; + aTexture.Gradient = xFactory->createLinearHorizontalGradient( aColors, + aStops ); + break; + + case GRADIENT_AXIAL: + // vcl considers center color as start color + ::std::swap(aColors[0],aColors[1]); + aTexture.Gradient = xFactory->createAxialHorizontalGradient( aColors, + aStops ); + break; + + default: // other cases can't happen + break; + } + + // apply border offset values + aTextureTransformation.translate( nOffsetX, + 0.0 ); + + // rotate texture according to gradient rotation + aTextureTransformation.translate( -0.5, -0.5 ); + aTextureTransformation.rotate( nRotation ); + + // to let the first strip of a rotated + // gradient start at the _edge_ of the + // bound rect (and not, due to rotation, + // slightly inside), slightly enlarge the + // gradient: + // + // y/2 sin(alpha) + x/2 cos(alpha) + // + // (values to change are not actual + // gradient scales, but original bound + // rect dimensions. Since we still want + // the border setting to apply after that, + // we multiply with that as above for + // nScaleX) + const double nScale( + ::basegfx::pruneScaleValue( + fabs( aBounds.getHeight()*sin(nRotation) ) + + fabs( aBounds.getWidth()*cos(nRotation) ))); + + aTextureTransformation.scale( nScale, nScale ); + + // translate back origin to center of + // primitive + aTextureTransformation.translate( 0.5*aBounds.getWidth(), + 0.5*aBounds.getHeight() ); + } + break; + + case GRADIENT_RADIAL: + // FALLTHROUGH intended + case GRADIENT_ELLIPTICAL: + // FALLTHROUGH intended + case GRADIENT_SQUARE: + // FALLTHROUGH intended + case GRADIENT_RECT: + { + // determine scale factors for the gradient (must + // be scaled up from [0,1]x[0,1] rect to object + // bounds). Will potentially changed in switch + // statement below. + // Respect border value, while doing so, the VCL + // gradient's border will effectively shrink the + // resulting gradient. + double nScaleX( aBounds.getWidth() * (1.0 - rGradient.GetBorder() / 100.0) ); + double nScaleY( aBounds.getHeight()* (1.0 - rGradient.GetBorder() / 100.0) ); + + // determine offset values. Since the border is + // divided half-by-half to both sides of the + // gradient, divide translation offset by an + // additional 2. Also respect offset here, but + // since VCL gradients have their center at [0,0] + // for zero offset, but canvas gradients have + // their top, left edge aligned with the + // primitive, and offset of 50% effectively must + // yield zero shift. Both values will potentially + // be adapted in switch statement below. + double nOffsetX( aBounds.getWidth() * + (2.0 * rGradient.GetOfsX() - 100.0 + rGradient.GetBorder()) / 200.0 ); + double nOffsetY( aBounds.getHeight() * + (2.0 * rGradient.GetOfsY() - 100.0 + rGradient.GetBorder()) / 200.0 ); + + // determine type of gradient (and necessary + // transformation matrix, should it be emulated by a + // generic gradient) + switch( rGradient.GetStyle() ) + { + case GRADIENT_RADIAL: + { + // create isotrophic scaling + if( nScaleX > nScaleY ) + { + nOffsetY -= (nScaleX - nScaleY) * 0.5; + nScaleY = nScaleX; + } + else + { + nOffsetX -= (nScaleY - nScaleX) * 0.5; + nScaleX = nScaleY; + } + + // enlarge gradient to match bound rect diagonal + aTextureTransformation.translate( -0.5, -0.5 ); + const double nScale( hypot(aBounds.getWidth(), aBounds.getHeight()) / nScaleX ); + aTextureTransformation.scale( nScale, nScale ); + aTextureTransformation.translate( 0.5, 0.5 ); + + aTexture.Gradient = xFactory->createEllipticalGradient( aColors, + aStops, + geometry::RealRectangle2D(0.0,0.0, + 1.0,1.0) ); + } + break; + + case GRADIENT_ELLIPTICAL: + { + // enlarge gradient slightly + aTextureTransformation.translate( -0.5, -0.5 ); + const double nSqrt2( sqrt(2.0) ); + aTextureTransformation.scale( nSqrt2,nSqrt2 ); + aTextureTransformation.translate( 0.5, 0.5 ); + + aTexture.Gradient = xFactory->createEllipticalGradient( + aColors, + aStops, + ::basegfx::unotools::rectangle2DFromB2DRectangle( + aBounds )); + } + break; + + case GRADIENT_SQUARE: + // create isotrophic scaling + if( nScaleX > nScaleY ) + { + nOffsetY -= (nScaleX - nScaleY) * 0.5; + nScaleY = nScaleX; + } + else + { + nOffsetX -= (nScaleY - nScaleX) * 0.5; + nScaleX = nScaleY; + } + + aTexture.Gradient = xFactory->createRectangularGradient( aColors, + aStops, + geometry::RealRectangle2D(0.0,0.0, + 1.0,1.0) ); + break; + + case GRADIENT_RECT: + aTexture.Gradient = xFactory->createRectangularGradient( + aColors, + aStops, + ::basegfx::unotools::rectangle2DFromB2DRectangle( + aBounds ) ); + break; + + default: // other cases can't happen + break; + } + + nScaleX = ::basegfx::pruneScaleValue( nScaleX ); + nScaleY = ::basegfx::pruneScaleValue( nScaleY ); + + aTextureTransformation.scale( nScaleX, nScaleY ); + + // rotate texture according to gradient rotation + aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY ); + aTextureTransformation.rotate( nRotation ); + aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY ); + + aTextureTransformation.translate( nOffsetX, nOffsetY ); + } + break; + + default: + ENSURE_OR_THROW( false, + "ImplRenderer::createGradientAction(): Unexpected gradient type" ); + break; + } + + // As the texture coordinate space is relative to + // the polygon coordinate space (NOT to the + // polygon itself), move gradient to the start of + // the actual polygon. If we skip this, the + // gradient will always display at the origin, and + // not within the polygon bound (which might be + // miles away from the origin). + aTextureTransformation.translate( aBounds.getMinX(), + aBounds.getMinY() ); + + ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform, + aTextureTransformation ); + + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + aDevicePoly, + rParms.mrCanvas, + getState( rParms.mrStates ), + aTexture ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + rParms.mrCurrActionIndex ) ); + + rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; + } + + // done, using native gradients + return; + } + } + + // cannot currently use native canvas gradients, as a + // finite step size is given (this funny feature is not + // supported by the XCanvas API) + pushState( rParms.mrStates, PUSH_ALL ); + + if( !bIsPolygonRectangle ) + { + // only clip, if given polygon is not a rectangle in + // the first place (the gradient is always limited to + // the given bound rect) + updateClipping( + aDevicePoly, + rParms, + true ); + } + + GDIMetaFile aTmpMtf; + rParms.mrVDev.AddGradientActions( rPoly.GetBoundRect(), + rGradient, + aTmpMtf ); + + createActions( aTmpMtf, rParms, bSubsettableActions ); + + popState( rParms.mrStates ); + } + + uno::Reference< rendering::XCanvasFont > ImplRenderer::createFont( double& o_rFontRotation, + const ::Font& rFont, + const ActionFactoryParameters& rParms ) const + { + rendering::FontRequest aFontRequest; + + if( rParms.mrParms.maFontName.isValid() ) + aFontRequest.FontDescription.FamilyName = rParms.mrParms.maFontName.getValue(); + else + aFontRequest.FontDescription.FamilyName = rFont.GetName(); + + aFontRequest.FontDescription.StyleName = rFont.GetStyleName(); + + aFontRequest.FontDescription.IsSymbolFont = (rFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL) ? util::TriState_YES : util::TriState_NO; + aFontRequest.FontDescription.IsVertical = rFont.IsVertical() ? util::TriState_YES : util::TriState_NO; + + // TODO(F2): improve vclenum->panose conversion + aFontRequest.FontDescription.FontDescription.Weight = + rParms.mrParms.maFontWeight.isValid() ? + rParms.mrParms.maFontWeight.getValue() : + ::canvas::tools::numeric_cast<sal_Int8>( ::basegfx::fround( rFont.GetWeight() ) ); + aFontRequest.FontDescription.FontDescription.Letterform = + rParms.mrParms.maFontLetterForm.isValid() ? + rParms.mrParms.maFontLetterForm.getValue() : + (rFont.GetItalic() == ITALIC_NONE) ? 0 : 9; + + LanguageType aLang = rFont.GetLanguage(); + aFontRequest.Locale = MsLangId::convertLanguageToLocale(aLang, false); + + // setup state-local text transformation, + // if the font be rotated + const short nFontAngle( rFont.GetOrientation() ); + if( nFontAngle != 0 ) + { + // set to unity transform rotated by font angle + const double nAngle( nFontAngle * (F_PI / 1800.0) ); + o_rFontRotation = -nAngle; + } + else + { + o_rFontRotation = 0.0; + } + + geometry::Matrix2D aFontMatrix; + ::canvas::tools::setIdentityMatrix2D( aFontMatrix ); + + // TODO(F2): use correct scale direction, font + // height might be width or anything else + + // TODO(Q3): This code smells of programming by + // coincidence (the next two if statements) + const ::Size rFontSizeLog( rFont.GetSize() ); + const sal_Int32 nFontWidthLog = rFontSizeLog.Width(); + if( nFontWidthLog != 0 ) + { + ::Font aTestFont = rFont; + aTestFont.SetWidth( 0 ); + sal_Int32 nNormalWidth = rParms.mrVDev.GetFontMetric( aTestFont ).GetWidth(); + if( nNormalWidth != nFontWidthLog ) + if( nNormalWidth ) + aFontMatrix.m00 = (double)nFontWidthLog / nNormalWidth; + } + + // #i52608# apply map mode scale also to font matrix - an + // anisotrophic mapmode must be reflected in an + // anisotrophic font matrix scale. + const OutDevState& rState( getState( rParms.mrStates ) ); + if( !::basegfx::fTools::equal( + rState.mapModeTransform.get(0,0), + rState.mapModeTransform.get(1,1)) ) + { + const double nScaleX( rState.mapModeTransform.get(0,0) ); + const double nScaleY( rState.mapModeTransform.get(1,1) ); + + // note: no reason to check for division by zero, we + // always have the value closer (or equal) to zero as + // the nominator. + if( fabs(nScaleX) < fabs(nScaleY) ) + aFontMatrix.m00 *= nScaleX / nScaleY; + else + aFontMatrix.m11 *= nScaleY / nScaleX; + } + aFontRequest.CellSize = (rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize(rFontSizeLog)).getY(); + + return rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest, + uno::Sequence< beans::PropertyValue >(), + aFontMatrix ); + } + + // create text effects such as shadow/relief/embossed + void ImplRenderer::createTextAction( const ::Point& rStartPoint, + const String rString, + int nIndex, + int nLength, + const sal_Int32* pCharWidths, + const ActionFactoryParameters& rParms, + bool bSubsettableActions ) + { + ENSURE_OR_THROW( nIndex >= 0 && nLength <= rString.Len() + nIndex, + "ImplRenderer::createTextWithEffectsAction(): Invalid text index" ); + + if( !nLength ) + return; // zero-length text, no visible output + + const OutDevState& rState( getState( rParms.mrStates ) ); + + // TODO(F2): implement all text effects + // if( rState.textAlignment ); // TODO(F2): NYI + + ::Color aShadowColor( COL_AUTO ); + ::Color aReliefColor( COL_AUTO ); + ::Size aShadowOffset; + ::Size aReliefOffset; + + uno::Reference<rendering::XColorSpace> xColorSpace( + rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + + if( rState.isTextEffectShadowSet ) + { + // calculate shadow offset (similar to outdev3.cxx) + // TODO(F3): better match with outdev3.cxx + sal_Int32 nShadowOffset = static_cast<sal_Int32>(1.5 + ((rParms.mrVDev.GetFont().GetHeight()-24.0)/24.0)); + if( nShadowOffset < 1 ) + nShadowOffset = 1; + + aShadowOffset.setWidth( nShadowOffset ); + aShadowOffset.setHeight( nShadowOffset ); + + // determine shadow color (from outdev3.cxx) + ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor( + rState.textColor, xColorSpace ); + bool bIsDark = (aTextColor.GetColor() == COL_BLACK) + || (aTextColor.GetLuminance() < 8); + + aShadowColor = bIsDark ? COL_LIGHTGRAY : COL_BLACK; + aShadowColor.SetTransparency( aTextColor.GetTransparency() ); + } + + if( rState.textReliefStyle ) + { + // calculate relief offset (similar to outdev3.cxx) + sal_Int32 nReliefOffset = rParms.mrVDev.PixelToLogic( Size( 1, 1 ) ).Height(); + nReliefOffset += nReliefOffset/2; + if( nReliefOffset < 1 ) + nReliefOffset = 1; + + if( rState.textReliefStyle == RELIEF_ENGRAVED ) + nReliefOffset = -nReliefOffset; + + aReliefOffset.setWidth( nReliefOffset ); + aReliefOffset.setHeight( nReliefOffset ); + + // determine relief color (from outdev3.cxx) + ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor( + rState.textColor, xColorSpace ); + + aReliefColor = ::Color( COL_LIGHTGRAY ); + + // we don't have a automatic color, so black is always + // drawn on white (literally copied from + // vcl/source/gdi/outdev3.cxx) + if( aTextColor.GetColor() == COL_BLACK ) + { + aTextColor = ::Color( COL_WHITE ); + getState( rParms.mrStates ).textColor = + ::vcl::unotools::colorToDoubleSequence( + aTextColor, xColorSpace ); + } + + if( aTextColor.GetColor() == COL_WHITE ) + aReliefColor = ::Color( COL_BLACK ); + aReliefColor.SetTransparency( aTextColor.GetTransparency() ); + } + + // create the actual text action + ActionSharedPtr pTextAction( + TextActionFactory::createTextAction( + rStartPoint, + aReliefOffset, + aReliefColor, + aShadowOffset, + aShadowColor, + rString, + nIndex, + nLength, + pCharWidths, + rParms.mrVDev, + rParms.mrCanvas, + rState, + rParms.mrParms, + bSubsettableActions ) ); + + ActionSharedPtr pStrikeoutTextAction; + + if ( rState.textStrikeoutStyle == STRIKEOUT_X || rState.textStrikeoutStyle == STRIKEOUT_SLASH ) + { + long nWidth = rParms.mrVDev.GetTextWidth( rString,nIndex,nLength ); + + xub_Unicode pChars[5]; + if ( rState.textStrikeoutStyle == STRIKEOUT_X ) + pChars[0] = 'X'; + else + pChars[0] = '/'; + pChars[3]=pChars[2]=pChars[1]=pChars[0]; + + long nStrikeoutWidth = nWidth; + String aStrikeoutTest( pChars, 4 ); + + if( aStrikeoutTest.Len() ) + { + nStrikeoutWidth = ( rParms.mrVDev.GetTextWidth( aStrikeoutTest ) + 2 ) / 4; + aStrikeoutTest.Erase(); + + if( nStrikeoutWidth <= 0 ) + nStrikeoutWidth = 1; + } + + long nMaxWidth = nStrikeoutWidth/2; + if ( nMaxWidth < 2 ) + nMaxWidth = 2; + nMaxWidth += nWidth + 1; + + long nFullStrikeoutWidth = 0; + String aStrikeoutText( pChars, 0 ); + while( (nFullStrikeoutWidth+=nStrikeoutWidth ) < nMaxWidth+1 ) + aStrikeoutText += pChars[0]; + + + sal_Int32 nStartPos = 0; + xub_StrLen nLen = aStrikeoutText.Len(); + + if( nLen ) + { + long nInterval = ( nWidth - nStrikeoutWidth * nLen ) / nLen; + nStrikeoutWidth += nInterval; + sal_Int32* pStrikeoutCharWidths = new sal_Int32[nLen]; + + for ( int i = 0;i<nLen; i++) + { + pStrikeoutCharWidths[i] = nStrikeoutWidth; + } + + for ( int i = 1;i< nLen; i++ ) + { + pStrikeoutCharWidths[ i ] += pStrikeoutCharWidths[ i-1 ]; + } + + pStrikeoutTextAction = + TextActionFactory::createTextAction( + rStartPoint, + aReliefOffset, + aReliefColor, + aShadowOffset, + aShadowColor, + aStrikeoutText, + nStartPos, + aStrikeoutText.Len(), + pStrikeoutCharWidths, + rParms.mrVDev, + rParms.mrCanvas, + rState, + rParms.mrParms, + bSubsettableActions ) ; + } + } + + if( pTextAction ) + { + maActions.push_back( + MtfAction( + pTextAction, + rParms.mrCurrActionIndex ) ); + + if ( pStrikeoutTextAction ) + { + maActions.push_back( + MtfAction( + pStrikeoutTextAction, + rParms.mrCurrActionIndex ) ); + } + + rParms.mrCurrActionIndex += pTextAction->getActionCount()-1; + } + } + + void ImplRenderer::updateClipping( const ::basegfx::B2DPolyPolygon& rClipPoly, + const ActionFactoryParameters& rParms, + bool bIntersect ) + { + ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); + ::basegfx::B2DPolyPolygon aClipPoly( rClipPoly ); + + const bool bEmptyClipRect( rState.clipRect.IsEmpty() ); + const bool bEmptyClipPoly( rState.clip.count() == 0 ); + + ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect, + "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" ); + + if( !bIntersect || + (bEmptyClipRect && bEmptyClipPoly) ) + { + rState.clip = rClipPoly; + } + else + { + if( !bEmptyClipRect ) + { + // TODO(P3): Use Liang-Barsky polygon clip here, + // after all, one object is just a rectangle! + + // convert rect to polygon beforehand, must revert + // to general polygon clipping here. + rState.clip = ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + // #121100# VCL rectangular clips always + // include one more pixel to the right + // and the bottom + ::basegfx::B2DRectangle( rState.clipRect.Left(), + rState.clipRect.Top(), + rState.clipRect.Right()+1, + rState.clipRect.Bottom()+1 ) ) ); + } + + // AW: Simplified + rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aClipPoly, rState.clip, true, false); + } + + // by now, our clip resides in the OutDevState::clip + // poly-polygon. + rState.clipRect.SetEmpty(); + + if( rState.clip.count() == 0 ) + { + if( rState.clipRect.IsEmpty() ) + { + rState.xClipPoly.clear(); + } + else + { + rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rParms.mrCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + // #121100# VCL rectangular clips + // always include one more pixel to + // the right and the bottom + ::basegfx::B2DRectangle( rState.clipRect.Left(), + rState.clipRect.Top(), + rState.clipRect.Right()+1, + rState.clipRect.Bottom()+1 ) ) ) ); + } + } + else + { + rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rParms.mrCanvas->getUNOCanvas()->getDevice(), + rState.clip ); + } + } + + void ImplRenderer::updateClipping( const ::Rectangle& rClipRect, + const ActionFactoryParameters& rParms, + bool bIntersect ) + { + ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) ); + + const bool bEmptyClipRect( rState.clipRect.IsEmpty() ); + const bool bEmptyClipPoly( rState.clip.count() == 0 ); + + ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect, + "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" ); + + if( !bIntersect || + (bEmptyClipRect && bEmptyClipPoly) ) + { + rState.clipRect = rClipRect; + rState.clip.clear(); + } + else if( bEmptyClipPoly ) + { + rState.clipRect.Intersection( rClipRect ); + rState.clip.clear(); + } + else + { + // TODO(P3): Handle a fourth case here, when all clip + // polygons are rectangular, once B2DMultiRange's + // sweep line implementation is done. + + // general case: convert to polygon and clip + // ----------------------------------------- + + // convert rect to polygon beforehand, must revert + // to general polygon clipping here. + ::basegfx::B2DPolyPolygon aClipPoly( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( rClipRect.Left(), + rClipRect.Top(), + rClipRect.Right(), + rClipRect.Bottom() ) ) ); + + rState.clipRect.SetEmpty(); + + // AW: Simplified + rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon( + aClipPoly, rState.clip, true, false); + } + + if( rState.clip.count() == 0 ) + { + if( rState.clipRect.IsEmpty() ) + { + rState.xClipPoly.clear(); + } + else + { + rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rParms.mrCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + // #121100# VCL rectangular clips + // always include one more pixel to + // the right and the bottom + ::basegfx::B2DRectangle( rState.clipRect.Left(), + rState.clipRect.Top(), + rState.clipRect.Right()+1, + rState.clipRect.Bottom()+1 ) ) ) ); + } + } + else + { + rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rParms.mrCanvas->getUNOCanvas()->getDevice(), + rState.clip ); + } + } + + bool ImplRenderer::createActions( GDIMetaFile& rMtf, + const ActionFactoryParameters& rFactoryParms, + bool bSubsettableActions ) + { + /* TODO(P2): interpret mtf-comments + ================================ + + - gradient fillings (do that via comments) + + - think about mapping. _If_ we do everything in logical + coordinates (which would solve the probs for stroke + widths and text offsets), then we would have to + recalc scaling for every drawing operation. This is + because the outdev map mode might change at any time. + Also keep in mind, that, although we've double precision + float arithmetic now, different offsets might still + generate different roundings (aka + 'OutputDevice::SetPixelOffset()) + + */ + + // alias common parameters + VectorOfOutDevStates& rStates(rFactoryParms.mrStates); + const CanvasSharedPtr& rCanvas(rFactoryParms.mrCanvas); + ::VirtualDevice& rVDev(rFactoryParms.mrVDev); + const Parameters& rParms(rFactoryParms.mrParms); + sal_Int32& io_rCurrActionIndex(rFactoryParms.mrCurrActionIndex); + + + // Loop over every metaaction + // ========================== + MetaAction* pCurrAct; + + // TODO(P1): think about caching + for( pCurrAct=rMtf.FirstAction(); + pCurrAct; + pCurrAct = rMtf.NextAction() ) + { + // execute every action, to keep VDev state up-to-date + // currently used only for + // - the map mode + // - the line/fill color when processing a META_TRANSPARENT_ACTION + // - SetFont to process font metric specific actions + pCurrAct->Execute( &rVDev ); + + switch( pCurrAct->GetType() ) + { + // ------------------------------------------------------------ + + // In the first part of this monster-switch, we + // handle all state-changing meta actions. These + // are all handled locally. + + // ------------------------------------------------------------ + + case META_PUSH_ACTION: + { + MetaPushAction* pPushAction = static_cast<MetaPushAction*>(pCurrAct); + pushState( rStates, + pPushAction->GetFlags() ); + } + break; + + case META_POP_ACTION: + popState( rStates ); + break; + + case META_TEXTLANGUAGE_ACTION: + // FALLTHROUGH intended + case META_REFPOINT_ACTION: + // handled via pCurrAct->Execute( &rVDev ) + break; + + case META_MAPMODE_ACTION: + // modify current mapModeTransformation + // transformation, such that subsequent + // coordinates map correctly + tools::calcLogic2PixelAffineTransform( getState( rStates ).mapModeTransform, + rVDev ); + break; + + // monitor clip regions, to assemble clip polygon on our own + case META_CLIPREGION_ACTION: + { + MetaClipRegionAction* pClipAction = static_cast<MetaClipRegionAction*>(pCurrAct); + + if( !pClipAction->IsClipping() ) + { + // clear clipping + getState( rStates ).clip.clear(); + } + else + { + if( !pClipAction->GetRegion().HasPolyPolygon() ) + { + VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip " + "region encountered, falling back to bounding box!" ); + + // #121806# explicitely kept integer + Rectangle aClipRect( + rVDev.LogicToPixel( + pClipAction->GetRegion().GetBoundRect() ) ); + + // intersect current clip with given rect + updateClipping( + aClipRect, + rFactoryParms, + false ); + } + else + { + // set new clip polygon (don't intersect + // with old one, just set it) + + // #121806# explicitely kept integer + updateClipping( + rVDev.LogicToPixel( + pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(), + rFactoryParms, + false ); + } + } + + break; + } + + case META_ISECTRECTCLIPREGION_ACTION: + { + MetaISectRectClipRegionAction* pClipAction = static_cast<MetaISectRectClipRegionAction*>(pCurrAct); + + // #121806# explicitely kept integer + Rectangle aClipRect( + rVDev.LogicToPixel( pClipAction->GetRect() ) ); + + // intersect current clip with given rect + updateClipping( + aClipRect, + rFactoryParms, + true ); + + break; + } + + case META_ISECTREGIONCLIPREGION_ACTION: + { + MetaISectRegionClipRegionAction* pClipAction = static_cast<MetaISectRegionClipRegionAction*>(pCurrAct); + + if( !pClipAction->GetRegion().HasPolyPolygon() ) + { + VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip " + "region encountered, falling back to bounding box!" ); + + // #121806# explicitely kept integer + Rectangle aClipRect( + rVDev.LogicToPixel( pClipAction->GetRegion().GetBoundRect() ) ); + + // intersect current clip with given rect + updateClipping( + aClipRect, + rFactoryParms, + true ); + } + else + { + // intersect current clip with given clip polygon + + // #121806# explicitely kept integer + updateClipping( + rVDev.LogicToPixel( + pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(), + rFactoryParms, + true ); + } + + break; + } + + case META_MOVECLIPREGION_ACTION: + // TODO(F2): NYI + break; + + case META_LINECOLOR_ACTION: + if( !rParms.maLineColor.isValid() ) + { + setStateColor( static_cast<MetaLineColorAction*>(pCurrAct), + getState( rStates ).isLineColorSet, + getState( rStates ).lineColor, + rCanvas ); + } + break; + + case META_FILLCOLOR_ACTION: + if( !rParms.maFillColor.isValid() ) + { + setStateColor( static_cast<MetaFillColorAction*>(pCurrAct), + getState( rStates ).isFillColorSet, + getState( rStates ).fillColor, + rCanvas ); + } + break; + + case META_TEXTCOLOR_ACTION: + { + if( !rParms.maTextColor.isValid() ) + { + // Text color is set unconditionally, thus, no + // use of setStateColor here + ::Color aColor( static_cast<MetaTextColorAction*>(pCurrAct)->GetColor() ); + + // force alpha part of color to + // opaque. transparent painting is done + // explicitely via META_TRANSPARENT_ACTION + aColor.SetTransparency(0); + + getState( rStates ).textColor = + ::vcl::unotools::colorToDoubleSequence( + aColor, + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + } + } + break; + + case META_TEXTFILLCOLOR_ACTION: + if( !rParms.maTextColor.isValid() ) + { + setStateColor( static_cast<MetaTextFillColorAction*>(pCurrAct), + getState( rStates ).isTextFillColorSet, + getState( rStates ).textFillColor, + rCanvas ); + } + break; + + case META_TEXTLINECOLOR_ACTION: + if( !rParms.maTextColor.isValid() ) + { + setStateColor( static_cast<MetaTextLineColorAction*>(pCurrAct), + getState( rStates ).isTextLineColorSet, + getState( rStates ).textLineColor, + rCanvas ); + } + break; + + case META_TEXTALIGN_ACTION: + { + ::cppcanvas::internal::OutDevState& rState = getState( rStates ); + const TextAlign eTextAlign( static_cast<MetaTextAlignAction*>(pCurrAct)->GetTextAlign() ); + + rState.textReferencePoint = eTextAlign; + } + break; + + case META_FONT_ACTION: + { + ::cppcanvas::internal::OutDevState& rState = getState( rStates ); + const ::Font& rFont( static_cast<MetaFontAction*>(pCurrAct)->GetFont() ); + + rState.xFont = createFont( rState.fontRotation, + rFont, + rFactoryParms ); + + // TODO(Q2): define and use appropriate enumeration types + rState.textReliefStyle = (sal_Int8)rFont.GetRelief(); + rState.textOverlineStyle = (sal_Int8)rFont.GetOverline(); + rState.textUnderlineStyle = rParms.maFontUnderline.isValid() ? + (rParms.maFontUnderline.getValue() ? (sal_Int8)UNDERLINE_SINGLE : (sal_Int8)UNDERLINE_NONE) : + (sal_Int8)rFont.GetUnderline(); + rState.textStrikeoutStyle = (sal_Int8)rFont.GetStrikeout(); + rState.textEmphasisMarkStyle = (sal_Int8)rFont.GetEmphasisMark(); + rState.isTextEffectShadowSet = (rFont.IsShadow() != FALSE); + rState.isTextWordUnderlineSet = (rFont.IsWordLineMode() != FALSE); + rState.isTextOutlineModeSet = (rFont.IsOutline() != FALSE); + } + break; + + case META_RASTEROP_ACTION: + // TODO(F2): NYI + break; + + case META_LAYOUTMODE_ACTION: + { + // TODO(F2): A lot is missing here + int nLayoutMode = static_cast<MetaLayoutModeAction*>(pCurrAct)->GetLayoutMode(); + ::cppcanvas::internal::OutDevState& rState = getState( rStates ); + switch( nLayoutMode & (TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_BIDI_STRONG) ) + { + case TEXT_LAYOUT_BIDI_LTR: + rState.textDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT; + break; + + case (TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG): + rState.textDirection = rendering::TextDirection::STRONG_LEFT_TO_RIGHT; + break; + + case TEXT_LAYOUT_BIDI_RTL: + rState.textDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT; + break; + + case (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG): + rState.textDirection = rendering::TextDirection::STRONG_RIGHT_TO_LEFT; + break; + } + + rState.textAlignment = 0; // TODO(F2): rendering::TextAlignment::LEFT_ALIGNED; + if( (nLayoutMode & (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_RIGHT) ) + && !(nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT ) ) + { + rState.textAlignment = 1; // TODO(F2): rendering::TextAlignment::RIGHT_ALIGNED; + } + } + break; + + // ------------------------------------------------------------ + + // In the second part of this monster-switch, we + // handle all recursing meta actions. These are the + // ones generating a metafile by themselves, which is + // then processed by recursively calling this method. + + // ------------------------------------------------------------ + + case META_GRADIENT_ACTION: + { + MetaGradientAction* pGradAct = static_cast<MetaGradientAction*>(pCurrAct); + createGradientAction( ::Polygon( pGradAct->GetRect() ), + pGradAct->GetGradient(), + rFactoryParms, + true, + bSubsettableActions ); + } + break; + + case META_HATCH_ACTION: + { + // TODO(F2): use native Canvas hatches here + GDIMetaFile aTmpMtf; + + rVDev.AddHatchActions( static_cast<MetaHatchAction*>(pCurrAct)->GetPolyPolygon(), + static_cast<MetaHatchAction*>(pCurrAct)->GetHatch(), + aTmpMtf ); + createActions( aTmpMtf, rFactoryParms, + bSubsettableActions ); + } + break; + + case META_EPS_ACTION: + { + MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pCurrAct); + const GDIMetaFile& rSubstitute = pAct->GetSubstitute(); + + // #121806# explicitely kept integer + const Size aMtfSize( rSubstitute.GetPrefSize() ); + const Size aMtfSizePixPre( rVDev.LogicToPixel( aMtfSize, + rSubstitute.GetPrefMapMode() ) ); + + // #i44110# correct null-sized output - there + // are metafiles which have zero size in at + // least one dimension + const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ), + ::std::max( aMtfSizePixPre.Height(), 1L ) ); + + // Setup local transform, such that the + // metafile renders itself into the given + // output rectangle + pushState( rStates, PUSH_ALL ); + + rVDev.Push(); + rVDev.SetMapMode( rSubstitute.GetPrefMapMode() ); + + const ::Point& rPos( rVDev.LogicToPixel( pAct->GetPoint() ) ); + const ::Size& rSize( rVDev.LogicToPixel( pAct->GetSize() ) ); + + getState( rStates ).transform.translate( rPos.X(), + rPos.Y() ); + getState( rStates ).transform.scale( (double)rSize.Width() / aMtfSizePix.Width(), + (double)rSize.Height() / aMtfSizePix.Height() ); + + createActions( const_cast<GDIMetaFile&>(pAct->GetSubstitute()), + rFactoryParms, + bSubsettableActions ); + + rVDev.Pop(); + popState( rStates ); + } + break; + + // handle metafile comments, to retrieve + // meta-information for gradients, fills and + // strokes. May skip actions, and may recurse. + case META_COMMENT_ACTION: + { + MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct); + + // Handle gradients + if ( pAct->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL ) + { + MetaGradientExAction* pGradAction = NULL; + bool bDone( false ); + while( !bDone && + (pCurrAct=rMtf.NextAction()) != NULL ) + { + switch( pCurrAct->GetType() ) + { + // extract gradient info + case META_GRADIENTEX_ACTION: + pGradAction = static_cast<MetaGradientExAction*>(pCurrAct); + break; + + // skip broken-down rendering, output gradient when sequence is ended + case META_COMMENT_ACTION: + if( static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) + { + bDone = true; + + if( pGradAction ) + { + createGradientAction( pGradAction->GetPolyPolygon(), + pGradAction->GetGradient(), + rFactoryParms, + false, + bSubsettableActions ); + } + } + break; + } + } + } + // TODO(P2): Handle drawing layer strokes, via + // XPATHSTROKE_SEQ_BEGIN comment + + // Handle drawing layer fills + else if( pAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) ) + { + const BYTE* pData = pAct->GetData(); + if ( pData ) + { + SvMemoryStream aMemStm( (void*)pData, pAct->GetDataSize(), STREAM_READ ); + + SvtGraphicFill aFill; + aMemStm >> aFill; + + // TODO(P2): Also handle gradients and + // hatches like this + + // only evaluate comment for pure + // bitmap fills. If a transparency + // gradient is involved (denoted by + // the FloatTransparent action), take + // the normal meta actions. + if( aFill.getFillType() == SvtGraphicFill::fillTexture && + !isActionContained( rMtf, + "XPATHFILL_SEQ_END", + META_FLOATTRANSPARENT_ACTION ) ) + { + rendering::Texture aTexture; + + // TODO(F1): the SvtGraphicFill + // can also transport metafiles + // here, handle that case, too + Graphic aGraphic; + aFill.getGraphic( aGraphic ); + + BitmapEx aBmpEx( aGraphic.GetBitmapEx() ); + const ::Size aBmpSize( aBmpEx.GetSizePixel() ); + + ::SvtGraphicFill::Transform aTransform; + aFill.getTransform( aTransform ); + + ::basegfx::B2DHomMatrix aMatrix; + + // convert to basegfx matrix + aMatrix.set(0,0, aTransform.matrix[ 0 ] ); + aMatrix.set(0,1, aTransform.matrix[ 1 ] ); + aMatrix.set(0,2, aTransform.matrix[ 2 ] ); + aMatrix.set(1,0, aTransform.matrix[ 3 ] ); + aMatrix.set(1,1, aTransform.matrix[ 4 ] ); + aMatrix.set(1,2, aTransform.matrix[ 5 ] ); + + ::basegfx::B2DHomMatrix aScale; + aScale.scale( aBmpSize.Width(), + aBmpSize.Height() ); + + // post-multiply with the bitmap + // size (XCanvas' texture assumes + // the given bitmap to be + // normalized to [0,1]x[0,1] + // rectangle) + aMatrix = aMatrix * aScale; + + // pre-multiply with the + // logic-to-pixel scale factor + // (the metafile comment works in + // logical coordinates). + ::basegfx::B2DHomMatrix aLogic2PixelTransform; + aMatrix *= tools::calcLogic2PixelLinearTransform( aLogic2PixelTransform, + rVDev ); + + ::basegfx::unotools::affineMatrixFromHomMatrix( + aTexture.AffineTransform, + aMatrix ); + + aTexture.Alpha = 1.0 - aFill.getTransparency(); + aTexture.Bitmap = + ::vcl::unotools::xBitmapFromBitmapEx( + rCanvas->getUNOCanvas()->getDevice(), + aBmpEx ); + if( aFill.isTiling() )
+ {
+ aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
+ aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
+ }
+ else
+ {
+ aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
+ aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
+ }
+ + ::PolyPolygon aPath; + aFill.getPath( aPath ); + + ::basegfx::B2DPolyPolygon aPoly( aPath.getB2DPolyPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + aPoly, + rCanvas, + getState( rStates ), + aTexture ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPolyAction->getActionCount()-1; + } + + // skip broken-down render output + skipContent( rMtf, + "XPATHFILL_SEQ_END", + io_rCurrActionIndex ); + } + } + } + } + break; + + // ------------------------------------------------------------ + + // In the third part of this monster-switch, we + // handle all 'acting' meta actions. These are all + // processed by constructing function objects for + // them, which will later ease caching. + + // ------------------------------------------------------------ + + case META_POINT_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() ) + { + ActionSharedPtr pPointAction( + internal::PointActionFactory::createPointAction( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( + static_cast<MetaPointAction*>(pCurrAct)->GetPoint() ), + rCanvas, + rState ) ); + + if( pPointAction ) + { + maActions.push_back( + MtfAction( + pPointAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPointAction->getActionCount()-1; + } + } + } + break; + + case META_PIXEL_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() ) + { + ActionSharedPtr pPointAction( + internal::PointActionFactory::createPointAction( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( + static_cast<MetaPixelAction*>(pCurrAct)->GetPoint() ), + rCanvas, + rState, + static_cast<MetaPixelAction*>(pCurrAct)->GetColor() ) ); + + if( pPointAction ) + { + maActions.push_back( + MtfAction( + pPointAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPointAction->getActionCount()-1; + } + } + } + break; + + case META_LINE_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() ) + { + MetaLineAction* pLineAct = static_cast<MetaLineAction*>(pCurrAct); + + const LineInfo& rLineInfo( pLineAct->GetLineInfo() ); + + const ::basegfx::B2DPoint aStartPoint( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetStartPoint() )); + const ::basegfx::B2DPoint aEndPoint( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetEndPoint() )); + + ActionSharedPtr pLineAction; + + if( rLineInfo.IsDefault() ) + { + // plain hair line + pLineAction = + internal::LineActionFactory::createLineAction( + aStartPoint, + aEndPoint, + rCanvas, + rState ); + + if( pLineAction ) + { + maActions.push_back( + MtfAction( + pLineAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pLineAction->getActionCount()-1; + } + } + else if( LINE_NONE != rLineInfo.GetStyle() ) + { + // 'thick' line + rendering::StrokeAttributes aStrokeAttributes; + + setupStrokeAttributes( aStrokeAttributes, + rFactoryParms, + rLineInfo ); + + // XCanvas can only stroke polygons, + // not simple lines - thus, handle + // this case via the polypolygon + // action + ::basegfx::B2DPolygon aPoly; + aPoly.append( aStartPoint ); + aPoly.append( aEndPoint ); + pLineAction = + internal::PolyPolyActionFactory::createPolyPolyAction( + ::basegfx::B2DPolyPolygon( aPoly ), + rCanvas, rState, aStrokeAttributes ); + + if( pLineAction ) + { + maActions.push_back( + MtfAction( + pLineAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pLineAction->getActionCount()-1; + } + } + // else: line style is default + // (i.e. invisible), don't generate action + } + } + break; + + case META_RECT_ACTION: + { + const Rectangle& rRect( + static_cast<MetaRectAction*>(pCurrAct)->GetRect() ); + + if( rRect.IsEmpty() ) + break; + + const OutDevState& rState( getState( rStates ) ); + const ::basegfx::B2DPoint aTopLeftPixel( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ) ); + const ::basegfx::B2DPoint aBottomRightPixel( + rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + + // #121100# OutputDevice::DrawRect() fills + // rectangles Apple-like, i.e. with one + // additional pixel to the right and bottom. + ::basegfx::B2DPoint(1,1) ); + + createFillAndStroke( ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRange( aTopLeftPixel, + aBottomRightPixel )), + rFactoryParms ); + break; + } + + case META_ROUNDRECT_ACTION: + { + const Rectangle& rRect( + static_cast<MetaRoundRectAction*>(pCurrAct)->GetRect()); + + if( rRect.IsEmpty() ) + break; + + ::basegfx::B2DPolygon aPoly( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRange( + ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ), + ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + + ::basegfx::B2DPoint(1,1) ), + static_cast<MetaRoundRectAction*>(pCurrAct)->GetHorzRound(), + static_cast<MetaRoundRectAction*>(pCurrAct)->GetVertRound() )); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_ELLIPSE_ACTION: + { + const Rectangle& rRect( + static_cast<MetaEllipseAction*>(pCurrAct)->GetRect() ); + + if( rRect.IsEmpty() ) + break; + + const ::basegfx::B2DRange aRange( + ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ), + ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) + + ::basegfx::B2DPoint(1,1) ); + + ::basegfx::B2DPolygon aPoly( + ::basegfx::tools::createPolygonFromEllipse( + aRange.getCenter(), + aRange.getWidth(), + aRange.getHeight() )); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_ARC_ACTION: + { + // TODO(F1): Missing basegfx functionality. Mind empty rects! + const Polygon aToolsPoly( static_cast<MetaArcAction*>(pCurrAct)->GetRect(), + static_cast<MetaArcAction*>(pCurrAct)->GetStartPoint(), + static_cast<MetaArcAction*>(pCurrAct)->GetEndPoint(), POLY_ARC ); + ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_PIE_ACTION: + { + // TODO(F1): Missing basegfx functionality. Mind empty rects! + const Polygon aToolsPoly( static_cast<MetaPieAction*>(pCurrAct)->GetRect(), + static_cast<MetaPieAction*>(pCurrAct)->GetStartPoint(), + static_cast<MetaPieAction*>(pCurrAct)->GetEndPoint(), POLY_PIE ); + ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_CHORD_ACTION: + { + // TODO(F1): Missing basegfx functionality. Mind empty rects! + const Polygon aToolsPoly( static_cast<MetaChordAction*>(pCurrAct)->GetRect(), + static_cast<MetaChordAction*>(pCurrAct)->GetStartPoint(), + static_cast<MetaChordAction*>(pCurrAct)->GetEndPoint(), POLY_CHORD ); + ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_POLYLINE_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() || + rState.fillColor.getLength() ) + { + MetaPolyLineAction* pPolyLineAct = static_cast<MetaPolyLineAction*>(pCurrAct); + + const LineInfo& rLineInfo( pPolyLineAct->GetLineInfo() ); + ::basegfx::B2DPolygon aPoly( pPolyLineAct->GetPolygon().getB2DPolygon() ); + aPoly.transform( rState.mapModeTransform ); + + ActionSharedPtr pLineAction; + + if( rLineInfo.IsDefault() ) + { + // plain hair line polygon + pLineAction = + internal::PolyPolyActionFactory::createLinePolyPolyAction( + ::basegfx::B2DPolyPolygon(aPoly), + rCanvas, + rState ); + + if( pLineAction ) + { + maActions.push_back( + MtfAction( + pLineAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pLineAction->getActionCount()-1; + } + } + else if( LINE_NONE != rLineInfo.GetStyle() ) + { + // 'thick' line polygon + rendering::StrokeAttributes aStrokeAttributes; + + setupStrokeAttributes( aStrokeAttributes, + rFactoryParms, + rLineInfo ); + + pLineAction = + internal::PolyPolyActionFactory::createPolyPolyAction( + ::basegfx::B2DPolyPolygon(aPoly), + rCanvas, + rState, + aStrokeAttributes ) ; + + if( pLineAction ) + { + maActions.push_back( + MtfAction( + pLineAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pLineAction->getActionCount()-1; + } + } + // else: line style is default + // (i.e. invisible), don't generate action + } + } + break; + + case META_POLYGON_ACTION: + { + ::basegfx::B2DPolygon aPoly( static_cast<MetaPolygonAction*>(pCurrAct)->GetPolygon().getB2DPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_POLYPOLYGON_ACTION: + { + ::basegfx::B2DPolyPolygon aPoly( static_cast<MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon().getB2DPolyPolygon() ); + aPoly.transform( getState( rStates ).mapModeTransform ); + createFillAndStroke( aPoly, + rFactoryParms ); + } + break; + + case META_BMP_ACTION: + { + MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pCurrAct); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + pAct->GetBitmap(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPSCALE_ACTION: + { + MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pCurrAct); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + pAct->GetBitmap(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPSCALEPART_ACTION: + { + MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pCurrAct); + + // crop bitmap to given source rectangle (no + // need to copy and convert the whole bitmap) + Bitmap aBmp( pAct->GetBitmap() ); + const Rectangle aCropRect( pAct->GetSrcPoint(), + pAct->GetSrcSize() ); + aBmp.Crop( aCropRect ); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPEX_ACTION: + { + MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pCurrAct); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + pAct->GetBitmapEx(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPEXSCALE_ACTION: + { + MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pCurrAct); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + pAct->GetBitmapEx(), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_BMPEXSCALEPART_ACTION: + { + MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pCurrAct); + + // crop bitmap to given source rectangle (no + // need to copy and convert the whole bitmap) + BitmapEx aBmp( pAct->GetBitmapEx() ); + const Rectangle aCropRect( pAct->GetSrcPoint(), + pAct->GetSrcSize() ); + aBmp.Crop( aCropRect ); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_MASK_ACTION: + { + MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pCurrAct); + + // create masked BitmapEx right here, as the + // canvas does not provide equivalent + // functionality + BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), + pAct->GetColor() )); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_MASKSCALE_ACTION: + { + MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pCurrAct); + + // create masked BitmapEx right here, as the + // canvas does not provide equivalent + // functionality + BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), + pAct->GetColor() )); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_MASKSCALEPART_ACTION: + { + MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pCurrAct); + + // create masked BitmapEx right here, as the + // canvas does not provide equivalent + // functionality + BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(), + pAct->GetColor() )); + + // crop bitmap to given source rectangle (no + // need to copy and convert the whole bitmap) + const Rectangle aCropRect( pAct->GetSrcPoint(), + pAct->GetSrcSize() ); + aBmp.Crop( aCropRect ); + + ActionSharedPtr pBmpAction( + internal::BitmapActionFactory::createBitmapAction( + aBmp, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pBmpAction ) + { + maActions.push_back( + MtfAction( + pBmpAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pBmpAction->getActionCount()-1; + } + } + break; + + case META_GRADIENTEX_ACTION: + // TODO(F1): use native Canvas gradients here + // action is ignored here, because redundant to META_GRADIENT_ACTION + break; + + case META_WALLPAPER_ACTION: + // TODO(F2): NYI + break; + + case META_TRANSPARENT_ACTION: + { + const OutDevState& rState( getState( rStates ) ); + if( rState.lineColor.getLength() || + rState.fillColor.getLength() ) + { + MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pCurrAct); + ::basegfx::B2DPolyPolygon aPoly( pAct->GetPolyPolygon().getB2DPolyPolygon() ); + aPoly.transform( rState.mapModeTransform ); + + ActionSharedPtr pPolyAction( + internal::PolyPolyActionFactory::createPolyPolyAction( + aPoly, + rCanvas, + rState, + pAct->GetTransparence() ) ); + + if( pPolyAction ) + { + maActions.push_back( + MtfAction( + pPolyAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPolyAction->getActionCount()-1; + } + } + } + break; + + case META_FLOATTRANSPARENT_ACTION: + { + MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pCurrAct); + + internal::MtfAutoPtr pMtf( + new ::GDIMetaFile( pAct->GetGDIMetaFile() ) ); + + // TODO(P2): Use native canvas gradients here (saves a lot of UNO calls) + internal::GradientAutoPtr pGradient( + new Gradient( pAct->GetGradient() ) ); + + DBG_TESTSOLARMUTEX(); + + ActionSharedPtr pFloatTransAction( + internal::TransparencyGroupActionFactory::createTransparencyGroupAction( + pMtf, + pGradient, + rParms, + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ), + getState( rStates ).mapModeTransform * + ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ), + rCanvas, + getState( rStates ) ) ); + + if( pFloatTransAction ) + { + maActions.push_back( + MtfAction( + pFloatTransAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pFloatTransAction->getActionCount()-1; + } + } + break; + + case META_TEXT_ACTION: + { + MetaTextAction* pAct = static_cast<MetaTextAction*>(pCurrAct); + XubString sText = XubString( pAct->GetText() ); + + if( rVDev.GetDigitLanguage()) + convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); + + createTextAction( + pAct->GetPoint(), + sText, + pAct->GetIndex(), + pAct->GetLen() == (USHORT)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), + NULL, + rFactoryParms, + bSubsettableActions ); + } + break; + + case META_TEXTARRAY_ACTION: + { + MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pCurrAct); + XubString sText = XubString( pAct->GetText() ); + + if( rVDev.GetDigitLanguage()) + convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); + + createTextAction( + pAct->GetPoint(), + sText, + pAct->GetIndex(), + pAct->GetLen() == (USHORT)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), + pAct->GetDXArray(), + rFactoryParms, + bSubsettableActions ); + } + break; + + case META_TEXTLINE_ACTION: + { + MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pCurrAct); + + const OutDevState& rState( getState( rStates ) ); + const ::Size aBaselineOffset( tools::getBaselineOffset( rState, + rVDev ) ); + const ::Point aStartPoint( pAct->GetStartPoint() ); + const ::basegfx::B2DSize aSize( rState.mapModeTransform * + ::basegfx::B2DSize(pAct->GetWidth(), + 0 )); + + ActionSharedPtr pPolyAction( + PolyPolyActionFactory::createPolyPolyAction( + tools::createTextLinesPolyPolygon( + rState.mapModeTransform * + ::basegfx::B2DPoint( + ::vcl::unotools::b2DPointFromPoint(pAct->GetStartPoint()) + + ::vcl::unotools::b2DSizeFromSize(aBaselineOffset)), + aSize.getX(), + tools::createTextLineInfo( rVDev, + rState )), + rCanvas, + rState ) ); + + if( pPolyAction.get() ) + { + maActions.push_back( + MtfAction( + pPolyAction, + io_rCurrActionIndex ) ); + + io_rCurrActionIndex += pPolyAction->getActionCount()-1; + } + } + break; + + case META_TEXTRECT_ACTION: + { + MetaTextRectAction* pAct = static_cast<MetaTextRectAction*>(pCurrAct); + + pushState( rStates, PUSH_ALL ); + + // use the VDev to break up the text rect + // action into readily formatted lines + GDIMetaFile aTmpMtf; + rVDev.AddTextRectActions( pAct->GetRect(), + pAct->GetText(), + pAct->GetStyle(), + aTmpMtf ); + + createActions( aTmpMtf, + rFactoryParms, + bSubsettableActions ); + + popState( rStates ); + + break; + } + + case META_STRETCHTEXT_ACTION: + { + MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pCurrAct); + XubString sText = XubString( pAct->GetText() ); + + if( rVDev.GetDigitLanguage()) + convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() ); + + const USHORT nLen( pAct->GetLen() == (USHORT)STRING_LEN ? + pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen() ); + + // #i70897# Nothing to do, actually... + if( nLen == 0 ) + break; + + // have to fit the text into the given + // width. This is achieved by internally + // generating a DX array, and uniformly + // distributing the excess/insufficient width + // to every logical character. + ::boost::scoped_array< sal_Int32 > pDXArray( new sal_Int32[nLen] ); + + rVDev.GetTextArray( pAct->GetText(), pDXArray.get(), + pAct->GetIndex(), pAct->GetLen() ); + + const sal_Int32 nWidthDifference( pAct->GetWidth() - pDXArray[ nLen-1 ] ); + + // Last entry of pDXArray contains total width of the text + sal_Int32* p=pDXArray.get(); + for( USHORT i=1; i<=nLen; ++i ) + { + // calc ratio for every array entry, to + // distribute rounding errors 'evenly' + // across the characters. Note that each + // entry represents the 'end' position of + // the corresponding character, thus, we + // let i run from 1 to nLen. + *p++ += (sal_Int32)i*nWidthDifference/nLen; + } + + createTextAction( + pAct->GetPoint(), + sText, + pAct->GetIndex(), + pAct->GetLen() == (USHORT)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(), + pDXArray.get(), + rFactoryParms, + bSubsettableActions ); + } + break; + + default: + OSL_ENSURE( false, + "Unknown meta action type encountered" ); + break; + } + + // increment action index (each mtf action counts _at + // least_ one. Some count for more, therefore, + // io_rCurrActionIndex is sometimes incremented by + // pAct->getActionCount()-1 above, the -1 being the + // correction for the unconditional increment here). + ++io_rCurrActionIndex; + } + + return true; + } + + + namespace + { + class ActionRenderer + { + public: + ActionRenderer( const ::basegfx::B2DHomMatrix& rTransformation ) : + maTransformation( rTransformation ), + mbRet( true ) + { + } + + bool result() + { + return mbRet; + } + + void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction ) + { + // ANDing the result. We want to fail if at least + // one action failed. + mbRet &= rAction.mpAction->render( maTransformation ); + } + + void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction, + const Action::Subset& rSubset ) + { + // ANDing the result. We want to fail if at least + // one action failed. + mbRet &= rAction.mpAction->render( maTransformation, + rSubset ); + } + + private: + ::basegfx::B2DHomMatrix maTransformation; + bool mbRet; + }; + + class AreaQuery + { + public: + AreaQuery( const ::basegfx::B2DHomMatrix& rTransformation ) : + maTransformation( rTransformation ), + maBounds() + { + } + + bool result() + { + return true; // nothing can fail here + } + + void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction ) + { + maBounds.expand( rAction.mpAction->getBounds( maTransformation ) ); + } + + void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction, + const Action::Subset& rSubset ) + { + maBounds.expand( rAction.mpAction->getBounds( maTransformation, + rSubset ) ); + } + + ::basegfx::B2DRange getBounds() const + { + return maBounds; + } + + private: + ::basegfx::B2DHomMatrix maTransformation; + ::basegfx::B2DRange maBounds; + }; + + // Doing that via inline class. Compilers tend to not inline free + // functions. + struct UpperBoundActionIndexComparator + { + bool operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rLHS, + const ::cppcanvas::internal::ImplRenderer::MtfAction& rRHS ) + { + const sal_Int32 nLHSCount( rLHS.mpAction ? + rLHS.mpAction->getActionCount() : 0 ); + const sal_Int32 nRHSCount( rRHS.mpAction ? + rRHS.mpAction->getActionCount() : 0 ); + + // compare end of action range, to have an action selected + // by lower_bound even if the requested index points in + // the middle of the action's range + return rLHS.mnOrigIndex + nLHSCount < rRHS.mnOrigIndex + nRHSCount; + } + }; + + /** Algorithm to apply given functor to a subset range + + @tpl Functor + + Functor to call for each element of the subset + range. Must provide the following method signatures: + bool result() (returning false if operation failed) + + */ + template< typename Functor > bool + forSubsetRange( Functor& rFunctor, + ImplRenderer::ActionVector::const_iterator aRangeBegin, + ImplRenderer::ActionVector::const_iterator aRangeEnd, + sal_Int32 nStartIndex, + sal_Int32 nEndIndex, + const ImplRenderer::ActionVector::const_iterator& rEnd ) + { + if( aRangeBegin == aRangeEnd ) + { + // only a single action. Setup subset, and call functor + Action::Subset aSubset; + aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ), + nStartIndex - aRangeBegin->mnOrigIndex ); + aSubset.mnSubsetEnd = ::std::min( aRangeBegin->mpAction->getActionCount(), + nEndIndex - aRangeBegin->mnOrigIndex ); + + ENSURE_OR_RETURN( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + "ImplRenderer::forSubsetRange(): Invalid indices" ); + + rFunctor( *aRangeBegin, aSubset ); + } + else + { + // more than one action. + + // render partial first, full intermediate, and + // partial last action + Action::Subset aSubset; + aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ), + nStartIndex - aRangeBegin->mnOrigIndex ); + aSubset.mnSubsetEnd = aRangeBegin->mpAction->getActionCount(); + + ENSURE_OR_RETURN( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + "ImplRenderer::forSubsetRange(): Invalid indices" ); + + rFunctor( *aRangeBegin, aSubset ); + + // first action rendered, skip to next + ++aRangeBegin; + + // render full middle actions + while( aRangeBegin != aRangeEnd ) + rFunctor( *aRangeBegin++ ); + + if( aRangeEnd == rEnd || + aRangeEnd->mnOrigIndex > nEndIndex ) + { + // aRangeEnd denotes end of action vector, + // + // or + // + // nEndIndex references something _after_ + // aRangeBegin, but _before_ aRangeEnd + // + // either way: no partial action left + return rFunctor.result(); + } + + aSubset.mnSubsetBegin = 0; + aSubset.mnSubsetEnd = nEndIndex - aRangeEnd->mnOrigIndex; + + ENSURE_OR_RETURN( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + "ImplRenderer::forSubsetRange(): Invalid indices" ); + + rFunctor( *aRangeEnd, aSubset ); + } + + return rFunctor.result(); + } + } + + bool ImplRenderer::getSubsetIndices( sal_Int32& io_rStartIndex, + sal_Int32& io_rEndIndex, + ActionVector::const_iterator& o_rRangeBegin, + ActionVector::const_iterator& o_rRangeEnd ) const + { + ENSURE_OR_RETURN( io_rStartIndex<=io_rEndIndex, + "ImplRenderer::getSubsetIndices(): invalid action range" ); + + ENSURE_OR_RETURN( !maActions.empty(), + "ImplRenderer::getSubsetIndices(): no actions to render" ); + + const sal_Int32 nMinActionIndex( maActions.front().mnOrigIndex ); + const sal_Int32 nMaxActionIndex( maActions.back().mnOrigIndex + + maActions.back().mpAction->getActionCount() ); + + // clip given range to permissible values (there might be + // ranges before and behind the valid indices) + io_rStartIndex = ::std::max( nMinActionIndex, + io_rStartIndex ); + io_rEndIndex = ::std::min( nMaxActionIndex, + io_rEndIndex ); + + if( io_rStartIndex == io_rEndIndex || + io_rStartIndex > io_rEndIndex ) + { + // empty range, don't render anything. The second + // condition e.g. happens if the requested range lies + // fully before or behind the valid action indices. + return false; + } + + + const ActionVector::const_iterator aBegin( maActions.begin() ); + const ActionVector::const_iterator aEnd( maActions.end() ); + + + // find start and end action + // ========================= + o_rRangeBegin = ::std::lower_bound( aBegin, aEnd, + MtfAction( ActionSharedPtr(), io_rStartIndex ), + UpperBoundActionIndexComparator() ); + o_rRangeEnd = ::std::lower_bound( aBegin, aEnd, + MtfAction( ActionSharedPtr(), io_rEndIndex ), + UpperBoundActionIndexComparator() ); + return true; + } + + + // Public methods + // ==================================================================== + + ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas, + const GDIMetaFile& rMtf, + const Parameters& rParams ) : + CanvasGraphicHelper( rCanvas ), + maActions() + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(mtf)" ); + + OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(), + "ImplRenderer::ImplRenderer(): Invalid canvas" ); + OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(), + "ImplRenderer::ImplRenderer(): Invalid graphic device" ); + + // make sure canvas and graphic device are valid; action + // creation don't check that every time + if( rCanvas.get() == NULL || + !rCanvas->getUNOCanvas().is() || + !rCanvas->getUNOCanvas()->getDevice().is() ) + { + // leave actions empty + return; + } + + VectorOfOutDevStates aStateStack; + + VirtualDevice aVDev; + aVDev.EnableOutput( FALSE ); + + // Setup VDev for state tracking and mapping + // ========================================= + + aVDev.SetMapMode( rMtf.GetPrefMapMode() ); + + const Size aMtfSize( rMtf.GetPrefSize() ); + const Size aMtfSizePixPre( aVDev.LogicToPixel( aMtfSize, + rMtf.GetPrefMapMode() ) ); + const Point aEmptyPt; + const Point aMtfOriginPix( aVDev.LogicToPixel( aEmptyPt ) ); + + // #i44110# correct null-sized output - there are shapes + // which have zero size in at least one dimension + const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ), + ::std::max( aMtfSizePixPre.Height(), 1L ) ); + + sal_Int32 nCurrActions(0); + ActionFactoryParameters aParms(aStateStack, + rCanvas, + aVDev, + rParams, + nCurrActions ); + + // init state stack + clearStateStack( aStateStack ); + + // Setup local state, such that the metafile renders + // itself into a one-by-one square at the origin for + // identity view and render transformations + getState( aStateStack ).transform.scale( 1.0 / aMtfSizePix.Width(), + 1.0 / aMtfSizePix.Height() ); + + tools::calcLogic2PixelAffineTransform( getState( aStateStack ).mapModeTransform, + aVDev ); + + ColorSharedPtr pColor( getCanvas()->createColor() ); + + // setup default text color to black + getState( aStateStack ).textColor = + getState( aStateStack ).textFillColor = + getState( aStateStack ).textLineColor = pColor->getDeviceColor( 0x000000FF ); + + // apply overrides from the Parameters struct + if( rParams.maFillColor.isValid() ) + { + getState( aStateStack ).isFillColorSet = true; + getState( aStateStack ).fillColor = pColor->getDeviceColor( rParams.maFillColor.getValue() ); + } + if( rParams.maLineColor.isValid() ) + { + getState( aStateStack ).isLineColorSet = true; + getState( aStateStack ).lineColor = pColor->getDeviceColor( rParams.maLineColor.getValue() ); + } + if( rParams.maTextColor.isValid() ) + { + getState( aStateStack ).isTextFillColorSet = true; + getState( aStateStack ).isTextLineColorSet = true; + getState( aStateStack ).textColor = + getState( aStateStack ).textFillColor = + getState( aStateStack ).textLineColor = pColor->getDeviceColor( rParams.maTextColor.getValue() ); + } + if( rParams.maFontName.isValid() || + rParams.maFontWeight.isValid() || + rParams.maFontLetterForm.isValid() || + rParams.maFontUnderline.isValid() ) + { + ::cppcanvas::internal::OutDevState& rState = getState( aStateStack ); + + rState.xFont = createFont( rState.fontRotation, + ::Font(), // default font + aParms ); + } + + createActions( const_cast<GDIMetaFile&>(rMtf), // HACK(Q2): + // we're + // changing + // the + // current + // action + // in + // createActions! + aParms, + true // TODO(P1): make subsettability configurable + ); + } + + ImplRenderer::ImplRenderer( const CanvasSharedPtr& rCanvas, + const BitmapEx& rBmpEx, + const Parameters& rParams ) : + CanvasGraphicHelper( rCanvas ), + maActions() + { + // TODO(F3): property modification parameters are + // currently ignored for Bitmaps + (void)rParams; + + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(bitmap)" ); + + OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(), + "ImplRenderer::ImplRenderer(): Invalid canvas" ); + OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(), + "ImplRenderer::ImplRenderer(): Invalid graphic device" ); + + // make sure canvas and graphic device are valid; action + // creation don't check that every time + if( rCanvas.get() == NULL || + !rCanvas->getUNOCanvas().is() || + !rCanvas->getUNOCanvas()->getDevice().is() ) + { + // leave actions empty + return; + } + + OutDevState aState; + + const Size aBmpSize( rBmpEx.GetSizePixel() ); + + // Setup local state, such that the bitmap renders itself + // into a one-by-one square for identity view and render + // transformations + aState.transform.scale( 1.0 / aBmpSize.Width(), + 1.0 / aBmpSize.Height() ); + + // create a single action for the provided BitmapEx + maActions.push_back( + MtfAction( + BitmapActionFactory::createBitmapAction( + rBmpEx, + ::basegfx::B2DPoint(), + rCanvas, + aState), + 0 ) ); + } + + ImplRenderer::~ImplRenderer() + { + } + + bool ImplRenderer::drawSubset( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::drawSubset()" ); + + ActionVector::const_iterator aRangeBegin; + ActionVector::const_iterator aRangeEnd; + + try + { + if( !getSubsetIndices( nStartIndex, nEndIndex, + aRangeBegin, aRangeEnd ) ) + return true; // nothing to render (but _that_ was successful) + + // now, aRangeBegin references the action in which the + // subset rendering must start, and aRangeEnd references + // the action in which the subset rendering must end (it + // might also end right at the start of the referenced + // action, such that zero of that action needs to be + // rendered). + + + // render subset of actions + // ======================== + + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::getRenderStateTransform( aMatrix, + getRenderState() ); + + ActionRenderer aRenderer( aMatrix ); + + return forSubsetRange( aRenderer, + aRangeBegin, + aRangeEnd, + nStartIndex, + nEndIndex, + maActions.end() ); + } + catch( uno::Exception& ) + { + OSL_ENSURE( false, + rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + // convert error to return value + return false; + } + } + + ::basegfx::B2DRange ImplRenderer::getSubsetArea( sal_Int32 nStartIndex, + sal_Int32 nEndIndex ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::getSubsetArea()" ); + + ActionVector::const_iterator aRangeBegin; + ActionVector::const_iterator aRangeEnd; + + if( !getSubsetIndices( nStartIndex, nEndIndex, + aRangeBegin, aRangeEnd ) ) + return ::basegfx::B2DRange(); // nothing to render -> empty range + + // now, aRangeBegin references the action in which the + // subset querying must start, and aRangeEnd references + // the action in which the subset querying must end (it + // might also end right at the start of the referenced + // action, such that zero of that action needs to be + // queried). + + + // query bounds for subset of actions + // ================================== + + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::getRenderStateTransform( aMatrix, + getRenderState() ); + + AreaQuery aQuery( aMatrix ); + forSubsetRange( aQuery, + aRangeBegin, + aRangeEnd, + nStartIndex, + nEndIndex, + maActions.end() ); + + return aQuery.getBounds(); + } + + bool ImplRenderer::draw() const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::draw()" ); + + ::basegfx::B2DHomMatrix aMatrix; + ::canvas::tools::getRenderStateTransform( aMatrix, + getRenderState() ); + + try + { + return ::std::for_each( maActions.begin(), maActions.end(), ActionRenderer( aMatrix ) ).result(); + } + catch( uno::Exception& ) + { + OSL_ENSURE( false, + rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + return false; + } + } + } +} diff --git a/cppcanvas/source/mtfrenderer/lineaction.cxx b/cppcanvas/source/mtfrenderer/lineaction.cxx new file mode 100644 index 000000000000..d32ed56a8001 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/lineaction.cxx @@ -0,0 +1,170 @@ +/************************************************************************* + * + * 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: lineaction.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_cppcanvas.hxx" + +#include <lineaction.hxx> +#include <outdevstate.hxx> + +#include <rtl/logfile.hxx> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <canvas/canvastools.hxx> + +#include <boost/utility.hpp> + +#include <cppcanvas/canvas.hxx> + +#include <mtftools.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + class LineAction : public Action, private ::boost::noncopyable + { + public: + LineAction( const ::basegfx::B2DPoint&, + const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState& ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + ::basegfx::B2DPoint maStartPoint; + ::basegfx::B2DPoint maEndPoint; + CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + }; + + LineAction::LineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DPoint& rEndPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + maStartPoint( rStartPoint ), + maEndPoint( rEndPoint ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + maState.DeviceColor = rState.lineColor; + } + + bool LineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::LineAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::LineAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + mpCanvas->getUNOCanvas()->drawLine( ::basegfx::unotools::point2DFromB2DPoint(maStartPoint), + ::basegfx::unotools::point2DFromB2DPoint(maEndPoint), + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + bool LineAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // line only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return render( rTransformation ); + } + + ::basegfx::B2DRange LineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( ::basegfx::B2DRange( maStartPoint, + maEndPoint ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange LineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // line only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 LineAction::getActionCount() const + { + return 1; + } + } + + ActionSharedPtr LineActionFactory::createLineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DPoint& rEndPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new LineAction( rStartPoint, + rEndPoint, + rCanvas, + rState) ); + } + + } +} diff --git a/cppcanvas/source/mtfrenderer/lineaction.hxx b/cppcanvas/source/mtfrenderer/lineaction.hxx new file mode 100644 index 000000000000..3d4f366eee89 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/lineaction.hxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * 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: lineaction.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 _CPPCANVAS_LINEACTION_HXX +#define _CPPCANVAS_LINEACTION_HXX + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> + +namespace basegfx { + class B2DPoint; +} + + +/* Definition of internal::LineActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class LineActionFactory + { + public: + /// Plain hair line from point 1 to point 2 + static ActionSharedPtr createLineAction( const ::basegfx::B2DPoint&, + const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState& ); + + private: + // static factory, disable big four + LineActionFactory(); + ~LineActionFactory(); + LineActionFactory(const LineActionFactory&); + LineActionFactory& operator=( const LineActionFactory& ); + }; + } +} + +#endif /* _CPPCANVAS_LINEACTION_HXX */ diff --git a/cppcanvas/source/mtfrenderer/makefile.mk b/cppcanvas/source/mtfrenderer/makefile.mk new file mode 100644 index 000000000000..e58c9f87e0e2 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/makefile.mk @@ -0,0 +1,61 @@ +#************************************************************************* +# +# 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.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. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=cppcanvas +TARGET=metafilerenderer +ENABLE_EXCEPTIONS=TRUE + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF + +SLOFILES = $(SLO)$/cachedprimitivebase.obj \ + $(SLO)$/bitmapaction.obj \ + $(SLO)$/implrenderer.obj \ + $(SLO)$/lineaction.obj \ + $(SLO)$/pointaction.obj \ + $(SLO)$/polypolyaction.obj \ + $(SLO)$/textaction.obj \ + $(SLO)$/transparencygroupaction.obj \ + $(SLO)$/mtftools.obj + +# ========================================================================== + +.INCLUDE : target.mk diff --git a/cppcanvas/source/mtfrenderer/mtftools.cxx b/cppcanvas/source/mtfrenderer/mtftools.cxx new file mode 100644 index 000000000000..e4e227955da6 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/mtftools.cxx @@ -0,0 +1,699 @@ +/************************************************************************* + * + * 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: mtftools.cxx,v $ + * $Revision: 1.14.6.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General 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_cppcanvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> +#include <canvas/verbosetrace.hxx> + +#include <com/sun/star/rendering/RenderState.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <canvas/canvastools.hxx> + +#include <vcl/gdimtf.hxx> +#include <vcl/metaact.hxx> +#include <vcl/virdev.hxx> +#include <vcl/metric.hxx> +#include <tools/poly.hxx> + +#include "mtftools.hxx" +#include "outdevstate.hxx" +#include "polypolyaction.hxx" + + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace tools + { + void initRenderState( rendering::RenderState& renderState, + const ::cppcanvas::internal::OutDevState& outdevState ) + { + ::canvas::tools::initRenderState( renderState ); + ::canvas::tools::setRenderStateTransform( renderState, + outdevState.transform ); + renderState.Clip = outdevState.xClipPoly; + } + + ::Size getBaselineOffset( const ::cppcanvas::internal::OutDevState& outdevState, + const VirtualDevice& rVDev ) + { + const ::FontMetric& aMetric = rVDev.GetFontMetric(); + + // calc offset for text output, the XCanvas always renders + // baseline offset. + switch( outdevState.textReferencePoint ) + { + case ALIGN_TOP: + return ::Size( 0, + aMetric.GetIntLeading() + aMetric.GetAscent() ); + + default: + ENSURE_OR_THROW( false, + "tools::getBaselineOffset(): Unexpected TextAlign value" ); + // FALLTHROUGH intended (to calm compiler warning - case won't happen) + case ALIGN_BASELINE: + return ::Size( 0, 0 ); + + case ALIGN_BOTTOM: + return ::Size( 0, + -aMetric.GetDescent() ); + + } + } + + ::basegfx::B2DHomMatrix& calcLogic2PixelLinearTransform( ::basegfx::B2DHomMatrix& o_rMatrix, + const VirtualDevice& rVDev ) + { + // select size value in the middle of the available range, + // to have headroom both when map mode scales up, and when + // it scales down. + const ::Size aSizeLogic( 0x00010000L, + 0x00010000L ); + + const ::Size aSizePixel( rVDev.LogicToPixel( aSizeLogic ) ); + + o_rMatrix.identity(); + o_rMatrix.scale( aSizePixel.Width() / (double)aSizeLogic.Width(), + aSizePixel.Height() / (double)aSizeLogic.Height() ); + + return o_rMatrix; + } + + ::basegfx::B2DHomMatrix& calcLogic2PixelAffineTransform( ::basegfx::B2DHomMatrix& o_rMatrix, + const VirtualDevice& rVDev ) + { + // retrieves scale + calcLogic2PixelLinearTransform(o_rMatrix, rVDev); + + // translate according to curr map mode/pref map mode offset + const ::Point aEmptyPoint; + const ::Point& rTranslatedPoint( + rVDev.LogicToPixel( aEmptyPoint )); + + o_rMatrix.translate(rTranslatedPoint.X(), + rTranslatedPoint.Y()); + + return o_rMatrix; + } + + bool modifyClip( rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DPoint& rOffset, + const ::basegfx::B2DVector* pScaling, + const double* pRotation ) + { + const ::Point aEmptyPoint; + + const bool bOffsetting( !rOffset.equalZero() ); + const bool bScaling( pScaling && + pScaling->getX() != 1.0 && + pScaling->getY() != 1.0 ); + const bool bRotation( pRotation && + *pRotation != 0.0 ); + + if( !bOffsetting && !bScaling && !bRotation ) + return false; // nothing to do + + if( rOutdevState.clip.count() ) + { + // general polygon case + + ::basegfx::B2DPolyPolygon aLocalClip( rOutdevState.clip ); + ::basegfx::B2DHomMatrix aTransform; + + if( bOffsetting ) + aTransform.translate( -rOffset.getX(), + -rOffset.getY() ); + if( bScaling ) + aTransform.scale( 1.0/pScaling->getX(), 1.0/pScaling->getY() ); + + if( bRotation ) + aTransform.rotate( - *pRotation ); + + aLocalClip.transform( aTransform ); + + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aLocalClip ); + + return true; + } + else if( !rOutdevState.clipRect.IsEmpty() ) + { + // simple rect case + + const ::Rectangle aLocalClipRect( rOutdevState.clipRect ); + + if( bRotation ) + { + // rotation involved - convert to polygon first, + // then transform that + ::basegfx::B2DPolygon aLocalClip( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( + (double)(aLocalClipRect.Left()), + (double)(aLocalClipRect.Top()), + (double)(aLocalClipRect.Right()), + (double)(aLocalClipRect.Bottom()) ) ) ); + ::basegfx::B2DHomMatrix aTransform; + + if( bOffsetting ) + aTransform.translate( -rOffset.getX(), + -rOffset.getY() ); + if( bScaling ) + aTransform.scale( 1.0/pScaling->getX(), 1.0/pScaling->getY() ); + + aTransform.rotate( - *pRotation ); + + aLocalClip.transform( aTransform ); + + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( aLocalClip ) ); + } + else if( bScaling ) + { + // scale and offset - do it on the fly, have to + // convert to float anyway. + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( + (double)(aLocalClipRect.Left() - rOffset.getX())/pScaling->getX(), + (double)(aLocalClipRect.Top() - rOffset.getY())/pScaling->getY(), + (double)(aLocalClipRect.Right() - rOffset.getX())/pScaling->getX(), + (double)(aLocalClipRect.Bottom() - rOffset.getY())/pScaling->getY() ) ) ) ); + } + else + { + // offset only - do it on the fly, have to convert + // to float anyway. + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( aLocalClipRect.Left() - rOffset.getX(), + aLocalClipRect.Top() - rOffset.getY(), + aLocalClipRect.Right() - rOffset.getX(), + aLocalClipRect.Bottom() - rOffset.getY() ) ) ) ); + } + + return true; + } + + // empty clip, nothing to do + return false; + } + + bool modifyClip( rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::Point& rOffset, + const ::basegfx::B2DVector* pScaling, + const double* pRotation ) + { + return modifyClip( o_rRenderState, + rOutdevState, + rCanvas, + ::basegfx::B2DPoint( rOffset.X(), + rOffset.Y() ), + pScaling, + pRotation ); + } + + bool modifyClip( rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DHomMatrix& rTransform ) + { + if( !rTransform.isIdentity() || + !rTransform.isInvertible() ) + return false; // nothing to do + + ::basegfx::B2DPolyPolygon aLocalClip; + + if( rOutdevState.clip.count() ) + { + aLocalClip = rOutdevState.clip; + } + else if( !rOutdevState.clipRect.IsEmpty() ) + { + const ::Rectangle aLocalClipRect( rOutdevState.clipRect ); + + aLocalClip = ::basegfx::B2DPolyPolygon( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( + aLocalClipRect.Left(), + aLocalClipRect.Top(), + aLocalClipRect.Right(), + aLocalClipRect.Bottom() ) ) ); + } + else + { + // empty clip, nothing to do + return false; + } + + // invert transformation and modify + ::basegfx::B2DHomMatrix aLocalTransform( rTransform ); + aLocalTransform.invert(); + + aLocalClip.transform( aLocalTransform ); + + o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aLocalClip ); + + return true; + } + + // create overline/underline/strikeout line info struct + TextLineInfo createTextLineInfo( const ::VirtualDevice& rVDev, + const ::cppcanvas::internal::OutDevState& rState ) + { + const BOOL bOldMode( rVDev.IsMapModeEnabled() ); + + // #i68512# Force metric regeneration with mapmode enabled + // (prolly OutDev bug) + rVDev.GetFontMetric(); + + // will restore map mode below + const_cast< ::VirtualDevice& >(rVDev).EnableMapMode( FALSE ); + + const ::FontMetric aMetric = rVDev.GetFontMetric(); + + TextLineInfo aTextInfo( + (aMetric.GetDescent() + 2) / 4.0, + ((aMetric.GetIntLeading() + 1.5) / 3.0), + (aMetric.GetIntLeading() / 2.0) - aMetric.GetAscent(), + aMetric.GetDescent() / 2.0, + (aMetric.GetIntLeading() - aMetric.GetAscent()) / 3.0, + rState.textOverlineStyle, + rState.textUnderlineStyle, + rState.textStrikeoutStyle ); + + const_cast< ::VirtualDevice& >(rVDev).EnableMapMode( bOldMode ); + + return aTextInfo; + } + + namespace + { + void appendRect( ::basegfx::B2DPolyPolygon& o_rPoly, + const ::basegfx::B2DPoint& rStartPos, + const double nX1, + const double nY1, + const double nX2, + const double nY2 ) + { + const double x( rStartPos.getX() ); + const double y( rStartPos.getY() ); + + o_rPoly.append( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( x + nX1, y + nY1, x + nX2, y + nY2 ) ) ); + } + + void appendRect( ::basegfx::B2DPolyPolygon& o_rPoly, + const double nX1, + const double nY1, + const double nX2, + const double nY2 ) + { + o_rPoly.append( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( nX1, nY1, nX2, nY2 ) ) ); + } + + void appendDashes( ::basegfx::B2DPolyPolygon& o_rPoly, + const double nX, + const double nY, + const double nLineWidth, + const double nLineHeight, + const double nDashWidth, + const double nDashSkip ) + { + const sal_Int32 nNumLoops( + static_cast< sal_Int32 >( + ::std::max( 1.0, + nLineWidth / nDashSkip ) + .5) ); + + double x = nX; + for( sal_Int32 i=0; i<nNumLoops; ++i ) + { + appendRect( o_rPoly, + x, nY, + x + nDashWidth, nY + nLineHeight ); + + x += nDashSkip; + } + } + } + + // create line actions for text such as underline and + // strikeout + ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const ::basegfx::B2DPoint rStartPos, + const double& rLineWidth, + const TextLineInfo& rTextLineInfo ) + { + // fill the polypolygon with all text lines + ::basegfx::B2DPolyPolygon aTextLinesPolyPoly; + + switch( rTextLineInfo.mnOverlineStyle ) + { + case UNDERLINE_NONE: // nothing to do + // FALLTHROUGH intended + case UNDERLINE_DONTKNOW: + break; + + case UNDERLINE_SMALLWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_WAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_SINGLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnOverlineOffset, + rLineWidth, + rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight ); + break; + + case UNDERLINE_BOLDDOTTED: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASH: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDLONGDASH: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASHDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASHDOTDOT:// TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLD: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight, + rLineWidth, + rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight ); + break; + + case UNDERLINE_DOUBLEWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DOUBLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight * 2.0 , + rLineWidth, + rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight ); + + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight, + rLineWidth, + rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight * 2.0 ); + break; + + case UNDERLINE_DASHDOTDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DOTTED: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnOverlineOffset, + rLineWidth, + rTextLineInfo.mnOverlineHeight, + rTextLineInfo.mnOverlineHeight, + 2*rTextLineInfo.mnOverlineHeight ); + break; + + case UNDERLINE_DASHDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DASH: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnOverlineOffset, + rLineWidth, + rTextLineInfo.mnOverlineHeight, + 3*rTextLineInfo.mnOverlineHeight, + 6*rTextLineInfo.mnOverlineHeight ); + break; + + case UNDERLINE_LONGDASH: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnOverlineOffset, + rLineWidth, + rTextLineInfo.mnOverlineHeight, + 6*rTextLineInfo.mnOverlineHeight, + 12*rTextLineInfo.mnOverlineHeight ); + break; + + default: + ENSURE_OR_THROW( false, + "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected overline case" ); + } + + switch( rTextLineInfo.mnUnderlineStyle ) + { + case UNDERLINE_NONE: // nothing to do + // FALLTHROUGH intended + case UNDERLINE_DONTKNOW: + break; + + case UNDERLINE_SMALLWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_WAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_SINGLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnUnderlineOffset + rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_BOLDDOTTED: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASH: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDLONGDASH: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASHDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDDASHDOTDOT:// TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLDWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_BOLD: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnUnderlineOffset + 2*rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_DOUBLEWAVE: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DOUBLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnUnderlineOffset - rTextLineInfo.mnLineHeight, + rLineWidth, + rTextLineInfo.mnUnderlineOffset ); + + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnUnderlineOffset + 2*rTextLineInfo.mnLineHeight, + rLineWidth, + rTextLineInfo.mnUnderlineOffset + 3*rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_DASHDOTDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DOTTED: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnLineHeight, + rTextLineInfo.mnLineHeight, + 2*rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_DASHDOT: // TODO(F3): NYI + // FALLTHROUGH intended + case UNDERLINE_DASH: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnLineHeight, + 3*rTextLineInfo.mnLineHeight, + 6*rTextLineInfo.mnLineHeight ); + break; + + case UNDERLINE_LONGDASH: + appendDashes( + aTextLinesPolyPoly, + rStartPos.getX(), + rStartPos.getY() + rTextLineInfo.mnUnderlineOffset, + rLineWidth, + rTextLineInfo.mnLineHeight, + 6*rTextLineInfo.mnLineHeight, + 12*rTextLineInfo.mnLineHeight ); + break; + + default: + ENSURE_OR_THROW( false, + "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected underline case" ); + } + + switch( rTextLineInfo.mnStrikeoutStyle ) + { + case STRIKEOUT_NONE: // nothing to do + // FALLTHROUGH intended + case STRIKEOUT_DONTKNOW: + break; + + case STRIKEOUT_SLASH: // TODO(Q1): we should handle this in the text layer + // FALLTHROUGH intended + case STRIKEOUT_X: + break; + + case STRIKEOUT_SINGLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnStrikeoutOffset, + rLineWidth, + rTextLineInfo.mnStrikeoutOffset + rTextLineInfo.mnLineHeight ); + break; + + case STRIKEOUT_BOLD: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnStrikeoutOffset, + rLineWidth, + rTextLineInfo.mnStrikeoutOffset + 2*rTextLineInfo.mnLineHeight ); + break; + + case STRIKEOUT_DOUBLE: + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnStrikeoutOffset - rTextLineInfo.mnLineHeight, + rLineWidth, + rTextLineInfo.mnStrikeoutOffset ); + + appendRect( + aTextLinesPolyPoly, + rStartPos, + 0, + rTextLineInfo.mnStrikeoutOffset + 2*rTextLineInfo.mnLineHeight, + rLineWidth, + rTextLineInfo.mnStrikeoutOffset + 3*rTextLineInfo.mnLineHeight ); + break; + + default: + ENSURE_OR_THROW( false, + "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected strikeout case" ); + } + + return aTextLinesPolyPoly; + } + + ::basegfx::B2DRange calcDevicePixelBounds( const ::basegfx::B2DRange& rBounds, + const rendering::ViewState& viewState, + const rendering::RenderState& renderState ) + { + ::basegfx::B2DHomMatrix aTransform; + ::canvas::tools::mergeViewAndRenderTransform( aTransform, + viewState, + renderState ); + + ::basegfx::B2DRange aTransformedBounds; + return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds, + rBounds, + aTransform ); + } + + // create line actions for text such as underline and + // strikeout + ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const double& rStartOffset, + const double& rLineWidth, + const TextLineInfo& rTextLineInfo ) + { + return createTextLinesPolyPolygon( + ::basegfx::B2DPoint( rStartOffset, + 0.0 ), + rLineWidth, + rTextLineInfo ); + } + } +} diff --git a/cppcanvas/source/mtfrenderer/mtftools.hxx b/cppcanvas/source/mtfrenderer/mtftools.hxx new file mode 100644 index 000000000000..d44272342ee9 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/mtftools.hxx @@ -0,0 +1,273 @@ +/************************************************************************* + * + * 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: mtftools.hxx,v $ + * $Revision: 1.9.16.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General 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 _CPPCANVAS_RENDERER_MTFTOOLS_HXX +#define _CPPCANVAS_RENDERER_MTFTOOLS_HXX + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> + + +class VirtualDevice; +class Point; +class Size; + +namespace basegfx +{ + class B2DVector; + class B2DPoint; +} +namespace com { namespace sun { namespace star { namespace rendering +{ + struct RenderState; +} } } } + + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + } + + namespace tools + { + /** Init render state from OutDevState + + This method initializes the given render state object, + sets up the transformation and the clip from the + OutDevState. + */ + void initRenderState( ::com::sun::star::rendering::RenderState& renderState, + const ::cppcanvas::internal::OutDevState& outdevState ); + + /** Calc output offset relative to baseline + + The XCanvas API always renders text relative to its + baseline. This method calculates an offset in logical + coordinates, depending on the OutDevState's + textReferencePoint and the font currently set, to offset + the text from the baseline. + + @param outdevState + State to take textReferencePoint from + + @param rVDev + VDev to obtain font metrics from. + */ + ::Size getBaselineOffset( const ::cppcanvas::internal::OutDevState& outdevState, + const VirtualDevice& rVDev ); + + /** Construct a matrix that converts from logical to pixel + coordinate system. + + This method calculates a matrix that approximates the + VirtualDevice's LogicToPixel conversion (disregarding any + offset components, thus the 'linear' in the method name - + the returned matrix is guaranteed to be linear). + + @param o_rMatrix + This matrix will receive the calculated transform, and is + also returned from this method. + + @return the calculated transformation matrix. + */ + ::basegfx::B2DHomMatrix& calcLogic2PixelLinearTransform( ::basegfx::B2DHomMatrix& o_rMatrix, + const VirtualDevice& rVDev ); + + /** Construct a matrix that converts from logical to pixel + coordinate system. + + This method calculates a matrix that approximates the + VirtualDevice's LogicToPixel conversion. + + @param o_rMatrix + This matrix will receive the calculated transform, and is + also returned from this method. + + @return the calculated transformation matrix. + */ + ::basegfx::B2DHomMatrix& calcLogic2PixelAffineTransform( ::basegfx::B2DHomMatrix& o_rMatrix, + const VirtualDevice& rVDev ); + + /** This method modifies the clip, to cancel the given + transformation. + + As the clip is relative to the render state + transformation, offsetting or scaling the render state + must modify the clip, to keep it at the same position + relative to the primitive at hand + + @param o_rRenderState + Render state to change the clip in + + @param rOutdevState + Input state. Is used to retrieve the original clip from + + @param rOffset + The clip is offsetted by the negative of this value. + + @param pScaling + The clip is inversely scaled by this value (if given) + + @param pRotation + The clip is inversely rotated by this value (if given) + + @return true, if the clip has changed, false if not + */ + bool modifyClip( ::com::sun::star::rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::Point& rOffset, + const ::basegfx::B2DVector* pScaling, + const double* pRotation ); + + /** This method modifies the clip, to cancel the given + transformation. + + As the clip is relative to the render state + transformation, offsetting or scaling the render state + must modify the clip, to keep it at the same position + relative to the primitive at hand + + @param o_rRenderState + Render state to change the clip in + + @param rOutdevState + Input state. Is used to retrieve the original clip from + + @param rOffset + The clip is offsetted by the negative of this value. + + @param pScaling + The clip is inversely scaled by this value (if given) + + @param pRotation + The clip is inversely rotated by this value (if given) + + @return true, if the clip has changed, false if not + */ + bool modifyClip( ::com::sun::star::rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DPoint& rOffset, + const ::basegfx::B2DVector* pScaling, + const double* pRotation ); + + /** This method modifies the clip, to cancel the given + transformation. + + As the clip is relative to the render state + transformation, transforming the render state further must + modify the clip, to keep it at the same position relative + to the primitive at hand + + @param o_rRenderState + Render state to change the clip in + + @param rOutdevState + Input state. Is used to retrieve the original clip from + + @param rTransform + The clip is transformed by the inverse of this value. + + @return true, if the clip has changed, false if not + */ + bool modifyClip( ::com::sun::star::rendering::RenderState& o_rRenderState, + const struct ::cppcanvas::internal::OutDevState& rOutdevState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DHomMatrix& rTransform ); + + struct TextLineInfo + { + TextLineInfo( const double& rLineHeight, + const double& rOverlineHeight, + const double& rOverlineOffset, + const double& rUnderlineOffset, + const double& rStrikeoutOffset, + sal_Int8 nOverlineStyle, + sal_Int8 nUnderlineStyle, + sal_Int8 nStrikeoutStyle ) : + mnLineHeight( rLineHeight ), + mnOverlineHeight( rOverlineHeight ), + mnOverlineOffset( rOverlineOffset ), + mnUnderlineOffset( rUnderlineOffset ), + mnStrikeoutOffset( rStrikeoutOffset ), + mnOverlineStyle( nOverlineStyle ), + mnUnderlineStyle( nUnderlineStyle ), + mnStrikeoutStyle( nStrikeoutStyle ) + { + } + + double mnLineHeight; + double mnOverlineHeight; + double mnOverlineOffset; + double mnUnderlineOffset; + double mnStrikeoutOffset; + sal_Int8 mnOverlineStyle; + sal_Int8 mnUnderlineStyle; + sal_Int8 mnStrikeoutStyle; + }; + + /** Transform given bounds to device coordinate system. + */ + ::basegfx::B2DRange calcDevicePixelBounds( const ::basegfx::B2DRange& rBounds, + const ::com::sun::star::rendering::ViewState& viewState, + const ::com::sun::star::rendering::RenderState& renderState ); + + /** Generate text underline/strikeout info struct from OutDev + state. + */ + TextLineInfo createTextLineInfo( const ::VirtualDevice& rVDev, + const ::cppcanvas::internal::OutDevState& rState ); + + /** Create a poly-polygon representing the given combination + of overline, strikeout and underline. + + @param rStartOffset + Offset in X direction, where the underline starts + + @param rLineWidth + Width of the line of text to overline/strikeout/underline + + @param rTextLineInfo + Common info needed for overline/strikeout/underline generation + */ + ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const double& rStartOffset, + const double& rLineWidth, + const TextLineInfo& rTextLineInfo ); + + ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const ::basegfx::B2DPoint rStartPos, + const double& rLineWidth, + const TextLineInfo& rTextLineInfo ); + } +} + +#endif /* _CPPCANVAS_RENDERER_MTFTOOLS_HXX */ diff --git a/cppcanvas/source/mtfrenderer/outdevstate.hxx b/cppcanvas/source/mtfrenderer/outdevstate.hxx new file mode 100644 index 000000000000..b1eee1ab6f2e --- /dev/null +++ b/cppcanvas/source/mtfrenderer/outdevstate.hxx @@ -0,0 +1,148 @@ +/************************************************************************* + * + * 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: outdevstate.hxx,v $ + * $Revision: 1.9.16.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General 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 _CPPCANVAS_OUTDEVSTATE_HXX +#define _CPPCANVAS_OUTDEVSTATE_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#ifndef _COM_SUN_STAR_RENDERING_STRINGCONTEXT_HPP__ +#include <com/sun/star/rendering/StringContext.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_RENDERSTATE_HPP__ +#include <com/sun/star/rendering/RenderState.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_XPOLYPOLYGON2D_HPP__ +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_XCANVASFONT_HPP__ +#include <com/sun/star/rendering/XCanvasFont.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_TEXTDIRECTION_HPP__ +#include <com/sun/star/rendering/TextDirection.hpp> +#endif +#include <basegfx/matrix/b2dhommatrix.hxx> +#ifndef _BGFX_POLYGON_B2DPOLYPOLGON_HXX +#include <basegfx/polygon/b2dpolypolygon.hxx> +#endif +#include <vcl/fntstyle.hxx> +#include <vcl/vclenum.hxx> +#include <vcl/outdev.hxx> +#include <vcl/outdev.hxx> + + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState + { + OutDevState() : + clip(), + clipRect(), + xClipPoly(), + + lineColor(), + fillColor(), + textColor(), + textFillColor(), + textLineColor(), + + xFont(), + transform(), + mapModeTransform(), + fontRotation(0.0), + + textEmphasisMarkStyle(EMPHASISMARK_NONE), + pushFlags(PUSH_ALL), + textDirection(::com::sun::star::rendering::TextDirection::WEAK_LEFT_TO_RIGHT), + textAlignment(0), // TODO(Q2): Synchronize with implrenderer + // and possibly new rendering::TextAlignment + textReliefStyle(RELIEF_NONE), + textOverlineStyle(UNDERLINE_NONE), + textUnderlineStyle(UNDERLINE_NONE), + textStrikeoutStyle(STRIKEOUT_NONE), + textReferencePoint(ALIGN_BASELINE), + + isTextOutlineModeSet( false ), + isTextEffectShadowSet( false ), + isTextWordUnderlineSet( false ), + + isLineColorSet( false ), + isFillColorSet( false ), + isTextFillColorSet( false ), + isTextLineColorSet( false ) + { + } + + ::basegfx::B2DPolyPolygon clip; + ::Rectangle clipRect; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > xClipPoly; + + ::com::sun::star::uno::Sequence< double > lineColor; + ::com::sun::star::uno::Sequence< double > fillColor; + ::com::sun::star::uno::Sequence< double > textColor; + ::com::sun::star::uno::Sequence< double > textFillColor; + ::com::sun::star::uno::Sequence< double > textLineColor; + + /** Current font. + + @attention Beware, this member can be NULL, and + nevertheless text output is generated. + */ + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > xFont; + ::basegfx::B2DHomMatrix transform; + ::basegfx::B2DHomMatrix mapModeTransform; + double fontRotation; + + sal_uInt16 textEmphasisMarkStyle; + sal_uInt16 pushFlags; + sal_Int8 textDirection; + sal_Int8 textAlignment; + sal_Int8 textReliefStyle; + sal_Int8 textOverlineStyle; + sal_Int8 textUnderlineStyle; + sal_Int8 textStrikeoutStyle; + TextAlign textReferencePoint; + + bool isTextOutlineModeSet; + bool isTextEffectShadowSet; + bool isTextWordUnderlineSet; + + bool isLineColorSet; + bool isFillColorSet; + bool isTextFillColorSet; + bool isTextLineColorSet; + }; + } +} + +#endif /* _CPPCANVAS_OUTDEVSTATE_HXX */ diff --git a/cppcanvas/source/mtfrenderer/pointaction.cxx b/cppcanvas/source/mtfrenderer/pointaction.cxx new file mode 100644 index 000000000000..a7adecec6ec2 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/pointaction.cxx @@ -0,0 +1,190 @@ +/************************************************************************* + * + * 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: pointaction.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_cppcanvas.hxx" + +#include <rtl/logfile.hxx> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <canvas/canvastools.hxx> + +#include <boost/utility.hpp> + +#include "pointaction.hxx" +#include "outdevstate.hxx" +#include "cppcanvas/canvas.hxx" +#include "mtftools.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + class PointAction : public Action, private ::boost::noncopyable + { + public: + PointAction( const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState& ); + PointAction( const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState&, + const ::Color& ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // default: disabled copy/assignment + PointAction(const PointAction&); + PointAction& operator = ( const PointAction& ); + + ::basegfx::B2DPoint maPoint; + CanvasSharedPtr mpCanvas; + ::com::sun::star::rendering::RenderState maState; + }; + + PointAction::PointAction( const ::basegfx::B2DPoint& rPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + maPoint( rPoint ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + maState.DeviceColor = rState.lineColor; + } + + PointAction::PointAction( const ::basegfx::B2DPoint& rPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::Color& rAltColor ) : + maPoint( rPoint ), + mpCanvas( rCanvas ), + maState() + { + tools::initRenderState(maState,rState); + maState.DeviceColor = ::vcl::unotools::colorToDoubleSequence( + rAltColor, + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + } + + bool PointAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PointAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PointAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + mpCanvas->getUNOCanvas()->drawPoint( ::basegfx::unotools::point2DFromB2DPoint(maPoint), + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + bool PointAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // point only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return render( rTransformation ); + } + + ::basegfx::B2DRange PointAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( ::basegfx::B2DRange( maPoint.getX()-1, + maPoint.getY()-1, + maPoint.getX()+1, + maPoint.getY()+1 ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange PointAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // point only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 PointAction::getActionCount() const + { + return 1; + } + } + + ActionSharedPtr PointActionFactory::createPointAction( const ::basegfx::B2DPoint& rPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new PointAction( rPoint, rCanvas, rState ) ); + } + + ActionSharedPtr PointActionFactory::createPointAction( const ::basegfx::B2DPoint& rPoint, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::Color& rColor ) + { + return ActionSharedPtr( new PointAction( rPoint, rCanvas, rState, rColor ) ); + } + } +} diff --git a/cppcanvas/source/mtfrenderer/pointaction.hxx b/cppcanvas/source/mtfrenderer/pointaction.hxx new file mode 100644 index 000000000000..54b63af172e9 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/pointaction.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: pointaction.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 _CPPCANVAS_POINTACTION_HXX +#define _CPPCANVAS_POINTACTION_HXX + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> + +class Color; +namespace basegfx { + class B2DPoint; +} + +/* Definition of internal::PointActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class PointActionFactory + { + public: + /// Point in current color + static ActionSharedPtr createPointAction( const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState& ); + + /// Point in given color + static ActionSharedPtr createPointAction( const ::basegfx::B2DPoint&, + const CanvasSharedPtr&, + const OutDevState&, + const ::Color& ); + + private: + // static factory, disable big four + PointActionFactory(); + ~PointActionFactory(); + PointActionFactory(const PointActionFactory&); + PointActionFactory& operator=( const PointActionFactory& ); + }; + } +} + +#endif /* _CPPCANVAS_POINTACTION_HXX */ diff --git a/cppcanvas/source/mtfrenderer/polypolyaction.cxx b/cppcanvas/source/mtfrenderer/polypolyaction.cxx new file mode 100644 index 000000000000..225f2e318764 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/polypolyaction.cxx @@ -0,0 +1,541 @@ +/************************************************************************* + * + * 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: polypolyaction.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_cppcanvas.hxx" + +#include <rtl/logfile.hxx> + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/TexturingMode.hpp> + +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <canvas/canvastools.hxx> + +#include <boost/utility.hpp> + +#include "cachedprimitivebase.hxx" +#include "polypolyaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + class PolyPolyAction : public CachedPrimitiveBase + { + public: + PolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + bool bFill, + bool bStroke ); + PolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + bool bFill, + bool bStroke, + int nTransparency ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; + const ::basegfx::B2DRange maBounds; + const CanvasSharedPtr mpCanvas; + + // stroke color is now implicit: the maState.DeviceColor member + rendering::RenderState maState; + + uno::Sequence< double > maFillColor; + }; + + PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + bool bFill, + bool bStroke ) : + CachedPrimitiveBase( rCanvas, false ), + mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), + maBounds( ::basegfx::tools::getRange(rPolyPoly) ), + mpCanvas( rCanvas ), + maState(), + maFillColor() + { + tools::initRenderState(maState,rState); + + if( bFill ) + maFillColor = rState.fillColor; + + if( bStroke ) + maState.DeviceColor = rState.lineColor; + } + + PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + bool bFill, + bool bStroke, + int nTransparency ) : + CachedPrimitiveBase( rCanvas, false ), + mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), + maBounds( ::basegfx::tools::getRange(rPolyPoly) ), + mpCanvas( rCanvas ), + maState(), + maFillColor() + { + tools::initRenderState(maState,rState); + + if( bFill ) + { + maFillColor = rState.fillColor; + + if( maFillColor.getLength() < 4 ) + maFillColor.realloc( 4 ); + + // TODO(F1): Color management + // adapt fill color transparency + maFillColor[3] = 1.0 - nTransparency / 100.0; + } + + if( bStroke ) + { + maState.DeviceColor = rState.lineColor; + + if( maState.DeviceColor.getLength() < 4 ) + maState.DeviceColor.realloc( 4 ); + + // TODO(F1): Color management + // adapt fill color transparency + maState.DeviceColor[3] = 1.0 - nTransparency / 100.0; + } + } + + bool PolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + +#ifdef SPECIAL_DEBUG + aLocalState.Clip.clear(); + aLocalState.DeviceColor = + ::vcl::unotools::colorToDoubleSequence( mpCanvas->getUNOCanvas()->getDevice(), + ::Color( 0x80FF0000 ) ); + + if( maState.Clip.is() ) + mpCanvas->getUNOCanvas()->fillPolyPolygon( maState.Clip, + mpCanvas->getViewState(), + aLocalState ); + + aLocalState.DeviceColor = maState.DeviceColor; +#endif + + if( maFillColor.getLength() ) + { + // TODO(E3): Use DBO's finalizer here, + // fillPolyPolygon() might throw + const uno::Sequence< double > aTmpColor( aLocalState.DeviceColor ); + aLocalState.DeviceColor = maFillColor; + + rCachedPrimitive = mpCanvas->getUNOCanvas()->fillPolyPolygon( mxPolyPoly, + mpCanvas->getViewState(), + aLocalState ); + + aLocalState.DeviceColor = aTmpColor; + } + + if( aLocalState.DeviceColor.getLength() ) + { + rCachedPrimitive = mpCanvas->getUNOCanvas()->drawPolyPolygon( mxPolyPoly, + mpCanvas->getViewState(), + aLocalState ); + } + + return true; + } + + bool PolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( + maBounds, + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 PolyPolyAction::getActionCount() const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + return 1; + } + + + // ------------------------------------------------------------------------------- + + class TexturedPolyPolyAction : public CachedPrimitiveBase + { + public: + TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::Texture& rTexture ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; + const ::basegfx::B2DRectangle maBounds; + const CanvasSharedPtr mpCanvas; + + // stroke color is now implicit: the maState.DeviceColor member + rendering::RenderState maState; + const rendering::Texture maTexture; + }; + + TexturedPolyPolyAction::TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::Texture& rTexture ) : + CachedPrimitiveBase( rCanvas, true ), + mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), + maBounds( ::basegfx::tools::getRange(rPolyPoly) ), + mpCanvas( rCanvas ), + maState(), + maTexture( rTexture ) + { + tools::initRenderState(maState,rState); + } + + bool TexturedPolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + uno::Sequence< rendering::Texture > aSeq(1); + aSeq[0] = maTexture; + + rCachedPrimitive = mpCanvas->getUNOCanvas()->fillTexturedPolyPolygon( mxPolyPoly, + mpCanvas->getViewState(), + aLocalState, + aSeq ); + return true; + } + + bool TexturedPolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( + maBounds, + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 TexturedPolyPolyAction::getActionCount() const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + return 1; + } + + // ------------------------------------------------------------------------------- + + class StrokedPolyPolyAction : public CachedPrimitiveBase + { + public: + StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::StrokeAttributes& rStrokeAttributes ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + using Action::render; + virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const; + + const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; + const ::basegfx::B2DRectangle maBounds; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const rendering::StrokeAttributes maStrokeAttributes; + }; + + StrokedPolyPolyAction::StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::StrokeAttributes& rStrokeAttributes ) : + CachedPrimitiveBase( rCanvas, false ), + mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), + maBounds( ::basegfx::tools::getRange(rPolyPoly) ), + mpCanvas( rCanvas ), + maState(), + maStrokeAttributes( rStrokeAttributes ) + { + tools::initRenderState(maState,rState); + maState.DeviceColor = rState.lineColor; + } + + bool StrokedPolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, + const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + rCachedPrimitive = mpCanvas->getUNOCanvas()->strokePolyPolygon( mxPolyPoly, + mpCanvas->getViewState(), + aLocalState, + maStrokeAttributes ); + return true; + } + + bool StrokedPolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, fail if subset + // requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return false; + + return CachedPrimitiveBase::render( rTransformation ); + } + + ::basegfx::B2DRange StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( + maBounds, + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + + // polygon only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 StrokedPolyPolyAction::getActionCount() const + { + // TODO(F1): Split up poly-polygon into polygons, or even + // line segments, when subsets are requested. + return 1; + } + } + + ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + OSL_ENSURE( rState.isLineColorSet || rState.isFillColorSet, + "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" ); + return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, + rState.isFillColorSet, + rState.isLineColorSet ) ); + } + + ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::Texture& rTexture ) + { + return ActionSharedPtr( new TexturedPolyPolyAction( rPoly, rCanvas, rState, rTexture ) ); + } + + ActionSharedPtr PolyPolyActionFactory::createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + OSL_ENSURE( rState.isLineColorSet, + "PolyPolyActionFactory::createLinePolyPolyAction() called with empty line color" ); + + return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, + false, + rState.isLineColorSet ) ); + } + + ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const rendering::StrokeAttributes& rStrokeAttributes ) + { + OSL_ENSURE( rState.isLineColorSet, + "PolyPolyActionFactory::createPolyPolyAction() for strokes called with empty line color" ); + return ActionSharedPtr( new StrokedPolyPolyAction( rPoly, rCanvas, rState, rStrokeAttributes ) ); + } + + ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + int nTransparency ) + { + OSL_ENSURE( rState.isLineColorSet || rState.isFillColorSet, + "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" ); + return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, + rState.isFillColorSet, + rState.isLineColorSet, + nTransparency ) ); + } + + } +} diff --git a/cppcanvas/source/mtfrenderer/polypolyaction.hxx b/cppcanvas/source/mtfrenderer/polypolyaction.hxx new file mode 100644 index 000000000000..3b0a5da0ff3c --- /dev/null +++ b/cppcanvas/source/mtfrenderer/polypolyaction.hxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * 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: polypolyaction.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 _CPPCANVAS_POLYPOLYACTION_HXX +#define _CPPCANVAS_POLYPOLYACTION_HXX + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> + + +namespace basegfx { + class B2DPolyPolygon; +} +namespace com { namespace sun { namespace star { namespace rendering +{ + struct Texture; + struct StrokeAttributes; +} } } } + + +/* Definition of internal::PolyPolyActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class PolyPolyActionFactory + { + public: + /// Create polygon, fill/stroke according to state + static ActionSharedPtr createPolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState& ); + + /// Create texture-filled polygon + static ActionSharedPtr createPolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + const ::com::sun::star::rendering::Texture& ); + + /// Create line polygon (always stroked, not filled) + static ActionSharedPtr createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState& ); + + /// Create stroked polygon + static ActionSharedPtr createPolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + const ::com::sun::star::rendering::StrokeAttributes& ); + + /// For transparent painting of the given polygon (normally, we take the colors always opaque) + static ActionSharedPtr createPolyPolyAction( const ::basegfx::B2DPolyPolygon&, + const CanvasSharedPtr&, + const OutDevState&, + int nTransparency ); + + private: + // static factory, disable big four + PolyPolyActionFactory(); + ~PolyPolyActionFactory(); + PolyPolyActionFactory(const PolyPolyActionFactory&); + PolyPolyActionFactory& operator=( const PolyPolyActionFactory& ); + }; + } +} + +#endif /* _CPPCANVAS_POLYPOLYACTION_HXX */ diff --git a/cppcanvas/source/mtfrenderer/textaction.cxx b/cppcanvas/source/mtfrenderer/textaction.cxx new file mode 100644 index 000000000000..f1191e6e57f3 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/textaction.cxx @@ -0,0 +1,2319 @@ +/************************************************************************* + * + * 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: textaction.cxx,v $ + * $Revision: 1.22.4.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General 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_cppcanvas.hxx" + +#include <canvas/debug.hxx> +#include <tools/diagnose_ex.h> +#include <canvas/verbosetrace.hxx> + +#include <rtl/logfile.hxx> + +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XCanvasFont.hpp> + +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +#include <tools/gen.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/virdev.hxx> + +#include <basegfx/tools/canvastools.hxx> +#include <canvas/canvastools.hxx> + +#include <boost/scoped_array.hpp> +#include <boost/bind.hpp> +#include <boost/utility.hpp> + +#include "textaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + namespace + { + void init( rendering::RenderState& o_rRenderState, + const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const CanvasSharedPtr& rCanvas ) + { + tools::initRenderState(o_rRenderState,rState); + + // #i36950# Offset clip back to origin (as it's also moved + // by rStartPoint) + // #i53964# Also take VCL font rotation into account, + // since this, opposed to the FontMatrix rotation + // elsewhere, _does_ get incorporated into the render + // state transform. + tools::modifyClip( o_rRenderState, + rState, + rCanvas, + rStartPoint, + NULL, + &rState.fontRotation ); + + ::basegfx::B2DHomMatrix aLocalTransformation; + + aLocalTransformation.rotate( rState.fontRotation ); + aLocalTransformation.translate( rStartPoint.getX(), + rStartPoint.getY() ); + ::canvas::tools::appendToRenderState( o_rRenderState, + aLocalTransformation ); + + o_rRenderState.DeviceColor = rState.textColor; + } + + void init( rendering::RenderState& o_rRenderState, + const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DHomMatrix& rTextTransform ) + { + init( o_rRenderState, rStartPoint, rState, rCanvas ); + + // TODO(F2): Also inversely-transform clip with + // rTextTransform (which is actually rather hard, as the + // text transform is _prepended_ to the render state)! + + // prepend extra font transform to render state + // (prepend it, because it's interpreted in the unit + // rect coordinate space) + ::canvas::tools::prependToRenderState( o_rRenderState, + rTextTransform ); + } + + void init( rendering::RenderState& o_rRenderState, + uno::Reference< rendering::XCanvasFont >& o_rFont, + const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const CanvasSharedPtr& rCanvas ) + { + // ensure that o_rFont is valid. It is possible that + // text actions are generated without previously + // setting a font. Then, just take a default font + if( !o_rFont.is() ) + { + // Use completely default FontRequest + const rendering::FontRequest aFontRequest; + + geometry::Matrix2D aFontMatrix; + ::canvas::tools::setIdentityMatrix2D( aFontMatrix ); + + o_rFont = rCanvas->getUNOCanvas()->createFont( + aFontRequest, + uno::Sequence< beans::PropertyValue >(), + aFontMatrix ); + } + + init( o_rRenderState, + rStartPoint, + rState, + rCanvas ); + } + + void init( rendering::RenderState& o_rRenderState, + uno::Reference< rendering::XCanvasFont >& o_rFont, + const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DHomMatrix& rTextTransform ) + { + init( o_rRenderState, o_rFont, rStartPoint, rState, rCanvas ); + + // TODO(F2): Also inversely-transform clip with + // rTextTransform (which is actually rather hard, as the + // text transform is _prepended_ to the render state)! + + // prepend extra font transform to render state + // (prepend it, because it's interpreted in the unit + // rect coordinate space) + ::canvas::tools::prependToRenderState( o_rRenderState, + rTextTransform ); + } + + ::basegfx::B2DPolyPolygon textLinesFromLogicalOffsets( const uno::Sequence< double >& rOffsets, + const tools::TextLineInfo& rTextLineInfo ) + { + return tools::createTextLinesPolyPolygon( + 0.0, + // extract character cell furthest to the right + *(::std::max_element( + rOffsets.getConstArray(), + rOffsets.getConstArray() + rOffsets.getLength() )), + rTextLineInfo ); + } + + uno::Sequence< double > setupDXArray( const sal_Int32* pCharWidths, + sal_Int32 nLen, + const OutDevState& rState ) + { + // convert character widths from logical units + uno::Sequence< double > aCharWidthSeq( nLen ); + double* pOutputWidths( aCharWidthSeq.getArray() ); + + // #143885# maintain (nearly) full precision of DX + // array, by circumventing integer-based + // OutDev-mapping + const double nScale( rState.mapModeTransform.get(0,0) ); + for( int i = 0; i < nLen; ++i ) + { + // TODO(F2): use correct scale direction + *pOutputWidths++ = *pCharWidths++ * nScale; + } + + return aCharWidthSeq; + } + + uno::Sequence< double > setupDXArray( const ::String& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const OutDevState& rState ) + { + // no external DX array given, create one from given + // string + ::boost::scoped_array< sal_Int32 > pCharWidths( new sal_Int32[nLen] ); + + rVDev.GetTextArray( rText, pCharWidths.get(), + static_cast<USHORT>(nStartPos), + static_cast<USHORT>(nLen) ); + + return setupDXArray( pCharWidths.get(), nLen, rState ); + } + + ::basegfx::B2DPoint adaptStartPoint( const ::basegfx::B2DPoint& rStartPoint, + const OutDevState& rState, + const uno::Sequence< double >& rOffsets ) + { + ::basegfx::B2DPoint aLocalPoint( rStartPoint ); + + if( rState.textAlignment ) + { + // text origin is right, not left. Modify start point + // accordingly, because XCanvas::drawTextLayout() + // always aligns left! + + const double nOffset( rOffsets[ rOffsets.getLength()-1 ] ); + + // correct start point for rotated text: rotate around + // former start point + aLocalPoint.setX( aLocalPoint.getX() + cos( rState.fontRotation )*nOffset ); + aLocalPoint.setY( aLocalPoint.getY() + sin( rState.fontRotation )*nOffset ); + } + + return aLocalPoint; + } + + /** Perform common setup for array text actions + + This method creates the XTextLayout object and + initializes it, e.g. with the logical advancements. + */ + void initArrayAction( rendering::RenderState& o_rRenderState, + uno::Reference< rendering::XTextLayout >& o_rTextLayout, + const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix* pTextTransform ) + { + ENSURE_OR_THROW( rOffsets.getLength(), + "::cppcanvas::internal::initArrayAction(): zero-length DX array" ); + + const ::basegfx::B2DPoint aLocalStartPoint( + adaptStartPoint( rStartPoint, rState, rOffsets ) ); + + uno::Reference< rendering::XCanvasFont > xFont( rState.xFont ); + + if( pTextTransform ) + init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas, *pTextTransform ); + else + init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas ); + + o_rTextLayout = xFont->createTextLayout( + rendering::StringContext( rText, nStartPos, nLen ), + rState.textDirection, + 0 ); + + ENSURE_OR_THROW( o_rTextLayout.is(), + "::cppcanvas::internal::initArrayAction(): Invalid font" ); + + o_rTextLayout->applyLogicalAdvancements( rOffsets ); + } + + double getLineWidth( ::VirtualDevice& rVDev, + const OutDevState& rState, + const rendering::StringContext& rStringContext ) + { + // TODO(F2): use correct scale direction + const ::basegfx::B2DSize aSize( rVDev.GetTextWidth( rStringContext.Text, + static_cast<USHORT>(rStringContext.StartPosition), + static_cast<USHORT>(rStringContext.Length) ), + 0 ); + + return (rState.mapModeTransform * aSize).getX(); + } + + uno::Sequence< double > + calcSubsetOffsets( rendering::RenderState& io_rRenderState, + double& o_rMinPos, + double& o_rMaxPos, + const uno::Reference< rendering::XTextLayout >& rOrigTextLayout, + const ::cppcanvas::internal::Action::Subset& rSubset ) + { + ENSURE_OR_THROW( rSubset.mnSubsetEnd > rSubset.mnSubsetBegin, + "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" ); + + uno::Sequence< double > aOrigOffsets( rOrigTextLayout->queryLogicalAdvancements() ); + const double* pOffsets( aOrigOffsets.getConstArray() ); + + ENSURE_OR_THROW( aOrigOffsets.getLength() >= rSubset.mnSubsetEnd, + "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" ); + + // TODO(F3): It currently seems that for RTL text, the + // DX offsets are nevertheless increasing in logical + // text order (I'd expect they are decreasing, + // mimicking the fact that the text is output + // right-to-left). This breaks text effects for ALL + // RTL languages. + + // determine leftmost position in given subset range - + // as the DX array contains the output positions + // starting with the second character (the first is + // assumed to have output position 0), correct begin + // iterator. + const double nMinPos( rSubset.mnSubsetBegin <= 0 ? 0 : + *(::std::min_element( pOffsets+rSubset.mnSubsetBegin-1, + pOffsets+rSubset.mnSubsetEnd )) ); + + // determine rightmost position in given subset range + // - as the DX array contains the output positions + // starting with the second character (the first is + // assumed to have output position 0), correct begin + // iterator. + const double nMaxPos( + *(::std::max_element( pOffsets + (rSubset.mnSubsetBegin <= 0 ? + 0 : rSubset.mnSubsetBegin-1), + pOffsets + rSubset.mnSubsetEnd )) ); + + + // adapt render state, to move text output to given offset + // ------------------------------------------------------- + + // TODO(F1): Strictly speaking, we also have to adapt + // the clip here, which normally should _not_ move + // with the output offset. Neglected for now, as it + // does not matter for drawing layer output + + if( rSubset.mnSubsetBegin > 0 ) + { + ::basegfx::B2DHomMatrix aTranslation; + if( rOrigTextLayout->getFont()->getFontRequest().FontDescription.IsVertical ) + { + // vertical text -> offset in y direction + aTranslation.translate( 0.0, nMinPos ); + } + else + { + // horizontal text -> offset in x direction + aTranslation.translate( nMinPos, 0.0 ); + } + + ::canvas::tools::appendToRenderState( io_rRenderState, + aTranslation ); + } + + + // reduce DX array to given substring + // ---------------------------------- + + const sal_Int32 nNewElements( rSubset.mnSubsetEnd - rSubset.mnSubsetBegin ); + uno::Sequence< double > aAdaptedOffsets( nNewElements ); + double* pAdaptedOffsets( aAdaptedOffsets.getArray() ); + + // move to new output position (subtract nMinPos, + // which is the new '0' position), copy only the range + // as given by rSubset. + ::std::transform( pOffsets + rSubset.mnSubsetBegin, + pOffsets + rSubset.mnSubsetEnd, + pAdaptedOffsets, + ::boost::bind( ::std::minus<double>(), + _1, + nMinPos ) ); + + o_rMinPos = nMinPos; + o_rMaxPos = nMaxPos; + + return aAdaptedOffsets; + } + + uno::Reference< rendering::XTextLayout > + createSubsetLayout( const rendering::StringContext& rOrigContext, + const ::cppcanvas::internal::Action::Subset& rSubset, + const uno::Reference< rendering::XTextLayout >& rOrigTextLayout ) + { + // create temporary new text layout with subset string + // --------------------------------------------------- + + const sal_Int32 nNewStartPos( rOrigContext.StartPosition + ::std::min( + rSubset.mnSubsetBegin, rOrigContext.Length-1 ) ); + const sal_Int32 nNewLength( ::std::max( + ::std::min( + rSubset.mnSubsetEnd - rSubset.mnSubsetBegin, + rOrigContext.Length ), + sal_Int32( 0 ) ) ); + + const rendering::StringContext aContext( rOrigContext.Text, + nNewStartPos, + nNewLength ); + + uno::Reference< rendering::XTextLayout > xTextLayout( + rOrigTextLayout->getFont()->createTextLayout( aContext, + rOrigTextLayout->getMainTextDirection(), + 0 ), + uno::UNO_QUERY_THROW ); + + return xTextLayout; + } + + /** Setup subset text layout + + @param io_rTextLayout + Must contain original (full set) text layout on input, + will contain subsetted text layout (or empty + reference, for empty subsets) on output. + + @param io_rRenderState + Must contain original render state on input, will + contain shifted render state concatenated with + rTransformation on output. + + @param rTransformation + Additional transformation, to be prepended to render + state + + @param rSubset + Subset to prepare + */ + void createSubsetLayout( uno::Reference< rendering::XTextLayout >& io_rTextLayout, + rendering::RenderState& io_rRenderState, + double& o_rMinPos, + double& o_rMaxPos, + const ::basegfx::B2DHomMatrix& rTransformation, + const Action::Subset& rSubset ) + { + ::canvas::tools::prependToRenderState(io_rRenderState, rTransformation); + + if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd ) + { + // empty range, empty layout + io_rTextLayout.clear(); + + return; + } + + ENSURE_OR_THROW( io_rTextLayout.is(), + "createSubsetLayout(): Invalid input layout" ); + + const rendering::StringContext& rOrigContext( io_rTextLayout->getText() ); + + if( rSubset.mnSubsetBegin == 0 && + rSubset.mnSubsetEnd == rOrigContext.Length ) + { + // full range, no need for subsetting + return; + } + + uno::Reference< rendering::XTextLayout > xTextLayout( + createSubsetLayout( rOrigContext, rSubset, io_rTextLayout ) ); + + if( xTextLayout.is() ) + { + xTextLayout->applyLogicalAdvancements( + calcSubsetOffsets( io_rRenderState, + o_rMinPos, + o_rMaxPos, + io_rTextLayout, + rSubset ) ); + } + + io_rTextLayout = xTextLayout; + } + + + /** Interface for renderEffectText functor below. + + This is interface is used from the renderEffectText() + method below, to call the client implementation. + */ + class TextRenderer + { + public: + virtual ~TextRenderer() {} + + /// Render text with given RenderState + virtual bool operator()( const rendering::RenderState& rRenderState ) const = 0; + }; + + /** Render effect text. + + @param rRenderer + Functor object, will be called to render the actual + part of the text effect (the text itself and the means + to render it are unknown to this method) + */ + bool renderEffectText( const TextRenderer& rRenderer, + const rendering::RenderState& rRenderState, + const rendering::ViewState& /*rViewState*/, + const uno::Reference< rendering::XCanvas >& xCanvas, + const ::Color& rShadowColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rReliefOffset ) + { + ::Color aEmptyColor( COL_AUTO ); + uno::Reference<rendering::XColorSpace> xColorSpace( + xCanvas->getDevice()->getDeviceColorSpace() ); + + // draw shadow text, if enabled + if( rShadowColor != aEmptyColor ) + { + rendering::RenderState aShadowState( rRenderState ); + ::basegfx::B2DHomMatrix aTranslate; + + aTranslate.translate( rShadowOffset.getX(), + rShadowOffset.getY() ); + + ::canvas::tools::appendToRenderState(aShadowState, aTranslate); + + aShadowState.DeviceColor = + ::vcl::unotools::colorToDoubleSequence( rShadowColor, + xColorSpace ); + + rRenderer( aShadowState ); + } + + // draw relief text, if enabled + if( rReliefColor != aEmptyColor ) + { + rendering::RenderState aReliefState( rRenderState ); + ::basegfx::B2DHomMatrix aTranslate; + + aTranslate.translate( rReliefOffset.getX(), + rReliefOffset.getY() ); + + ::canvas::tools::appendToRenderState(aReliefState, aTranslate); + + aReliefState.DeviceColor = + ::vcl::unotools::colorToDoubleSequence( rReliefColor, + xColorSpace ); + + rRenderer( aReliefState ); + } + + // draw normal text + rRenderer( rRenderState ); + + return true; + } + + + ::basegfx::B2DRange calcEffectTextBounds( const ::basegfx::B2DRange& rTextBounds, + const ::basegfx::B2DRange& rLineBounds, + const ::basegfx::B2DSize& rReliefOffset, + const ::basegfx::B2DSize& rShadowOffset, + const rendering::RenderState& rRenderState, + const rendering::ViewState& rViewState ) + { + ::basegfx::B2DRange aBounds( rTextBounds ); + + // add extends of text lines + aBounds.expand( rLineBounds ); + + // TODO(Q3): Provide this functionality at the B2DRange + ::basegfx::B2DRange aTotalBounds( aBounds ); + aTotalBounds.expand( + ::basegfx::B2DRange( aBounds.getMinX() + rReliefOffset.getX(), + aBounds.getMinY() + rReliefOffset.getY(), + aBounds.getMaxX() + rReliefOffset.getX(), + aBounds.getMaxY() + rReliefOffset.getY() ) ); + aTotalBounds.expand( + ::basegfx::B2DRange( aBounds.getMinX() + rShadowOffset.getX(), + aBounds.getMinY() + rShadowOffset.getY(), + aBounds.getMaxX() + rShadowOffset.getX(), + aBounds.getMaxY() + rShadowOffset.getY() ) ); + + return tools::calcDevicePixelBounds( aTotalBounds, + rViewState, + rRenderState ); + } + + void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize, + uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines, + const CanvasSharedPtr& rCanvas, + const uno::Sequence< double >& rOffsets, + const tools::TextLineInfo rLineInfo ) + { + const ::basegfx::B2DPolyPolygon aPoly( + textLinesFromLogicalOffsets( + rOffsets, + rLineInfo ) ); + + o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange(); + + o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aPoly ); + } + + void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize, + uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines, + const CanvasSharedPtr& rCanvas, + double nLineWidth, + const tools::TextLineInfo rLineInfo ) + { + const ::basegfx::B2DPolyPolygon aPoly( + tools::createTextLinesPolyPolygon( 0.0, nLineWidth, + rLineInfo ) ); + + o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange(); + + o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aPoly ); + } + + + // ------------------------------------------------------------------------- + + class TextAction : public Action, private ::boost::noncopyable + { + public: + TextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + TextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XCanvasFont > mxFont; + const rendering::StringContext maStringContext; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const sal_Int8 maTextDirection; + }; + + TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxFont( rState.xFont ), + maStringContext( rString, nStartPos, nLen ), + mpCanvas( rCanvas ), + maState(), + maTextDirection( rState.textDirection ) + { + init( maState, mxFont, + rStartPoint, + rState, rCanvas ); + + ENSURE_OR_THROW( mxFont.is(), + "::cppcanvas::internal::TextAction(): Invalid font" ); + } + + TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxFont( rState.xFont ), + maStringContext( rString, nStartPos, nLen ), + mpCanvas( rCanvas ), + maState(), + maTextDirection( rState.textDirection ) + { + init( maState, mxFont, + rStartPoint, + rState, rCanvas, rTextTransform ); + + ENSURE_OR_THROW( mxFont.is(), + "::cppcanvas::internal::TextAction(): Invalid font" ); + } + + bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + mpCanvas->getUNOCanvas()->drawText( maStringContext, mxFont, + mpCanvas->getViewState(), aLocalState, maTextDirection ); + + return true; + } + + bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_ENSURE( false, + "TextAction::render(): Subset not supported by this object" ); + + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // _subsettable_ text + return render( rTransformation ); + } + + ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + // create XTextLayout, to have the + // XTextLayout::queryTextBounds() method available + uno::Reference< rendering::XTextLayout > xTextLayout( + mxFont->createTextLayout( + maStringContext, + maTextDirection, + 0 ) ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + xTextLayout->queryTextBounds() ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_ENSURE( false, + "TextAction::getBounds(): Subset not supported by this object" ); + + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // _subsettable_ text + return getBounds( rTransformation ); + } + + sal_Int32 TextAction::getActionCount() const + { + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // _subsettable_ text + return 1; + } + + + // ------------------------------------------------------------------------- + + class EffectTextAction : + public Action, + public TextRenderer, + private ::boost::noncopyable + { + public: + EffectTextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + EffectTextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + /// Interface TextRenderer + virtual bool operator()( const rendering::RenderState& rRenderState ) const; + + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XCanvasFont > mxFont; + const rendering::StringContext maStringContext; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const tools::TextLineInfo maTextLineInfo; + ::basegfx::B2DSize maLinesOverallSize; + const double mnLineWidth; + uno::Reference< rendering::XPolyPolygon2D > mxTextLines; + const ::basegfx::B2DSize maReliefOffset; + const ::Color maReliefColor; + const ::basegfx::B2DSize maShadowOffset; + const ::Color maShadowColor; + const sal_Int8 maTextDirection; + }; + + EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxFont( rState.xFont ), + maStringContext( rText, nStartPos, nLen ), + mpCanvas( rCanvas ), + maState(), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ), + maTextDirection( rState.textDirection ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + mnLineWidth, + maTextLineInfo ); + + init( maState, mxFont, + rStartPoint, + rState, rCanvas ); + + ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(), + "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" ); + } + + EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxFont( rState.xFont ), + maStringContext( rText, nStartPos, nLen ), + mpCanvas( rCanvas ), + maState(), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ), + maTextDirection( rState.textDirection ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + mnLineWidth, + maTextLineInfo ); + + init( maState, mxFont, + rStartPoint, + rState, rCanvas, rTextTransform ); + + ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(), + "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" ); + } + + bool EffectTextAction::operator()( const rendering::RenderState& rRenderState ) const + { + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() ); + + rCanvas->fillPolyPolygon( mxTextLines, + rViewState, + rRenderState ); + + rCanvas->drawText( maStringContext, mxFont, + rViewState, + rRenderState, + maTextDirection ); + + return true; + } + + bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return renderEffectText( *this, + aLocalState, + mpCanvas->getViewState(), + mpCanvas->getUNOCanvas(), + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); + } + + bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_ENSURE( false, + "EffectTextAction::render(): Subset not supported by this object" ); + + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // subsettable text + return render( rTransformation ); + } + + ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + // create XTextLayout, to have the + // XTextLayout::queryTextBounds() method available + uno::Reference< rendering::XTextLayout > xTextLayout( + mxFont->createTextLayout( + maStringContext, + maTextDirection, + 0 ) ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + xTextLayout->queryTextBounds() ), + ::basegfx::B2DRange( 0,0, + maLinesOverallSize.getX(), + maLinesOverallSize.getY() ), + maReliefOffset, + maShadowOffset, + aLocalState, + mpCanvas->getViewState() ); + } + + ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_ENSURE( false, + "EffectTextAction::getBounds(): Subset not supported by this object" ); + + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // _subsettable_ text + return getBounds( rTransformation ); + } + + sal_Int32 EffectTextAction::getActionCount() const + { + // TODO(P1): Retrieve necessary font metric info for + // TextAction from XCanvas. Currently, the + // TextActionFactory does not generate this object for + // subsettable text + return 1; + } + + + // ------------------------------------------------------------------------- + + class TextArrayAction : public Action, private ::boost::noncopyable + { + public: + TextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + TextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XTextLayout > mxTextLayout; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + }; + + TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxTextLayout(), + mpCanvas( rCanvas ), + maState() + { + initArrayAction( maState, + mxTextLayout, + rStartPoint, + rString, + nStartPos, + nLen, + rOffsets, + rCanvas, + rState, NULL ); + } + + TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::rtl::OUString& rString, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxTextLayout(), + mpCanvas( rCanvas ), + maState() + { + initArrayAction( maState, + mxTextLayout, + rStartPoint, + rString, + nStartPos, + nLen, + rOffsets, + rCanvas, + rState, + &rTextTransform ); + } + + bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + +#ifdef SPECIAL_DEBUG + aLocalState.Clip.clear(); + aLocalState.DeviceColor = + ::vcl::unotools::colorToDoubleSequence( mpCanvas->getUNOCanvas()->getDevice(), + ::Color( 0x80FF0000 ) ); + + if( maState.Clip.is() ) + mpCanvas->getUNOCanvas()->drawPolyPolygon( maState.Clip, + mpCanvas->getViewState(), + aLocalState ); + + aLocalState.DeviceColor = maState.DeviceColor; +#endif + + mpCanvas->getUNOCanvas()->drawTextLayout( mxTextLayout, + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::render( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout ); + + double nDummy0, nDummy1; + createSubsetLayout( xTextLayout, + aLocalState, + nDummy0, + nDummy1, + rTransformation, + rSubset ); + + if( !xTextLayout.is() ) + return true; // empty layout, render nothing + + mpCanvas->getUNOCanvas()->drawTextLayout( xTextLayout, + mpCanvas->getViewState(), + aLocalState ); + + return true; + } + + ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + mxTextLayout->queryTextBounds() ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::getBounds( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout ); + + double nDummy0, nDummy1; + createSubsetLayout( xTextLayout, + aLocalState, + nDummy0, + nDummy1, + rTransformation, + rSubset ); + + if( !xTextLayout.is() ) + return ::basegfx::B2DRange(); // empty layout, empty bounds + + return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + xTextLayout->queryTextBounds() ), + mpCanvas->getViewState(), + aLocalState ); + } + + sal_Int32 TextArrayAction::getActionCount() const + { + const rendering::StringContext& rOrigContext( mxTextLayout->getText() ); + + return rOrigContext.Length; + } + + + // ------------------------------------------------------------------------- + + class EffectTextArrayAction : + public Action, + public TextRenderer, + private ::boost::noncopyable + { + public: + EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // TextRenderer interface + virtual bool operator()( const rendering::RenderState& rRenderState ) const; + + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XTextLayout > mxTextLayout; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const tools::TextLineInfo maTextLineInfo; + ::basegfx::B2DSize maLinesOverallSize; + uno::Reference< rendering::XPolyPolygon2D > mxTextLines; + const ::basegfx::B2DSize maReliefOffset; + const ::Color maReliefColor; + const ::basegfx::B2DSize maShadowOffset; + const ::Color maShadowColor; + }; + + EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxTextLayout(), + mpCanvas( rCanvas ), + maState(), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + rOffsets, + maTextLineInfo ); + + initArrayAction( maState, + mxTextLayout, + rStartPoint, + rText, + nStartPos, + nLen, + rOffsets, + rCanvas, + rState, NULL ); + } + + EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::rtl::OUString& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxTextLayout(), + mpCanvas( rCanvas ), + maState(), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + rOffsets, + maTextLineInfo ); + + initArrayAction( maState, + mxTextLayout, + rStartPoint, + rText, + nStartPos, + nLen, + rOffsets, + rCanvas, + rState, + &rTextTransform ); + } + + bool EffectTextArrayAction::operator()( const rendering::RenderState& rRenderState ) const + { + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() ); + + rCanvas->fillPolyPolygon( mxTextLines, + rViewState, + rRenderState ); + + rCanvas->drawTextLayout( mxTextLayout, + rViewState, + rRenderState ); + + return true; + } + + bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return renderEffectText( *this, + aLocalState, + mpCanvas->getViewState(), + mpCanvas->getUNOCanvas(), + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); + } + + class EffectTextArrayRenderHelper : public TextRenderer + { + public: + EffectTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas, + const uno::Reference< rendering::XTextLayout >& rTextLayout, + const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon, + const rendering::ViewState& rViewState ) : + mrCanvas( rCanvas ), + mrTextLayout( rTextLayout ), + mrLinePolygon( rLinePolygon ), + mrViewState( rViewState ) + { + } + + // TextRenderer interface + virtual bool operator()( const rendering::RenderState& rRenderState ) const + { + mrCanvas->fillPolyPolygon( mrLinePolygon, + mrViewState, + rRenderState ); + + mrCanvas->drawTextLayout( mrTextLayout, + mrViewState, + rRenderState ); + + return true; + } + + private: + const uno::Reference< rendering::XCanvas >& mrCanvas; + const uno::Reference< rendering::XTextLayout >& mrTextLayout; + const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon; + const rendering::ViewState& mrViewState; + }; + + bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout ); + const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() ); + + double nMinPos(0.0); + double nMaxPos(aTextBounds.X2 - aTextBounds.X1); + + createSubsetLayout( xTextLayout, + aLocalState, + nMinPos, + nMaxPos, + rTransformation, + rSubset ); + + if( !xTextLayout.is() ) + return true; // empty layout, render nothing + + + // create and setup local line polygon + // =================================== + + uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() ); + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + + uno::Reference< rendering::XPolyPolygon2D > xTextLines( + ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + xCanvas->getDevice(), + tools::createTextLinesPolyPolygon( + 0.0, nMaxPos - nMinPos, + maTextLineInfo ) ) ); + + + // render everything + // ================= + + return renderEffectText( + EffectTextArrayRenderHelper( xCanvas, + xTextLayout, + xTextLines, + rViewState ), + aLocalState, + rViewState, + xCanvas, + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); + } + + ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + mxTextLayout->queryTextBounds() ), + ::basegfx::B2DRange( 0,0, + maLinesOverallSize.getX(), + maLinesOverallSize.getY() ), + maReliefOffset, + maShadowOffset, + aLocalState, + mpCanvas->getViewState() ); + } + + ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout ); + const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() ); + + double nMinPos(0.0); + double nMaxPos(aTextBounds.X2 - aTextBounds.X1); + + createSubsetLayout( xTextLayout, + aLocalState, + nMinPos, + nMaxPos, + rTransformation, + rSubset ); + + if( !xTextLayout.is() ) + return ::basegfx::B2DRange(); // empty layout, empty bounds + + + // create and setup local line polygon + // =================================== + + const ::basegfx::B2DPolyPolygon aPoly( + tools::createTextLinesPolyPolygon( + 0.0, nMaxPos - nMinPos, + maTextLineInfo ) ); + + return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D( + xTextLayout->queryTextBounds() ), + ::basegfx::tools::getRange( aPoly ), + maReliefOffset, + maShadowOffset, + aLocalState, + mpCanvas->getViewState() ); + } + + sal_Int32 EffectTextArrayAction::getActionCount() const + { + const rendering::StringContext& rOrigContext( mxTextLayout->getText() ); + + return rOrigContext.Length; + } + + + // ------------------------------------------------------------------------- + + class OutlineAction : + public Action, + public TextRenderer, + private ::boost::noncopyable + { + public: + OutlineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::basegfx::B2DRectangle& rOutlineBounds, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly, + const ::std::vector< sal_Int32 >& rPolygonGlyphMap, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + OutlineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::basegfx::B2DRectangle& rOutlineBounds, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly, + const ::std::vector< sal_Int32 >& rPolygonGlyphMap, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + // TextRenderer interface + virtual bool operator()( const rendering::RenderState& rRenderState ) const; + + // TODO(P2): This is potentially a real mass object + // (every character might be a separate TextAction), + // thus, make it as lightweight as possible. For + // example, share common RenderState among several + // TextActions, maybe using maOffsets for the + // translation. + + uno::Reference< rendering::XPolyPolygon2D > mxTextPoly; + + /** This vector denotes the index of the start polygon + for the respective glyph sequence. + + To get a polygon index range for a given character + index i, take [ maPolygonGlyphMap[i], + maPolygonGlyphMap[i+1] ). Note that this is wrong + for BiDi + */ + const ::std::vector< sal_Int32 > maPolygonGlyphMap; + const uno::Sequence< double > maOffsets; + const CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + double mnOutlineWidth; + const uno::Sequence< double > maFillColor; + const tools::TextLineInfo maTextLineInfo; + ::basegfx::B2DSize maLinesOverallSize; + const ::basegfx::B2DRectangle maOutlineBounds; + uno::Reference< rendering::XPolyPolygon2D > mxTextLines; + const ::basegfx::B2DSize maReliefOffset; + const ::Color maReliefColor; + const ::basegfx::B2DSize maShadowOffset; + const ::Color maShadowColor; + }; + + double calcOutlineWidth( const OutDevState& rState, + VirtualDevice& rVDev ) + { + const ::basegfx::B2DSize aFontSize( 0, + rVDev.GetFont().GetHeight() / 64.0 ); + + const double nOutlineWidth( + (rState.mapModeTransform * aFontSize).getY() ); + + return nOutlineWidth < 1.0 ? 1.0 : nOutlineWidth; + } + + OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::basegfx::B2DRectangle& rOutlineBounds, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly, + const ::std::vector< sal_Int32 >& rPolygonGlyphMap, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mxTextPoly( rTextPoly ), + maPolygonGlyphMap( rPolygonGlyphMap ), + maOffsets( rOffsets ), + mpCanvas( rCanvas ), + maState(), + mnOutlineWidth( calcOutlineWidth(rState,rVDev) ), + maFillColor( + ::vcl::unotools::colorToDoubleSequence( + ::Color( COL_WHITE ), + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + maOutlineBounds( rOutlineBounds ), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + rOffsets, + maTextLineInfo ); + + init( maState, + rStartPoint, + rState, + rCanvas ); + } + + OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const ::basegfx::B2DRectangle& rOutlineBounds, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly, + const ::std::vector< sal_Int32 >& rPolygonGlyphMap, + const uno::Sequence< double >& rOffsets, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const ::basegfx::B2DHomMatrix& rTextTransform ) : + mxTextPoly( rTextPoly ), + maPolygonGlyphMap( rPolygonGlyphMap ), + maOffsets( rOffsets ), + mpCanvas( rCanvas ), + maState(), + mnOutlineWidth( calcOutlineWidth(rState,rVDev) ), + maFillColor( + ::vcl::unotools::colorToDoubleSequence( + ::Color( COL_WHITE ), + rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )), + maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ), + maLinesOverallSize(), + maOutlineBounds( rOutlineBounds ), + mxTextLines(), + maReliefOffset( rReliefOffset ), + maReliefColor( rReliefColor ), + maShadowOffset( rShadowOffset ), + maShadowColor( rShadowColor ) + { + initEffectLinePolyPolygon( maLinesOverallSize, + mxTextLines, + rCanvas, + rOffsets, + maTextLineInfo ); + + init( maState, + rStartPoint, + rState, + rCanvas, + rTextTransform ); + } + + bool OutlineAction::operator()( const rendering::RenderState& rRenderState ) const + { + const rendering::ViewState& rViewState( mpCanvas->getViewState() ); + const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() ); + + rendering::StrokeAttributes aStrokeAttributes; + + aStrokeAttributes.StrokeWidth = mnOutlineWidth; + aStrokeAttributes.MiterLimit = 1.0; + aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; + aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; + aStrokeAttributes.JoinType = rendering::PathJoinType::MITER; + + rendering::RenderState aLocalState( rRenderState ); + aLocalState.DeviceColor = maFillColor; + + // TODO(P1): implement caching + + // background of text + rCanvas->fillPolyPolygon( mxTextPoly, + rViewState, + aLocalState ); + + // border line of text + rCanvas->strokePolyPolygon( mxTextPoly, + rViewState, + rRenderState, + aStrokeAttributes ); + + // underlines/strikethrough - background + rCanvas->fillPolyPolygon( mxTextLines, + rViewState, + aLocalState ); + // underlines/strikethrough - border + rCanvas->strokePolyPolygon( mxTextLines, + rViewState, + rRenderState, + aStrokeAttributes ); + + return true; + } + + bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this ); + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return renderEffectText( *this, + aLocalState, + mpCanvas->getViewState(), + mpCanvas->getUNOCanvas(), + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); + } + + class OutlineTextArrayRenderHelper : public TextRenderer + { + public: + OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas, + const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon, + const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon, + const rendering::ViewState& rViewState, + double nOutlineWidth ) : + maFillColor( + ::vcl::unotools::colorToDoubleSequence( + ::Color( COL_WHITE ), + rCanvas->getDevice()->getDeviceColorSpace() )), + mnOutlineWidth( nOutlineWidth ), + mrCanvas( rCanvas ), + mrTextPolygon( rTextPolygon ), + mrLinePolygon( rLinePolygon ), + mrViewState( rViewState ) + { + } + + // TextRenderer interface + virtual bool operator()( const rendering::RenderState& rRenderState ) const + { + rendering::StrokeAttributes aStrokeAttributes; + + aStrokeAttributes.StrokeWidth = mnOutlineWidth; + aStrokeAttributes.MiterLimit = 1.0; + aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT; + aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT; + aStrokeAttributes.JoinType = rendering::PathJoinType::MITER; + + rendering::RenderState aLocalState( rRenderState ); + aLocalState.DeviceColor = maFillColor; + + // TODO(P1): implement caching + + // background of text + mrCanvas->fillPolyPolygon( mrTextPolygon, + mrViewState, + aLocalState ); + + // border line of text + mrCanvas->strokePolyPolygon( mrTextPolygon, + mrViewState, + rRenderState, + aStrokeAttributes ); + + // underlines/strikethrough - background + mrCanvas->fillPolyPolygon( mrLinePolygon, + mrViewState, + aLocalState ); + // underlines/strikethrough - border + mrCanvas->strokePolyPolygon( mrLinePolygon, + mrViewState, + rRenderState, + aStrokeAttributes ); + + return true; + } + + private: + const uno::Sequence< double > maFillColor; + double mnOutlineWidth; + const uno::Reference< rendering::XCanvas >& mrCanvas; + const uno::Reference< rendering::XPolyPolygon2D >& mrTextPolygon; + const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon; + const rendering::ViewState& mrViewState; + }; + + bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::OutlineAction::render( subset )" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::OutlineAction: 0x%X", this ); + + if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd ) + return true; // empty range, render nothing + +#if 1 + // TODO(F3): Subsetting NYI for outline text! + return render( rTransformation ); +#else + const rendering::StringContext rOrigContext( mxTextLayout->getText() ); + + if( rSubset.mnSubsetBegin == 0 && + rSubset.mnSubsetEnd == rOrigContext.Length ) + { + // full range, no need for subsetting + return render( rTransformation ); + } + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + + // create and setup local Text polygon + // =================================== + + uno::Reference< rendering::XPolyPolygon2D > xTextPolygon(); + + // TODO(P3): Provide an API method for that! + + if( !xTextLayout.is() ) + return false; + + // render everything + // ================= + + return renderEffectText( + OutlineTextArrayRenderHelper( + xCanvas, + mnOutlineWidth, + xTextLayout, + xTextLines, + rViewState ), + aLocalState, + rViewState, + xCanvas, + maShadowColor, + maShadowOffset, + maReliefColor, + maReliefOffset ); +#endif + } + + ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return calcEffectTextBounds( maOutlineBounds, + ::basegfx::B2DRange( 0,0, + maLinesOverallSize.getX(), + maLinesOverallSize.getY() ), + maReliefOffset, + maShadowOffset, + aLocalState, + mpCanvas->getViewState() ); + } + + ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& /*rSubset*/ ) const + { + OSL_ENSURE( false, + "OutlineAction::getBounds(): Subset not yet supported by this object" ); + + return getBounds( rTransformation ); + } + + sal_Int32 OutlineAction::getActionCount() const + { + // TODO(F3): Subsetting NYI for outline text! + return maOffsets.getLength(); + } + + + // ====================================================================== + // + // Action factory methods + // + // ====================================================================== + + /** Create an outline action + + This method extracts the polygonal outline from the + text, and creates a properly setup OutlineAction from + it. + */ + ActionSharedPtr createOutline( const ::basegfx::B2DPoint& rStartPoint, + const ::basegfx::B2DSize& rReliefOffset, + const ::Color& rReliefColor, + const ::basegfx::B2DSize& rShadowOffset, + const ::Color& rShadowColor, + const String& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const sal_Int32* pDXArray, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const Renderer::Parameters& rParms ) + { + // operate on raw DX array here (in logical coordinate + // system), to have a higher resolution + // PolyPolygon. That polygon is then converted to + // device coordinate system. + + // #i68512# Temporarily switch off font rotation + // (which is already contained in the render state + // transformation matrix - otherwise, glyph polygons + // will be rotated twice) + const ::Font aOrigFont( rVDev.GetFont() ); + ::Font aUnrotatedFont( aOrigFont ); + aUnrotatedFont.SetOrientation(0); + rVDev.SetFont( aUnrotatedFont ); + + // TODO(F3): Don't understand parameter semantics of + // GetTextOutlines() + ::basegfx::B2DPolyPolygon aResultingPolyPolygon; + PolyPolyVector aVCLPolyPolyVector; + const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText, + static_cast<USHORT>(nStartPos), + static_cast<USHORT>(nStartPos), + static_cast<USHORT>(nLen), + TRUE, 0, pDXArray ) ); + rVDev.SetFont(aOrigFont); + + if( !bHaveOutlines ) + return ActionSharedPtr(); + + ::std::vector< sal_Int32 > aPolygonGlyphMap; + + // first glyph starts at polygon index 0 + aPolygonGlyphMap.push_back( 0 ); + + // remove offsetting from mapmode transformation + // (outline polygons must stay at origin, only need to + // be scaled) + ::basegfx::B2DHomMatrix aMapModeTransform( + rState.mapModeTransform ); + aMapModeTransform.set(0,2, 0.0); + aMapModeTransform.set(1,2, 0.0); + + PolyPolyVector::const_iterator aIter( aVCLPolyPolyVector.begin() ); + const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() ); + for( ; aIter!= aEnd; ++aIter ) + { + ::basegfx::B2DPolyPolygon aPolyPolygon; + + aPolyPolygon = aIter->getB2DPolyPolygon(); + aPolyPolygon.transform( aMapModeTransform ); + + // append result to collecting polypoly + for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i ) + { + // #i47795# Ensure closed polygons (since + // FreeType returns the glyph outlines + // open) + const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) ); + const sal_uInt32 nCount( rPoly.count() ); + if( nCount<3 || + rPoly.isClosed() ) + { + // polygon either degenerate, or + // already closed. + aResultingPolyPolygon.append( rPoly ); + } + else + { + ::basegfx::B2DPolygon aPoly(rPoly); + aPoly.setClosed(true); + + aResultingPolyPolygon.append( aPoly ); + } + } + + // TODO(F3): Depending on the semantics of + // GetTextOutlines(), this here is wrong! + + // calc next glyph index + aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() ); + } + + const uno::Sequence< double > aCharWidthSeq( + pDXArray ? + setupDXArray( pDXArray, nLen, rState ) : + setupDXArray( rText, + nStartPos, + nLen, + rVDev, + rState )); + const uno::Reference< rendering::XPolyPolygon2D > xTextPoly( + ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + rCanvas->getUNOCanvas()->getDevice(), + aResultingPolyPolygon ) ); + + if( rParms.maTextTransformation.isValid() ) + { + return ActionSharedPtr( + new OutlineAction( + rStartPoint, + rReliefOffset, + rReliefColor, + rShadowOffset, + rShadowColor, + ::basegfx::tools::getRange(aResultingPolyPolygon), + xTextPoly, + aPolygonGlyphMap, + aCharWidthSeq, + rVDev, + rCanvas, + rState, + rParms.maTextTransformation.getValue() ) ); + } + else + { + return ActionSharedPtr( + new OutlineAction( + rStartPoint, + rReliefOffset, + rReliefColor, + rShadowOffset, + rShadowColor, + ::basegfx::tools::getRange(aResultingPolyPolygon), + xTextPoly, + aPolygonGlyphMap, + aCharWidthSeq, + rVDev, + rCanvas, + rState ) ); + } + } + + } // namespace + + + // --------------------------------------------------------------------------------- + + ActionSharedPtr TextActionFactory::createTextAction( const ::Point& rStartPoint, + const ::Size& rReliefOffset, + const ::Color& rReliefColor, + const ::Size& rShadowOffset, + const ::Color& rShadowColor, + const String& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const sal_Int32* pDXArray, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const Renderer::Parameters& rParms, + bool bSubsettable ) + { + const ::Size aBaselineOffset( tools::getBaselineOffset( rState, + rVDev ) ); + // #143885# maintain (nearly) full precision positioning, + // by circumventing integer-based OutDev-mapping + const ::basegfx::B2DPoint aStartPoint( + rState.mapModeTransform * + ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(), + rStartPoint.Y() + aBaselineOffset.Height()) ); + + const ::basegfx::B2DSize aReliefOffset( + rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rReliefOffset ) ); + const ::basegfx::B2DSize aShadowOffset( + rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rShadowOffset ) ); + + if( rState.isTextOutlineModeSet ) + { + return createOutline( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + pDXArray, + rVDev, + rCanvas, + rState, + rParms ); + } + + // convert DX array to device coordinate system (and + // create it in the first place, if pDXArray is NULL) + const uno::Sequence< double > aCharWidths( + pDXArray ? + setupDXArray( pDXArray, nLen, rState ) : + setupDXArray( rText, + nStartPos, + nLen, + rVDev, + rState )); + + // determine type of text action to create + // ======================================= + + const ::Color aEmptyColor( COL_AUTO ); + + // no DX array, and no need to subset - no need to store + // DX array, then. + if( !pDXArray && !bSubsettable ) + { + // effects, or not? + if( !rState.textOverlineStyle && + !rState.textUnderlineStyle && + !rState.textStrikeoutStyle && + rReliefColor == aEmptyColor && + rShadowColor == aEmptyColor ) + { + // nope + if( rParms.maTextTransformation.isValid() ) + { + return ActionSharedPtr( new TextAction( + aStartPoint, + rText, + nStartPos, + nLen, + rCanvas, + rState, + rParms.maTextTransformation.getValue() ) ); + } + else + { + return ActionSharedPtr( new TextAction( + aStartPoint, + rText, + nStartPos, + nLen, + rCanvas, + rState ) ); + } + } + else + { + // at least one of the effects requested + if( rParms.maTextTransformation.isValid() ) + return ActionSharedPtr( new EffectTextAction( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + rVDev, + rCanvas, + rState, + rParms.maTextTransformation.getValue() ) ); + else + return ActionSharedPtr( new EffectTextAction( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + rVDev, + rCanvas, + rState ) ); + } + } + else + { + // DX array necessary - any effects? + if( !rState.textOverlineStyle && + !rState.textUnderlineStyle && + !rState.textStrikeoutStyle && + rReliefColor == aEmptyColor && + rShadowColor == aEmptyColor ) + { + // nope + if( rParms.maTextTransformation.isValid() ) + return ActionSharedPtr( new TextArrayAction( + aStartPoint, + rText, + nStartPos, + nLen, + aCharWidths, + rCanvas, + rState, + rParms.maTextTransformation.getValue() ) ); + else + return ActionSharedPtr( new TextArrayAction( + aStartPoint, + rText, + nStartPos, + nLen, + aCharWidths, + rCanvas, + rState ) ); + } + else + { + // at least one of the effects requested + if( rParms.maTextTransformation.isValid() ) + return ActionSharedPtr( new EffectTextArrayAction( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + aCharWidths, + rVDev, + rCanvas, + rState, + rParms.maTextTransformation.getValue() ) ); + else + return ActionSharedPtr( new EffectTextArrayAction( + aStartPoint, + aReliefOffset, + rReliefColor, + aShadowOffset, + rShadowColor, + rText, + nStartPos, + nLen, + aCharWidths, + rVDev, + rCanvas, + rState ) ); + } + } +#if defined __GNUC__ +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 1 + // Unreachable; to avoid bogus warning: + return ActionSharedPtr(); +#endif +#endif + } + } +} diff --git a/cppcanvas/source/mtfrenderer/textaction.hxx b/cppcanvas/source/mtfrenderer/textaction.hxx new file mode 100644 index 000000000000..53f08b63d6df --- /dev/null +++ b/cppcanvas/source/mtfrenderer/textaction.hxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * 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: textaction.hxx,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. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_TEXTACTION_HXX +#define _CPPCANVAS_TEXTACTION_HXX + +#include <com/sun/star/uno/Sequence.hxx> + +#include <action.hxx> +#include <cppcanvas/canvas.hxx> +#include <cppcanvas/renderer.hxx> +#include <tools/poly.hxx> +#include <tools/gen.hxx> + +class VirtualDevice; +class Point; +class Color; +class String; + + +/* Definition of internal::TextActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + /** Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class TextActionFactory + { + public: + /** Create text action, optionally shadow/relief effect + + Note that this method accepts all coordinates in + logical coordinates. + + @param pDXArray + Pointer to array of logical character offsets (or NULL) + + @param bSubsettable + When this parameter is set to true, the generated + action might consume slightly more memory, but is + subsettable (Action::render( Subset ) works on + characters) + */ + static ActionSharedPtr createTextAction( const ::Point& rStartPoint, + const ::Size& rReliefOffset, + const ::Color& rReliefColor, + const ::Size& rShadowOffset, + const ::Color& rShadowColor, + const ::String& rText, + sal_Int32 nStartPos, + sal_Int32 nLen, + const sal_Int32* pDXArray, + VirtualDevice& rVDev, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState, + const Renderer::Parameters& rParms, + bool bSubsettable ); + + private: + // static factory, disable big four + TextActionFactory(); + ~TextActionFactory(); + TextActionFactory(const TextActionFactory&); + TextActionFactory& operator=( const TextActionFactory& ); + }; + } +} + +#endif /* _CPPCANVAS_TEXTACTION_HXX */ diff --git a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx new file mode 100644 index 000000000000..b17baf6526a2 --- /dev/null +++ b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx @@ -0,0 +1,595 @@ +/************************************************************************* + * + * 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: transparencygroupaction.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_cppcanvas.hxx" + +#include <tools/gen.hxx> + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> +#include <canvas/canvastools.hxx> + +#include <rtl/logfile.hxx> + +#include <com/sun/star/rendering/XBitmap.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <rtl/math.hxx> + +#include <vcl/metaact.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/svapp.hxx> +#include <vcl/outdev.hxx> +#include <vcl/virdev.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/gradient.hxx> + +#include <canvas/canvastools.hxx> + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <boost/utility.hpp> + +#include "transparencygroupaction.hxx" +#include "outdevstate.hxx" +#include "mtftools.hxx" +#include "cppcanvas/vclfactory.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + // free support functions + // ====================== + namespace + { + class TransparencyGroupAction : public Action, private ::boost::noncopyable + { + public: + /** Create new transparency group action. + + @param rGroupMtf + Metafile that groups all actions to be rendered + transparent + + @param rParms + Render parameters + + @param rDstPoint + Left, top edge of destination, in current state + coordinate system + + @param rDstSize + Size of the transparency group object, in current + state coordinate system. + + @param nAlpha + Alpha value, must be in the range [0,1] + */ + TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + double nAlpha, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + /** Create new transparency group action. + + @param rGroupMtf + Metafile that groups all actions to be rendered + transparent. + + @param rAlphaGradient + VCL gradient, to be rendered into the action's alpha + channel. + + @param rParms + Render parameters + + @param rDstPoint + Left, top edge of destination, in current state + coordinate system + + @param rDstSize + Size of the transparency group object, in current + state coordinate system. + */ + TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; + virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const; + + virtual sal_Int32 getActionCount() const; + + private: + MtfAutoPtr mpGroupMtf; + GradientAutoPtr mpAlphaGradient; + + const Renderer::Parameters maParms; + + const ::basegfx::B2DSize maDstSize; + + mutable uno::Reference< rendering::XBitmap > mxBufferBitmap; // contains last rendered version + mutable ::basegfx::B2DHomMatrix maLastTransformation; // contains last active transformation + mutable Subset maLastSubset; // contains last effective subset + + // transformation for + // mxBufferBitmap content + CanvasSharedPtr mpCanvas; + rendering::RenderState maState; + const double mnAlpha; + }; + + + /** Setup transformation such that the next render call is + moved rPoint away, and scaled according to the ratio + given by src and dst size. + */ + void implSetupTransform( rendering::RenderState& rRenderState, + const ::basegfx::B2DPoint& rDstPoint ) + { + ::basegfx::B2DHomMatrix aLocalTransformation; + + aLocalTransformation.translate( rDstPoint.getX(), + rDstPoint.getY() ); + ::canvas::tools::appendToRenderState( rRenderState, + aLocalTransformation ); + } + + TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + double nAlpha, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mpGroupMtf( rGroupMtf ), + mpAlphaGradient(), + maParms( rParms ), + maDstSize( rDstSize ), + mxBufferBitmap(), + maLastTransformation(), + mpCanvas( rCanvas ), + maState(), + mnAlpha( nAlpha ) + { + tools::initRenderState(maState,rState); + implSetupTransform( maState, rDstPoint ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, + rState, + rCanvas, + rDstPoint, + NULL, + NULL ); + + maLastSubset.mnSubsetBegin = 0; + maLastSubset.mnSubsetEnd = -1; + } + + TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) : + mpGroupMtf( rGroupMtf ), + mpAlphaGradient( rAlphaGradient ), + maParms( rParms ), + maDstSize( rDstSize ), + mxBufferBitmap(), + maLastTransformation(), + mpCanvas( rCanvas ), + maState(), + mnAlpha( 1.0 ) + { + tools::initRenderState(maState,rState); + implSetupTransform( maState, rDstPoint ); + + // correct clip (which is relative to original transform) + tools::modifyClip( maState, + rState, + rCanvas, + rDstPoint, + NULL, + NULL ); + + maLastSubset.mnSubsetBegin = 0; + maLastSubset.mnSubsetEnd = -1; + } + + // TODO(P3): The whole float transparency handling is a mess, + // this should be refactored. What's more, the old idea of + // having only internal 'metaactions', and not the original + // GDIMetaFile now looks a lot less attractive. Try to move + // into the direction of having a direct GDIMetaFile2XCanvas + // renderer, and maybe a separate metafile XCanvas + // implementation. + bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TransparencyGroupAction::render()" ); + RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TransparencyGroupAction: 0x%X", this ); + + // determine overall transformation matrix (render, view, + // and passed transformation) + ::basegfx::B2DHomMatrix aTransform; + ::canvas::tools::getRenderStateTransform( aTransform, maState ); + aTransform = rTransformation * aTransform; + + ::basegfx::B2DHomMatrix aTotalTransform; + ::canvas::tools::getViewStateTransform( aTotalTransform, mpCanvas->getViewState() ); + aTotalTransform = aTotalTransform * aTransform; + + // since pure translational changes to the transformation + // does not matter, remove them before comparing + aTotalTransform.set( 0, 2, 0.0 ); + aTotalTransform.set( 1, 2, 0.0 ); + + // if there's no buffer bitmap, or as soon as the + // total transformation changes, we've got to + // re-render the bitmap + if( !mxBufferBitmap.is() || + aTotalTransform != maLastTransformation || + rSubset.mnSubsetBegin != maLastSubset.mnSubsetBegin || + rSubset.mnSubsetEnd != maLastSubset.mnSubsetEnd ) + { + DBG_TESTSOLARMUTEX(); + + // determine total scaling factor of the + // transformation matrix - need to make the bitmap + // large enough + ::basegfx::B2DTuple aScale; + ::basegfx::B2DTuple aTranslate; + double nRotate; + double nShearX; + if( !aTotalTransform.decompose( aScale, + aTranslate, + nRotate, + nShearX ) ) + { + OSL_ENSURE( false, + "TransparencyGroupAction::render(): non-decomposable transformation" ); + return false; + } + + // output size of metafile + ::Size aOutputSizePixel( ::basegfx::fround( aScale.getX() * maDstSize.getX() ), + ::basegfx::fround( aScale.getY() * maDstSize.getY() ) ); + + // pixel size of cache bitmap: round up to nearest int + ::Size aBitmapSizePixel( static_cast<sal_Int32>( aScale.getX() * maDstSize.getX() )+1, + static_cast<sal_Int32>( aScale.getY() * maDstSize.getY() )+1 ); + + ::Point aEmptyPoint; + + // render our content into an appropriately sized + // VirtualDevice with alpha channel + VirtualDevice aVDev( + *::Application::GetDefaultDevice(), 0, 0 ); + aVDev.SetOutputSizePixel( aBitmapSizePixel ); + aVDev.SetMapMode(); + + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != -1 ) + { + // true subset - extract referenced + // metaactions from mpGroupMtf + GDIMetaFile aMtf; + MetaAction* pCurrAct; + int nCurrActionIndex; + + // extract subset actions + for( nCurrActionIndex=0, + pCurrAct=mpGroupMtf->FirstAction(); + pCurrAct; + ++nCurrActionIndex, pCurrAct = mpGroupMtf->NextAction() ) + { + switch( pCurrAct->GetType() ) + { + case META_PUSH_ACTION: + case META_POP_ACTION: + case META_CLIPREGION_ACTION: + case META_ISECTRECTCLIPREGION_ACTION: + case META_ISECTREGIONCLIPREGION_ACTION: + case META_MOVECLIPREGION_ACTION: + case META_LINECOLOR_ACTION: + case META_FILLCOLOR_ACTION: + case META_TEXTCOLOR_ACTION: + case META_TEXTFILLCOLOR_ACTION: + case META_TEXTLINECOLOR_ACTION: + case META_TEXTALIGN_ACTION: + case META_FONT_ACTION: + case META_RASTEROP_ACTION: + case META_REFPOINT_ACTION: + case META_LAYOUTMODE_ACTION: + // state-changing action - copy as-is + aMtf.AddAction( pCurrAct->Clone() ); + break; + + case META_GRADIENT_ACTION: + case META_HATCH_ACTION: + case META_EPS_ACTION: + case META_COMMENT_ACTION: + case META_POINT_ACTION: + case META_PIXEL_ACTION: + case META_LINE_ACTION: + case META_RECT_ACTION: + case META_ROUNDRECT_ACTION: + case META_ELLIPSE_ACTION: + case META_ARC_ACTION: + case META_PIE_ACTION: + case META_CHORD_ACTION: + case META_POLYLINE_ACTION: + case META_POLYGON_ACTION: + case META_POLYPOLYGON_ACTION: + case META_BMP_ACTION: + case META_BMPSCALE_ACTION: + case META_BMPSCALEPART_ACTION: + case META_BMPEX_ACTION: + case META_BMPEXSCALE_ACTION: + case META_BMPEXSCALEPART_ACTION: + case META_MASK_ACTION: + case META_MASKSCALE_ACTION: + case META_MASKSCALEPART_ACTION: + case META_GRADIENTEX_ACTION: + case META_WALLPAPER_ACTION: + case META_TRANSPARENT_ACTION: + case META_FLOATTRANSPARENT_ACTION: + case META_TEXT_ACTION: + case META_TEXTARRAY_ACTION: + case META_TEXTLINE_ACTION: + case META_TEXTRECT_ACTION: + case META_STRETCHTEXT_ACTION: + // output-generating action - only + // copy, if we're within the + // requested subset + if( rSubset.mnSubsetBegin <= nCurrActionIndex && + rSubset.mnSubsetEnd > nCurrActionIndex ) + { + aMtf.AddAction( pCurrAct->Clone() ); + } + break; + + default: + OSL_ENSURE( false, + "Unknown meta action type encountered" ); + break; + } + } + + aVDev.DrawTransparent( aMtf, + aEmptyPoint, + aOutputSizePixel, + *mpAlphaGradient ); + } + else + { + // no subsetting - render whole mtf + aVDev.DrawTransparent( *mpGroupMtf, + aEmptyPoint, + aOutputSizePixel, + *mpAlphaGradient ); + } + + + // update buffered bitmap and transformation + BitmapSharedPtr aBmp( VCLFactory::getInstance().createBitmap( + mpCanvas, + aVDev.GetBitmapEx( + aEmptyPoint, + aBitmapSizePixel ) ) ); + mxBufferBitmap = aBmp->getUNOBitmap(); + maLastTransformation = aTotalTransform; + maLastSubset = rSubset; + } + + // determine target transformation (we can't simply pass + // aTotalTransform as assembled above, since we must take + // the canvas' view state as is, it might contain clipping + // (which, in turn, is relative to the view + // transformation)) + + // given that aTotalTransform is the identity + // transformation, we could simply render our bitmap + // as-is. Now, since the mxBufferBitmap content already + // accounts for scale changes in the overall + // transformation, we must factor this out + // before. Generally, the transformation matrix should be + // structured like this: + // Translation*Rotation*Shear*Scale. Thus, to neutralize + // the contained scaling, we've got to right-multiply with + // the inverse. + ::basegfx::B2ISize aBmpSize( + ::basegfx::unotools::b2ISizeFromIntegerSize2D( mxBufferBitmap->getSize() ) ); + + ::basegfx::B2DHomMatrix aScaleCorrection; + aScaleCorrection.scale( (double)maDstSize.getX() / aBmpSize.getX(), + (double)maDstSize.getY() / aBmpSize.getY() ); + aTransform = aTransform * aScaleCorrection; + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::setRenderStateTransform(aLocalState, aTransform); + +#ifdef SPECIAL_DEBUG + aLocalState.Clip.clear(); + aLocalState.DeviceColor = + ::vcl::unotools::colorToDoubleSequence( + ::Color( 0x80FF0000 ), + mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ); + + if( maState.Clip.is() ) + mpCanvas->getUNOCanvas()->fillPolyPolygon( maState.Clip, + mpCanvas->getViewState(), + aLocalState ); + + aLocalState.DeviceColor = maState.DeviceColor; +#endif + + if( ::rtl::math::approxEqual(mnAlpha, 1.0) ) + { + // no further alpha changes necessary -> draw directly + mpCanvas->getUNOCanvas()->drawBitmap( mxBufferBitmap, + mpCanvas->getViewState(), + aLocalState ); + } + else + { + // add alpha modulation value to DeviceColor + uno::Sequence<rendering::ARGBColor> aCols(1); + aCols[0] = rendering::ARGBColor( mnAlpha, 1.0, 1.0, 1.0); + aLocalState.DeviceColor = + mpCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()->convertFromARGB( + aCols); + + mpCanvas->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap, + mpCanvas->getViewState(), + aLocalState ); + } + + return true; + } + + // TODO(P3): The whole float transparency handling is a mess, + // this should be refactored. What's more, the old idea of + // having only internal 'metaactions', and not the original + // GDIMetaFile now looks a lot less attractive. Try to move + // into the direction of having a direct GDIMetaFile2XCanvas + // renderer, and maybe a separate metafile XCanvas + // implementation. + bool TransparencyGroupAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + Subset aSubset; + + aSubset.mnSubsetBegin = 0; + aSubset.mnSubsetEnd = -1; + + return render( rTransformation, aSubset ); + } + + ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const + { + rendering::RenderState aLocalState( maState ); + ::canvas::tools::prependToRenderState(aLocalState, rTransformation); + + return tools::calcDevicePixelBounds( + ::basegfx::B2DRange( 0,0, + maDstSize.getX(), + maDstSize.getY() ), + mpCanvas->getViewState(), + aLocalState ); + } + + ::basegfx::B2DRange TransparencyGroupAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, + const Subset& rSubset ) const + { + // TODO(F3): Currently, the bounds for + // TransparencyGroupAction subsets equal those of the + // full set, although this action is able to render + // true subsets. + + // polygon only contains a single action, empty bounds + // if subset requests different range + if( rSubset.mnSubsetBegin != 0 || + rSubset.mnSubsetEnd != 1 ) + return ::basegfx::B2DRange(); + + return getBounds( rTransformation ); + } + + sal_Int32 TransparencyGroupAction::getActionCount() const + { + return mpGroupMtf.get() ? mpGroupMtf->GetActionCount() : 0; + } + + } + + ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + double nAlpha, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf, + rParms, + rDstPoint, + rDstSize, + nAlpha, + rCanvas, + rState ) ); + } + + ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf, + rAlphaGradient, + rParms, + rDstPoint, + rDstSize, + rCanvas, + rState ) ); + } + + } +} diff --git a/cppcanvas/source/mtfrenderer/transparencygroupaction.hxx b/cppcanvas/source/mtfrenderer/transparencygroupaction.hxx new file mode 100644 index 000000000000..db102eba60bb --- /dev/null +++ b/cppcanvas/source/mtfrenderer/transparencygroupaction.hxx @@ -0,0 +1,143 @@ +/************************************************************************* + * + * 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: transparencygroupaction.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 _CPPCANVAS_TRANSPARENCYGROUPACTION_HXX +#define _CPPCANVAS_TRANSPARENCYGROUPACTION_HXX + +#include <cppcanvas/canvas.hxx> +#include <cppcanvas/renderer.hxx> +#include <action.hxx> + +#include <memory> // auto_ptr + +namespace basegfx { + class B2DPoint; + class B2DVector; +} + +class GDIMetaFile; +class Gradient; + + +/* Definition of internal::TransparencyGroupActionFactory class */ + +namespace cppcanvas +{ + namespace internal + { + struct OutDevState; + + typedef ::std::auto_ptr< GDIMetaFile > MtfAutoPtr; + typedef ::std::auto_ptr< Gradient > GradientAutoPtr; + + /** Transparency group action. + + This action groups a bunch of other actions, to be + rendered with the given transparency setting against the + background. + + Creates encapsulated converters between GDIMetaFile and + XCanvas. The Canvas argument is deliberately placed at the + constructor, to force reconstruction of this object for a + new canvas. This considerably eases internal state + handling, since a lot of the internal state (e.g. fonts, + text layout) is Canvas-dependent. + */ + class TransparencyGroupActionFactory + { + public: + /** Create new transparency group action. + + @param rGroupMtf + Metafile that groups all actions to be rendered + transparent + + @param rParms + Render parameters + + @param rDstPoint + Left, top edge of destination, in current state + coordinate system + + @param rDstSize + Size of the transparency group object, in current + state coordinate system. + + @param nAlpha + Alpha value, must be in the range [0,1] + */ + static ActionSharedPtr createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + double nAlpha, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + /** Create new transparency group action. + + @param rGroupMtf + Metafile that groups all actions to be rendered + transparent. + + @param rAlphaGradient + VCL gradient, to be rendered into the action's alpha + channel. + + @param rParms + Render parameters + + @param rDstPoint + Left, top edge of destination, in current state + coordinate system + + @param rDstSize + Size of the transparency group object, in current + state coordinate system. + */ + static ActionSharedPtr createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::basegfx::B2DPoint& rDstPoint, + const ::basegfx::B2DVector& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ); + + private: + // static factory, disable big four + TransparencyGroupActionFactory(); + ~TransparencyGroupActionFactory(); + TransparencyGroupActionFactory(const TransparencyGroupActionFactory&); + TransparencyGroupActionFactory& operator=( const TransparencyGroupActionFactory& ); + }; + } +} + +#endif /*_CPPCANVAS_TRANSPARENCYGROUPACTION_HXX */ diff --git a/cppcanvas/source/tools/canvasgraphichelper.cxx b/cppcanvas/source/tools/canvasgraphichelper.cxx new file mode 100644 index 000000000000..e4d92ff6ebfb --- /dev/null +++ b/cppcanvas/source/tools/canvasgraphichelper.cxx @@ -0,0 +1,154 @@ +/************************************************************************* + * + * 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: canvasgraphichelper.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_cppcanvas.hxx" + +#include <canvasgraphichelper.hxx> + +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> + +#include <canvas/canvastools.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include <cppcanvas/polypolygon.hxx> +#include "tools.hxx" + + +using namespace ::com::sun::star; + +/* Implementation of CanvasGraphicHelper class */ + +namespace cppcanvas +{ + + namespace internal + { + CanvasGraphicHelper::CanvasGraphicHelper( const CanvasSharedPtr& rParentCanvas ) : + maClipPolyPolygon(), + mpCanvas( rParentCanvas ), + mxGraphicDevice() + { + OSL_ENSURE( mpCanvas.get() != NULL && + mpCanvas->getUNOCanvas().is(), + "CanvasGraphicHelper::CanvasGraphicHelper: no valid canvas" ); + + if( mpCanvas.get() != NULL && + mpCanvas->getUNOCanvas().is() ) + { + mxGraphicDevice = mpCanvas->getUNOCanvas()->getDevice(); + } + + ::canvas::tools::initRenderState( maRenderState ); + } + + void CanvasGraphicHelper::setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ) + { + ::canvas::tools::setRenderStateTransform( maRenderState, rMatrix ); + } + + ::basegfx::B2DHomMatrix CanvasGraphicHelper::getTransformation() const + { + ::basegfx::B2DHomMatrix aMatrix; + return ::canvas::tools::getRenderStateTransform( aMatrix, + maRenderState ); + } + + void CanvasGraphicHelper::setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) + { + // TODO(T3): not thread-safe. B2DPolyPolygon employs copy-on-write + maClipPolyPolygon.reset( rClipPoly ); + maRenderState.Clip.clear(); + } + + void CanvasGraphicHelper::setClip() + { + maClipPolyPolygon.reset(); + maRenderState.Clip.clear(); + } + + ::basegfx::B2DPolyPolygon const* CanvasGraphicHelper::getClip() const + { + return !maClipPolyPolygon ? NULL : &(*maClipPolyPolygon); + } + + const rendering::RenderState& CanvasGraphicHelper::getRenderState() const + { + if( maClipPolyPolygon && !maRenderState.Clip.is() ) + { + uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return maRenderState; + + maRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + xCanvas->getDevice(), + *maClipPolyPolygon ); + } + + return maRenderState; + } + + void CanvasGraphicHelper::setRGBAColor( Color::IntSRGBA aColor ) + { + maRenderState.DeviceColor = tools::intSRGBAToDoubleSequence( mxGraphicDevice, + aColor ); + } + + Color::IntSRGBA CanvasGraphicHelper::getRGBAColor() const + { + return tools::doubleSequenceToIntSRGBA( mxGraphicDevice, + maRenderState.DeviceColor ); + } + + void CanvasGraphicHelper::setCompositeOp( CompositeOp aOp ) + { + maRenderState.CompositeOperation = (sal_Int8)aOp; + } + + CanvasGraphic::CompositeOp CanvasGraphicHelper::getCompositeOp() const + { + return static_cast<CompositeOp>(maRenderState.CompositeOperation); + } + + CanvasSharedPtr CanvasGraphicHelper::getCanvas() const + { + return mpCanvas; + } + + uno::Reference< rendering::XGraphicDevice > CanvasGraphicHelper::getGraphicDevice() const + { + return mxGraphicDevice; + } + + } +} diff --git a/cppcanvas/source/tools/makefile.mk b/cppcanvas/source/tools/makefile.mk new file mode 100644 index 000000000000..4a222544fc44 --- /dev/null +++ b/cppcanvas/source/tools/makefile.mk @@ -0,0 +1,54 @@ +#************************************************************************* +# +# 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.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. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=cppcanvas +TARGET=cppcanvastools +ENABLE_EXCEPTIONS=TRUE + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF + +SLOFILES = $(SLO)$/canvasgraphichelper.obj \ + $(SLO)$/tools.obj + +# ========================================================================== + +.INCLUDE : target.mk diff --git a/cppcanvas/source/tools/tools.cxx b/cppcanvas/source/tools/tools.cxx new file mode 100644 index 000000000000..0428f13ad9c3 --- /dev/null +++ b/cppcanvas/source/tools/tools.cxx @@ -0,0 +1,65 @@ +/************************************************************************* + * + * 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: tools.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_cppcanvas.hxx" + +#include <tools.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace tools + { + uno::Sequence< double > intSRGBAToDoubleSequence( const uno::Reference< rendering::XGraphicDevice >&, + Color::IntSRGBA aColor ) + { + uno::Sequence< double > aRes( 4 ); + + aRes[0] = getRed(aColor) / 255.0; + aRes[1] = getGreen(aColor) / 255.0; + aRes[2] = getBlue(aColor) / 255.0; + aRes[3] = getAlpha(aColor) / 255.0; + + return aRes; + } + + Color::IntSRGBA doubleSequenceToIntSRGBA( const uno::Reference< rendering::XGraphicDevice >&, + const uno::Sequence< double >& rColor ) + { + return makeColor( static_cast<sal_uInt8>( 255*rColor[0] + .5 ), + static_cast<sal_uInt8>( 255*rColor[1] + .5 ), + static_cast<sal_uInt8>( 255*rColor[2] + .5 ), + static_cast<sal_uInt8>( 255*rColor[3] + .5 ) ); + } + } +} diff --git a/cppcanvas/source/wrapper/basegfxfactory.cxx b/cppcanvas/source/wrapper/basegfxfactory.cxx new file mode 100644 index 000000000000..debc296807cd --- /dev/null +++ b/cppcanvas/source/wrapper/basegfxfactory.cxx @@ -0,0 +1,167 @@ +/************************************************************************* + * + * 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: basegfxfactory.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_cppcanvas.hxx" + +#include <rtl/instance.hxx> +#include <osl/getglobalmutex.hxx> +#include <osl/diagnose.h> + +#include <com/sun/star/rendering/InterpolationMode.hpp> + +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <cppcanvas/basegfxfactory.hxx> + +#include "implpolypolygon.hxx" +#include "implbitmap.hxx" +#include "impltext.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + /* Singleton handling */ + struct InitInstance2 + { + BaseGfxFactory* operator()() + { + return new BaseGfxFactory(); + } + }; + + BaseGfxFactory& BaseGfxFactory::getInstance() + { + return *rtl_Instance< BaseGfxFactory, InitInstance2, ::osl::MutexGuard, + ::osl::GetGlobalMutex >::create( + InitInstance2(), ::osl::GetGlobalMutex()); + } + + BaseGfxFactory::BaseGfxFactory() + { + } + + BaseGfxFactory::~BaseGfxFactory() + { + } + + PolyPolygonSharedPtr BaseGfxFactory::createPolyPolygon( const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DPolygon& rPoly ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "BaseGfxFactory::createPolyPolygon(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return PolyPolygonSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return PolyPolygonSharedPtr(); + + return PolyPolygonSharedPtr( + new internal::ImplPolyPolygon( rCanvas, + ::basegfx::unotools::xPolyPolygonFromB2DPolygon( + xCanvas->getDevice(), + rPoly) ) ); + } + + PolyPolygonSharedPtr BaseGfxFactory::createPolyPolygon( const CanvasSharedPtr& rCanvas, + const ::basegfx::B2DPolyPolygon& rPolyPoly ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "BaseGfxFactory::createPolyPolygon(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return PolyPolygonSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return PolyPolygonSharedPtr(); + + return PolyPolygonSharedPtr( + new internal::ImplPolyPolygon( rCanvas, + ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + xCanvas->getDevice(), + rPolyPoly) ) ); + } + + BitmapSharedPtr BaseGfxFactory::createBitmap( const CanvasSharedPtr& rCanvas, + const ::basegfx::B2ISize& rSize ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "BaseGfxFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( + new internal::ImplBitmap( rCanvas, + xCanvas->getDevice()->createCompatibleBitmap( + ::basegfx::unotools::integerSize2DFromB2ISize(rSize) ) ) ); + } + + BitmapSharedPtr BaseGfxFactory::createAlphaBitmap( const CanvasSharedPtr& rCanvas, + const ::basegfx::B2ISize& rSize ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "BaseGfxFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( + new internal::ImplBitmap( rCanvas, + xCanvas->getDevice()->createCompatibleAlphaBitmap( + ::basegfx::unotools::integerSize2DFromB2ISize(rSize) ) ) ); + } + + TextSharedPtr BaseGfxFactory::createText( const CanvasSharedPtr& rCanvas, const ::rtl::OUString& rText ) const + { + return TextSharedPtr( new internal::ImplText( rCanvas, + rText ) ); + } + +} diff --git a/cppcanvas/source/wrapper/implbitmap.cxx b/cppcanvas/source/wrapper/implbitmap.cxx new file mode 100644 index 000000000000..080bc215063a --- /dev/null +++ b/cppcanvas/source/wrapper/implbitmap.cxx @@ -0,0 +1,129 @@ +/************************************************************************* + * + * 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: implbitmap.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_cppcanvas.hxx" + +#include "implbitmap.hxx" +#include "implbitmapcanvas.hxx" + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <canvas/canvastools.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + + namespace internal + { + + ImplBitmap::ImplBitmap( const CanvasSharedPtr& rParentCanvas, + const uno::Reference< rendering::XBitmap >& rBitmap ) : + CanvasGraphicHelper( rParentCanvas ), + mxBitmap( rBitmap ), + mpBitmapCanvas() + { + OSL_ENSURE( mxBitmap.is(), "ImplBitmap::ImplBitmap: no valid bitmap" ); + + uno::Reference< rendering::XBitmapCanvas > xBitmapCanvas( rBitmap, + uno::UNO_QUERY ); + if( xBitmapCanvas.is() ) + mpBitmapCanvas.reset( new ImplBitmapCanvas( + uno::Reference< rendering::XBitmapCanvas >(rBitmap, + uno::UNO_QUERY) ) ); + } + + ImplBitmap::~ImplBitmap() + { + } + + bool ImplBitmap::draw() const + { + CanvasSharedPtr pCanvas( getCanvas() ); + + OSL_ENSURE( pCanvas.get() != NULL && + pCanvas->getUNOCanvas().is(), + "ImplBitmap::draw: invalid canvas" ); + + if( pCanvas.get() == NULL || + !pCanvas->getUNOCanvas().is() ) + { + return false; + } + + // TODO(P1): implement caching + pCanvas->getUNOCanvas()->drawBitmap( mxBitmap, + pCanvas->getViewState(), + getRenderState() ); + + return true; + } + + bool ImplBitmap::drawAlphaModulated( double nAlphaModulation ) const + { + CanvasSharedPtr pCanvas( getCanvas() ); + + OSL_ENSURE( pCanvas.get() != NULL && + pCanvas->getUNOCanvas().is(), + "ImplBitmap::drawAlphaModulated(): invalid canvas" ); + + if( pCanvas.get() == NULL || + !pCanvas->getUNOCanvas().is() ) + { + return false; + } + + rendering::RenderState aLocalState( getRenderState() ); + uno::Sequence<rendering::ARGBColor> aCol(1); + aCol[0] = rendering::ARGBColor( nAlphaModulation, 1.0, 1.0, 1.0 ); + aLocalState.DeviceColor = + pCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace()->convertFromARGB(aCol); + + // TODO(P1): implement caching + pCanvas->getUNOCanvas()->drawBitmapModulated( mxBitmap, + pCanvas->getViewState(), + aLocalState ); + + return true; + } + + BitmapCanvasSharedPtr ImplBitmap::getBitmapCanvas() const + { + return mpBitmapCanvas; + } + + uno::Reference< rendering::XBitmap > ImplBitmap::getUNOBitmap() const + { + return mxBitmap; + } + } +} diff --git a/cppcanvas/source/wrapper/implbitmap.hxx b/cppcanvas/source/wrapper/implbitmap.hxx new file mode 100644 index 000000000000..c910476875e1 --- /dev/null +++ b/cppcanvas/source/wrapper/implbitmap.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: implbitmap.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 _CPPCANVAS_IMPLBITMAP_HXX +#define _CPPCANVAS_IMPLBITMAP_HXX + +#include <com/sun/star/uno/Reference.hxx> +#ifndef _COM_SUN_STAR_RENDERING_XBITMAP_HPP__ +#include <com/sun/star/rendering/XBitmap.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_XGRAPHICDEVICE_HPP__ +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#endif + +#include <cppcanvas/bitmap.hxx> +#include <canvasgraphichelper.hxx> + + +/*Definition of ImplBitmap */ + +namespace cppcanvas +{ + + namespace internal + { + // share partial CanvasGraphic implementation from CanvasGraphicHelper + class ImplBitmap : public virtual ::cppcanvas::Bitmap, protected CanvasGraphicHelper + { + public: + + ImplBitmap( const CanvasSharedPtr& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap >& rBitmap ); + + virtual ~ImplBitmap(); + + // CanvasGraphic implementation (that was not already implemented by CanvasGraphicHelper) + virtual bool draw() const; + virtual bool drawAlphaModulated( double nAlphaModulation ) const; + + virtual BitmapCanvasSharedPtr getBitmapCanvas() const; + + // Bitmap implementation + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap > getUNOBitmap() const; + + private: + // default: disabled copy/assignment + ImplBitmap(const ImplBitmap&); + ImplBitmap& operator=( const ImplBitmap& ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > mxBitmap; + BitmapCanvasSharedPtr mpBitmapCanvas; + }; + } +} + +#endif /* _CPPCANVAS_IMPLBITMAP_HXX */ diff --git a/cppcanvas/source/wrapper/implbitmapcanvas.cxx b/cppcanvas/source/wrapper/implbitmapcanvas.cxx new file mode 100644 index 000000000000..8c7caa8ece20 --- /dev/null +++ b/cppcanvas/source/wrapper/implbitmapcanvas.cxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * 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: implbitmapcanvas.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_cppcanvas.hxx" + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/XBitmapCanvas.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include "implbitmapcanvas.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + ImplBitmapCanvas::ImplBitmapCanvas( const uno::Reference< rendering::XBitmapCanvas >& rCanvas ) : + ImplCanvas( uno::Reference< rendering::XCanvas >(rCanvas, + uno::UNO_QUERY) ), + mxBitmapCanvas( rCanvas ), + mxBitmap( rCanvas, + uno::UNO_QUERY ) + { + OSL_ENSURE( mxBitmapCanvas.is(), "ImplBitmapCanvas::ImplBitmapCanvas(): Invalid canvas" ); + OSL_ENSURE( mxBitmap.is(), "ImplBitmapCanvas::ImplBitmapCanvas(): Invalid bitmap" ); + } + + ImplBitmapCanvas::~ImplBitmapCanvas() + { + } + + ::basegfx::B2ISize ImplBitmapCanvas::getSize() const + { + OSL_ENSURE( mxBitmap.is(), "ImplBitmapCanvas::getSize(): Invalid canvas" ); + return ::basegfx::unotools::b2ISizeFromIntegerSize2D( mxBitmap->getSize() ); + } + + CanvasSharedPtr ImplBitmapCanvas::clone() const + { + return BitmapCanvasSharedPtr( new ImplBitmapCanvas( *this ) ); + } + } +} diff --git a/cppcanvas/source/wrapper/implbitmapcanvas.hxx b/cppcanvas/source/wrapper/implbitmapcanvas.hxx new file mode 100644 index 000000000000..1aac433ce782 --- /dev/null +++ b/cppcanvas/source/wrapper/implbitmapcanvas.hxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * 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: implbitmapcanvas.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 _CPPCANVAS_IMPLBITMAPCANVAS_HXX +#define _CPPCANVAS_IMPLBITMAPCANVAS_HXX + +#ifndef _COM_SUN_STAR_RENDERING_XBITMAPCANVAS_HPP__ +#include <com/sun/star/rendering/XBitmapCanvas.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_XBITMAP_HPP__ +#include <com/sun/star/rendering/XBitmap.hpp> +#endif + +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif +#include <basegfx/vector/b2dsize.hxx> +#include <cppcanvas/bitmapcanvas.hxx> + +#include <implcanvas.hxx> + + +namespace cppcanvas +{ + namespace internal + { + // share Canvas implementation from ImplCanvas + class ImplBitmapCanvas : public virtual BitmapCanvas, protected virtual ImplCanvas + { + public: + ImplBitmapCanvas( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmapCanvas >& rCanvas ); + virtual ~ImplBitmapCanvas(); + + virtual ::basegfx::B2ISize getSize() const; + + virtual CanvasSharedPtr clone() const; + + // take compiler-provided default copy constructor + //ImplBitmapCanvas(const ImplBitmapCanvas&); + + private: + // default: disabled assignment + ImplBitmapCanvas& operator=( const ImplBitmapCanvas& ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > mxBitmapCanvas; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap > mxBitmap; + }; + } +} + +#endif /* _CPPCANVAS_IMPLBITMAPCANVAS_HXX */ diff --git a/cppcanvas/source/wrapper/implcanvas.cxx b/cppcanvas/source/wrapper/implcanvas.cxx new file mode 100644 index 000000000000..7dac599a1b3a --- /dev/null +++ b/cppcanvas/source/wrapper/implcanvas.cxx @@ -0,0 +1,144 @@ +/************************************************************************* + * + * 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: implcanvas.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_cppcanvas.hxx" + +#include <rtl/ustring.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include <com/sun/star/rendering/XCanvas.hpp> + +#include <canvas/canvastools.hxx> +#include <cppcanvas/polypolygon.hxx> + +#include "implfont.hxx" +#include "implcolor.hxx" +#include "implcanvas.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + ImplCanvas::ImplCanvas( const uno::Reference< rendering::XCanvas >& xCanvas ) : + maViewState(), + maClipPolyPolygon(), + mxCanvas( xCanvas ) + { + OSL_ENSURE( mxCanvas.is(), "Canvas::Canvas() invalid XCanvas" ); + + ::canvas::tools::initViewState( maViewState ); + } + + ImplCanvas::~ImplCanvas() + { + } + + void ImplCanvas::setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ) + { + ::canvas::tools::setViewStateTransform( maViewState, rMatrix ); + } + + ::basegfx::B2DHomMatrix ImplCanvas::getTransformation() const + { + ::basegfx::B2DHomMatrix aMatrix; + return ::canvas::tools::getViewStateTransform( aMatrix, + maViewState ); + } + + void ImplCanvas::setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) + { + // TODO(T3): not thread-safe. B2DPolyPolygon employs copy-on-write + maClipPolyPolygon.reset( rClipPoly ); + maViewState.Clip.clear(); + } + + void ImplCanvas::setClip() + { + maClipPolyPolygon.reset(); + maViewState.Clip.clear(); + } + + ::basegfx::B2DPolyPolygon const* ImplCanvas::getClip() const + { + return !maClipPolyPolygon ? NULL : &(*maClipPolyPolygon); + } + + FontSharedPtr ImplCanvas::createFont( const ::rtl::OUString& rFontName, const double& rCellSize ) const + { + return FontSharedPtr( new ImplFont( getUNOCanvas(), rFontName, rCellSize ) ); + } + + ColorSharedPtr ImplCanvas::createColor() const + { + return ColorSharedPtr( new ImplColor( getUNOCanvas()->getDevice() ) ); + } + + CanvasSharedPtr ImplCanvas::clone() const + { + return CanvasSharedPtr( new ImplCanvas( *this ) ); + } + + void ImplCanvas::clear() const + { + OSL_ENSURE( mxCanvas.is(), "ImplCanvas::clear(): Invalid XCanvas" ); + mxCanvas->clear(); + } + + uno::Reference< rendering::XCanvas > ImplCanvas::getUNOCanvas() const + { + OSL_ENSURE( mxCanvas.is(), "ImplCanvas::getUNOCanvas(): Invalid XCanvas" ); + + return mxCanvas; + } + + rendering::ViewState ImplCanvas::getViewState() const + { + if( maClipPolyPolygon && !maViewState.Clip.is() ) + { + if( !mxCanvas.is() ) + return maViewState; + + maViewState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + mxCanvas->getDevice(), + *maClipPolyPolygon ); + } + + return maViewState; + } + + } +} diff --git a/cppcanvas/source/wrapper/implcanvas.hxx b/cppcanvas/source/wrapper/implcanvas.hxx new file mode 100644 index 000000000000..48563bb5a348 --- /dev/null +++ b/cppcanvas/source/wrapper/implcanvas.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: implcanvas.hxx,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. + * + ************************************************************************/ + +#ifndef _CPPCANVAS_IMPLCANVAS_HXX +#define _CPPCANVAS_IMPLCANVAS_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/ViewState.hpp> +#include <cppcanvas/canvas.hxx> + +#include <boost/optional.hpp> + +namespace rtl +{ + class OUString; +} + +namespace basegfx +{ + class B2DHomMatrix; + class B2DPolyPolygon; +} + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XCanvas; +} } } } + + +/* Definition of ImplCanvas */ + +namespace cppcanvas +{ + + namespace internal + { + + class ImplCanvas : public virtual Canvas + { + public: + ImplCanvas( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas >& rCanvas ); + virtual ~ImplCanvas(); + + virtual void setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ); + virtual ::basegfx::B2DHomMatrix getTransformation() const; + + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ); + virtual void setClip(); + virtual ::basegfx::B2DPolyPolygon const* getClip() const; + + virtual FontSharedPtr createFont( const ::rtl::OUString& rFontName, const double& rCellSize ) const; + + virtual ColorSharedPtr createColor() const; + + virtual CanvasSharedPtr clone() const; + + virtual void clear() const; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas > getUNOCanvas() const; + + virtual ::com::sun::star::rendering::ViewState getViewState() const; + + // take compiler-provided default copy constructor + //ImplCanvas(const ImplCanvas&); + + private: + // default: disabled assignment + ImplCanvas& operator=( const ImplCanvas& ); + + mutable ::com::sun::star::rendering::ViewState maViewState; + boost::optional<basegfx::B2DPolyPolygon> maClipPolyPolygon; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas > mxCanvas; + }; + + } +} + +#endif /* _CPPCANVAS_IMPLCANVAS_HXX */ diff --git a/cppcanvas/source/wrapper/implcolor.cxx b/cppcanvas/source/wrapper/implcolor.cxx new file mode 100644 index 000000000000..5deff0ee3757 --- /dev/null +++ b/cppcanvas/source/wrapper/implcolor.cxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * 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: implcolor.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_cppcanvas.hxx" + +#include <implcolor.hxx> +#include <tools.hxx> + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + ImplColor::ImplColor( const uno::Reference< rendering::XGraphicDevice >& rDevice ) : + mxDevice( rDevice ) + { + OSL_ENSURE( mxDevice.is(), "ImplColor::ImplColor(): Invalid graphic device" ); + } + + ImplColor::~ImplColor() + { + } + + Color::IntSRGBA ImplColor::getIntSRGBA( uno::Sequence< double >& rDeviceColor ) const + { + OSL_ENSURE( mxDevice.is(), "ImplColor::getIntSRGBA(): Invalid graphic device" ); + + // TODO(F1): Color space handling + return tools::doubleSequenceToIntSRGBA( mxDevice, rDeviceColor ); + } + + uno::Sequence< double > ImplColor::getDeviceColor( Color::IntSRGBA aSRGBA ) const + { + OSL_ENSURE( mxDevice.is(), "ImplColor::getDeviceColor(): Invalid graphic device" ); + + // TODO(F1): Color space handling + return tools::intSRGBAToDoubleSequence( mxDevice, aSRGBA ); + } + + } +} diff --git a/cppcanvas/source/wrapper/implcolor.hxx b/cppcanvas/source/wrapper/implcolor.hxx new file mode 100644 index 000000000000..8515353dbac7 --- /dev/null +++ b/cppcanvas/source/wrapper/implcolor.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: implcolor.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 _CPPCANVAS_IMPLCOLOR_HXX +#define _CPPCANVAS_IMPLCOLOR_HXX + +#include <com/sun/star/uno/Sequence.hxx> + +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif + +#ifndef _COM_SUN_STAR_RENDERING_XGRAPHICDEVICE_HPP__ +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#endif +#include <cppcanvas/color.hxx> + + +/* Definition of Color class */ + +namespace cppcanvas +{ + namespace internal + { + class ImplColor : public Color + { + public: + ImplColor( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice >& rDevice ); + virtual ~ImplColor(); + + virtual IntSRGBA getIntSRGBA( ::com::sun::star::uno::Sequence< double >& rDeviceColor ) const; + virtual ::com::sun::star::uno::Sequence< double > getDeviceColor( IntSRGBA aSRGBA ) const; + + private: + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > mxDevice; + }; + + } +} + +#endif /* _CPPCANVAS_IMPLCOLOR_HXX */ diff --git a/cppcanvas/source/wrapper/implcustomsprite.cxx b/cppcanvas/source/wrapper/implcustomsprite.cxx new file mode 100644 index 000000000000..d151cf9d02a9 --- /dev/null +++ b/cppcanvas/source/wrapper/implcustomsprite.cxx @@ -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: implcustomsprite.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_cppcanvas.hxx" + +#include <basegfx/polygon/b2dpolypolygon.hxx> + +#include "implcustomsprite.hxx" +#include "implcanvas.hxx" + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + ImplCustomSprite::ImplCustomSprite( const uno::Reference< rendering::XSpriteCanvas >& rParentCanvas, + const uno::Reference< rendering::XCustomSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ) : + ImplSprite( rParentCanvas, + uno::Reference< rendering::XSprite >(rSprite, + uno::UNO_QUERY), + rTransformArbiter ), + mpLastCanvas(), + mxCustomSprite( rSprite ) + { + OSL_ENSURE( rParentCanvas.is(), "ImplCustomSprite::ImplCustomSprite(): Invalid canvas" ); + OSL_ENSURE( mxCustomSprite.is(), "ImplCustomSprite::ImplCustomSprite(): Invalid sprite" ); + } + + ImplCustomSprite::~ImplCustomSprite() + { + } + + CanvasSharedPtr ImplCustomSprite::getContentCanvas() const + { + OSL_ENSURE( mxCustomSprite.is(), "ImplCustomSprite::getContentCanvas(): Invalid sprite" ); + + if( !mxCustomSprite.is() ) + return CanvasSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( mxCustomSprite->getContentCanvas() ); + + if( !xCanvas.is() ) + return CanvasSharedPtr(); + + // cache content canvas C++ wrapper + if( mpLastCanvas.get() == NULL || + mpLastCanvas->getUNOCanvas() != xCanvas ) + { + mpLastCanvas = CanvasSharedPtr( new ImplCanvas( xCanvas ) ); + } + + return mpLastCanvas; + } + } +} diff --git a/cppcanvas/source/wrapper/implcustomsprite.hxx b/cppcanvas/source/wrapper/implcustomsprite.hxx new file mode 100644 index 000000000000..1991beccbbd4 --- /dev/null +++ b/cppcanvas/source/wrapper/implcustomsprite.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: implcustomsprite.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 _CPPCANVAS_IMPLCUSTOMSPRITE_HXX +#define _CPPCANVAS_IMPLCUSTOMSPRITE_HXX + +#include <sal/types.h> + +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif +#include <cppcanvas/canvas.hxx> +#include <cppcanvas/customsprite.hxx> + +#include <implsprite.hxx> +#include <implspritecanvas.hxx> + + +namespace cppcanvas +{ + namespace internal + { + // share Sprite implementation of ImplSprite + class ImplCustomSprite : public virtual CustomSprite, protected virtual ImplSprite + { + public: + ImplCustomSprite( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCustomSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ); + virtual ~ImplCustomSprite(); + + virtual CanvasSharedPtr getContentCanvas() const; + + private: + // default: disabled copy/assignment + ImplCustomSprite(const ImplCustomSprite&); + ImplCustomSprite& operator=( const ImplCustomSprite& ); + + mutable CanvasSharedPtr mpLastCanvas; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCustomSprite > mxCustomSprite; + }; + } +} + +#endif /* _CPPCANVAS_IMPLCUSTOMSPRITE_HXX */ diff --git a/cppcanvas/source/wrapper/implfont.cxx b/cppcanvas/source/wrapper/implfont.cxx new file mode 100644 index 000000000000..03133c0bfcca --- /dev/null +++ b/cppcanvas/source/wrapper/implfont.cxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * 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: implfont.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_cppcanvas.hxx" + +#include <implfont.hxx> +#include <canvas/canvastools.hxx> + + +using namespace ::com::sun::star; + +/* Definition of Font class */ + +namespace cppcanvas +{ + namespace internal + { + + ImplFont::ImplFont( const uno::Reference< rendering::XCanvas >& rCanvas, + const ::rtl::OUString& rFontName, + const double& rCellSize ) : + mxCanvas( rCanvas ), + mxFont( NULL ) + { + OSL_ENSURE( mxCanvas.is(), "ImplFont::ImplFont(): Invalid Canvas" ); + + rendering::FontRequest aFontRequest; + aFontRequest.FontDescription.FamilyName = rFontName; + aFontRequest.CellSize = rCellSize; + + geometry::Matrix2D aFontMatrix; + ::canvas::tools::setIdentityMatrix2D( aFontMatrix ); + + mxFont = mxCanvas->createFont( aFontRequest, + uno::Sequence< beans::PropertyValue >(), + aFontMatrix ); + } + + + ImplFont::~ImplFont() + { + } + + ::rtl::OUString ImplFont::getName() const + { + OSL_ENSURE( mxFont.is(), "ImplFont::getName(): Invalid Font" ); + + return mxFont->getFontRequest().FontDescription.FamilyName; + } + + double ImplFont::getCellSize() const + { + OSL_ENSURE( mxFont.is(), "ImplFont::getCellSize(): Invalid Font" ); + + return mxFont->getFontRequest().CellSize; + } + + uno::Reference< rendering::XCanvasFont > ImplFont::getUNOFont() const + { + OSL_ENSURE( mxFont.is(), "ImplFont::getUNOFont(): Invalid Font" ); + + return mxFont; + } + + } +} diff --git a/cppcanvas/source/wrapper/implfont.hxx b/cppcanvas/source/wrapper/implfont.hxx new file mode 100644 index 000000000000..e1e9b89d284f --- /dev/null +++ b/cppcanvas/source/wrapper/implfont.hxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * 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: implfont.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 _CPPCANVAS_IMPLFONT_HXX +#define _CPPCANVAS_IMPLFONT_HXX + +#include <com/sun/star/uno/Reference.hxx> + +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif + +#ifndef _COM_SUN_STAR_RENDERING_XCANVAS_HPP__ +#include <com/sun/star/rendering/XCanvas.hpp> +#endif +#include <cppcanvas/font.hxx> + +namespace rtl +{ + class OUString; +} + +namespace com { namespace sun { namespace star { namespace rendering +{ + class XCanvasFont; +} } } } + +/* Definition of Font class */ + +namespace cppcanvas +{ + + namespace internal + { + + class ImplFont : public Font + { + public: + ImplFont( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvas >& rCanvas, + const ::rtl::OUString& rFontName, + const double& rCellSize ); + + virtual ~ImplFont(); + + virtual ::rtl::OUString getName() const; + virtual double getCellSize() const; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XCanvasFont > getUNOFont() const; + + private: + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas > mxCanvas; + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvasFont > mxFont; + }; + } +} + +#endif /* _CPPCANVAS_IMPLFONT_HXX */ diff --git a/cppcanvas/source/wrapper/implpolypolygon.cxx b/cppcanvas/source/wrapper/implpolypolygon.cxx new file mode 100644 index 000000000000..283256be01a8 --- /dev/null +++ b/cppcanvas/source/wrapper/implpolypolygon.cxx @@ -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: implpolypolygon.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_cppcanvas.hxx" + +#include <rtl/math.hxx> + +#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tools/canvastools.hxx> + +#include "implpolypolygon.hxx" +#include "tools.hxx" + + +using namespace ::com::sun::star; + + +namespace cppcanvas +{ + namespace internal + { + ImplPolyPolygon::ImplPolyPolygon( const CanvasSharedPtr& rParentCanvas, + const uno::Reference< rendering::XPolyPolygon2D >& rPolyPoly ) : + CanvasGraphicHelper( rParentCanvas ), + mxPolyPoly( rPolyPoly ), + maStrokeAttributes(1.0, + 10.0, + uno::Sequence< double >(), + uno::Sequence< double >(), + rendering::PathCapType::ROUND, + rendering::PathCapType::ROUND, + rendering::PathJoinType::ROUND ), + maFillColor(), + maStrokeColor(), + mbFillColorSet( false ), + mbStrokeColorSet( false ) + { + OSL_ENSURE( mxPolyPoly.is(), "PolyPolygonImpl::PolyPolygonImpl: no valid polygon" ); + } + + ImplPolyPolygon::~ImplPolyPolygon() + { + } + + void ImplPolyPolygon::addPolygon( const ::basegfx::B2DPolygon& rPoly ) + { + OSL_ENSURE( mxPolyPoly.is(), + "ImplPolyPolygon::addPolygon(): Invalid polygon" ); + + if( !mxPolyPoly.is() ) + return; + + uno::Reference< rendering::XGraphicDevice > xDevice( getGraphicDevice() ); + + OSL_ENSURE( xDevice.is(), + "ImplPolyPolygon::addPolygon(): Invalid graphic device" ); + + if( !xDevice.is() ) + return; + + mxPolyPoly->addPolyPolygon( geometry::RealPoint2D(0.0, 0.0), + ::basegfx::unotools::xPolyPolygonFromB2DPolygon( + xDevice, + rPoly) ); + } + + void ImplPolyPolygon::addPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ) + { + OSL_ENSURE( mxPolyPoly.is(), + "ImplPolyPolygon::addPolyPolygon(): Invalid polygon" ); + + if( !mxPolyPoly.is() ) + return; + + uno::Reference< rendering::XGraphicDevice > xDevice( getGraphicDevice() ); + + OSL_ENSURE( xDevice.is(), + "ImplPolyPolygon::addPolyPolygon(): Invalid graphic device" ); + + if( !xDevice.is() ) + return; + + mxPolyPoly->addPolyPolygon( geometry::RealPoint2D(0.0, 0.0), + ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( + xDevice, + rPoly) ); + } + + void ImplPolyPolygon::setRGBAFillColor( Color::IntSRGBA aColor ) + { + maFillColor = tools::intSRGBAToDoubleSequence( getGraphicDevice(), + aColor ); + mbFillColorSet = true; + } + + void ImplPolyPolygon::setRGBALineColor( Color::IntSRGBA aColor ) + { + maStrokeColor = tools::intSRGBAToDoubleSequence( getGraphicDevice(), + aColor ); + mbStrokeColorSet = true; + } + + Color::IntSRGBA ImplPolyPolygon::getRGBAFillColor() const + { + return tools::doubleSequenceToIntSRGBA( getGraphicDevice(), + maFillColor ); + } + + Color::IntSRGBA ImplPolyPolygon::getRGBALineColor() const + { + return tools::doubleSequenceToIntSRGBA( getGraphicDevice(), + maStrokeColor ); + } + + void ImplPolyPolygon::setStrokeWidth( const double& rStrokeWidth ) + { + maStrokeAttributes.StrokeWidth = rStrokeWidth; + } + + double ImplPolyPolygon::getStrokeWidth() const + { + return maStrokeAttributes.StrokeWidth; + } + + bool ImplPolyPolygon::draw() const + { + CanvasSharedPtr pCanvas( getCanvas() ); + + OSL_ENSURE( pCanvas.get() != NULL && + pCanvas->getUNOCanvas().is(), + "ImplBitmap::draw: invalid canvas" ); + + if( pCanvas.get() == NULL || + !pCanvas->getUNOCanvas().is() ) + return false; + + if( mbFillColorSet ) + { + rendering::RenderState aLocalState( getRenderState() ); + aLocalState.DeviceColor = maFillColor; + + pCanvas->getUNOCanvas()->fillPolyPolygon( mxPolyPoly, + pCanvas->getViewState(), + aLocalState ); + } + + if( mbStrokeColorSet ) + { + rendering::RenderState aLocalState( getRenderState() ); + aLocalState.DeviceColor = maStrokeColor; + + if( ::rtl::math::approxEqual(maStrokeAttributes.StrokeWidth, 1.0) ) + pCanvas->getUNOCanvas()->drawPolyPolygon( mxPolyPoly, + pCanvas->getViewState(), + aLocalState ); + else + pCanvas->getUNOCanvas()->strokePolyPolygon( mxPolyPoly, + pCanvas->getViewState(), + aLocalState, + maStrokeAttributes ); + } + + return true; + } + + uno::Reference< rendering::XPolyPolygon2D > ImplPolyPolygon::getUNOPolyPolygon() const + { + return mxPolyPoly; + } + + } +} diff --git a/cppcanvas/source/wrapper/implpolypolygon.hxx b/cppcanvas/source/wrapper/implpolypolygon.hxx new file mode 100644 index 000000000000..6a50cf512ed6 --- /dev/null +++ b/cppcanvas/source/wrapper/implpolypolygon.hxx @@ -0,0 +1,102 @@ +/************************************************************************* + * + * 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: implpolypolygon.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 _CANVAS_IMPLPOLYPOLYGON_HXX +#define _CANVAS_IMPLPOLYPOLYGON_HXX + +#include <com/sun/star/uno/Reference.hxx> +#ifndef _COM_SUN_STAR_RENDERING_XPOLYPOLYGON2D_HPP__ +#include <com/sun/star/rendering/XPolyPolygon2D.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_XGRAPHICDEVICE_HPP__ +#include <com/sun/star/rendering/XGraphicDevice.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_STROKEATTRIBUTES_HPP__ +#include <com/sun/star/rendering/StrokeAttributes.hpp> +#endif + +#include <cppcanvas/polypolygon.hxx> +#include <canvasgraphichelper.hxx> + +namespace com { namespace sun { namespace star { namespace rendering +{ + struct RealPoint2D; +} } } } + + +namespace cppcanvas +{ + namespace internal + { + + class ImplPolyPolygon : public virtual ::cppcanvas::PolyPolygon, protected CanvasGraphicHelper + { + public: + ImplPolyPolygon( const CanvasSharedPtr& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D >& rPolyPoly ); + + virtual ~ImplPolyPolygon(); + + virtual void addPolygon( const ::basegfx::B2DPolygon& rPoly ); + virtual void addPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly ); + + virtual void setRGBAFillColor( Color::IntSRGBA ); + virtual void setRGBALineColor( Color::IntSRGBA ); + virtual Color::IntSRGBA getRGBAFillColor() const; + virtual Color::IntSRGBA getRGBALineColor() const; + + virtual void setStrokeWidth( const double& rStrokeWidth ); + virtual double getStrokeWidth() const; + + virtual bool draw() const; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XPolyPolygon2D > getUNOPolyPolygon() const; + + private: + // default: disabled copy/assignment + ImplPolyPolygon(const ImplPolyPolygon&); + ImplPolyPolygon& operator= ( const ImplPolyPolygon& ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D > mxPolyPoly; + + ::com::sun::star::rendering::StrokeAttributes maStrokeAttributes; + + ::com::sun::star::uno::Sequence< double > maFillColor; + ::com::sun::star::uno::Sequence< double > maStrokeColor; + bool mbFillColorSet; + bool mbStrokeColorSet; + }; + + } +} + +#endif /* _CANVAS_IMPLPOLYPOLYGON_HXX */ diff --git a/cppcanvas/source/wrapper/implsprite.cxx b/cppcanvas/source/wrapper/implsprite.cxx new file mode 100644 index 000000000000..aa7fadcb2e3b --- /dev/null +++ b/cppcanvas/source/wrapper/implsprite.cxx @@ -0,0 +1,239 @@ +/************************************************************************* + * + * 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: implsprite.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_cppcanvas.hxx" + +#include <com/sun/star/rendering/XSprite.hpp> +#include <com/sun/star/rendering/XAnimatedSprite.hpp> + +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <canvas/canvastools.hxx> + +#include "implsprite.hxx" + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + ImplSprite::ImplSprite( const uno::Reference< rendering::XSpriteCanvas >& rParentCanvas, + const uno::Reference< rendering::XSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ) : + mxGraphicDevice(), + mxSprite( rSprite ), + mxAnimatedSprite(), + mpTransformArbiter( rTransformArbiter ) + { + // Avoiding ternary operator in initializer list (Solaris + // compiler bug, when function call and temporary is + // involved) + if( rParentCanvas.is() ) + mxGraphicDevice = rParentCanvas->getDevice(); + + OSL_ENSURE( rParentCanvas.is() , "ImplSprite::ImplSprite(): Invalid canvas"); + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::ImplSprite(): Invalid graphic device"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::ImplSprite(): Invalid sprite"); + OSL_ENSURE( mpTransformArbiter.get(), "ImplSprite::ImplSprite(): Invalid transformation arbiter"); + } + + ImplSprite::ImplSprite( const uno::Reference< rendering::XSpriteCanvas >& rParentCanvas, + const uno::Reference< rendering::XAnimatedSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ) : + mxGraphicDevice(), + mxSprite( uno::Reference< rendering::XSprite >(rSprite, + uno::UNO_QUERY) ), + mxAnimatedSprite( rSprite ), + mpTransformArbiter( rTransformArbiter ) + { + // Avoiding ternary operator in initializer list (Solaris + // compiler bug, when function call and temporary is + // involved) + if( rParentCanvas.is() ) + mxGraphicDevice = rParentCanvas->getDevice(); + + OSL_ENSURE( rParentCanvas.is() , "ImplSprite::ImplSprite(): Invalid canvas"); + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::ImplSprite(): Invalid graphic device"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::ImplSprite(): Invalid sprite"); + OSL_ENSURE( mpTransformArbiter.get(), "ImplSprite::ImplSprite(): Invalid transformation arbiter"); + } + + ImplSprite::~ImplSprite() + { + // hide the sprite on the canvas. If we don't hide the + // sprite, it will stay on the canvas forever, since the + // canvas naturally keeps a list of visible sprites + // (otherwise, it wouldn't be able to paint them + // autonomously) + if( mxSprite.is() ) + mxSprite->hide(); + } + + void ImplSprite::setAlpha( const double& rAlpha ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::setAlpha(): Invalid sprite"); + + if( mxSprite.is() ) + mxSprite->setAlpha( rAlpha ); + } + + void ImplSprite::movePixel( const ::basegfx::B2DPoint& rNewPos ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::movePixel(): Invalid sprite"); + + if( mxSprite.is() ) + { + rendering::ViewState aViewState; + rendering::RenderState aRenderState; + + ::canvas::tools::initViewState( aViewState ); + ::canvas::tools::initRenderState( aRenderState ); + + mxSprite->move( ::basegfx::unotools::point2DFromB2DPoint( rNewPos ), + aViewState, + aRenderState ); + } + } + + void ImplSprite::move( const ::basegfx::B2DPoint& rNewPos ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::move(): Invalid sprite"); + + if( mxSprite.is() ) + { + rendering::ViewState aViewState; + rendering::RenderState aRenderState; + + ::canvas::tools::initViewState( aViewState ); + ::canvas::tools::initRenderState( aRenderState ); + + ::canvas::tools::setViewStateTransform( aViewState, + mpTransformArbiter->getTransformation() ); + + mxSprite->move( ::basegfx::unotools::point2DFromB2DPoint( rNewPos ), + aViewState, + aRenderState ); + } + } + + void ImplSprite::transform( const ::basegfx::B2DHomMatrix& rMatrix ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::transform(): Invalid sprite"); + + if( mxSprite.is() ) + { + geometry::AffineMatrix2D aMatrix; + + mxSprite->transform( ::basegfx::unotools::affineMatrixFromHomMatrix( aMatrix, + rMatrix ) ); + } + } + + void ImplSprite::setClipPixel( const ::basegfx::B2DPolyPolygon& rClipPoly ) + { + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::setClip(): Invalid canvas"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::transform(): Invalid sprite"); + + if( mxSprite.is() && mxGraphicDevice.is() ) + mxSprite->clip( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( mxGraphicDevice, + rClipPoly ) ); + } + + void ImplSprite::setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) + { + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::setClip(): Invalid canvas"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::transform(): Invalid sprite"); + + if( mxSprite.is() && mxGraphicDevice.is() ) + { + ::basegfx::B2DPolyPolygon aTransformedClipPoly( rClipPoly ); + + // extract linear part of canvas view transformation (linear means: + // without translational components) + ::basegfx::B2DHomMatrix aViewTransform( mpTransformArbiter->getTransformation() ); + aViewTransform.set( 0, 2, 0.0 ); + aViewTransform.set( 1, 2, 0.0 ); + + // transform polygon from view to device coordinate space + aTransformedClipPoly.transform( aViewTransform ); + + mxSprite->clip( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( mxGraphicDevice, + aTransformedClipPoly ) ); + } + } + + void ImplSprite::setClip() + { + OSL_ENSURE( mxGraphicDevice.is(), "ImplSprite::setClip(): Invalid canvas"); + OSL_ENSURE( mxSprite.is(), "ImplSprite::setClip(): Invalid sprite"); + + if( mxSprite.is() && mxGraphicDevice.is() ) + mxSprite->clip( uno::Reference< rendering::XPolyPolygon2D >() ); + } + + void ImplSprite::show() + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::show(): Invalid sprite"); + + if( mxSprite.is() ) + mxSprite->show(); + } + + void ImplSprite::hide() + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::hide(): Invalid sprite"); + + if( mxSprite.is() ) + mxSprite->hide(); + } + + void ImplSprite::setPriority( double fPriority ) + { + OSL_ENSURE( mxSprite.is(), "ImplSprite::setPriority(): Invalid sprite"); + + if( mxSprite.is() ) + mxSprite->setPriority(fPriority); + } + + uno::Reference< rendering::XSprite > ImplSprite::getUNOSprite() const + { + return mxSprite; + } + + uno::Reference< rendering::XGraphicDevice > ImplSprite::getGraphicDevice() const + { + return mxGraphicDevice; + } + } +} diff --git a/cppcanvas/source/wrapper/implsprite.hxx b/cppcanvas/source/wrapper/implsprite.hxx new file mode 100644 index 000000000000..38e1b2fdd3b4 --- /dev/null +++ b/cppcanvas/source/wrapper/implsprite.hxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * 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: implsprite.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 _CPPCANVAS_IMPLSPRITE_HXX +#define _CPPCANVAS_IMPLSPRITE_HXX + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#include <com/sun/star/rendering/XSprite.hpp> + +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif +#include <cppcanvas/sprite.hxx> + +#include <implspritecanvas.hxx> + + +namespace cppcanvas +{ + namespace internal + { + class ImplSprite : public virtual Sprite + { + public: + ImplSprite( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ); + ImplSprite( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& rParentCanvas, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XAnimatedSprite >& rSprite, + const ImplSpriteCanvas::TransformationArbiterSharedPtr& rTransformArbiter ); + virtual ~ImplSprite(); + + virtual void setAlpha( const double& rAlpha ); + virtual void movePixel( const ::basegfx::B2DPoint& rNewPos ); + virtual void move( const ::basegfx::B2DPoint& rNewPos ); + virtual void transform( const ::basegfx::B2DHomMatrix& rMatrix ); + virtual void setClipPixel( const ::basegfx::B2DPolyPolygon& rClipPoly ); + virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ); + virtual void setClip(); + + virtual void show(); + virtual void hide(); + + virtual void setPriority( double fPriority ); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSprite > getUNOSprite() const; + + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XGraphicDevice > + getGraphicDevice() const; + + private: + // default: disabled copy/assignment + ImplSprite(const ImplSprite&); + ImplSprite& operator=( const ImplSprite& ); + + ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice > mxGraphicDevice; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XSprite > mxSprite; + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XAnimatedSprite > mxAnimatedSprite; + ImplSpriteCanvas::TransformationArbiterSharedPtr mpTransformArbiter; + }; + } +} + +#endif /* _CPPCANVAS_IMPLSPRITE_HXX */ diff --git a/cppcanvas/source/wrapper/implspritecanvas.cxx b/cppcanvas/source/wrapper/implspritecanvas.cxx new file mode 100644 index 000000000000..77805077d613 --- /dev/null +++ b/cppcanvas/source/wrapper/implspritecanvas.cxx @@ -0,0 +1,162 @@ +/************************************************************************* + * + * 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: implspritecanvas.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_cppcanvas.hxx" +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <com/sun/star/rendering/InterpolationMode.hpp> + +#include <implspritecanvas.hxx> +#include <implcustomsprite.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + ImplSpriteCanvas::TransformationArbiter::TransformationArbiter() : + maTransformation() + { + } + + void ImplSpriteCanvas::TransformationArbiter::setTransformation( const ::basegfx::B2DHomMatrix& rViewTransform ) + { + maTransformation = rViewTransform; + } + + ::basegfx::B2DHomMatrix ImplSpriteCanvas::TransformationArbiter::getTransformation() const + { + return maTransformation; + } + + + ImplSpriteCanvas::ImplSpriteCanvas( const uno::Reference< rendering::XSpriteCanvas >& rCanvas ) : + ImplCanvas( uno::Reference< rendering::XCanvas >(rCanvas, + uno::UNO_QUERY) ), + ImplBitmapCanvas( uno::Reference< rendering::XBitmapCanvas >(rCanvas, + uno::UNO_QUERY) ), + mxSpriteCanvas( rCanvas ), + mpTransformArbiter( new TransformationArbiter() ) + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::ImplSpriteCanvas(): Invalid canvas" ); + } + + ImplSpriteCanvas::ImplSpriteCanvas(const ImplSpriteCanvas& rOrig) : + Canvas(), + BitmapCanvas(), + SpriteCanvas(), + ImplCanvas( rOrig ), + ImplBitmapCanvas( rOrig ), + mxSpriteCanvas( rOrig.getUNOSpriteCanvas() ), + mpTransformArbiter( new TransformationArbiter() ) + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::ImplSpriteCanvas( const ImplSpriteCanvas& ): Invalid canvas" ); + + mpTransformArbiter->setTransformation( getTransformation() ); + } + + ImplSpriteCanvas::~ImplSpriteCanvas() + { + } + + void ImplSpriteCanvas::setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ) + { + mpTransformArbiter->setTransformation( rMatrix ); + + ImplCanvas::setTransformation( rMatrix ); + } + + bool ImplSpriteCanvas::updateScreen( bool bUpdateAll ) const + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::updateScreen(): Invalid canvas" ); + + if( !mxSpriteCanvas.is() ) + return false; + + return mxSpriteCanvas->updateScreen( bUpdateAll ); + } + + CustomSpriteSharedPtr ImplSpriteCanvas::createCustomSprite( const ::basegfx::B2DSize& rSize ) const + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::createCustomSprite(): Invalid canvas" ); + + if( !mxSpriteCanvas.is() ) + return CustomSpriteSharedPtr(); + + return CustomSpriteSharedPtr( + new ImplCustomSprite( mxSpriteCanvas, + mxSpriteCanvas->createCustomSprite( ::basegfx::unotools::size2DFromB2DSize(rSize) ), + mpTransformArbiter ) ); + } + + SpriteSharedPtr ImplSpriteCanvas::createClonedSprite( const SpriteSharedPtr& rSprite ) const + { + OSL_ENSURE( mxSpriteCanvas.is(), "ImplSpriteCanvas::createCustomSprite(): Invalid canvas" ); + OSL_ENSURE( rSprite.get() != NULL && rSprite->getUNOSprite().is(), + "ImplSpriteCanvas::createCustomSprite(): Invalid sprite" ); + + if( !mxSpriteCanvas.is() || + rSprite.get() == NULL || + !rSprite->getUNOSprite().is() ) + { + return SpriteSharedPtr(); + } + + return SpriteSharedPtr( + new ImplSprite( mxSpriteCanvas, + mxSpriteCanvas->createClonedSprite( rSprite->getUNOSprite() ), + mpTransformArbiter ) ); + } + + SpriteSharedPtr ImplSpriteCanvas::createSpriteFromBitmaps( const uno::Sequence< uno::Reference< rendering::XBitmap > >& rAnimationBitmaps, + sal_Int8 nInterpolationMode ) + { + return SpriteSharedPtr( new internal::ImplSprite( mxSpriteCanvas, + mxSpriteCanvas->createSpriteFromBitmaps( rAnimationBitmaps, + nInterpolationMode ), + mpTransformArbiter ) ); + } + + CanvasSharedPtr ImplSpriteCanvas::clone() const + { + return SpriteCanvasSharedPtr( new ImplSpriteCanvas( *this ) ); + } + + uno::Reference< rendering::XSpriteCanvas > ImplSpriteCanvas::getUNOSpriteCanvas() const + { + return mxSpriteCanvas; + } + + } +} diff --git a/cppcanvas/source/wrapper/implspritecanvas.hxx b/cppcanvas/source/wrapper/implspritecanvas.hxx new file mode 100644 index 000000000000..d7a1afc0d084 --- /dev/null +++ b/cppcanvas/source/wrapper/implspritecanvas.hxx @@ -0,0 +1,113 @@ +/************************************************************************* + * + * 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: implspritecanvas.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 _CPPCANVAS_IMPLSPRITECANVAS_HXX +#define _CPPCANVAS_IMPLSPRITECANVAS_HXX + +#ifndef _COM_SUN_STAR_RENDERING_XSPRITECANVAS_HPP__ +#include <com/sun/star/rendering/XSpriteCanvas.hpp> +#endif +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#include <boost/shared_ptr.hpp> +#endif + + +#include <cppcanvas/spritecanvas.hxx> + +#include <implbitmapcanvas.hxx> + + +namespace cppcanvas +{ + namespace internal + { + class ImplSpriteCanvas : public virtual SpriteCanvas, protected virtual ImplBitmapCanvas + { + public: + ImplSpriteCanvas( const ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas >& rCanvas ); + ImplSpriteCanvas(const ImplSpriteCanvas&); + + virtual ~ImplSpriteCanvas(); + + virtual void setTransformation( const ::basegfx::B2DHomMatrix& rMatrix ); + + virtual bool updateScreen( bool bUpdateAll ) const; + + virtual CustomSpriteSharedPtr createCustomSprite( const ::basegfx::B2DSize& ) const; + virtual SpriteSharedPtr createClonedSprite( const SpriteSharedPtr& ) const; + + SpriteSharedPtr createSpriteFromBitmaps( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XBitmap > >& animationBitmaps, + sal_Int8 interpolationMode ); + + virtual CanvasSharedPtr clone() const; + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rendering::XSpriteCanvas > getUNOSpriteCanvas() const; + + /** This class passes the view transformation + to child sprites + + This helper class is necessary, because the + ImplSpriteCanvas object cannot hand out shared ptrs of + itself, but has somehow pass an object to child + sprites those can query for the canvas' view transform. + */ + class TransformationArbiter + { + public: + TransformationArbiter(); + + void setTransformation( const ::basegfx::B2DHomMatrix& rViewTransform ); + ::basegfx::B2DHomMatrix getTransformation() const; + + private: + ::basegfx::B2DHomMatrix maTransformation; + }; + + typedef ::boost::shared_ptr< TransformationArbiter > TransformationArbiterSharedPtr; + + private: + // default: disabled assignment + ImplSpriteCanvas& operator=( const ImplSpriteCanvas& ); + + const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XSpriteCanvas > mxSpriteCanvas; + TransformationArbiterSharedPtr mpTransformArbiter; + }; + } +} + +#endif /* _CPPCANVAS_IMPLSPRITECANVAS_HXX */ diff --git a/cppcanvas/source/wrapper/impltext.cxx b/cppcanvas/source/wrapper/impltext.cxx new file mode 100644 index 000000000000..58a95910d0f1 --- /dev/null +++ b/cppcanvas/source/wrapper/impltext.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * 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: impltext.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_cppcanvas.hxx" + +#include <impltext.hxx> +#include <canvas/canvastools.hxx> + +#ifndef _COM_SUN_STAR_RENDERING_TEXTDIRECTION_HPP__ +#include <com/sun/star/rendering/TextDirection.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_XCANVAS_HPP__ +#include <com/sun/star/rendering/XCanvas.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_STRINGCONTEXT_HPP__ +#include <com/sun/star/rendering/StringContext.hpp> +#endif +#include <rtl/ustring.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + namespace internal + { + + ImplText::ImplText( const CanvasSharedPtr& rParentCanvas, + const ::rtl::OUString& rText ) : + CanvasGraphicHelper( rParentCanvas ), + mpFont(), + maText(rText) + { + } + + ImplText::~ImplText() + { + } + + bool ImplText::draw() const + { + CanvasSharedPtr pCanvas( getCanvas() ); + + OSL_ENSURE( pCanvas.get() != NULL && + pCanvas->getUNOCanvas().is(), + "ImplBitmap::draw: invalid canvas" ); + + rendering::StringContext aText; + aText.Text = maText; + aText.StartPosition = 0; + aText.Length = maText.getLength(); + + // TODO(P1): implement caching + // TODO(F2): where to get current BiDi status? + sal_Int8 nBidiOption = rendering::TextDirection::WEAK_LEFT_TO_RIGHT; + pCanvas->getUNOCanvas()->drawText( aText, + mpFont->getUNOFont(), + pCanvas->getViewState(), + getRenderState(), + nBidiOption ); + + return true; + } + + void ImplText::setFont( const FontSharedPtr& rFont ) + { + mpFont = rFont; + } + + FontSharedPtr ImplText::getFont() + { + return mpFont; + } + } +} diff --git a/cppcanvas/source/wrapper/impltext.hxx b/cppcanvas/source/wrapper/impltext.hxx new file mode 100644 index 000000000000..9f91cde6199a --- /dev/null +++ b/cppcanvas/source/wrapper/impltext.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: impltext.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 _CANVAS_IMPLTEXT_HXX +#define _CANVAS_IMPLTEXT_HXX + +#ifndef _COM_SUN_STAR_RENDERING_RENDERSTATE_HPP__ +#include <com/sun/star/rendering/RenderState.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_STRINGCONTEXT_HPP__ +#include <com/sun/star/rendering/StringContext.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_XCANVAS_HPP__ +#include <com/sun/star/rendering/XCanvas.hpp> +#endif +#ifndef _COM_SUN_STAR_RENDERING_XCANVASFONT_HPP__ +#include <com/sun/star/rendering/XCanvasFont.hpp> +#endif + +#include <cppcanvas/text.hxx> +#include <canvasgraphichelper.hxx> + + +namespace cppcanvas +{ + namespace internal + { + + class ImplText : public virtual ::cppcanvas::Text, protected CanvasGraphicHelper + { + public: + + ImplText( const CanvasSharedPtr& rParentCanvas, + const ::rtl::OUString& rText ); + + virtual ~ImplText(); + + virtual bool draw() const; + + virtual void setFont( const FontSharedPtr& ); + virtual FontSharedPtr getFont(); + + private: + // default: disabled copy/assignment + ImplText(const ImplText&); + ImplText& operator= ( const ImplText& ); + + FontSharedPtr mpFont; + ::rtl::OUString maText; + }; + } +} + +#endif /* _CANVAS_IMPLTEXT_HXX */ diff --git a/cppcanvas/source/wrapper/makefile.mk b/cppcanvas/source/wrapper/makefile.mk new file mode 100644 index 000000000000..ed5d78ab6b49 --- /dev/null +++ b/cppcanvas/source/wrapper/makefile.mk @@ -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: makefile.mk,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. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=cppcanvas +TARGET=canvaswrapper +ENABLE_EXCEPTIONS=TRUE + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Common ---------------------------------------------------------- + +.IF "$(verbose)"!="" || "$(VERBOSE)"!="" +CDEFS+= -DVERBOSE +.ENDIF + +SLOFILES = $(SLO)$/implbitmap.obj \ + $(SLO)$/implcanvas.obj \ + $(SLO)$/implcolor.obj \ + $(SLO)$/implfont.obj \ + $(SLO)$/vclfactory.obj \ + $(SLO)$/basegfxfactory.obj \ + $(SLO)$/impltext.obj \ + $(SLO)$/implpolypolygon.obj \ + $(SLO)$/implbitmapcanvas.obj \ + $(SLO)$/implspritecanvas.obj \ + $(SLO)$/implsprite.obj \ + $(SLO)$/implcustomsprite.obj + +# ========================================================================== + +.INCLUDE : target.mk diff --git a/cppcanvas/source/wrapper/vclfactory.cxx b/cppcanvas/source/wrapper/vclfactory.cxx new file mode 100644 index 000000000000..c83a4f258f23 --- /dev/null +++ b/cppcanvas/source/wrapper/vclfactory.cxx @@ -0,0 +1,366 @@ +/************************************************************************* + * + * 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: vclfactory.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_cppcanvas.hxx" +#include <rtl/instance.hxx> +#include <osl/getglobalmutex.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/rendering/InterpolationMode.hpp> +#include <vcl/window.hxx> +#include <vcl/graph.hxx> +#include <vcl/canvastools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> + +#include <cppcanvas/vclfactory.hxx> + +#include <implbitmapcanvas.hxx> +#include <implspritecanvas.hxx> +#include <implpolypolygon.hxx> +#include <implbitmap.hxx> +#include <implrenderer.hxx> +#include <impltext.hxx> +#include <implsprite.hxx> + + +using namespace ::com::sun::star; + +namespace cppcanvas +{ + /* Singleton handling */ + struct InitInstance + { + VCLFactory* operator()() + { + return new VCLFactory(); + } + }; + + VCLFactory& VCLFactory::getInstance() + { + return *rtl_Instance< VCLFactory, InitInstance, ::osl::MutexGuard, + ::osl::GetGlobalMutex >::create( + InitInstance(), ::osl::GetGlobalMutex()); + } + + VCLFactory::VCLFactory() + { + } + + VCLFactory::~VCLFactory() + { + } + + BitmapCanvasSharedPtr VCLFactory::createCanvas( const ::Window& rVCLWindow ) + { + return BitmapCanvasSharedPtr( + new internal::ImplBitmapCanvas( + uno::Reference< rendering::XBitmapCanvas >( + rVCLWindow.GetCanvas(), + uno::UNO_QUERY) ) ); + } + + BitmapCanvasSharedPtr VCLFactory::createCanvas( const uno::Reference< rendering::XBitmapCanvas >& xCanvas ) + { + return BitmapCanvasSharedPtr( + new internal::ImplBitmapCanvas( xCanvas ) ); + } + + SpriteCanvasSharedPtr VCLFactory::createSpriteCanvas( const ::Window& rVCLWindow ) const + { + return SpriteCanvasSharedPtr( + new internal::ImplSpriteCanvas( + uno::Reference< rendering::XSpriteCanvas >( + rVCLWindow.GetSpriteCanvas(), + uno::UNO_QUERY) ) ); + } + + SpriteCanvasSharedPtr VCLFactory::createSpriteCanvas( const uno::Reference< rendering::XSpriteCanvas >& xCanvas ) const + { + return SpriteCanvasSharedPtr( + new internal::ImplSpriteCanvas( xCanvas ) ); + } + + SpriteCanvasSharedPtr VCLFactory::createFullscreenSpriteCanvas( const ::Window& rVCLWindow, + const Size& rFullscreenSize ) const + { + return SpriteCanvasSharedPtr( + new internal::ImplSpriteCanvas( + uno::Reference< rendering::XSpriteCanvas >( + rVCLWindow.GetFullscreenSpriteCanvas( rFullscreenSize ), + uno::UNO_QUERY) ) ); + } + + PolyPolygonSharedPtr VCLFactory::createPolyPolygon( const CanvasSharedPtr& rCanvas, + const ::Polygon& rPoly ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createPolyPolygon(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return PolyPolygonSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return PolyPolygonSharedPtr(); + + return PolyPolygonSharedPtr( + new internal::ImplPolyPolygon( rCanvas, + ::vcl::unotools::xPolyPolygonFromPolygon( + xCanvas->getDevice(), + rPoly) ) ); + } + + PolyPolygonSharedPtr VCLFactory::createPolyPolygon( const CanvasSharedPtr& rCanvas, + const ::PolyPolygon& rPolyPoly ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createPolyPolygon(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return PolyPolygonSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return PolyPolygonSharedPtr(); + + return PolyPolygonSharedPtr( + new internal::ImplPolyPolygon( rCanvas, + ::vcl::unotools::xPolyPolygonFromPolyPolygon( + xCanvas->getDevice(), + rPolyPoly) ) ); + } + + BitmapSharedPtr VCLFactory::createBitmap( const CanvasSharedPtr& rCanvas, + const ::Size& rSize ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( + new internal::ImplBitmap( rCanvas, + xCanvas->getDevice()->createCompatibleBitmap( + ::vcl::unotools::integerSize2DFromSize(rSize) ) ) ); + } + + BitmapSharedPtr VCLFactory::createAlphaBitmap( const CanvasSharedPtr& rCanvas, + const ::Size& rSize ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( + new internal::ImplBitmap( rCanvas, + xCanvas->getDevice()->createCompatibleAlphaBitmap( + ::vcl::unotools::integerSize2DFromSize(rSize) ) ) ); + } + + BitmapSharedPtr VCLFactory::createBitmap( const CanvasSharedPtr& rCanvas, + const ::Bitmap& rBitmap ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( new internal::ImplBitmap( rCanvas, + ::vcl::unotools::xBitmapFromBitmap( + xCanvas->getDevice(), + rBitmap) ) ); + } + + BitmapSharedPtr VCLFactory::createBitmap( const CanvasSharedPtr& rCanvas, + const ::BitmapEx& rBmpEx ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createBitmap(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return BitmapSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return BitmapSharedPtr(); + + return BitmapSharedPtr( new internal::ImplBitmap( rCanvas, + ::vcl::unotools::xBitmapFromBitmapEx( + xCanvas->getDevice(), + rBmpEx) ) ); + } + + RendererSharedPtr VCLFactory::createRenderer( const CanvasSharedPtr& rCanvas, + const ::Graphic& rGraphic, + const Renderer::Parameters& rParms ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createRenderer(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return RendererSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return RendererSharedPtr(); + + if( rGraphic.GetType() == GRAPHIC_GDIMETAFILE ) + return RendererSharedPtr( new internal::ImplRenderer( rCanvas, + rGraphic.GetGDIMetaFile(), + rParms ) ); + else + return RendererSharedPtr( new internal::ImplRenderer( rCanvas, + rGraphic.GetBitmapEx(), + rParms ) ); + } + + RendererSharedPtr VCLFactory::createRenderer( const CanvasSharedPtr& rCanvas, + const ::GDIMetaFile& rMtf, + const Renderer::Parameters& rParms ) const + { + return RendererSharedPtr( new internal::ImplRenderer( rCanvas, + rMtf, + rParms ) ); + } + + SpriteSharedPtr VCLFactory::createAnimatedSprite( const SpriteCanvasSharedPtr& rCanvas, const ::Animation& rAnim ) const + { + OSL_ENSURE( rCanvas.get() != NULL && + rCanvas->getUNOCanvas().is(), + "VCLFactory::createAnimatedSprite(): Invalid canvas" ); + + if( rCanvas.get() == NULL ) + return SpriteSharedPtr(); + + uno::Reference< rendering::XCanvas > xCanvas( rCanvas->getUNOCanvas() ); + if( !xCanvas.is() ) + return SpriteSharedPtr(); + + uno::Reference< rendering::XSpriteCanvas > xSpriteCanvas( rCanvas->getUNOSpriteCanvas() ); + if( !xSpriteCanvas.is() ) + return SpriteSharedPtr(); + + if( rAnim.IsEmpty() ) + return SpriteSharedPtr(); + + internal::ImplSpriteCanvas* pSpriteCanvas = dynamic_cast< internal::ImplSpriteCanvas* >( rCanvas.get() ); + if( !pSpriteCanvas ) + return SpriteSharedPtr(); + + const USHORT nBitmaps( rAnim.Count() ); + uno::Sequence< uno::Reference< rendering::XBitmap > > aBitmapSequence( nBitmaps ); + uno::Reference< rendering::XBitmap >* pBitmaps = aBitmapSequence.getArray(); + + unsigned int i; + BitmapEx aBmpEx; + BitmapEx aRestoreBuffer; + aBmpEx.SetSizePixel( rAnim.GetDisplaySizePixel() ); + aRestoreBuffer.SetSizePixel( rAnim.GetDisplaySizePixel() ); + aBmpEx.Erase( ::Color( 255, 0,0,0 ) ); // clear alpha channel + aRestoreBuffer = aBmpEx; + const Point aEmptyPoint; + + for( i=0; i<nBitmaps; ++i ) + { + const AnimationBitmap& rAnimBmp( rAnim.Get((USHORT)i) ); + + // Handle dispose according to GIF spec: a + // DISPOSE_PREVIOUS does _not_ mean to revert to the + // previous frame, but to revert to the last frame with + // DISPOSE_NOT + + // dispose previous + if( rAnimBmp.eDisposal == DISPOSE_BACK ) + { + // simply clear bitmap to transparent + aBmpEx.Erase( ::Color( 255, 0,0,0 ) ); + } + else if( rAnimBmp.eDisposal == DISPOSE_PREVIOUS ) + { + // copy in last known full frame + aBmpEx = aRestoreBuffer; + } + // I have exactly _no_ idea what DISPOSE_FULL is supposed + // to do. It's apparently not set anywhere in our code + OSL_ENSURE( rAnimBmp.eDisposal!=DISPOSE_FULL, + "VCLFactory::createAnimatedSprite(): Somebody set the deprecated DISPOSE_FULL at the Animation" ); + + // update display + aBmpEx.CopyPixel( Rectangle( rAnimBmp.aPosPix, + rAnimBmp.aSizePix ), + Rectangle( aEmptyPoint, + rAnimBmp.aSizePix ), + &rAnimBmp.aBmpEx ); + + // store last DISPOSE_NOT frame, for later + // DISPOSE_PREVIOUS updates + if( rAnimBmp.eDisposal == DISPOSE_NOT ) + aRestoreBuffer = aBmpEx; + + pBitmaps[i] = ::vcl::unotools::xBitmapFromBitmapEx( + xCanvas->getDevice(), + aBmpEx); + } + + return pSpriteCanvas->createSpriteFromBitmaps( aBitmapSequence, + rendering::InterpolationMode::NEAREST_NEIGHBOR ); + } + + TextSharedPtr VCLFactory::createText( const CanvasSharedPtr& rCanvas, const ::rtl::OUString& rText ) const + { + return TextSharedPtr( new internal::ImplText( rCanvas, + rText ) ); + } + +} |