summaryrefslogtreecommitdiff
path: root/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'cppcanvas/source/mtfrenderer/transparencygroupaction.cxx')
-rw-r--r--cppcanvas/source/mtfrenderer/transparencygroupaction.cxx592
1 files changed, 592 insertions, 0 deletions
diff --git a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
new file mode 100644
index 000000000000..a8984d41e585
--- /dev/null
+++ b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx
@@ -0,0 +1,592 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_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 ) );
+ }
+
+ }
+}