--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/platform/symbian/bitmap/MaskedBitmap.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,670 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Default implementation of bitmap class.
+*
+*/
+
+
+// INCLUDE FILES
+#include "MaskedBitmap.h"
+#include "BitmapTiler.h"
+#include <fbs.h>
+#include <bitstd.h>
+#include <bitdev.h>
+
+// CONSTANTS
+static const TInt KCompressRatioThreshold = 16;
+
+// ======================== STATIC FACTORY FUNCTIONS ===========================
+#define GET_PIX_GRAY2(buf, x, y, w) (((TUint32*)((TUint8*)buf + y*w))[x>>5] & (1<<(x&0x1f)))
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::CopyBitmap
+// -----------------------------------------------------------------------------
+TInt BitmapUtil::CopyBitmap( const CFbsBitmap& aSource, CFbsBitmap& aDestination )
+ {
+ TSize size( aSource.SizeInPixels() );
+ TDisplayMode displayMode( aSource.DisplayMode() );
+ TInt err( aDestination.Create( size, displayMode ) );
+ if( !err )
+ {
+ err = BitmapUtil::CopyBitmapData( aSource, aDestination, size, displayMode );
+ if( err )
+ {
+ aDestination.Reset();
+ }
+ }
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::CopyBitmapData
+// -----------------------------------------------------------------------------
+TInt BitmapUtil::CopyBitmapData( const CFbsBitmap& aSource, CFbsBitmap& aDestination,
+ const TSize& aSize, const TDisplayMode& aDisplayMode )
+ {
+ HBufC8* scanLine = HBufC8::New( aSource.ScanLineLength( aSize.iWidth, aDisplayMode ) );
+ if( scanLine )
+ {
+ TPtr8 scanPtr( scanLine->Des() );
+ TPoint pp;
+ for( pp.iY = 0; pp.iY < aSize.iHeight; ++pp.iY )
+ {
+ aSource.GetScanLine( scanPtr, pp, aSize.iWidth, aDisplayMode );
+ aDestination.SetScanLine( scanPtr, pp.iY );
+ }
+
+ delete scanLine;
+ return KErrNone;
+ }
+ return KErrNoMemory; // scanLine alloc failed
+ }
+
+// -----------------------------------------------------------------------------
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+CMaskedBitmap::CMaskedBitmap()
+ {
+ }
+
+
+CMaskedBitmap::CMaskedBitmap(CFbsBitmap* aBitmap, CFbsBitmap* aMask)
+: iBitmap(aBitmap),iMask(aMask)
+ {
+ }
+
+// ----------------------------------------------------------------------------
+//
+// Second phase constructors. Can leave.
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::ConstructL()
+ {
+ iBitmap = new (ELeave) CFbsBitmap;
+ iMask = new (ELeave) CFbsBitmap;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// Two-phased constructors.
+// -----------------------------------------------------------------------------
+CMaskedBitmap* CMaskedBitmap::NewL()
+ {
+ CMaskedBitmap* self = new( ELeave ) CMaskedBitmap;
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+CMaskedBitmap::~CMaskedBitmap()
+ {
+ delete iBitmap;
+ delete iMask;
+ delete iScaledBitmap;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::CreateCopyMode
+// -----------------------------------------------------------------------------
+TInt CMaskedBitmap::CreateCopyingDisplayMode( const TSize& aSize, const CMaskedBitmap& aCopyFrom )
+ {
+ if (aCopyFrom.HasMask())
+ {
+ return Create(aSize,aCopyFrom.Bitmap().DisplayMode(),aCopyFrom.Mask().DisplayMode());
+ }
+ else
+ {
+ return Create(aSize,aCopyFrom.Bitmap().DisplayMode());
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Create
+// -----------------------------------------------------------------------------
+TInt CMaskedBitmap::Create( const TSize& aSize, TDisplayMode aDisplayMode )
+ {
+ Reset();
+ return iBitmap->Create( aSize, aDisplayMode );
+ }
+
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Create
+// -----------------------------------------------------------------------------
+TInt CMaskedBitmap::Create( const TSize& aSize, TDisplayMode aBitmapDisplayMode,
+ TDisplayMode aMaskDisplayMode )
+ {
+ Reset();
+ TInt err( iBitmap->Create( aSize, aBitmapDisplayMode ) );
+ if( err )
+ {
+ return err;
+ }
+ err = iMask->Create( aSize, aMaskDisplayMode );
+ if( err )
+ {
+ iBitmap->Reset();
+ }
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Copy
+// -----------------------------------------------------------------------------
+TInt CMaskedBitmap::Copy( const CFbsBitmap& aBitmap, TBool aDuplicate )
+ {
+ Reset();
+
+ TInt err( KErrNone );
+ TInt bitmapHandle( aBitmap.Handle() );
+ if( bitmapHandle )
+ {
+ if( aDuplicate )
+ {
+ err = iBitmap->Duplicate( bitmapHandle );
+ }
+ else
+ {
+ err = BitmapUtil::CopyBitmap( aBitmap, *iBitmap );
+ }
+ }
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Copy
+// -----------------------------------------------------------------------------
+TInt CMaskedBitmap::Copy( const CFbsBitmap& aBitmap, const CFbsBitmap& aMask, TBool aDuplicate )
+ {
+ Reset();
+
+ TInt bitmapHandle( aBitmap.Handle() );
+ TInt maskHandle( aMask.Handle() );
+ if( bitmapHandle && maskHandle &&
+ aBitmap.SizeInPixels() != aMask.SizeInPixels() )
+ {
+ return KErrArgument;
+ }
+
+ TInt err( KErrNone );
+ if( bitmapHandle )
+ {
+ if( aDuplicate )
+ {
+ err = iBitmap->Duplicate( bitmapHandle );
+ }
+ else
+ {
+ err = BitmapUtil::CopyBitmap( aBitmap, *iBitmap );
+ }
+ }
+
+ if( !err && maskHandle )
+ {
+ if( aDuplicate )
+ {
+ err = iMask->Duplicate( maskHandle );
+ }
+ else
+ {
+ err = BitmapUtil::CopyBitmap( aMask, *iMask );
+ }
+ if( err )
+ {
+ iBitmap->Reset();
+ }
+ }
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Copy
+// -----------------------------------------------------------------------------
+TInt CMaskedBitmap::Copy( const CMaskedBitmap& aBitmap, TBool aDuplicate )
+ {
+ return Copy( aBitmap.Bitmap(), aBitmap.Mask(), aDuplicate );
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Reset
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::Reset()
+ {
+ iBitmap->Reset();
+ iMask->Reset();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::IsCreated
+// -----------------------------------------------------------------------------
+TBool CMaskedBitmap::IsCreated() const
+ {
+ return ( iBitmap->Handle() != 0 );
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Bitmap
+// -----------------------------------------------------------------------------
+const CFbsBitmap& CMaskedBitmap::Bitmap() const
+ {
+ return *iBitmap;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::HasMask
+// -----------------------------------------------------------------------------
+TBool CMaskedBitmap::HasMask() const
+ {
+ return ( iMask->Handle() != 0 );
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Mask
+// -----------------------------------------------------------------------------
+const CFbsBitmap& CMaskedBitmap::Mask() const
+ {
+ return *iMask;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::BitBlt
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::BitBlt( CFbsBitGc& aContext, const TPoint& aPoint ) const
+ {
+ TSize s(iBitmap->SizeInPixels());
+ if (!(s.iWidth>0 && s.iHeight>0))
+ {
+ return;
+ }
+ if( iBitmap->Handle() )
+ {
+ if( iMask->Handle() )
+ {
+ aContext.BitBltMasked( aPoint, iBitmap, s, iMask, iInvertMask );
+ }
+ else
+ {
+ aContext.BitBlt( aPoint, iBitmap, s );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::BitBlt
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::BitBlt( CFbsBitGc& aContext, const TPoint& aPoint, const TRect& aSource ) const
+ {
+ if (!(aSource.Width()>0 && aSource.Height()>0))
+ {
+ return;
+ }
+ if( iBitmap->Handle() )
+ {
+ if( iMask->Handle() )
+ {
+
+ aContext.BitBltMasked( aPoint, iBitmap, aSource, iMask, iInvertMask );
+ }
+ else
+ {
+ aContext.BitBlt( aPoint, iBitmap, aSource );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::DrawBitmap
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::DrawBitmap( CFbsBitGc& aContext, const TRect& aTarget ) const
+ {
+ TSize s(iBitmap->SizeInPixels());
+ if (!(aTarget.Width()>0 && aTarget.Height()>0 && s.iWidth>0 && s.iHeight>0))
+ {
+ return;
+ }
+ if( iBitmap->Handle() )
+ {
+ // ### FIXME DrawBitmapMasked is too buggy to use 2.8/week52, so no transparency with scaling
+ if( iMask->Handle() )
+ {
+ aContext.DrawBitmapMasked( aTarget, iBitmap, s, iMask, iInvertMask );
+ }
+ else
+ {
+ aContext.DrawBitmap( aTarget, iBitmap );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::DrawBitmap
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::DrawBitmap( CFbsBitGc& aContext, const TRect& aTarget, const TRect& aSource) const
+ {
+ if (!(aSource.Width()>0 && aSource.Height()>0 && aTarget.Width()>0 && aTarget.Height()>0))
+ {
+ return;
+ }
+ if( iBitmap->Handle() )
+ {
+ // ### FIXME DrawBitmapMasked is too buggy to use 2.8/week52, so no transparency with scaling
+ if( iMask->Handle() )
+ {
+ aContext.DrawBitmapMasked( aTarget, iBitmap, aSource, iMask, iInvertMask );
+ }
+ else
+ {
+ aContext.DrawBitmap( aTarget, iBitmap, aSource );
+ }
+ }
+ }
+
+// Internal interface
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::SetFilename
+// -----------------------------------------------------------------------------
+CFbsBitmap& CMaskedBitmap::BitmapModifyable()
+ {
+ return *iBitmap;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::SetFilename
+// -----------------------------------------------------------------------------
+CFbsBitmap& CMaskedBitmap::MaskModifyable()
+ {
+ return *iMask;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::SetFrameIndex
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::SetFrameIndex( TInt aFrameIndex )
+ {
+ iFrameIndex = aFrameIndex;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::SetFrameDelay
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::SetFrameDelay( TTimeIntervalMicroSeconds32 aFrameDelay )
+ {
+ iFrameDelay = aFrameDelay;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::FrameIndex
+// -----------------------------------------------------------------------------
+TInt CMaskedBitmap::FrameIndex() const
+ {
+ return iFrameIndex;
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::FrameDelay
+// -----------------------------------------------------------------------------
+TTimeIntervalMicroSeconds32 CMaskedBitmap::FrameDelay() const
+ {
+ return iFrameDelay;
+ }
+
+// Private methods
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::SizeInPixels
+// -----------------------------------------------------------------------------
+TSize CMaskedBitmap::SizeInPixels() const
+ {
+ return iBitmap->SizeInPixels();
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::Resize
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::Resize(TSize aSize)
+ {
+ iBitmap->Resize(aSize);
+ if (iMask)
+ {
+ iMask->Resize(aSize);
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMaskedBitmap::TileInBitmapRect
+// -----------------------------------------------------------------------------
+void CMaskedBitmap::TileInBitmapRect( CFbsBitGc& gc, const TRect& bmpRect, const TPoint& srcPt )
+ {
+ if (!HasMask())
+ {
+ gc.UseBrushPattern(iBitmap);
+ gc.SetBrushStyle(CGraphicsContext::EPatternedBrush);
+ gc.SetBrushOrigin(srcPt);
+ gc.DrawRect(bmpRect);
+ gc.DiscardBrushPattern();
+ }
+ else
+ {
+ gc.SetBrushStyle(CGraphicsContext::ENullBrush);
+ TPoint off(srcPt.iX, srcPt.iY);
+ for (TInt x = off.iX; x<bmpRect.iBr.iX; x+=SizeInPixels().iWidth)
+ {
+ for (TInt y = off.iY; y<bmpRect.iBr.iY; y+=SizeInPixels().iHeight)
+ {
+ TRect rect(TPoint(x,y), SizeInPixels());
+ BitBlt(gc, rect.iTl);
+ }
+ }
+ }
+ }
+
+void CMaskedBitmap::TileInBitmapRect( CFbsBitmap* trgBmp, const TRect& aTrgRect, const TPoint& aOffset )
+ {
+ trgBmp->LockHeap();
+
+ TSize sz = trgBmp->SizeInPixels();
+ TUint32* buf = (TUint32*)(trgBmp->DataAddress());
+
+ // bitmap with 32-bit depth doesn't need padding for a scanline.
+ TInt padding = trgBmp->DisplayMode() == EColor16MU ? 0 : (sz.iWidth & 1);
+
+ TInt32 stride = padding;
+ stride += sz.iWidth - aTrgRect.Width();
+
+ // calculate the offset in image space
+ TRect srcRect( TPoint(0,0), iBitmap->SizeInPixels() );
+ const TSize& imgSz = srcRect.Size();
+ TPoint offset( aOffset.iX % imgSz.iWidth, aOffset.iY % imgSz.iHeight );
+
+ // prepare to fetch scanline
+ TBool fastAccess = EFalse;
+ if( !iBitmap->IsCompressedInRAM() && ( !HasMask() || !iMask->IsCompressedInRAM() ) )
+ fastAccess = ETrue;
+
+ CScanLineFetcher* fetcher = 0;
+
+ // possible OOM
+ TRAPD( err,
+ if( fastAccess )
+ fetcher = CFastScanLineFetcher::NewL( this, offset.iX, offset.iY );
+ else
+ fetcher = CCompressedScanLineFetcher::NewL( this, offset.iX, offset.iY );
+ );
+ if( err )
+ {
+ trgBmp->UnlockHeap();
+ return;
+ }
+
+ if( trgBmp->DisplayMode() == EColor16MU )
+ {
+ // starting address in trgBmp
+ buf += (TUint32)( aTrgRect.iTl.iX + aTrgRect.iTl.iY * ( sz.iWidth + padding ) );
+
+ if( HasMask() )
+ {
+ if( iMask->DisplayMode() == EGray2 )
+ {
+ // 1-bit mask
+ TScanLineTiler<TSrcScanLineMasked, TUint32*> tiler( aTrgRect.Width(), offset.iX );
+ TileBitmap<TSrcScanLineMasked, TUint32*>( buf, stride, *fetcher, tiler, aTrgRect.Height(),
+ srcRect.Width(), srcRect.Height(), offset );
+ }
+ else
+ {
+ // alpha blending
+ TScanLineTiler<TSrcScanLineAlpha, TUint32*> tiler( aTrgRect.Width(), offset.iX );
+ TileBitmap<TSrcScanLineAlpha, TUint32*>( buf, stride, *fetcher, tiler, aTrgRect.Height(),
+ srcRect.Width(), srcRect.Height(), offset );
+ }
+ }
+ else
+ {
+ // direct drawing
+ TScanLineTiler<TSrcScanLine, TUint32*> tiler( aTrgRect.Width(), offset.iX );
+ TileBitmap<TSrcScanLine, TUint32*>( buf, stride, *fetcher, tiler, aTrgRect.Height(),
+ srcRect.Width(), srcRect.Height(), offset );
+ }
+ }
+ else if( trgBmp->DisplayMode() == EColor64K )
+ {
+ // starting address in trgBmp
+ TUint16* buf16 = (TUint16*)buf;
+ buf16 += (TUint32)( aTrgRect.iTl.iX + aTrgRect.iTl.iY * ( sz.iWidth + padding ) );
+ if( HasMask() )
+ {
+ if( iMask->DisplayMode() == EGray2 )
+ {
+ // 1-bit mask
+ TScanLineTiler<TSrcScanLineMasked, TUint16*> tiler( aTrgRect.Width(), offset.iX );
+ TileBitmap<TSrcScanLineMasked, TUint16*>( buf16, stride, *fetcher, tiler, aTrgRect.Height(),
+ srcRect.Width(), srcRect.Height(), offset );
+ }
+ else
+ {
+ // alpha blending
+ TScanLineTiler<TSrcScanLineAlpha, TUint16*> tiler( aTrgRect.Width(), offset.iX );
+ TileBitmap<TSrcScanLineAlpha, TUint16*>( buf16, stride, *fetcher, tiler, aTrgRect.Height(),
+ srcRect.Width(), srcRect.Height(), offset );
+ }
+ }
+ else
+ {
+ // direct drawing
+ TScanLineTiler<TSrcScanLine, TUint16*> tiler( aTrgRect.Width(), offset.iX );
+ TileBitmap<TSrcScanLine, TUint16*>( buf16, stride, *fetcher, tiler, aTrgRect.Height(),
+ srcRect.Width(), srcRect.Height(), offset );
+ }
+ }
+
+ delete fetcher;
+ trgBmp->UnlockHeap();
+ }
+
+
+TBool CMaskedBitmap::IsFullyTransparent()
+ {
+ if (!iMask || !iMask->Handle())
+ {
+ return EFalse;
+ }
+
+ if( iMask->DisplayMode() != EGray2 )
+ {
+ return EFalse; // fully transparent png? rare, dont bother
+ }
+
+ TUint32* msk = iMask->DataAddress();
+ TSize mskSz = iMask->SizeInPixels();
+ TInt mskScanLineW = iMask->ScanLineLength( mskSz.iWidth, iMask->DisplayMode() );
+
+ TUint32 trgMask;
+
+ iMask->LockHeap();
+
+ for( TInt y=0; y<mskSz.iHeight; ++y )
+ {
+ for( TInt x=0; x<mskSz.iWidth; ++x )
+ {
+ trgMask = GET_PIX_GRAY2(msk, x, y, mskScanLineW);
+
+ if (trgMask)
+ {
+ return EFalse;
+ }
+ }
+ }
+
+ iMask->UnlockHeap();
+ return ETrue;
+ }
+
+void CMaskedBitmap::CompressIfNeeded( TInt aRawSize )
+ {
+ // check if the image is highly compressed
+ TSize sz = iBitmap->SizeInPixels();
+ if( KCompressRatioThreshold * aRawSize < sz.iWidth * sz.iHeight )
+ {
+ iBitmap->Compress();
+ if( HasMask() )
+ iMask->Compress();
+ }
+ }
+
+CMaskedBitmap* CMaskedBitmap::ScaleImageToSize( TSize newSize )
+{
+ if (iScaledBitmap && iScaledBitmap->SizeInPixels() == newSize)
+ return iScaledBitmap;
+
+ delete iScaledBitmap;
+ iScaledBitmap = CMaskedBitmap::NewL();
+
+ CFbsBitmap& bmp = iScaledBitmap->BitmapModifyable();
+ bmp.Create(newSize, iBitmap->DisplayMode());
+
+ // scale the image quickly
+ CFbsBitGc* bitGc;
+ CFbsBitmapDevice* bitDevice = CFbsBitmapDevice::NewL( &bmp );
+ CleanupStack::PushL( bitDevice );
+ User::LeaveIfError( bitDevice->CreateContext( bitGc ) );
+ CleanupStack::PushL( bitGc );
+ bitGc->DrawBitmap(TRect(TPoint(0,0), newSize), iBitmap, iBitmap->SizeInPixels());
+ CleanupStack::PopAndDestroy(2);
+
+ CFbsBitmap& msk = iScaledBitmap->MaskModifyable();
+ if( HasMask() ) {
+ msk.Create(newSize, iMask->DisplayMode());
+
+ // scale the image quickly
+ CFbsBitGc* bitGc;
+ CFbsBitmapDevice* bitDevice = CFbsBitmapDevice::NewL( &msk );
+ CleanupStack::PushL( bitDevice );
+ User::LeaveIfError( bitDevice->CreateContext( bitGc ) );
+ CleanupStack::PushL( bitGc );
+ bitGc->DrawBitmap(TRect(TPoint(0,0), newSize), iMask, iMask->SizeInPixels());
+ CleanupStack::PopAndDestroy(2);
+ }
+
+ return iScaledBitmap;
+}
+
+// End of File