javauis/lcdui_akn/lcdgr/src/LcdFbsImage.cpp
branchRCL_3
changeset 14 04becd199f91
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_akn/lcdgr/src/LcdFbsImage.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,480 @@
+/*
+* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+*
+*/
+
+#include <bitdev.h>
+#include <bitstd.h>
+#include <lcdgdrv.h>
+#include "LcdFbsImage.h"
+
+#ifdef LCDGR_ACCELERATED_BITGDI
+const TUid KJvmExeUid = { 0x102033E6 };
+#endif
+
+/**
+ * Copy bitmap data from (aColorBitmap,aAlphaBitmap) to aFbsImage.
+ */
+extern void CopyBitmapsL
+(
+    CLcdGraphicsDriver& /* aDriver */,  // not used yet
+    CLcdFbsImage&       aFbsImage,
+    CFbsBitmap*         aColorBitmap,
+    CFbsBitmap*         aAlphaBitmap,
+    TBool               aInvertMask
+);
+
+/**
+ * Create a CFbsBitmap of size aSize in displaymode aMode
+ */
+LOCAL_C CFbsBitmap* CreateBitmapL(const TSize& aSize, TDisplayMode aMode);
+
+/**
+ * Set alpha channel in EColor16MA mode aBitmap from aAlphaBitmap. If aAlphaBitmap is
+ * in a mode other than EGray256 this procedure will create a temporary bitmap in
+ * EGray256 mode and copy pixels from aAlphaBitmap into that first. It is expected
+ * that aAlphaBitmap would be a binary mask.
+ */
+LOCAL_C void SetAlphaChannelL(CFbsBitmap* aBitmap, CFbsBitmap* aAlphaBitmap, TBool aInvert);
+
+/**
+ * Set the alpha channel in an EColor16MA mode aBitmap from an EGray256 mode
+ * aGray256Bitmap.
+ */
+LOCAL_C void SetAlphaChannel(CFbsBitmap* aBitmap, CFbsBitmap* aGray256Bitmap, TBool aInvert);
+
+/**
+ * Copy alpha information from EColor16MA bitmap aSource, into EGray2 or EGray256
+ * bitmap aTarget.
+ */
+LOCAL_C void GetAlphaChannelL(CFbsBitmap* aTarget, CFbsBitmap* aSource, TBool aInvert);
+
+/**
+ * Copy alpha channel from EColor16MA bitmap into an EGray256 bitmap
+ */
+LOCAL_C void GetAlphaChannel(CFbsBitmap* aTargetGray256, CFbsBitmap* aSourceColor16MA, TBool aInvert);
+
+#ifdef _DEBUG
+//
+// debug only - check that EColor16MA aBitmap is fully opaque
+//
+LOCAL_C TBool CheckOpaque(CFbsBitmap* aBitmap);
+#endif
+
+
+/*************************************************************
+ *
+ * CLcdFbsImage potentially public bitmapped image class.
+ *
+ ************************************************************/
+
+CLcdFbsImage* CLcdFbsImage::NewL(const TSize& aSize, TDisplayMode aColorMode, TDisplayMode aAlphaMode)
+{
+    CLcdFbsImage* image = new(ELeave) CLcdFbsImage;
+    CleanupStack::PushL(image);
+    image->iColorBitmap = CreateBitmapL(aSize, aColorMode);
+    if (aAlphaMode)
+    {
+        image->iAlphaBitmap = CreateBitmapL(aSize, aAlphaMode);
+    }
+    CleanupStack::Pop(image);
+    return image;
+}
+
+CLcdFbsImage* CLcdFbsImage::NewL(CFbsBitmap* aColorBitmap, CFbsBitmap* aAlphaBitmap)
+{
+    CLcdFbsImage* image = new(ELeave) CLcdFbsImage;
+
+    CleanupStack::PushL(image);
+    image->iColorBitmap = DuplicateBitmapL(aColorBitmap);
+    if (aAlphaBitmap)
+    {
+        image->iAlphaBitmap = DuplicateBitmapL(aAlphaBitmap);
+    }
+    CleanupStack::Pop(image);
+
+    return image;
+}
+
+CLcdFbsImage::~CLcdFbsImage()
+{
+    ASSERT(0 == iRefCount);
+    delete iAlphaBitmap;
+    delete iColorBitmap;
+}
+
+TSize CLcdFbsImage::Size() const
+{
+    return iColorBitmap->SizeInPixels();
+}
+
+void CLcdFbsImage::AddRef()
+{
+    ++iRefCount;
+}
+
+void CLcdFbsImage::RemoveRef()
+{
+    --iRefCount;
+    if (iRefCount == 0)
+    {
+        delete this;
+    }
+}
+
+/**
+ *@return the color bitmap
+ */
+CFbsBitmap* CLcdFbsImage::ColorBitmap() const
+{
+    return iColorBitmap;
+}
+
+/**
+ *@return the alpha bitmap if any
+ */
+CFbsBitmap* CLcdFbsImage::AlphaBitmap() const
+{
+    return iAlphaBitmap;
+}
+
+void CLcdFbsImage::CreateAlphaBitmapL()
+{
+    if (iAlphaBitmap)
+    {
+        User::Leave(KErrAlreadyExists);
+    }
+
+    iAlphaBitmap = CreateBitmapL(Size(), EGray256);
+}
+
+/**
+ * Create a bitmap of size aSize in display mode aMode.
+ */
+LOCAL_C CFbsBitmap* CreateBitmapL(const TSize& aSize, TDisplayMode aMode)
+{
+    TInt err = KErrNotSupported;
+
+    CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
+    CleanupStack::PushL(bitmap);
+
+#ifdef LCDGR_ACCELERATED_BITGDI
+    //
+    // Attempt to create hardware bitmap which can be used with a
+    // hardware graphics accelerator. Very few if any devices
+    // appear to support RHardwareBitmap so this is very unlikely
+    // to be used.
+    //
+    err = bitmap->CreateHardwareBitmap(aSize, aMode, KJvmExeUid);
+#endif
+
+    if (err != KErrNone)
+    {
+        //
+        // Fallback to software only bitmap if hardware unavailable/not supported.
+        //
+        err = bitmap->Create(aSize, aMode);
+    }
+
+    User::LeaveIfError(err);
+
+    CleanupStack::Pop(bitmap);
+
+    return bitmap;
+}
+
+/**
+ * Create a new bitmap in a given mode and copy the data.
+ * Slowish closest match copy. We could use lcd graphics driver for some
+ * of these copies but is good enough for now.
+ */
+CFbsBitmap* CLcdFbsImage::CopyBitmapL(CFbsBitmap* aBitmap, TDisplayMode aMode, TBool aInvert)
+{
+    CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
+    CleanupStack::PushL(bitmap);
+    User::LeaveIfError(bitmap->Create(aBitmap->SizeInPixels(), aMode));
+    CopyBitmapL(bitmap, aBitmap, aInvert);
+    CleanupStack::Pop(bitmap);
+    return bitmap;
+}
+
+/**
+ * Copy bitmap content from aSource to aTarget optionally inverting.
+ */
+void CLcdFbsImage::CopyBitmapL(CFbsBitmap* aTarget, CFbsBitmap* aSource, TBool aInvert)
+{
+    CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(aTarget);
+    CleanupStack::PushL(device);
+    CFbsBitGc* gc = NULL;
+    User::LeaveIfError(device->CreateContext(gc));
+
+    // Don't alpha blend (Either copy the alpha component or write opaque pixels)
+    TInt drawMode = CGraphicsContext::EDrawModeWriteAlpha;
+    if (aInvert)
+    {
+        // Invert pixel values - only really makes sense for binary masks
+        // For EColor16MA images the alpha component is not inverted
+        drawMode |= CGraphicsContext::EInvertPen;
+    }
+
+    gc->SetDrawMode(CGraphicsContext::TDrawMode(drawMode));
+    gc->BitBlt(TPoint(), aSource);
+    delete gc;
+    CleanupStack::PopAndDestroy(device);
+}
+
+/**
+ * Dup the handle. This requires an FBSERV ipc.
+ */
+CFbsBitmap* CLcdFbsImage::DuplicateBitmapL(CFbsBitmap* aBitmap)
+{
+    CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
+    CleanupStack::PushL(bitmap);
+    User::LeaveIfError(bitmap->Duplicate(aBitmap->Handle()));
+    CleanupStack::Pop(bitmap);
+    return bitmap;
+}
+
+/**
+ * Copy bitmap data from (aColorBitmap,aAlphaBitmap) to aFbsImage.
+ */
+extern void CopyBitmapsL
+(
+    CLcdGraphicsDriver& /* aDriver */,  // not used yet
+    CLcdFbsImage&       aFbsImage,
+    CFbsBitmap*         aColorBitmap,
+    CFbsBitmap*         aAlphaBitmap,
+    TBool               aInvertMask
+)
+{
+    //
+    // First copy the the pixel color data.
+    //
+    CLcdFbsImage::CopyBitmapL(aFbsImage.ColorBitmap(), aColorBitmap, EFalse);
+
+    //
+    // If target colour bitmap contains alpha channel, copy any alpha data
+    // into it.
+    //
+    if (aFbsImage.ColorBitmap()->DisplayMode() == EColor16MA)
+    {
+        ASSERT(NULL == aFbsImage.AlphaBitmap());
+        if (aAlphaBitmap)
+        {
+            SetAlphaChannelL(aFbsImage.ColorBitmap(), aAlphaBitmap, aInvertMask);
+        }
+#ifdef _DEBUG
+        else
+        {
+            ASSERT(CheckOpaque(aFbsImage.ColorBitmap()));
+        }
+#endif
+    }
+    else if (aFbsImage.AlphaBitmap())
+    {
+        if (aAlphaBitmap)
+        {
+            CLcdFbsImage::CopyBitmapL(aFbsImage.AlphaBitmap(), aAlphaBitmap, EFalse);
+        }
+        else if (aColorBitmap->DisplayMode() == EColor16MA)
+        {
+            GetAlphaChannelL(aFbsImage.AlphaBitmap(), aColorBitmap, aInvertMask);
+        }
+    }
+}
+
+
+//
+// Set the alpha channel in a bitmap in a mode that contains alpha
+// information from an alpha bitmap.
+//
+// Not the cheapest, but this is hopefully an edge case.
+//
+// EColor16M,Gray256 is the most likely format, so a dedicated blitter
+// could help.
+//
+LOCAL_C void SetAlphaChannelL(CFbsBitmap* aBitmap, CFbsBitmap* aAlphaBitmap, TBool aInvert)
+{
+    ASSERT(aBitmap->DisplayMode() == EColor16MA);
+    if (aAlphaBitmap->DisplayMode() != EGray256)
+    {
+        CFbsBitmap* alpha = CLcdFbsImage::CopyBitmapL(aAlphaBitmap, EGray256, EFalse);
+        SetAlphaChannel(aBitmap, alpha, aInvert);
+        delete alpha;
+    }
+    else
+    {
+        SetAlphaChannel(aBitmap, aAlphaBitmap, aInvert);
+    }
+}
+
+//
+// Set the alpha channel in an EColor16MA bitmap from an EGray256
+// bitmap.
+//
+LOCAL_C void SetAlphaChannel(CFbsBitmap* aBitmap, CFbsBitmap* aGray256Bitmap, TBool aInvert)
+{
+    ASSERT(aBitmap->DisplayMode()        == EColor16MA);
+    ASSERT(aGray256Bitmap->DisplayMode() == EGray256);
+
+    TAcceleratedBitmapSpec targetSpec(aBitmap);
+    TAcceleratedBitmapInfo target;
+    TAcceleratedBitmapSpec sourceSpec(aGray256Bitmap);
+    TAcceleratedBitmapInfo source;
+    TBitmapLockCount count;
+
+    targetSpec.Lock(count);
+    sourceSpec.Lock(count);
+
+    targetSpec.GetInfo(target);
+    sourceSpec.GetInfo(source);
+
+    ASSERT(target.iSize == source.iSize);
+
+    TUint8* tgtAddress   = target.iAddress;
+    TInt    tgtLinePitch = target.iLinePitch;
+    TUint8* srcAddress   = source.iAddress;
+    TInt    srcLinePitch = source.iLinePitch;
+
+    TUint32 mask = aInvert ? 0xff:0x00;
+    for (TInt h=target.iSize.iHeight; --h>=0;)
+    {
+        TUint8*  src = srcAddress;
+        TUint32* tgt = (TUint32*)tgtAddress;
+        TUint32* end = tgt + target.iSize.iWidth;
+        while (tgt < end)
+        {
+            TUint32 alpha = (*src) ^ mask;
+            TUint32 pixel = *tgt;
+            pixel &= 0x00ffffff;
+            pixel |= (alpha << 24);
+            *tgt = pixel;
+            ++src;
+            ++tgt;
+        }
+        tgtAddress += tgtLinePitch;
+        srcAddress += srcLinePitch;
+    }
+
+    sourceSpec.Unlock(count);
+    targetSpec.Unlock(count);
+}
+
+
+//
+// Copy alpha information from EColor16MA bitmap aSource, into EGray2 or EGray256
+// bitmap aTarget.
+//
+LOCAL_C void GetAlphaChannelL(CFbsBitmap* aTarget, CFbsBitmap* aSource, TBool aInvert)
+{
+    ASSERT(aTarget->DisplayMode() == EGray2 || aTarget->DisplayMode() == EGray256);
+    if (aTarget->DisplayMode() == EGray2)
+    {
+        TSize size = aSource->SizeInPixels();
+        CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
+        CleanupStack::PushL(bitmap);
+        User::LeaveIfError(bitmap->Create(size, EGray256));
+        GetAlphaChannel(bitmap, aSource, aInvert);
+        CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(aTarget);
+        CleanupStack::PushL(device);
+        CFbsBitGc* context = NULL;
+        User::LeaveIfError(device->CreateContext(context));
+        context->BitBlt(TPoint(), bitmap);
+        delete context;
+        CleanupStack::PopAndDestroy(device);
+        CleanupStack::PopAndDestroy(bitmap);
+    }
+    else
+    {
+        GetAlphaChannel(aTarget, aSource, aInvert);
+    }
+}
+
+//
+// Copy alpha channel from EColor16MA bitmap into an EGray256 bitmap
+//
+LOCAL_C void GetAlphaChannel(CFbsBitmap* aTargetGray256, CFbsBitmap* aSourceColor16MA, TBool aInvert)
+{
+    ASSERT(aTargetGray256->DisplayMode()   == EGray256);
+    ASSERT(aSourceColor16MA->DisplayMode() == EColor16MA);
+
+    TAcceleratedBitmapSpec targetSpec(aTargetGray256);
+    TAcceleratedBitmapInfo target;
+    TAcceleratedBitmapSpec sourceSpec(aSourceColor16MA);
+    TAcceleratedBitmapInfo source;
+    TBitmapLockCount count;
+
+    targetSpec.Lock(count);
+    sourceSpec.Lock(count);
+
+    targetSpec.GetInfo(target);
+    sourceSpec.GetInfo(source);
+
+    ASSERT(target.iSize == source.iSize);
+
+    TUint8* tgtAddress   = target.iAddress;
+    TInt    tgtLinePitch = target.iLinePitch;
+    TUint8* srcAddress   = source.iAddress;
+    TInt    srcLinePitch = source.iLinePitch;
+
+    TUint32 mask = aInvert ? 0xff:0x00;
+    for (TInt h=target.iSize.iHeight; --h>=0;)
+    {
+        TUint32*  src = (TUint32*)srcAddress;
+        TUint8*   tgt = (TUint8*)tgtAddress;
+        TUint8*   end = tgt + target.iSize.iWidth;
+        while (tgt < end)
+        {
+            *tgt++ = (TUint8)(((*src++)>>24)^mask);
+        }
+        tgtAddress += tgtLinePitch;
+        srcAddress += srcLinePitch;
+    }
+
+    sourceSpec.Unlock(count);
+    targetSpec.Unlock(count);
+}
+
+#ifdef _DEBUG
+LOCAL_C TBool CheckOpaque(CFbsBitmap* aBitmap)
+{
+    ASSERT(aBitmap->DisplayMode() == EColor16MA);
+    TAcceleratedBitmapSpec spec(aBitmap);
+    TAcceleratedBitmapInfo info;
+    TBitmapLockCount count;
+
+    spec.Lock(count);
+    spec.GetInfo(info);
+
+    TUint8* address = info.iAddress;
+    TInt    linePitch = info.iLinePitch;
+    TUint32 accum = 0xff000000;
+
+    for (TInt h=info.iSize.iHeight; --h>=0;)
+    {
+        TUint32* src = (TUint32*)address;
+        TUint32* end = src + info.iSize.iWidth;
+        while (src < end)
+        {
+            accum &= *src++;
+        }
+        address += linePitch;
+    }
+
+    spec.Unlock(count);
+
+    return (accum == 0xff000000);
+}
+#endif