diff options
author | Rüdiger Timm <rt@openoffice.org> | 2005-03-30 07:32:26 +0000 |
---|---|---|
committer | Rüdiger Timm <rt@openoffice.org> | 2005-03-30 07:32:26 +0000 |
commit | 25caa140aec0b837903f8c01d1a92d0cf7805b2a (patch) | |
tree | cb596af8e5648c7cfbf03f5118670017b05250e8 /cppcanvas/source/mtfrenderer/transparencygroupaction.cxx | |
parent | a7f89fdd4d3b9904ddcfba283b1a3ed5f6b67be4 (diff) |
INTEGRATION: CWS presfixes02 (1.3.2); FILE MERGED
2005/03/23 19:28:09 thb 1.3.2.2: #i38985# At least one of the reasons for the Solaris crash was requesting a zero-sized bitmap here. Now distinguishing between bitmap and output size (the former is rounded _up_ to the nearest integer)
2005/03/14 16:04:55 thb 1.3.2.1: #i35136# #i36914# #i41113# #i44100# #i40115# #i41839# #i44404# Merge from presfixes01 patches
Diffstat (limited to 'cppcanvas/source/mtfrenderer/transparencygroupaction.cxx')
-rw-r--r-- | cppcanvas/source/mtfrenderer/transparencygroupaction.cxx | 578 |
1 files changed, 417 insertions, 161 deletions
diff --git a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx index 3ec922f4d5fc..06a06f741353 100644 --- a/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx +++ b/cppcanvas/source/mtfrenderer/transparencygroupaction.cxx @@ -2,9 +2,9 @@ * * $RCSfile: transparencygroupaction.cxx,v $ * - * $Revision: 1.3 $ + * $Revision: 1.4 $ * - * last change: $Author: vg $ $Date: 2005-03-10 13:27:00 $ + * last change: $Author: rt $ $Date: 2005-03-30 08:32:26 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -80,6 +80,9 @@ #include <rtl/math.hxx> #endif +#ifndef _SV_METAACT_HXX +#include <vcl/metaact.hxx> +#endif #ifndef _SV_BITMAPEX_HXX #include <vcl/bitmapex.hxx> #endif @@ -122,6 +125,8 @@ #include <basegfx/tools/canvastools.hxx> #endif +#include <boost/utility.hpp> + #include <mtftools.hxx> #include <cppcanvas/vclfactory.hxx> @@ -136,6 +141,92 @@ namespace cppcanvas // ====================== 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 ::Point& rDstPoint, + const ::Size& 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 ::Point& rDstPoint, + const ::Size& 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 sal_Int32 getActionCount() const; + + private: + MtfAutoPtr mpGroupMtf; + GradientAutoPtr mpAlphaGradient; + + const Renderer::Parameters maParms; + + const ::Size 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. @@ -150,180 +241,345 @@ namespace cppcanvas ::canvas::tools::appendToRenderState( rRenderState, aLocalTransformation ); } - } - TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf, - const Renderer::Parameters& rParms, - const ::Point& rDstPoint, - const ::Size& 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 ); - } + TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::Point& rDstPoint, + const ::Size& 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 ); - TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf, - GradientAutoPtr& rAlphaGradient, - const Renderer::Parameters& rParms, - const ::Point& rDstPoint, - const ::Size& 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 ); - } + maLastSubset.mnSubsetBegin = 0; + maLastSubset.mnSubsetEnd = -1; + } - TransparencyGroupAction::~TransparencyGroupAction() - { - // outline, because of incomplete types in header - } + TransparencyGroupAction::TransparencyGroupAction( MtfAutoPtr& rGroupMtf, + GradientAutoPtr& rAlphaGradient, + const Renderer::Parameters& rParms, + const ::Point& rDstPoint, + const ::Size& 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 ); - // 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 - { - 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 ); - - // as soon as the total transformation changes, we've got - // to re-render the bitmap - if( aTotalTransform != maLastTransformation) + 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 { - 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 ) ) + 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 ); + + // as soon as the total transformation changes, we've got + // to re-render the bitmap + if( 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.Width() ), + ::basegfx::fround( aScale.getY() * maDstSize.Height() ) ); + + // pixel size of cache bitmap: round up to nearest int + ::Size aBitmapSizePixel( static_cast<sal_Int32>( aScale.getX() * maDstSize.Width() )+1, + static_cast<sal_Int32>( aScale.getY() * maDstSize.Height() )+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.Width() / aBmpSize.getX(), + (double)maDstSize.Height() / aBmpSize.getY() ); + aTransform = aTransform * aScaleCorrection; + + rendering::RenderState aLocalState( maState ); + ::canvas::tools::setRenderStateTransform(aLocalState, aTransform); + + if( ::rtl::math::approxEqual(mnAlpha, 1.0) ) + { + // no further alpha changes necessary -> draw directly + mpCanvas->getUNOCanvas()->drawBitmap( mxBufferBitmap, + mpCanvas->getViewState(), + aLocalState ); + } + else { - OSL_ENSURE( false, - "TransparencyGroupAction::render(): non-decomposable transformation" ); - return false; + // add alpha modulation value to DeviceColor + aLocalState.DeviceColor.realloc(4); + aLocalState.DeviceColor[0] = 1.0; + aLocalState.DeviceColor[1] = 1.0; + aLocalState.DeviceColor[2] = 1.0; + aLocalState.DeviceColor[3] = mnAlpha; + mpCanvas->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap, + mpCanvas->getViewState(), + aLocalState ); } - ::Size aSize( ::basegfx::fround( aScale.getX() * maDstSize.Width() ), - ::basegfx::fround( aScale.getY() * maDstSize.Height() ) ); - - // render our content into an appropriately sized - // VirtualDevice with alpha channel - VirtualDevice aVDev( - *::Application::GetDefaultDevice(), 0, 0 ); - aVDev.SetOutputSizePixel( aSize ); - aVDev.SetMapMode(); - - ::Point aEmptyPoint; - aVDev.DrawTransparent( *mpGroupMtf, - aEmptyPoint, - aSize, - *mpAlphaGradient ); - - - // update buffered bitmap and transformation - BitmapSharedPtr aBmp( VCLFactory::getInstance().createBitmap( - mpCanvas, - aVDev.GetBitmapEx( - aEmptyPoint, - aSize ) ) ); - mxBufferBitmap = aBmp->getUNOBitmap(); - maLastTransformation = aTotalTransform; + return true; } - // 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.Width() / aBmpSize.getX(), - (double)maDstSize.Height() / aBmpSize.getY() ); - aTransform = aTransform * aScaleCorrection; - - rendering::RenderState aLocalState( maState ); - ::canvas::tools::setRenderStateTransform(aLocalState, aTransform); - - if( ::rtl::math::approxEqual(mnAlpha, 1.0) ) + // 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 { - // no further alpha changes necessary -> draw directly - mpCanvas->getUNOCanvas()->drawBitmap( mxBufferBitmap, - mpCanvas->getViewState(), - aLocalState ); + Subset aSubset; + + aSubset.mnSubsetBegin = 0; + aSubset.mnSubsetEnd = -1; + + return render( rTransformation, aSubset ); } - else + + sal_Int32 TransparencyGroupAction::getActionCount() const { - // add alpha modulation value to DeviceColor - aLocalState.DeviceColor.realloc(4); - aLocalState.DeviceColor[0] = 1.0; - aLocalState.DeviceColor[1] = 1.0; - aLocalState.DeviceColor[2] = 1.0; - aLocalState.DeviceColor[3] = mnAlpha; - mpCanvas->getUNOCanvas()->drawBitmapModulated( mxBufferBitmap, - mpCanvas->getViewState(), - aLocalState ); + return mpGroupMtf.get() ? mpGroupMtf->GetActionCount() : 0; } - return true; + } + + ActionSharedPtr TransparencyGroupActionFactory::createTransparencyGroupAction( MtfAutoPtr& rGroupMtf, + const Renderer::Parameters& rParms, + const ::Point& rDstPoint, + const ::Size& 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 ::Point& rDstPoint, + const ::Size& rDstSize, + const CanvasSharedPtr& rCanvas, + const OutDevState& rState ) + { + return ActionSharedPtr( new TransparencyGroupAction(rGroupMtf, + rAlphaGradient, + rParms, + rDstPoint, + rDstSize, + rCanvas, + rState ) ); } } |