webengine/osswebengine/WebCore/platform/symbian/bitmap/MaskedBitmap.cpp
changeset 0 dd21522fd290
child 1 7c90e6132015
--- /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