javauis/lcdui_akn/lcdgr/src/CMIDGraphicsFactory.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 27 Apr 2010 16:30:29 +0300
branchRCL_3
changeset 14 04becd199f91
permissions -rw-r--r--
Revision: v2.1.22 Kit: 201017

/*
* 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 <e32base.h>
#include <f32file.h>
#include <barsc.h>
#include <barsread.h>

#include <lcdgr.h>
#include <lcdgdrv.h>
#include <lcdgr.rsg>


//
// Proxies
//
#include "CMIDImage.h"
#include "CMIDGraphics.h"
#include "CMIDImageDecoder.h"
#include "MMIDCanvasGraphicsItemPainter.h"

//
// Implementation
//
#include "MidProxyMap.h"
#include "LcdImage.h"
#include "LcdGraphics.h"
#include "LcdFbsImage.h"
#include "LcdFbsImageCache.h"

#include "s60commonutils.h"

struct TGraphicsMode
{
    TDisplayMode iScreenMode;
    TDisplayMode iPrimaryMode;
    TDisplayMode iTransparencyMode;
    TDisplayMode iUiColorMode;
    TDisplayMode iUiAlphaMode;
    TBool        iUiInvertMask;
};

struct TGraphicsConfig
{
    TGraphicsMode   iGraphicsMode;
    TBool           iUpdateRequired;
    TBool           iDoubleBuffer;
};

TBool ValidGraphicsMode(const TGraphicsMode& aConfig);

TBool IsAlpha(CFbsBitmap* aBitmap);

TInt CompareScreenMode(const TGraphicsMode& aLhs, const TGraphicsMode& aRhs)
{
    return aLhs.iScreenMode - aRhs.iScreenMode;
}

NONSHARABLE_CLASS(CMIDGraphicsFactory) : public CBase
        , public MMIDGraphicsFactory
        , private MImageTypeMap
{
public:
    CMIDGraphicsFactory(RFs&);
    void ConstructL(TDisplayMode);
    ~CMIDGraphicsFactory();

    virtual void            Dispose();
    virtual TDisplayMode    DisplayMode() const;
    virtual TBool           DoubleBuffer() const;
    virtual MMIDImage*      NewMutableImageL(const TSize& aSize);
    virtual MMIDImage*      NewImageL(const TSize& aSize, TInt aTransparency);
    virtual MMIDImage*      NewImageL(MMIDImageDecoder* aDecoder);
    virtual MMIDImage*      NewImageL(MMIDCanvas* aCanvas);
    virtual MMIDGraphics*   NewGraphicsL(MMIDCanvas* aCanvas);
    virtual MMIDGraphics*   NewGraphicsL(MMIDCustomItem* aCustomItem);
    virtual MMIDGraphics*   NewGraphicsL(MMIDImage* aImage);
    virtual MMIDGraphics*   NewGraphicsL(MMIDCanvasGraphicsItemPainter* aCanvasGraphicsPainter);
    virtual MMIDImageDecoder* NewImageDecoderL();

private:
    virtual TImageType GetImageType(MMIDImage::TTransparencyType aType);

private:
    void LoadConfigL(RArray<TGraphicsMode>& aModeArray, const TLinearOrder<TGraphicsMode>&);
    void ConfigureL(TGraphicsMode& aMode);
    TImageType MutableImageType() const;

    virtual MMIDGraphics*   NewGraphicsL(
        const CFbsBitmap* aBitmap, TBool aIsImageTarget, TBool aIsCanvasGraphicsItem);

private:
    RFs&                iFsSession;
    CLcdGraphicsDriver* iDriver;
    CLcdFbsImageCache*  iBitmapCache;
    CMIDProxyMap*       iProxyMap;
    TGraphicsConfig     iConfig;
    TInt                iConfigError;   // indicates an error when loading config from resource file
    TImageType          iImageTypeArray[3];
};

//
// Configuration resource file and constants.
//
_LIT(KLcdgrResourceFileName, "lcdgr.rsc");
const TInt KDefaultDisplayMode = MMIDBitmapImage::EDefaultDisplayMode;

//
// The one and only export.
//
EXPORT_C MMIDGraphicsFactory*   NewFactoryL(RFs& aFsSession, TDisplayMode aScreenMode)
{
    CMIDGraphicsFactory* factory = new(ELeave) CMIDGraphicsFactory(aFsSession);
    CleanupStack::PushL(factory);
    factory->ConstructL(aScreenMode);
    CleanupStack::Pop(factory);
    return factory;
}

CMIDGraphicsFactory::CMIDGraphicsFactory(RFs& aFsSession)
        : iFsSession(aFsSession)
{
    //
    // initialize default configuration.
    //
    iConfig.iGraphicsMode.iPrimaryMode          = (TDisplayMode)KDefaultDisplayMode;
    iConfig.iGraphicsMode.iTransparencyMode = (TDisplayMode)KDefaultDisplayMode;
    iConfig.iGraphicsMode.iUiColorMode  = (TDisplayMode)KDefaultDisplayMode;
    iConfig.iGraphicsMode.iUiAlphaMode  = (TDisplayMode)KDefaultDisplayMode;
    iConfig.iGraphicsMode.iUiInvertMask = EFalse;
    iConfig.iUpdateRequired = EFalse;
    iConfig.iDoubleBuffer   = EFalse;
}

void CMIDGraphicsFactory::ConstructL(TDisplayMode aScreenMode)
{
    //
    // Array of graphics modes sorted on screen mode.
    //
    RArray<TGraphicsMode> modeArray(4, _FOFF(TGraphicsMode, iScreenMode));
    TLinearOrder<TGraphicsMode> screenModeOrder(CompareScreenMode);
    CleanupClosePushL(modeArray);
    TGraphicsMode mode;

    //
    // Load config from resource file.
    //
    TRAP(iConfigError, LoadConfigL(modeArray, screenModeOrder)); // ignore error - we'll just use defaults
    if (iConfigError)
    {
        modeArray.Reset();
        mode.iScreenMode       = aScreenMode;
        mode.iPrimaryMode      = aScreenMode;
        mode.iTransparencyMode = EGray2;
        mode.iUiColorMode      = aScreenMode;
        mode.iUiAlphaMode      = EGray2;
        mode.iUiInvertMask     = EFalse;
        modeArray.AppendL(mode);
    }
    else
    {
        mode.iScreenMode = aScreenMode;
        TInt index = modeArray.FindInOrder(mode, screenModeOrder);
        if (index < 0)
        {
            //
            // Configuration file does not list screen mode.
            //
            User::Leave(KErrNotSupported);
        }
        mode = modeArray[index];
    }
    ASSERT(mode.iScreenMode == aScreenMode);

    //
    // Evaluate configuration, validating any loaded values and filling
    // in defaults. This also populates the image type array.
    //
    ConfigureL(mode);
    CleanupStack::PopAndDestroy();      // modes

    iDriver = CLcdGraphicsDriver::NewL(iConfig.iGraphicsMode.iPrimaryMode);

    //
    // Construct bitmap cache for UI controls.
    //
    iBitmapCache = CLcdFbsImageCache::NewL(*iDriver,
                                           iConfig.iGraphicsMode.iUiColorMode,
                                           iConfig.iGraphicsMode.iUiAlphaMode,
                                           iConfig.iGraphicsMode.iUiInvertMask);

    iProxyMap = new(ELeave) CMIDProxyMap;
}

CMIDGraphicsFactory::~CMIDGraphicsFactory()
{
    if (iBitmapCache)
    {
        delete iBitmapCache;
        iBitmapCache = NULL;
    }
    if (iProxyMap)
    {
        delete iProxyMap;
        iProxyMap = NULL;
    }
    if (iDriver)
    {
        delete iDriver;
        iDriver = NULL;
    }
}

void CMIDGraphicsFactory::Dispose()
{
    delete this;
}

TDisplayMode CMIDGraphicsFactory::DisplayMode() const
{
    return iConfig.iGraphicsMode.iPrimaryMode;
}

TBool CMIDGraphicsFactory::DoubleBuffer() const
{
    return iConfig.iDoubleBuffer;
}

MMIDImage* CMIDGraphicsFactory::NewMutableImageL(const TSize& aSize)
{
    CLcdImage* image = new(ELeave) CLcdImage(*iDriver, ETrue);
    CleanupStack::PushL(image);
    image->ConstructL(aSize, MutableImageType());
    CMIDImage* proxy = new(ELeave) CMIDImage(*iBitmapCache, *this, image);
    CleanupStack::Pop(image);
    CleanupStack::PushL(proxy);
    proxy->ConstructL();
    CleanupStack::Pop(proxy);
    return proxy;
}

MMIDImage* CMIDGraphicsFactory::NewImageL(const TSize& aSize, TInt aTransparency)
{
    CLcdImage* image = new(ELeave) CLcdImage(*iDriver, EFalse);
    CleanupStack::PushL(image);
    image->ConstructL(aSize, iImageTypeArray[aTransparency]);
    CMIDImage* proxy = new(ELeave) CMIDImage(*iBitmapCache, *this, image);
    CleanupStack::Pop(image);
    CleanupStack::PushL(proxy);
    proxy->ConstructL();
    CleanupStack::Pop(proxy);
    return proxy;
}

MMIDImage* CMIDGraphicsFactory::NewImageL(MMIDImageDecoder* aDecoder)
{
    MMIDBitmapImage* bitmapImage = aDecoder->BitmapImage();
    if (!bitmapImage)
    {
        User::Leave(KErrArgument);
    }

    CFbsBitmap* colorBitmap = bitmapImage->ColorBitmap();
    CFbsBitmap* alphaBitmap = bitmapImage->AlphaBitmap();

    TInt index = MMIDImage::ENone;
    if (alphaBitmap)
    {
        if (IsAlpha(alphaBitmap))
        {
            index = MMIDImage::EAlpha;
        }
        else
        {
            index = MMIDImage::EMask;
        }
    }

    CLcdImage* image = new(ELeave) CLcdImage(*iDriver, EFalse);
    CleanupStack::PushL(image);
    image->ConstructL(colorBitmap, alphaBitmap, iImageTypeArray[index]);
    CMIDImage* proxy = new(ELeave) CMIDImage(*iBitmapCache, *this, image);
    CleanupStack::Pop(image);
    CleanupStack::PushL(proxy);
    proxy->ConstructL();
    CleanupStack::Pop(proxy);
    return proxy;
}

/**
 * Create a framebuffer image
 */
MMIDImage* CMIDGraphicsFactory::NewImageL(MMIDCanvas* aCanvas)
{
    CFbsBitmap* colorBitmap = aCanvas->FrameBuffer();
    CFbsBitmap* alphaBitmap = NULL;

    if (NULL == colorBitmap)
    {
        User::Leave(KErrNotSupported);
    }

    CLcdImage* image = new(ELeave) CLcdImage(*iDriver, ETrue);
    CleanupStack::PushL(image);
    image->ConstructL(colorBitmap, alphaBitmap, MutableImageType());
    CMIDImage* proxy = new(ELeave) CMIDImage(*iBitmapCache, *this, image);
    CleanupStack::Pop(image);
    CleanupStack::PushL(proxy);
    proxy->ConstructL();
    CleanupStack::Pop(proxy);
    return proxy;
}


#ifdef RD_JAVA_NGA_ENABLED
// ---------------------------------------------------------------------------
// NGA extension
// ---------------------------------------------------------------------------
//
MMIDGraphics* CMIDGraphicsFactory::NewGraphicsL(MMIDCanvas* aCanvas)
{
    CLcdGraphics* graphics = CLcdGraphics::NewL(*iDriver, aCanvas->FrameBuffer());
    CleanupStack::PushL(graphics);
    CMIDGraphics* proxy = new(ELeave) CMIDGraphics(*iProxyMap, graphics, EFalse, aCanvas);
    CleanupStack::Pop(graphics);
    return proxy;
}

#else // !RD_JAVA_NGA_ENABLED

MMIDGraphics* CMIDGraphicsFactory::NewGraphicsL(MMIDCanvas* aCanvas)
{
    CCoeControl&      window    = aCanvas->Control();
    MDirectContainer& container = aCanvas->DirectContainer();

    CLcdGraphics* graphics = CLcdGraphics::NewL(*iDriver, window, container, iConfig.iUpdateRequired);
    CleanupStack::PushL(graphics);
    CMIDGraphics* proxy = new(ELeave) CMIDGraphics(*iProxyMap, graphics, EFalse);
    CleanupStack::Pop(graphics);
    return proxy;
}
#endif // RD_JAVA_NGA_ENABLED

MMIDGraphics* CMIDGraphicsFactory::NewGraphicsL(MMIDCustomItem* aCustomItem)
{
    return NewGraphicsL(aCustomItem->FrameBuffer(), EFalse, EFalse);
}

MMIDGraphics* CMIDGraphicsFactory::NewGraphicsL(MMIDImage* aImage)
{
    //
    // All mutable images must be registered bitmap images as we currently
    // rely on BITGDI to render many primitives.
    //
    // We could have a separate map for mutable images if necessary.
    //
    MMIDBitmapImage* image = iBitmapCache->GetBitmapImage(aImage);
    ASSERT(image);
    MMIDGraphics* graphics = NewGraphicsL(image->ColorBitmap(), ETrue, EFalse);

    //Graphics duplicates the fbs handle.
    image->RemoveRef();
    return graphics;
}

MMIDGraphics* CMIDGraphicsFactory::NewGraphicsL(MMIDCanvasGraphicsItemPainter* aCanvasGraphicsItemPainter)
{
    return NewGraphicsL(aCanvasGraphicsItemPainter->FrameBuffer(), EFalse, ETrue);
}

MMIDGraphics* CMIDGraphicsFactory::NewGraphicsL(
    const CFbsBitmap* aBitmap, TBool aIsImageTarget, TBool aIsCanvasGraphicsItem)

{
    if (NULL == aBitmap)
    {
        User::Leave(KErrArgument);
    }

    if (aBitmap->DisplayMode() != iConfig.iGraphicsMode.iPrimaryMode)
    {
        User::Leave(KErrArgument);
    }

    CLcdGraphics* graphics = CLcdGraphics::NewL(*iDriver, aBitmap);
    CleanupStack::PushL(graphics);
    CMIDGraphics* proxy = new(ELeave) CMIDGraphics(*iProxyMap, graphics, aIsImageTarget);
    CleanupStack::Pop(graphics);

    // CLcdGraphics instance has to know that rendering target bitmap is framebuffer
    // of CanavsGraphicsItem. Its because drawing images its not allowed to
    // transparent target and CanvasGraphicsItem is transparent by default.
    graphics->SetCanvasGraphicsItemtarget(aIsCanvasGraphicsItem);

    return proxy;
}

MMIDImageDecoder* CMIDGraphicsFactory::NewImageDecoderL()
{
    CMIDImageDecoder* decoder = new(ELeave) CMIDImageDecoder(iFsSession, DisplayMode());
    CleanupStack::PushL(decoder);
    decoder->ConstructL();
    CleanupStack::Pop(decoder);
    return decoder;
}

void CMIDGraphicsFactory::LoadConfigL(RArray<TGraphicsMode>& aModeArray, const TLinearOrder<TGraphicsMode>& aOrder)
{
    TFileName fileName;

    fileName.Append(KLcdgrResourceFileName);
    fileName = java::util::S60CommonUtils::ResourceLanguageFileNameL(fileName);

    RResourceFile configFile;
    configFile.OpenL(iFsSession, fileName);
    CleanupClosePushL(configFile);
    configFile.ConfirmSignatureL();

    //
    // read R_GRAPHICS_CONFIG
    //

    //
    // WARNING! TResourceReader will panic or endless loop on error
    // (e.g. if the config file is corrupt).
    //

    HBufC8* resourceData = configFile.AllocReadLC(R_GRAPHICS_CONFIG);
    TResourceReader reader;
    reader.SetBuffer(resourceData);

    int count = reader.ReadInt16();
    for (int i=0; i<count; i++)
    {
        TGraphicsMode mode;
        mode.iScreenMode  = (TDisplayMode)reader.ReadInt16();
        mode.iPrimaryMode = (TDisplayMode)reader.ReadInt16();
        mode.iTransparencyMode = (TDisplayMode)reader.ReadInt16();
        mode.iUiColorMode  = (TDisplayMode)reader.ReadInt16();
        mode.iUiAlphaMode  = (TDisplayMode)reader.ReadInt16();
        mode.iUiInvertMask = (TBool)reader.ReadInt16();
        aModeArray.InsertInOrderL(mode, aOrder);
    }

    iConfig.iUpdateRequired = (TBool)reader.ReadInt16();
    iConfig.iDoubleBuffer   = (TBool)reader.ReadInt16();

    CleanupStack::PopAndDestroy(resourceData);

    CleanupStack::PopAndDestroy(); //configFile
}


void CMIDGraphicsFactory::ConfigureL(TGraphicsMode& aMode)
{
    //
    // Fill in defaulted values.
    //
    if (aMode.iPrimaryMode == KDefaultDisplayMode)
    {
        aMode.iPrimaryMode = aMode.iScreenMode;
    }

    if (aMode.iTransparencyMode == KDefaultDisplayMode)
    {
        if (aMode.iPrimaryMode == EColor16MA)
        {
            aMode.iTransparencyMode = ENone;
        }
        else
        {
            aMode.iTransparencyMode = EGray2;
        }
    }

    //
    // Validate the configuration.
    //

    if (aMode.iUiColorMode == KDefaultDisplayMode)
    {
        aMode.iUiColorMode = aMode.iPrimaryMode;
    }

    if (aMode.iUiAlphaMode == KDefaultDisplayMode)
    {
        aMode.iUiAlphaMode = EGray2;
    }

    if (!ValidGraphicsMode(aMode))
    {
        User::Leave(KErrNotSupported);
    }

    iConfig.iGraphicsMode = aMode;

    //
    // configure opaque image type
    //
    iImageTypeArray[MMIDImage::ENone].iColorMode    = aMode.iPrimaryMode;
    iImageTypeArray[MMIDImage::ENone].iAlphaMode    = ENone;
    iImageTypeArray[MMIDImage::ENone].iTransparency = ETransparencyNone;

    //
    // Configure transparent image type
    //
    iImageTypeArray[MMIDImage::EMask].iColorMode = aMode.iPrimaryMode;
    if (aMode.iPrimaryMode == EColor16MA)
    {
        iImageTypeArray[MMIDImage::EMask].iAlphaMode    = ENone;
        iImageTypeArray[MMIDImage::EMask].iTransparency = ETransparencyMaskChannel;
    }
    else
    {
        iImageTypeArray[MMIDImage::EMask].iAlphaMode    = aMode.iTransparencyMode;
        iImageTypeArray[MMIDImage::EMask].iTransparency = ETransparencyMaskBitmap;
    }

    //
    // Configure alpha image type
    //
    iImageTypeArray[MMIDImage::EAlpha].iColorMode = aMode.iPrimaryMode;
    if (aMode.iPrimaryMode == EColor16MA)
    {
        iImageTypeArray[MMIDImage::EAlpha].iAlphaMode    = ENone;
        iImageTypeArray[MMIDImage::EAlpha].iTransparency = ETransparencyAlphaChannel;
    }
    else
    {
        iImageTypeArray[MMIDImage::EAlpha].iAlphaMode    = EGray256;
        iImageTypeArray[MMIDImage::EAlpha].iTransparency = ETransparencyAlphaBitmap;
    }

    iConfig.iGraphicsMode   = aMode;

#ifdef __WINS__
    iConfig.iUpdateRequired = ETrue;
#endif
}

TImageType CMIDGraphicsFactory::MutableImageType() const
{
    return iImageTypeArray[MMIDImage::ENone];
}

TBool ValidGraphicsMode(const TGraphicsMode& aMode)
{
    if (aMode.iPrimaryMode == EColor16MA)
    {
        if (aMode.iTransparencyMode != ENone)
        {
            return EFalse;
        }
    }
    else
    {
        // transparency alpha mode must be EGray2 or matched mode.
        if ((aMode.iTransparencyMode != EGray2) && (aMode.iTransparencyMode != aMode.iPrimaryMode))
        {
            return EFalse;
        }
    }

    return ETrue;
}

TBool IsAlpha(CFbsBitmap* aBitmap)
{
    TBool alpha = EFalse;

    if (aBitmap->DisplayMode() == EGray256)
    {
        TSize size = aBitmap->SizeInPixels();
        TInt  scan = CFbsBitmap::ScanLineLength(size.iWidth, EGray256);

        aBitmap->LockHeap();

        TUint8* address = (TUint8*)aBitmap->DataAddress();
        for (TInt h = size.iHeight; --h>=0;)
        {
            TUint8* pix = address;
            TUint8* end = address + size.iWidth;
            while (pix < end)
            {
                TUint8 value = *pix++;
                if ((value > 0) && (value < 255))
                {
                    alpha = ETrue;
                    goto endLoop;
                }
            }
            address += scan;
        }

endLoop:

        aBitmap->UnlockHeap();
    }

    return alpha;
}

#define TYPE_ARRAY_SIZE (sizeof(iImageTypeArray)/sizeof(iImageTypeArray[0]))

TImageType CMIDGraphicsFactory::GetImageType(MMIDImage::TTransparencyType aType)
{
    ASSERT((0 <= aType) && (aType < TYPE_ARRAY_SIZE));
    return iImageTypeArray[ aType ];
}