diff options
author | Kurt Zenker <kz@openoffice.org> | 2005-11-02 12:05:00 +0000 |
---|---|---|
committer | Kurt Zenker <kz@openoffice.org> | 2005-11-02 12:05:00 +0000 |
commit | b12095385e462a77fa9d7a7604abb08f34499ddf (patch) | |
tree | df5fc126c36d0b7a82e958f50a0aa1ec951c4c64 /canvas/source | |
parent | 8855922d5c283533b4660ab6d05c1f3a458870ec (diff) |
INTEGRATION: CWS canvas02 (1.1.2); FILE ADDED
2005/10/20 10:52:50 thb 1.1.2.13: #i48939# Now having different paths for Windows and X11, as clip vs. XOR polygon performance differs largely
2005/10/11 15:41:32 thb 1.1.2.12: #i54170# Corrected license headers
2005/10/10 22:07:08 thb 1.1.2.11: #i48939# Made code compile (almost) warning-free for gcc
2005/09/22 21:00:53 thb 1.1.2.10: #i48939# Employing faster XOR masking for the special case nontransparent, non-alpha bitmap redraw in backbuffer (incidently, that matches the typical slide transition sprite update)
2005/09/07 08:12:06 mbu 1.1.2.9: added comments with deprecated version for handling the clipping regions
2005/08/24 22:06:10 thb 1.1.2.8: Restored previous version (darn windows cvs wrapper seems to ignore signals)
2005/08/24 22:00:32 thb 1.1.2.7: #i52876
2005/08/18 15:32:07 mbu 1.1.2.6: now using SetTriangleClipRegion()
2005/08/02 14:33:34 thb 1.1.2.5: #i48939# moved polyPolygonFromXPolyPolygon2D to canvastools
2005/07/22 00:11:58 thb 1.1.2.4: #i48939# Factored out stubby corner sprite bound rect rendering to canvastools; finished removal of actual redraw methods from ::canvas::Sprite
2005/07/21 14:52:50 thb 1.1.2.3: #i48939# Factored out round up/down to integer; removed backend specific methods from base Sprite interface; removed updateScreen overwrite from SpriteCanvasBase (too much backend specifics need to be passed to HW canvases); now passing the target OutputDevice directly via Sprite::redraw() method in VCL canvas; made XFont -> impl font conversion dynamic cast, too; removed the getSpriteTargetSurface crap from SpriteCanvas
2005/07/03 20:25:19 thb 1.1.2.2: #i48939# Reworked ParametricPolyPolygon, to extract state in an atomic operation; added more state checking 'isXDirty()' methods to canvascustomspritehelper; added various comments and notes
2005/06/17 23:44:52 thb 1.1.2.1: #i48939# The new canvas base classes expect more functionality in delegate members; these are the helper implementations
Diffstat (limited to 'canvas/source')
-rw-r--r-- | canvas/source/vcl/spritehelper.cxx | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/canvas/source/vcl/spritehelper.cxx b/canvas/source/vcl/spritehelper.cxx new file mode 100644 index 000000000000..2acf37f2c0f3 --- /dev/null +++ b/canvas/source/vcl/spritehelper.cxx @@ -0,0 +1,424 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: spritehelper.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: kz $ $Date: 2005-11-02 13:05:00 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> + +#include <rtl/math.hxx> + +#include <vcl/outdev.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/alpha.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/canvastools.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolygoncutandtouch.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <canvas/canvastools.hxx> + +#include "spritehelper.hxx" + +using namespace ::com::sun::star; + + +namespace vclcanvas +{ + SpriteHelper::SpriteHelper() : + mpBackBuffer(), + mpBackBufferMask(), + mpSpriteCanvas(), + maContent(), + mbShowSpriteBounds(false) + { + } + + void SpriteHelper::init( const geometry::RealSize2D& rSpriteSize, + const SpriteCanvasRef& rSpriteCanvas, + const BackBufferSharedPtr& rBackBuffer, + const BackBufferSharedPtr& rBackBufferMask, + bool bShowSpriteBounds ) + { + ENSURE_AND_THROW( rSpriteCanvas.get() && rBackBuffer && rBackBufferMask, + "SpriteHelper::init(): Invalid sprite canvas or back buffer" ); + + mpBackBuffer = rBackBuffer; + mpBackBufferMask = rBackBufferMask; + mpSpriteCanvas = rSpriteCanvas; + mbShowSpriteBounds = bShowSpriteBounds; + + CanvasCustomSpriteHelper::init( rSpriteSize, rSpriteCanvas.get() ); + } + + void SpriteHelper::disposing() + { + mpBackBuffer.reset(); + mpBackBufferMask.reset(); + mpSpriteCanvas.clear(); + + // forward to parent + CanvasCustomSpriteHelper::disposing(); + } + + void SpriteHelper::redraw( OutputDevice& rTargetSurface, + const ::basegfx::B2DPoint& rPos, + bool& io_bSurfacesDirty, + bool bBufferedUpdate ) const + { + if( !mpSpriteCanvas.get() || + !mpBackBuffer || + !mpBackBufferMask ) + { + return; // we're disposed + } + + // log output pos in device pixel + VERBOSE_TRACE( "SpriteHelper::redraw(): output pos is (%f, %f)", + rPos.getX(), + rPos.getY() ); + + const double fAlpha( getAlpha() ); + + if( isActive() && + !::basegfx::fTools::equalZero( fAlpha ) ) + { + const Point aEmptyPoint; + const ::basegfx::B2DVector& rOrigOutputSize( getSizePixel() ); + + // might get changed below (e.g. adapted for + // transformations). IMPORTANT: both position and size are + // rounded to integer values. From now on, only those + // rounded values are used, to keep clip and content in + // sync. + ::Size aOutputSize( ::vcl::unotools::sizeFromB2DSize( rOrigOutputSize ) ); + ::Point aOutPos( ::vcl::unotools::pointFromB2DPoint( rPos ) ); + + + // TODO(F3): Support for alpha-VDev + + // Do we have to update our bitmaps (necessary if virdev + // was painted to, or transformation changed)? + const bool bNeedBitmapUpdate( io_bSurfacesDirty || + hasTransformChanged() || + maContent->IsEmpty() ); + + // updating content of sprite cache - surface is no + // longer dirty in relation to our cache + io_bSurfacesDirty = false; + transformUpdated(); + + if( bNeedBitmapUpdate ) + { + Bitmap aBmp( mpBackBuffer->getOutDev().GetBitmap( aEmptyPoint, + aOutputSize ) ); + + if( isContentFullyOpaque() ) + { + // optimized case: content canvas is fully + // opaque. Note: since we retrieved aBmp directly + // from an OutDev, it's already a 'display bitmap' + // on windows. + maContent = BitmapEx( aBmp ); + } + else + { + // sprite content might contain alpha, create + // BmpEx, then. + Bitmap aMask( mpBackBufferMask->getOutDev().GetBitmap( aEmptyPoint, + aOutputSize ) ); + + if( aMask.GetBitCount() != 1 ) + { + OSL_ENSURE(false, + "CanvasCustomSprite::redraw(): Mask bitmap is not " + "monochrome (performance!)"); + aMask.MakeMono(255); + } + + // Note: since we retrieved aBmp and aMask + // directly from an OutDev, it's already a + // 'display bitmap' on windows. + maContent = BitmapEx( aBmp, aMask ); + } + } + + ::basegfx::B2DHomMatrix aTransform( getTransformation() ); + + // check whether matrix is "easy" to handle - pure + // translations or scales are handled by OutputDevice + // alone + const bool bIdentityTransform( aTransform.isIdentity() ); + + // make transformation absolute (put sprite to final + // output position). Need to happen here, as we also have + // to translate the clip polygon + aTransform.translate( aOutPos.X(), + aOutPos.Y() ); + + if( !bIdentityTransform ) + { + if( !::basegfx::fTools::equalZero( aTransform.get(0,1) ) || + !::basegfx::fTools::equalZero( aTransform.get(1,0) ) ) + { + // "complex" transformation, employ affine + // transformator + + // modify output position, to account for the fact + // that transformBitmap() always normalizes its output + // bitmap into the smallest enclosing box. + ::basegfx::B2DRectangle aDestRect; + ::canvas::tools::calcTransformedRectBounds( aDestRect, + ::basegfx::B2DRectangle(0, + 0, + rOrigOutputSize.getX(), + rOrigOutputSize.getY()), + aTransform ); + + aOutPos.X() = ::basegfx::fround( aDestRect.getMinX() ); + aOutPos.Y() = ::basegfx::fround( aDestRect.getMinY() ); + + // TODO(P3): Use optimized bitmap transformation here. + + // actually re-create the bitmap ONLY if necessary + if( bNeedBitmapUpdate ) + maContent = tools::transformBitmap( *maContent, + aTransform, + uno::Sequence<double>(), + tools::MODULATE_NONE ); + + aOutputSize = maContent->GetSizePixel(); + } + else + { + // relatively 'simplistic' transformation - + // retrieve scale and translational offset + aOutputSize.setWidth ( + ::basegfx::fround( rOrigOutputSize.getX() * aTransform.get(0,0) ) ); + aOutputSize.setHeight( + ::basegfx::fround( rOrigOutputSize.getY() * aTransform.get(1,1) ) ); + + aOutPos.X() = ::basegfx::fround( aTransform.get(0,2) ); + aOutPos.Y() = ::basegfx::fround( aTransform.get(1,2) ); + } + } + + // transformBitmap() might return empty bitmaps, for tiny + // scales. + if( !!(*maContent) ) + { + // when true, fast path for slide transition has + // already redrawn the sprite. + bool bSpriteRedrawn( false ); + + rTargetSurface.Push( PUSH_CLIPREGION ); + + // apply clip (if any) + if( getClip().is() ) + { + ::basegfx::B2DPolyPolygon aClipPoly( + ::canvas::tools::polyPolygonFromXPolyPolygon2D( + getClip() )); + + if( aClipPoly.count() ) + { + // aTransform already contains the + // translational component, moving the clip to + // the final sprite output position. + aClipPoly.transform( aTransform ); + + if( mbShowSpriteBounds ) + { + // Paint green sprite clip area + rTargetSurface.SetLineColor( Color( 0,255,0 ) ); + rTargetSurface.SetFillColor(); + + rTargetSurface.DrawPolyPolygon( aClipPoly ); + } + +#ifndef WNT + // as a matter of fact, this fast path only + // performs well for X11 - under Windows, the + // clip via SetTriangleClipRegion is faster. + if( bBufferedUpdate && + ::rtl::math::approxEqual(fAlpha, 1.0) && + !maContent->IsTransparent() ) + { + // fast path for slide transitions + // (buffered, no alpha, no mask (because + // full slide is contained in the sprite)) + + // XOR bitmap onto backbuffer, clear area + // that should be _visible_ with black, + // XOR bitmap again on top of that - + // result: XOR cancels out where no black + // has been rendered, and yields the + // original bitmap, where black is + // underneath. + rTargetSurface.Push( PUSH_RASTEROP ); + rTargetSurface.SetRasterOp( ROP_XOR ); + rTargetSurface.DrawBitmap( aOutPos, + aOutputSize, + maContent->GetBitmap() ); + + rTargetSurface.SetLineColor(); + rTargetSurface.SetFillColor( COL_BLACK ); + rTargetSurface.SetRasterOp( ROP_0 ); + rTargetSurface.DrawPolyPolygon( aClipPoly ); + + rTargetSurface.SetRasterOp( ROP_XOR ); + rTargetSurface.DrawBitmap( aOutPos, + aOutputSize, + maContent->GetBitmap() ); + + rTargetSurface.Pop(); + + bSpriteRedrawn = true; + } + else +#endif + { + // redraw is direcly on the front buffer, + // or using alpha blending - cannot use + // XOR, thus, employing the still somewhat + // speedier triangle clip method + const ::basegfx::B2DPolyPolygon aPreparedClip(::basegfx::tools::addPointsAtCutsAndTouches(aClipPoly)); + ::basegfx::B2DPolygon aTriangulatedClip(::basegfx::triangulator::triangulate(aPreparedClip)); + + // restrict the clipping area to the visible portion of the output device. + Size aSize(rTargetSurface.GetOutputSizePixel()); + ::basegfx::B2DRange aOutputRect(::basegfx::B2DPoint(0,0),::basegfx::B2DPoint(aSize.Width(),aSize.Height())); + ::basegfx::B2DPolygon aClippedClip(::basegfx::tools::clipTriangleListOnRange(aTriangulatedClip,aOutputRect)); + + PolyPolygon aPolyPoly( aClippedClip ); + rTargetSurface.SetTriangleClipRegion(aPolyPoly); + } + } + } + + if( !bSpriteRedrawn ) + { + if( ::rtl::math::approxEqual(fAlpha, 1.0) ) + { + // no alpha modulation -> just copy to output + if( maContent->IsTransparent() ) + rTargetSurface.DrawBitmapEx( aOutPos, aOutputSize, *maContent ); + else + rTargetSurface.DrawBitmap( aOutPos, aOutputSize, maContent->GetBitmap() ); + } + else + { + // TODO(P3): Switch to OutputDevice::DrawTransparent() + // here + + // draw semi-transparent + BYTE nColor( static_cast<UINT8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) ); + AlphaMask aAlpha( maContent->GetSizePixel(), + &nColor ); + + // mask out fully transparent areas + if( maContent->IsTransparent() ) + aAlpha.Replace( maContent->GetMask(), 255 ); + + // alpha-blend to output + rTargetSurface.DrawBitmapEx( aOutPos, aOutputSize, + BitmapEx( maContent->GetBitmap(), + aAlpha ) ); + } + } + + rTargetSurface.Pop(); + + if( mbShowSpriteBounds ) + { + ::PolyPolygon aMarkerPoly( + ::canvas::tools::getBoundMarkPolyPolygon( + ::basegfx::B2DRectangle(aOutPos.X(), + aOutPos.Y(), + aOutPos.X() + aOutputSize.Width()-1, + aOutPos.Y() + aOutputSize.Height()-1) ) ); + + // Paint little red sprite area markers + rTargetSurface.SetLineColor( Color( 255,0,0 ) ); + rTargetSurface.SetFillColor(); + + for( int i=0; i<aMarkerPoly.Count(); ++i ) + { + rTargetSurface.DrawPolyLine( aMarkerPoly.GetObject(i) ); + } + } + } + } + } + + void SpriteHelper::clearSurface() + { + ENSURE_AND_THROW( mpBackBuffer && mpBackBufferMask, + "SpriteHelper::clearSurface(): disposed" ); + + const ::Point aEmptyPoint; + const ::Rectangle aSpriteRect( aEmptyPoint, + ::vcl::unotools::sizeFromB2DSize( getSizePixel() ) ); + const ::Color aWhiteColor( COL_WHITE ); + + OutputDevice& rOutDev( mpBackBuffer->getOutDev() ); + rOutDev.EnableMapMode( FALSE ); + rOutDev.SetFillColor( aWhiteColor ); + rOutDev.SetLineColor(); + rOutDev.DrawRect( aSpriteRect ); + + OutputDevice& rMaskOutDev( mpBackBufferMask->getOutDev() ); + rMaskOutDev.SetDrawMode( DRAWMODE_DEFAULT ); + rMaskOutDev.EnableMapMode( FALSE ); + rMaskOutDev.SetFillColor( aWhiteColor ); + rMaskOutDev.SetLineColor(); + rMaskOutDev.DrawRect( aSpriteRect ); + rMaskOutDev.SetDrawMode( DRAWMODE_BLACKLINE | DRAWMODE_BLACKFILL | DRAWMODE_BLACKTEXT | + DRAWMODE_BLACKGRADIENT | DRAWMODE_BLACKBITMAP ); + } + + ::basegfx::B2DPolyPolygon SpriteHelper::polyPolygonFromXPolyPolygon2D( uno::Reference< rendering::XPolyPolygon2D >& xPoly ) const + { + return ::canvas::tools::polyPolygonFromXPolyPolygon2D( xPoly ); + } + +} |