--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uiacceltk/hitchcock/coretoolkit/rendervg10/src/HuiVg10Texture.cpp Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,1656 @@
+/*
+* Copyright (c) 2006-2008 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: Implementation for CHuiVg10Texture, OpenVG 1.0 Texture.
+*
+*/
+
+
+
+#include <e32def.h>
+#include <e32math.h>
+
+#include "HuiVg10RenderPlugin.h"
+#include "HuiVg10Texture.h"
+#include "HuiVg10TextureManager.h"
+#include "uiacceltk/HuiTextureHandle.h"
+#include "uiacceltk/HuiEnv.h"
+#include "uiacceltk/HuiTextureManager.h"
+#include "uiacceltk/HuiTextureProcessor.h"
+#include "uiacceltk/HuiUtil.h"
+#include "uiacceltk/HuiPanic.h"
+
+// temporary hack until the openvg headers are fixed..
+#ifndef OPENVG_VERSION_1_0_1
+ #warning using temporary hack to define OPENVG_VERSION_1_0_1, see TSW: SKYA-7QQB8
+ #define OPENVG_VERSION_1_0_1
+#endif
+
+#ifdef __NVG
+ #include <EGL/egl.h>
+ #include <nvg.h>
+ #include <AknIconUtils.h>
+ #include "HuiRenderSurface.h"
+ #include "NVGIcon.h"
+#endif
+
+
+/**
+ * Bitmap color mode conversion.
+ *
+ * @param aBitmap Source bitmap to convert.
+ * @param aDisplayMode Target display mode.
+ * @param aCopyMode Desired copy behavior.
+ * @returns a new bitmap with the desired display mode.
+ */
+static CFbsBitmap& ConvertBitmapL(const CFbsBitmap& aBitmap, TDisplayMode aDisplayMode, TBitmapCopyMode aCopyMode = EAllowDuplication, TSize aNewSize = TSize(0,0))
+ {
+ // Functionality moved to Texture Manager
+ // (to avoid recreating the bitmaps & bmpDevices every time)
+ CHuiTextureManager& tmpMgr = CHuiStatic::Env().TextureManager();
+ CHuiVg10TextureManager& textureMgr = static_cast<CHuiVg10TextureManager&>(tmpMgr);
+
+ return textureMgr.ConvertBitmapL(aBitmap, aDisplayMode, aCopyMode, aNewSize);
+ }
+
+/**
+ * Replace the alpha channel of an EColor16MA bitmap (in-place).
+ *
+ * @param aBitmap Destination bitmap.
+ * @param aMaskBitmap Alpha channel source bitmap.
+ */
+static void ReplaceAlphaChannelL(CFbsBitmap& aBitmap, const CFbsBitmap& aMaskBitmap)
+ {
+ ASSERT(aBitmap.DisplayMode() == EColor16MA);
+ ASSERT(aBitmap.SizeInPixels() == aMaskBitmap.SizeInPixels());
+
+ CFbsBitmap& convMask = ConvertBitmapL(aMaskBitmap, EGray256);
+
+ aBitmap.BeginDataAccess();
+ convMask.BeginDataAccess();
+ TSize size = aBitmap.SizeInPixels();
+ TUint32* dest32 = (TUint32*)aBitmap.DataAddress();
+ const TUint8* src8 = (const TUint8*)convMask.DataAddress();
+ TInt destStride = CFbsBitmap::ScanLineLength(size.iWidth, aBitmap.DisplayMode()) >> 2;
+ TInt srcStride = CFbsBitmap::ScanLineLength(size.iWidth, convMask.DisplayMode());
+
+ for (TInt y = 0; y < size.iHeight; y++)
+ {
+ TUint32* d = dest32;
+ const TUint8* s = src8;
+
+ for (TInt x = 0; x < size.iWidth; x++)
+ {
+ *d &= ~0xff000000;
+ *d++ |= (*s++) << 24;
+ }
+
+ dest32 += destStride;
+ src8 += srcStride;
+ }
+
+ aBitmap.EndDataAccess();
+ convMask.EndDataAccess(ETrue);
+ }
+
+#if !defined(OPENVG_VERSION_1_0_1)
+/**
+ * Convert a native Symbian EColor16MU/A bitmap to an OpenVG 1.0 equivalent (in-place).
+ *
+ * @param aBitmap Bitmap to convert.
+ */
+static void ConvertPixelComponentOrdering(CFbsBitmap& aBitmap)
+ {
+ ASSERT(aBitmap.DisplayMode() == EColor16MA || aBitmap.DisplayMode() == EColor16MU);
+
+ aBitmap.BeginDataAccess();
+ TSize size = aBitmap.SizeInPixels();
+ TUint32* dest32 = (TUint32*)aBitmap.DataAddress();
+ TInt destStride = CFbsBitmap::ScanLineLength(size.iWidth, aBitmap.DisplayMode()) >> 2;
+
+ for (TInt y = 0; y < size.iHeight; y++)
+ {
+ TUint32* d = dest32;
+
+ for (TInt x = 0; x < size.iWidth; x++)
+ {
+ *d++ = (*d << 8) | ((*d & 0xff000000) >> 24);
+ }
+
+ dest32 += destStride;
+ }
+ aBitmap.EndDataAccess();
+ }
+#endif
+
+/* Vg10Texture internal flags. */
+enum
+ {
+ /** Content has been uploaded. */
+ EFlagHasContent = 0x1,
+
+ /** The texture has an alpha channel. */
+ EFlagHasAlpha = 0x2
+ };
+
+
+CHuiVg10Texture* CHuiVg10Texture::NewL(CHuiVg10RenderPlugin& aRenderPlugin, const THuiTextureHandle* aExistingTexture)
+ {
+ CHuiVg10Texture* self = CHuiVg10Texture::NewLC(aRenderPlugin, aExistingTexture);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CHuiVg10Texture* CHuiVg10Texture::NewLC(CHuiVg10RenderPlugin& aRenderPlugin, const THuiTextureHandle* aExistingTexture)
+ {
+ CHuiVg10Texture* self = new (ELeave) CHuiVg10Texture(aRenderPlugin);
+ CleanupStack::PushL(self);
+ self->ConstructL(aExistingTexture);
+ return self;
+ }
+
+
+CHuiVg10Texture::CHuiVg10Texture(CHuiVg10RenderPlugin& aRenderPlugin)
+ : iRenderPlugin(aRenderPlugin),
+ iInternalFlags(0),
+ iShadowEnabled(EFalse)
+ {
+ }
+
+
+void CHuiVg10Texture::ConstructL(const THuiTextureHandle* aExistingTexture)
+ {
+ CHuiTexture::BaseConstructL();
+
+ SetSegmentCountL(1);
+ SetSegmentName(0, 0);
+ SetSegmentSize(0, TSize(0, 0));
+ SetSegmentTextureSize(0, TSize(0, 0));
+
+ if(aExistingTexture)
+ {
+ // Take over the existing texture (single named texture object).
+ ASSERT(aExistingTexture->SegmentCount() == 1);
+ ASSERT(SegmentCount() == 1);
+ SetSegmentName(0, aExistingTexture->Name());
+ SetSegmentSize(0, aExistingTexture->SegmentSize(0));
+ SetSegmentTextureSize(0, aExistingTexture->SegmentTextureSize(0));
+ SetSize(aExistingTexture->Size());
+
+ // Copy attributes
+ const CHuiVg10Texture* vgTex = reinterpret_cast<const CHuiVg10Texture*>(aExistingTexture);
+ iInternalFlags = vgTex->iInternalFlags;
+ // Note: shared shadows not supported
+ }
+ }
+
+
+CHuiVg10Texture::~CHuiVg10Texture()
+ {
+ Reset();
+ }
+
+
+TBool CHuiVg10Texture::HasAlpha() const
+ {
+ return (iInternalFlags & EFlagHasAlpha) != 0;
+ }
+
+
+TBool CHuiVg10Texture::HasContent() const
+ {
+ if(!CHuiTexture::HasContent())
+ {
+ return EFalse;
+ }
+
+ return (iInternalFlags & EFlagHasContent) != 0;
+ }
+
+
+TSize CHuiVg10Texture::MaxTextureSize() const
+ {
+ if (iRenderPlugin.IsReleased())
+ {
+ HUI_DEBUG(_L("CHuiVg10Texture::MaxTextureSize() - Vg10 context not available, cannot get maximum texture size, returning (0,0)."));
+ return TSize(0,0);
+ }
+
+ int maxWidth = vgGeti(VG_MAX_IMAGE_WIDTH)-1;
+ int maxHeight = vgGeti(VG_MAX_IMAGE_HEIGHT)-1;
+ HUI_VG_INVARIANT();
+ ASSERT(maxWidth > 0 && maxHeight > 0);
+
+ return TSize(maxWidth, maxHeight);
+ }
+
+void CHuiVg10Texture::UploadL(const CFbsBitmap& aBitmap,
+ const CFbsBitmap* aMaskBitmap,
+ THuiTextureUploadFlags aTextureFlags)
+ {
+ Reset(); // Must delete old content before calling SetupSegmentsL
+
+ TBool invalidMaskSize = (aMaskBitmap && (aBitmap.SizeInPixels() != aMaskBitmap->SizeInPixels()));
+
+ CFbsBitmap* maskBitmap = (CFbsBitmap*)aMaskBitmap;
+
+ if (invalidMaskSize)
+ {
+ maskBitmap = &ConvertBitmapL(*aMaskBitmap, aMaskBitmap->DisplayMode(), EAlwaysCopy, aBitmap.SizeInPixels());
+ }
+
+ SetupSegmentsL(aBitmap.SizeInPixels(), aBitmap.SizeInPixels(), aTextureFlags);
+ SegmentUploadL(0, aBitmap, maskBitmap, aTextureFlags);
+ }
+
+void CHuiVg10Texture::UploadL(THuiTextureFormat aTextureFormat,
+ const TSize& aTextureSize,
+ const TUint8* aTextureBuffer,
+ THuiTextureUploadFlags aTextureFlags,
+ TUint aTextureBufferSize)
+ {
+ Reset(); // Must delete old content before calling SetupSegmentsL
+ SetupSegmentsL(aTextureSize, aTextureSize, aTextureFlags);
+ SegmentUploadL(0, aTextureFormat, aTextureSize, aTextureBuffer, aTextureBufferSize);
+ }
+
+
+void CHuiVg10Texture::PartialUploadL(THuiTextureFormat aFormat,
+ const TPoint& aOrigin,
+ const TSize& aSize,
+ const TUint8* aBuffer)
+ {
+ ASSERT(SegmentCount() == 1);
+ SegmentPartialUpload(0, aFormat, aOrigin, aSize, aBuffer);
+ }
+
+
+void CHuiVg10Texture::SegmentUploadL(TInt aSegment,
+ const CFbsBitmap& aBitmap,
+ const CFbsBitmap* aMaskBitmap,
+ THuiTextureUploadFlags aFlags)
+ {
+ ASSERT(aSegment >= 0 && aSegment < SegmentCount());
+ ASSERT(aBitmap.SizeInPixels() == Size());
+ ASSERT(aMaskBitmap && aBitmap.SizeInPixels() == aMaskBitmap->SizeInPixels() || !aMaskBitmap);
+
+ PushEGLContext();
+ if(aSegment < 0 || aSegment >= SegmentCount())
+ {
+ User::Leave(KErrArgument);
+ }
+
+ // Clear any previous image data
+ ResetSegment(aSegment);
+
+#ifdef __NVG
+ // Check if the bitmap is extended and has NVG data
+ TUid bitmaptype = aBitmap.ExtendedBitmapType();
+ TUid masktype = KNullUid;
+ if (aMaskBitmap)
+ {
+ masktype = aMaskBitmap->ExtendedBitmapType();
+ // extended bitmap and mask
+ if (bitmaptype == masktype && bitmaptype != KNullUid)
+ {
+ SegmentUploadNvgL(aBitmap, aMaskBitmap, aFlags);
+ // We now have working texture data, no need to do anything else
+ PopEGLContext();
+ return;
+ }
+ }
+ else if (bitmaptype != KNullUid)
+ {
+ SegmentUploadNvgL(aBitmap, aMaskBitmap, aFlags);
+ // We now have working texture data, no need to do anything else
+ PopEGLContext();
+ return;
+ }
+#endif
+
+ VGImageFormat imageSourceFormat = (VGImageFormat)(-1);
+ VGImageFormat imageInternalFormat = VG_sXRGB_8888; // TODO: get the most optimal image format from the renderer
+ VGbitfield qualityFlags = VG_IMAGE_QUALITY_BETTER | VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_NONANTIALIASED;
+ TBool hasAlpha = (aMaskBitmap != NULL);
+ TBool conversionRequired = ETrue;
+ TSize size = Size();
+ TSize textureSize = MaxTextureSize();
+ textureSize.iWidth = Min(size.iWidth, textureSize.iWidth);
+ textureSize.iHeight = Min(size.iHeight, textureSize.iHeight);
+
+ // See if there is a native color mode we could use without conversion
+ switch (aBitmap.DisplayMode())
+ {
+ case EGray256:
+ imageSourceFormat = VG_A_8;
+ conversionRequired = EFalse;
+ break;
+ case EColor64K:
+ imageSourceFormat = VG_sRGB_565;
+ conversionRequired = EFalse;
+ break;
+ case EColor4K:
+ imageSourceFormat = VG_sRGB_565;
+ conversionRequired = ETrue;
+ break;
+#if defined(OPENVG_VERSION_1_0_1)
+ case EColor16MU:
+ imageSourceFormat = VG_sXRGB_8888;
+ conversionRequired = EFalse;
+ break;
+ case EColor16M:
+ imageSourceFormat = VG_sXRGB_8888;
+ conversionRequired = ETrue;
+ break;
+ case EColor16MA:
+ imageSourceFormat = VG_sARGB_8888;
+ hasAlpha = ETrue;
+ conversionRequired = EFalse;
+ break;
+ case EColor16MAP:
+ imageSourceFormat = VG_sARGB_8888_PRE;
+ hasAlpha = ETrue;
+ conversionRequired = EFalse;
+ break;
+#else // defined(OPENVG_VERSION_1_0_1)
+ case EColor16MU:
+ case EColor16M:
+ imageSourceFormat = VG_sRGBX_8888;
+ break;
+ case EColor16MA:
+ imageSourceFormat = VG_sRGBA_8888;
+ hasAlpha = ETrue;
+ break;
+ case EColor16MAP:
+ imageSourceFormat = VG_sRGBA_8888_PRE;
+ hasAlpha = ETrue;
+ break;
+#endif // defined(OPENVG_VERSION_1_0_1)
+ default:
+#ifdef _DEBUG
+ RDebug::Printf("CHuiVg10Texture::SegmentUploadL - unknown display mode %d", aBitmap.DisplayMode());
+#endif
+ conversionRequired = ETrue;
+ imageSourceFormat = VG_sXRGB_8888;
+ }
+
+ if (aBitmap.IsCompressedInRAM() || aMaskBitmap)
+ {
+ conversionRequired = ETrue;
+ }
+
+ if (hasAlpha)
+ {
+ imageInternalFormat = VG_sRGBA_8888_PRE;
+ }
+ else
+ {
+ imageInternalFormat = imageSourceFormat;
+ }
+
+ // Create the actual image
+ VGImage image = vgCreateImage(imageInternalFormat, textureSize.iWidth, textureSize.iHeight, qualityFlags);
+
+ if (image == VG_INVALID_HANDLE)
+ {
+ User::Leave(KErrNoMemory);
+ }
+
+ if (!conversionRequired)
+ {
+ // No data conversion is required and we can upload the pixels as such
+ aBitmap.BeginDataAccess();
+ const void* data = aBitmap.DataAddress();
+ TInt stride = CFbsBitmap::ScanLineLength(size.iWidth, aBitmap.DisplayMode());
+ vgImageSubData(image, data, stride, imageSourceFormat, 0, 0, textureSize.iWidth, textureSize.iHeight);
+ aBitmap.EndDataAccess( ETrue );
+ }
+ else
+ {
+ // One or more conversion steps are needed
+ if (hasAlpha)
+ {
+ // Alpha channel needs to be accounted for
+#if defined(OPENVG_VERSION_1_0_1)
+ imageSourceFormat = VG_sARGB_8888;
+ CFbsBitmap& convBitmap = ConvertBitmapL(aBitmap, EColor16MA);
+#else // defined(OPENVG_VERSION_1_0_1)
+ imageSourceFormat = VG_sRGBA_8888;
+ CFbsBitmap& convBitmap = ConvertBitmapL(aBitmap, EColor16MA);
+#endif // defined(OPENVG_VERSION_1_0_1)
+
+ // Bake the alpha channel into the converted bitmap
+ if (aMaskBitmap)
+ {
+ if (aMaskBitmap->IsCompressedInRAM() || masktype != KNullUid)
+ {
+ CFbsBitmap& noncompressedMask = ConvertBitmapL(*aMaskBitmap, EGray256, EAlwaysCopy);
+ ReplaceAlphaChannelL(convBitmap, noncompressedMask);
+ }
+ else
+ {
+ ReplaceAlphaChannelL(convBitmap, *aMaskBitmap);
+ }
+ }
+ #if !defined(OPENVG_VERSION_1_0_1)
+ // Match the native OpenVG 1.0 pixel component ordering
+ ASSERT(convBitmap.Handle() != aBitmap.Handle());
+ ConvertPixelComponentOrdering(convBitmap);
+ #endif
+ convBitmap.BeginDataAccess();
+ const void* data = convBitmap.DataAddress();
+ TInt stride = CFbsBitmap::ScanLineLength(size.iWidth, convBitmap.DisplayMode());
+ vgImageSubData(image, data, stride, imageSourceFormat, 0, 0, textureSize.iWidth, textureSize.iHeight);
+ convBitmap.EndDataAccess( ETrue );
+ }
+ else
+ {
+ // No alpha channel -- just opaque pixel data
+#if defined(OPENVG_VERSION_1_0_1)
+ TDisplayMode mode = EColor16MU;
+ if (imageSourceFormat == VG_sRGB_565)
+ {
+ mode = EColor64K;
+ }
+ else if (imageSourceFormat == VG_A_8)
+ {
+ mode = EGray256;
+ }
+ else
+ {
+ imageSourceFormat = VG_sXRGB_8888;
+ }
+ CFbsBitmap& convBitmap = ConvertBitmapL(aBitmap, mode);
+#else // defined(OPENVG_VERSION_1_0_1)
+ imageSourceFormat = VG_sRGBX_8888;
+ CFbsBitmap& convBitmap = ConvertBitmapL(aBitmap, EColor16MU);
+
+ // Match the native OpenVG 1.0 pixel component ordering
+ ASSERT(convBitmap.Handle() != aBitmap.Handle());
+ ConvertPixelComponentOrdering(convBitmap);
+#endif // defined(OPENVG_VERSION_1_0_1)
+
+ convBitmap.BeginDataAccess();
+ const void* data = convBitmap.DataAddress();
+ TInt stride = CFbsBitmap::ScanLineLength(size.iWidth, convBitmap.DisplayMode());
+ vgImageSubData(image, data, stride, imageSourceFormat, 0, 0, textureSize.iWidth, textureSize.iHeight);
+ convBitmap.EndDataAccess( ETrue );
+ }
+ }
+
+ // Save the image handle
+ SetSegmentName(0, (TUint)image);
+
+ // The texture now has content.
+ iInternalFlags |= EFlagHasContent;
+
+ if (hasAlpha)
+ {
+ iInternalFlags |= EFlagHasAlpha;
+ }
+
+ // Keep the shadow in sync with the image contents
+ if (IsShadowEnabled())
+ {
+ // if this fails there is nothing we can do
+ // There will be no shadow if something goes wrong here
+ TRAP_IGNORE( GenerateShadowL() );
+ }
+ PopEGLContext();
+ // Wake up refresh. It is likely that the new texture will be visible on
+ // the screen.
+ CHuiStatic::ContinueRefresh();
+ }
+
+static void ConvertBufferRgb888TosRGBX8888(const TUint8* aSrc, TUint8* aDest, TInt aCount)
+{
+ while (aCount--)
+ {
+ *aDest++ = *aSrc++;
+ *aDest++ = *aSrc++;
+ *aDest++ = *aSrc++;
+ *aDest++ = 0xff;
+ }
+}
+
+static void ConvertBufferLa88TosRGBA8888(const TUint8* aSrc, TUint8* aDest, TInt aCount)
+{
+ while (aCount--)
+ {
+ TUint8 l = *aSrc++;
+ TUint8 a = *aSrc++;
+ *aDest++ = l;
+ *aDest++ = l;
+ *aDest++ = l;
+ *aDest++ = a;
+ }
+}
+
+#if !defined(OPENVG_VERSION_1_0_1)
+static void ConvertBufferRgba8888TosRGBA8888(const TUint8* aSrc, TUint8* aDest, TInt aCount)
+{
+ while (aCount--)
+ {
+ TUint8 r = *aSrc++;
+ TUint8 g = *aSrc++;
+ TUint8 b = *aSrc++;
+ TUint8 a = *aSrc++;
+ *aDest++ = a;
+ *aDest++ = r;
+ *aDest++ = g;
+ *aDest++ = b;
+ }
+}
+#endif
+
+void CHuiVg10Texture::SegmentClearL(TInt aSegment,
+ TBool aWithAlpha,
+ const TRgb& aColor,
+ TUint8 aAlpha)
+ {
+ ASSERT(aSegment >= 0 && aSegment < SegmentCount());
+
+ if(aSegment < 0 || aSegment >= SegmentCount())
+ {
+ User::Leave(KErrArgument);
+ }
+
+ // Clear any previous image data
+ TSize size = Size();
+ ResetSegment(aSegment);
+
+ // Create the actual image
+ VGImageFormat imageInternalFormat = aWithAlpha ? VG_sRGBA_8888 : VG_sRGBX_8888;
+ VGbitfield qualityFlags = VG_IMAGE_QUALITY_BETTER | VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_NONANTIALIASED;
+ VGImage image = vgCreateImage(imageInternalFormat, size.iWidth, size.iHeight, qualityFlags);
+
+ if (image == VG_INVALID_HANDLE)
+ {
+ User::Leave(KErrNoMemory);
+ }
+
+ // Set the clear color
+ VGfloat scale = 1.0f / 255.0f;
+ VGfloat color[] = {
+ aColor.Red() * scale,
+ aColor.Green() * scale,
+ aColor.Blue() * scale,
+ aWithAlpha ? (aAlpha * scale) : 1.0f
+ };
+
+ vgSetfv(VG_CLEAR_COLOR, 4, color);
+ vgClearImage(image, 0, 0, size.iWidth, size.iHeight);
+
+ // The texture now has content.
+ iInternalFlags |= EFlagHasContent;
+
+ if (aWithAlpha)
+ {
+ iInternalFlags |= EFlagHasAlpha;
+ }
+
+ // Keep the shadow in sync with the image contents
+ if (IsShadowEnabled())
+ {
+ GenerateShadowL();
+ }
+
+ HUI_VG_INVARIANT();
+ }
+
+void CHuiVg10Texture::SegmentUploadL(TInt aSegment,
+ THuiTextureFormat aFormat,
+ const TSize& aSize,
+ const TUint8* aBuffer,
+ TUint /*aBufferSize*/)
+ {
+ ASSERT(aSegment >= 0 && aSegment < SegmentCount());
+ ASSERT(aSize == Size());
+
+ SegmentPartialUploadInternal(aSegment, aFormat, TPoint(0, 0), aSize, aBuffer, ETrue);
+ }
+
+void CHuiVg10Texture::SegmentPartialUpload(
+ TInt aSegment,
+ THuiTextureFormat aFormat,
+ const TPoint& aOrigin,
+ const TSize& aSize,
+ const TUint8* aBuffer)
+ {
+ SegmentPartialUploadInternal(aSegment, aFormat, aOrigin, aSize, aBuffer, EFalse);
+ }
+
+void CHuiVg10Texture::SegmentPartialUploadInternal(
+ TInt aSegment,
+ THuiTextureFormat aFormat,
+ const TPoint& aOrigin,
+ const TSize& aSize,
+ const TUint8* aBuffer,
+ TBool aCreateImage)
+ {
+ ASSERT(aSegment >= 0 && aSegment < SegmentCount());
+
+ if (aSegment < 0 || aSegment >= SegmentCount())
+ {
+ // we return without doing anything because we are called by a non-leaving function
+ return;
+ }
+
+ if (aOrigin.iX < 0 || aOrigin.iY < 0)
+ {
+ // we return without doing anything because we are called by a non-leaving function
+ return;
+ }
+
+ HUI_DEBUG4(_L("CHuiVg10Texture::SegmentPartialUploadInternal() - Uploading partial image (%ix%i pixels, offset x: %i y: %i)."),
+ aSize.iWidth, aSize.iHeight, aOrigin.iX, aOrigin.iY);
+
+ VGImageFormat imageSourceFormat = (VGImageFormat)(-1);
+ VGImageFormat imageInternalFormat = VG_sRGBX_8888; // TODO: get the most optimal image format from the renderer
+ VGbitfield qualityFlags = VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_BETTER; // TODO: get this from hitchcock
+ TBool hasAlpha = EFalse;
+ TBool conversionRequired = ETrue;
+ TInt sourceStride = 0;
+
+ switch (aFormat)
+ {
+ case EHuiTextureFormatRgb565:
+ imageSourceFormat = VG_sRGB_565;
+ conversionRequired = EFalse;
+ sourceStride = aSize.iWidth * 2;
+ break;
+ case EHuiTextureFormatRgb888:
+ imageSourceFormat = VG_sRGBX_8888;
+ sourceStride = aSize.iWidth * 4;
+ break;
+ case EHuiTextureFormatLa88:
+ // We have to expand this format to RGBA, since there is no luminance-alpha format in OpenVG 1.0.1
+ imageSourceFormat = VG_sRGBA_8888;
+ sourceStride = aSize.iWidth * 4;
+ hasAlpha = ETrue;
+ break;
+#if defined(OPENVG_VERSION_1_0_1)
+ case EHuiTextureFormatRgba8888:
+ imageSourceFormat = VG_sARGB_8888;
+ conversionRequired = EFalse;
+ hasAlpha = ETrue;
+ sourceStride = aSize.iWidth * 4;
+ break;
+#else // defined(OPENVG_VERSION_1_0_1)
+ case EHuiTextureFormatRgba8888:
+ imageSourceFormat = VG_sRGBA_8888;
+ sourceStride = aSize.iWidth * 4;
+ hasAlpha = ETrue;
+ break;
+#endif // defined(OPENVG_VERSION_1_0_1)
+
+ // Compressed formats are not supported
+ default:
+ // we return without doing anything because we are called by a non-leaving function
+ return;
+ }
+
+ // Use a matching internal format
+ imageInternalFormat = imageSourceFormat;
+
+ // Create the actual image if required
+ VGImage image = VG_INVALID_HANDLE;
+
+ if (aCreateImage)
+ {
+ image = vgCreateImage(imageInternalFormat, aSize.iWidth, aSize.iHeight, qualityFlags);
+ }
+ else
+ {
+ image = (VGImage)SegmentName(0);
+
+ // Verify the dimensions
+ if (aOrigin.iX + aSize.iWidth >= Size().iWidth ||
+ aOrigin.iY + aSize.iHeight >= Size().iHeight)
+ {
+ // we return without doing anything because we are called by a non-leaving function
+ return;
+ }
+ }
+
+ if (image == VG_INVALID_HANDLE)
+ {
+ // we return without doing anything because we are called by a non-leaving function
+ return;
+ }
+
+ if (!conversionRequired)
+ {
+ // No data conversion is required and we can upload the pixels as such
+ vgImageSubData(image, aBuffer, sourceStride, imageSourceFormat, aOrigin.iX, aOrigin.iY, aSize.iWidth, aSize.iHeight);
+ HUI_VG_INVARIANT();
+ }
+ else
+ {
+ // One or more conversion steps are needed
+ TInt pixels = aSize.iWidth * aSize.iHeight;
+ TUint8* convBuffer = NULL;
+ convBuffer = new TUint8[sourceStride * aSize.iHeight];
+ // there are no leaving functions until our buffer is deleted
+ // We cannot put convBuffer onto cleanup stack because we cannot leave.
+
+ if ( !convBuffer )
+ {
+ // we return without doing anything because we are called by a non-leaving function
+ return;
+ }
+
+ switch (aFormat)
+ {
+ case EHuiTextureFormatRgb888:
+ ConvertBufferRgb888TosRGBX8888(aBuffer, convBuffer, pixels);
+ break;
+ case EHuiTextureFormatLa88:
+ ConvertBufferLa88TosRGBA8888(aBuffer, convBuffer, pixels);
+ break;
+#if !defined(OPENVG_VERSION_1_0_1)
+ case EHuiTextureFormatRgba8888:
+ ConvertBufferRgba8888TosRGBA8888(aBuffer, convBuffer, pixels);
+ break;
+#endif // defined(OPENVG_VERSION_1_0_1)
+ default:
+ ASSERT(0);
+ }
+
+ vgImageSubData(image, convBuffer, sourceStride, imageSourceFormat, aOrigin.iX, aOrigin.iY, aSize.iWidth, aSize.iHeight);
+ delete[] convBuffer;
+ HUI_VG_INVARIANT();
+ }
+
+ // Save the image handle
+ SetSegmentName(0, (TUint)image);
+
+ // The texture now has content.
+ iInternalFlags |= EFlagHasContent;
+
+ if (hasAlpha)
+ {
+ iInternalFlags |= EFlagHasAlpha;
+ }
+
+ // Keep the shadow in sync with the image contents
+ if (IsShadowEnabled())
+ {
+ // We cannot leave, we just try our best.
+ // If this fails, we have no shadow
+ TRAP_IGNORE( GenerateShadowL() );
+ }
+
+ HUI_VG_INVARIANT();
+ }
+
+void CHuiVg10Texture::Reset()
+ {
+ CHuiTexture::Reset();
+
+ if (iShadow.Name())
+ {
+ vgDestroyImage((VGImage)iShadow.Name());
+ iShadow.SetName(0);
+ }
+
+ iShadowEnabled = EFalse;
+
+#ifdef __NVG
+ CHuiTexture::SetNvgContent(EFalse);
+ iIsExtended = EFalse;
+
+ delete iNVGData;
+ iNVGData = NULL;
+ delete iIconCommands;
+ iIconCommands = NULL;
+#endif
+ }
+
+void CHuiVg10Texture::ResetSegment(TInt aSegment)
+ {
+ HUI_DEBUG1(_L("CHuiVg10Texture::ResetSegment() - Trying to delete image for segment %i."), aSegment);
+ HUI_VG_INVARIANT();
+ ASSERT(aSegment>=0 && aSegment < SegmentCount());
+
+ VGImage image = (VGImage)SegmentName(aSegment);
+ if (image != VG_INVALID_HANDLE)
+ {
+ vgDestroyImage(image);
+ }
+
+ SetSegmentName(aSegment, VG_INVALID_HANDLE);
+ SetSegmentTextureSize(aSegment, TSize(0, 0));
+ SetSegmentSize(aSegment, TSize(0, 0));
+ SetSegmentOffset(aSegment, TPoint(0, 0));
+
+ // There is no content anymore
+ iInternalFlags &= ~(EFlagHasContent | EFlagHasAlpha);
+
+ HUI_VG_INVARIANT();
+ }
+
+
+void CHuiVg10Texture::InitSegmentL(TInt /*aSegment*/)
+ {
+ // Nothing to do
+ }
+
+
+void CHuiVg10Texture::SetupSegmentsL(const TSize& aLogicalSize,
+ const TSize& aTextureSize,
+ THuiTextureUploadFlags aFlags)
+ {
+ // Assert that the sizes are valid.
+ ASSERT(aTextureSize.iWidth > 0 && aTextureSize.iHeight > 0);
+ ASSERT(aLogicalSize.iWidth > 0 && aLogicalSize.iHeight > 0);
+
+ HUI_DEBUG4(_L("CHuiVg10Texture::SetupSegments() - Configuring a single %ix%i texture segment for %ix%i bitmap."),
+ aTextureSize.iWidth, aTextureSize.iHeight,
+ aTextureSize.iWidth, aTextureSize.iHeight);
+
+ // All textures use only a single segment with OpenVG.
+ SetSegmentCountL(1);
+
+ SetSegment(0, aLogicalSize, TPoint(0, 0), aTextureSize);
+ SetSegmentName(0, (TUint)VG_INVALID_HANDLE);
+
+ // The logical size always matches the texture size
+ SetSize(aLogicalSize);
+
+ // Enable shadow generation if requested
+ if (aFlags & EHuiTextureUploadFlagGenerateShadow)
+ {
+ EnableShadow(ETrue);
+ }
+ }
+
+void CHuiVg10Texture::TextureExtension(const TUid& aExtensionUid, TAny** aExtensionParameters)
+ {
+ CHuiTexture::TextureExtension(aExtensionUid, aExtensionParameters);
+ }
+
+void CHuiVg10Texture::EnableShadow(TBool aEnable)
+ {
+ CHuiTexture::EnableShadow(aEnable);
+ iShadowEnabled = aEnable;
+
+ if (!aEnable && iShadow.Name())
+ {
+ vgDestroyImage((VGImage)iShadow.Name());
+ iShadow.SetName(0);
+ HUI_VG_INVARIANT();
+ }
+
+ if (aEnable)
+ {
+ // We cannot leave, we just try our best.
+ // If this fails, we have no shadow
+ TRAP_IGNORE( GenerateShadowL() );
+ }
+
+ HUI_VG_INVARIANT();
+ }
+
+TBool CHuiVg10Texture::IsShadowEnabled() const
+ {
+ return iShadowEnabled;
+ }
+
+TBool CHuiVg10Texture::GetShadowTexture(THuiTextureHandle& aHandle) const
+ {
+ if (iShadowEnabled && iShadow.SegmentName(0))
+ {
+ aHandle = iShadow;
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+void CHuiVg10Texture::UpdateShadowSizeL(const TSize& aSize)
+ {
+ VGImage shadow = VG_INVALID_HANDLE;
+
+ if (iShadow.Name())
+ {
+ shadow = (VGImage)(iShadow.Name());
+ TInt w = vgGetParameteri(shadow, VG_IMAGE_WIDTH);
+ TInt h = vgGetParameteri(shadow, VG_IMAGE_HEIGHT);
+
+ if (w != aSize.iWidth || h != aSize.iHeight)
+ {
+ // Destroy the old shadow image -- a new one will be created below
+ vgDestroyImage(shadow);
+ iShadow.SetName(0);
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ ASSERT(!iShadow.Name());
+
+ shadow = vgCreateImage(VG_sRGBA_8888_PRE, aSize.iWidth, aSize.iHeight,
+ VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_NONANTIALIASED);
+
+ if (shadow == VG_INVALID_HANDLE)
+ {
+ return;
+ }
+ iShadow.SetName(shadow);
+ iShadow.SetSize(aSize);
+
+ HUI_VG_INVARIANT();
+ }
+
+void CHuiVg10Texture::GenerateShadowL()
+ {
+ if (iRenderPlugin.IsReleased())
+ {
+ HUI_DEBUG(_L("CHuiVg10Texture::GenerateShadowL - VG context not available, cannot generate texture object."));
+ return;
+ }
+
+ if (!IsShadowEnabled() || !(iInternalFlags & EFlagHasContent))
+ {
+ return;
+ }
+
+ CHuiTextureProcessor& proc = CHuiStatic::Env().TextureManager().Processor();
+ TSize size = Size();
+
+ switch(ShadowStyle())
+ {
+ case EHuiTextureShadowStyleIcon:
+ {
+ // TODO: Allow for smaller shadow images as an optimization
+ TSize shadowSize(size.iWidth, size.iHeight);
+ UpdateShadowSizeL(shadowSize);
+ proc.BlurL(Handle(), iShadow, shadowSize, 4,
+ CHuiTextureProcessor::EBlurFlagWhite |
+ CHuiTextureProcessor::EBlurFlagAlpha |
+ CHuiTextureProcessor::EBlurFlagExpandEdges);
+ break;
+ }
+
+ case EHuiTextureShadowStyleRasterizedText:
+ {
+ TSize shadowSize(size.iWidth, size.iHeight);
+ UpdateShadowSizeL(shadowSize);
+ proc.BlurL(Handle(), iShadow, shadowSize, 4,
+ CHuiTextureProcessor::EBlurFlagWhite |
+ CHuiTextureProcessor::EBlurFlagAlpha |
+ CHuiTextureProcessor::EBlurFlagExpandEdges);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ HUI_VG_INVARIANT();
+ }
+
+#ifdef __NVG
+HBufC8* CHuiVg10Texture::ReadNVGDataL(const CFbsBitmap& aBitmap)
+ {
+ // Fetch the extended data
+ aBitmap.BeginDataAccess();
+ const TUint32* data = aBitmap.DataAddress();
+ TInt dataSize = aBitmap.DataSize();
+ TUint8* compressedData = new (ELeave) TUint8[dataSize];
+ CleanupStack::PushL(compressedData);
+ Mem::Copy(compressedData, data, dataSize);
+ aBitmap.EndDataAccess(ETrue);
+
+ // Create a descriptor out of the extended bitmap data. The iNVGData
+ // will now contain the direct OpenVG commands
+ TPtr8 nvgDataPtr(compressedData, dataSize, dataSize);
+ HBufC8* dataBuf = nvgDataPtr.AllocL();
+
+ CleanupStack::PopAndDestroy(compressedData);
+ return dataBuf;
+ }
+
+void CHuiVg10Texture::SegmentUploadNvgL(const CFbsBitmap& aBitmap, const CFbsBitmap* aMaskBitmap, THuiTextureUploadFlags aFlags)
+ {
+ HUI_VG_INVARIANT();
+
+ VGImage image = VG_INVALID_HANDLE;
+ HBufC8* dataBuf = ReadNVGDataL(aBitmap);
+ CleanupStack::PushL(dataBuf);
+ HBufC8* maskDataBuf = NULL;
+ TAknIconHeader header = GetNvgIconHeader(dataBuf);
+ TAknIconHeader maskHeader(header); // DUMMY Creation, since default constructor is missing!
+
+ if (aMaskBitmap)
+ {
+ maskDataBuf = ReadNVGDataL(*aMaskBitmap);
+ CleanupStack::PushL(maskDataBuf);
+ maskHeader = GetNvgIconHeader(maskDataBuf);
+ }
+
+ // The trick here is to check the texture upload flags, and determine
+ // whether we want to draw from NVG object cache directly or raster
+ // the NVG data to a PBuffer
+ if (aFlags & EHuiTextureUploadFlagUsePureNvg)
+ {
+ // Save the NVG data for future use
+ if (iNVGData)
+ {
+ delete iNVGData;
+ iNVGData = NULL;
+ }
+ iNVGData = dataBuf;
+
+ // TODO: If the NVG ObjectCache is still up-to-date, we could possibly
+ // create the object cached NVG icon for faster drawing, and maybe
+ // discard the iNVGData completely (to save RAM?)
+ CreateObjCachedNVGIconL(); // NOTE: The OPENVG_OBJECT_CACHING has to be defined in NVG!
+
+ // Mark the texture as an NVG texture
+ CHuiTexture::SetNvgContent(ETrue);
+ iIsExtended = ETrue;
+ }
+ else // By default, use the "OPTION C" -way!
+ {
+ // Use the same way to create the rendered image as in OPTION_C (see below)
+ CNvgEngine& nvgEngine = iRenderPlugin.NvgEngine();
+ iIsExtended = ETrue; // I'm an NVG texture yet..
+
+ // Make sure we don't leak memory
+ if (iNVGData)
+ {
+ delete iNVGData;
+ iNVGData = NULL;
+ }
+
+ // Create the real image from NVG databuf
+ iNVGData = dataBuf;
+ image = CreateRenderedImage(&nvgEngine, dataBuf, Size());
+
+ // New functionality for checking the mask
+ if (header.GetBitmapId() != maskHeader.GetBitmapId() &&
+ CompareNvgData(dataBuf, maskDataBuf) != 0)
+ {
+ VGImage maskImg = VG_INVALID_HANDLE;
+ // The mask is from different bitmap => we have to create
+ // a separate mask image for masking the NVG icon
+ maskImg = CreateRenderedImage(&nvgEngine, maskDataBuf, Size());
+ ReplaceVGImageAlphaChannelL(image, maskImg, Size());
+ vgDestroyImage(maskImg);
+ }
+
+ // Save the image handle
+ SetSegmentName(0, (TUint)image);
+
+ // No need for object cached cmds, if any did exist
+ delete iIconCommands; // No effect, if iIconCommands aren't created
+ iIconCommands = NULL;
+
+ // If the VGImage texture creation was successful, we are no longer "NVG
+ // texture" in a sense. If not, we will use the NVG data directly for drawing
+ if (image != VG_INVALID_HANDLE)
+ {
+ CHuiTexture::SetNvgContent(EFalse);
+ iIsExtended = EFalse;
+ }
+ }
+
+ if (aMaskBitmap)
+ {
+ CleanupStack::PopAndDestroy(maskDataBuf);
+ }
+ CleanupStack::Pop(dataBuf);
+
+ // The texture now has content.
+ iInternalFlags |= EFlagHasContent;
+ iInternalFlags |= EFlagHasAlpha;
+
+ HUI_VG_INVARIANT();
+ }
+
+TInt CHuiVg10Texture::CompareNvgData(HBufC8* aNVGData1, HBufC8* aNVGData2)
+ {
+ TInt lengthAfterHeader1 = aNVGData1->Length() - KIconHeaderLength;
+ TInt lengthAfterHeader2 = aNVGData2->Length() - KIconHeaderLength;
+
+ TPtr8 firstNoHeader((TUint8 *)aNVGData1->Des().Ptr() + KIconHeaderLength, lengthAfterHeader1, lengthAfterHeader1);
+ TPtr8 secondNoHeader((TUint8 *)aNVGData2->Des().Ptr() + KIconHeaderLength, lengthAfterHeader2, lengthAfterHeader2);
+
+ TInt returnValue = firstNoHeader.Compare(secondNoHeader);
+ return returnValue;
+ }
+
+VGImage CHuiVg10Texture::CreateRenderedImage(CNvgEngine* aNvgEngine, HBufC8* aNVGData, const TSize& aDestSize)
+ {
+ HUI_VG_INVARIANT();
+
+ // Image placeholder
+ VGImage image = VG_INVALID_HANDLE;
+
+ if ( !iIsExtended )
+ {
+ // If called outside of the context, do nothing.
+ // Image will be VG_INVALID_HANDLE
+ HUI_DEBUG(_L("CHuiVg10Texture::CreateRenderedImage() - Texture not extended, can't create rendered image"));
+ return image;
+ }
+
+ // Check if we already have an existing image.
+ if (SegmentCount() == 1)
+ {
+ image = (VGImage)SegmentName(0);
+ if( image != VG_INVALID_HANDLE )
+ {
+ HUI_DEBUG1(_L("CHuiVg10Texture::CreateRenderedImage() - Image already exists: %d"), image);
+ return image;
+ }
+ }
+
+ // NVGEngine is needed to do the drawing of the extended bitmap to VGImage
+ if (!aNvgEngine || !aNVGData)
+ {
+ HUI_DEBUG(_L("CHuiVg10Texture::CreateRenderedImage() - No NvgEngine / NVGData!"));
+ return image;
+ }
+
+ // Get the needed egl contexts & stuff for creating the proper eglSurface
+ EGLContext context = iRenderPlugin.EglSharedContext();
+ MHuiRenderSurface* oldSurface = CHuiStatic::CurrentRenderSurface();
+
+#ifndef __WINS__ // Should possibly query the supported mode instead?
+ VGImageFormat imageInternalFormat = VG_sARGB_8888_PRE;
+#else
+ VGImageFormat imageInternalFormat = VG_sARGB_8888;
+#endif
+
+ VGbitfield qualityFlags = VG_IMAGE_QUALITY_NONANTIALIASED; // | VG_IMAGE_QUALITY_BETTER | VG_IMAGE_QUALITY_FASTER;
+ image = vgCreateImage(imageInternalFormat, aDestSize.iWidth, aDestSize.iHeight, qualityFlags);
+
+ // Get the configs and displays etc. needed for creating the surface
+ EGLDisplay display = iRenderPlugin.EglDisplay();
+
+#if 1
+ // Returns the same config, as below!
+ // The config used with the current renderer surface has the same parameters
+ // that are needed with the PBufferSurface from vgImage
+ EGLConfig config = iRenderPlugin.EglConfig(0);
+#else
+ // This structure can be used, if surface config params have to be changed
+ // Better way though might be to change the vgImage VGImageFormat accordingly..
+ const TInt BITS_PER_CHANNEL = 8;
+ // Choose an EGL config
+ const EGLint attrs[] =
+ {
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT,
+ EGL_RED_SIZE, BITS_PER_CHANNEL,
+ EGL_GREEN_SIZE, BITS_PER_CHANNEL,
+ EGL_BLUE_SIZE, BITS_PER_CHANNEL,
+ EGL_ALPHA_SIZE, BITS_PER_CHANNEL,
+ EGL_NONE
+ };
+ TInt configCount = iRenderPlugin.EglChooseConfig(attrs);
+ ASSERT(configCount > 0);
+ EGLConfig config = iRenderPlugin.EglConfig(0);
+#endif
+
+ // The VGImage will act as the surface, so the drawing will go directly to the VGImage
+ EGLSurface newSurface = eglCreatePbufferFromClientBuffer(
+ display, EGL_OPENVG_IMAGE,
+ static_cast<EGLClientBuffer>(image), // Use the image as buffer
+ config, NULL);
+
+ // Report error in debug mode, if failed creating the surface
+ if ( newSurface == EGL_NO_SURFACE )
+ {
+ HUI_DEBUG1(_L("CHuiVg10Texture::CreateRenderedImage() - EGL Surface could not be created, eglErr: %04x"), eglGetError() );
+ if ( image != VG_INVALID_HANDLE )
+ {
+ vgDestroyImage( image );
+ image = VG_INVALID_HANDLE;
+ }
+
+ HUI_VG_INVARIANT();
+ return image;
+ }
+
+ // Set the new VGImage related eglSurface as current, and start drawing onto it!
+ // We use the old context, our surface should be compatible with it
+ if ( eglMakeCurrent( display, newSurface, newSurface, context ) == EGL_FALSE )
+ {
+ // Report error in debug mode
+ HUI_DEBUG1(_L("CHuiVg10Texture::CreateRenderedImage() - EGL Surface could not be made current, eglErr: %04x"), eglGetError());
+ if ( image != VG_INVALID_HANDLE )
+ {
+ vgDestroyImage( image );
+ image = VG_INVALID_HANDLE;
+ }
+
+ eglDestroySurface( display, newSurface );
+ HUI_VG_INVARIANT();
+ return image;
+ }
+ CHuiStatic::SetCurrentRenderSurface( NULL );
+
+
+ // VKN TODO: It would be better, if the GC could somehow spot that openVg
+ // state has changed, and would restore it's own state. Could use the same
+ // AddRestoreStateFlags as the paint is currently using..
+ //
+ // Get the current statematrix and store it for the duration of NVG drawing
+ TReal32 matrix[9];
+ vgGetMatrix(matrix);
+ vgLoadIdentity();
+
+ // Render the NVGtexture into the image buffer. No transformations are done for this.
+ SetNvgParamsFromIconHeader(*aNvgEngine, aNVGData);
+
+ if (iIconCommands)
+ {
+ //HUI_DEBUG(_L("CHuiVg10Texture::CreateRenderedImage() - Drawing iIconCommands"));
+ iIconCommands->Draw(aDestSize, aNvgEngine);
+ }
+ else
+ {
+ // If ObjectCached version failed, try to use the old way
+ //HUI_DEBUG(_L("CHuiVg10Texture::CreateRenderedImage() - Drawing with DrawNvg"));
+ VGint blendMode = vgGeti(VG_BLEND_MODE);
+ vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+ aNvgEngine->DrawNvg(GetNvgDataWithoutHeader(aNVGData), aDestSize, NULL, NULL);
+ vgSeti(VG_BLEND_MODE, blendMode);
+ }
+
+ // NVG-TLV icon margin special case check:
+ // Check, if the icon has to be margin corrected
+ TAknIconHeader iconheader = GetNvgIconHeader(aNVGData);
+ TSize size = aDestSize; // For using the correct size also later on
+ if (iconheader.IsMarginCorrection())
+ {
+ size = ApplyMargin(image, aDestSize, display, newSurface, context);
+ if( size != aDestSize)
+ {
+ // Redo the drawing, this time to the correct size
+ if (iIconCommands)
+ iIconCommands->Draw(size, aNvgEngine);
+ else
+ aNvgEngine->DrawNvg(GetNvgDataWithoutHeader(aNVGData), size, NULL, NULL);
+ }
+ }
+
+ // The NVG draw messes up the paint, scissoring & rects, so mark them as dirty
+ TInt dirtyFlags = EHuiVg10GcStateFlagDirtyPaint |
+ EHuiVg10GcStateFlagDirtyScissor |
+ EHuiVg10GcStateFlagDirtyScissorRects;
+ iRenderPlugin.AddRestoreStateFlags(dirtyFlags);
+
+#ifdef _DEBUG
+ // TODO: There's something in the DrawNvg() code, which causes OpenVg to set
+ // error code => PANIC, if not for this temp check here. REMOVE ONCE THE TSW ERROR IS FIXED!
+ VGErrorCode err = vgGetError();
+ if (err)
+ {
+ RDebug::Print(_L("CHuiVG10Texture::CreateRenderedImage - Error in NVG draw: %04x"), err);
+ }
+#endif
+
+ HUI_VG_INVARIANT();
+
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(matrix);
+ oldSurface->MakeCurrent(); // This will also call the SetCurrentRenderSurface
+
+ // Now we should have a rendered image in the image variable!
+ // Release the surface, but not the context because we used a shared context
+ if ( newSurface != EGL_NO_SURFACE )
+ {
+ eglDestroySurface( display, newSurface );
+ }
+
+ // NVG-TLV color correction special case check: If the icon has
+ // some color specified in the icon header, set the new icon color
+ TUint32 iconColor = iconheader.GetIconColor();
+ if (iconColor & 0x00FFFFFF)
+ {
+ SetIconColor(image, size, iconColor);
+ }
+
+ HUI_VG_INVARIANT();
+
+ return image;
+ }
+
+TBool CHuiVg10Texture::IsExtended() const
+ {
+ return iIsExtended;
+ }
+
+HBufC8* CHuiVg10Texture::GetExtendedTextureData() const
+ {
+ return iNVGData;
+ }
+
+MNVGIcon* CHuiVg10Texture::GetIconCommandsData() const
+ {
+ return iIconCommands;
+ }
+
+void CHuiVg10Texture::CreateObjCachedNVGIconL()
+ {
+ HUI_VG_INVARIANT();
+ // Just to be sure that we don't leak memory
+ if (iIconCommands)
+ {
+ HUI_DEBUG(_L("CHuiVg10Texture::CreateObjCachedNVGIconL() - deleting old iIconCommands. Should never come here"));
+ delete iIconCommands;
+ iIconCommands = NULL;
+ }
+
+ // Fetch the NvgDecoder engine for creating the obj cached icon
+ CNvgEngine& nvgEngine = iRenderPlugin.NvgEngine();
+
+ //Set Parameters from Icon Header
+ SetNvgParamsFromIconHeader(nvgEngine, iNVGData);
+
+ // Parse the header info out of the nvg data
+ TPtr8 nvgDataVoidIC = GetNvgDataWithoutHeader(iNVGData);
+
+ iIconCommands = nvgEngine.CreateNVGIcon(nvgDataVoidIC, Size());
+
+ HUI_VG_INVARIANT();
+ }
+
+TAknIconHeader CHuiVg10Texture::GetNvgIconHeader(HBufC8* aNVGData)
+ {
+ // Parse the icon header info from the extended data
+ TPtr8 IconHeaderPtr((TUint8*)aNVGData->Des().Ptr(), KIconHeaderLength, KIconHeaderLength);
+ TAknIconHeader iconheader(IconHeaderPtr);
+
+ return iconheader;
+ }
+
+TPtr8 CHuiVg10Texture::GetNvgDataWithoutHeader(HBufC8* aNVGData)
+ {
+ // The rest of the data (after the iconheader) are the OVG drawing instructions
+ TInt lengthAfterHeader = aNVGData->Length() - KIconHeaderLength;
+ TPtr8 nvgDataVoidIC((TUint8 *)aNVGData->Des().Ptr() + KIconHeaderLength, lengthAfterHeader, lengthAfterHeader);
+
+ return nvgDataVoidIC;
+ }
+
+void CHuiVg10Texture::SetNvgParamsFromIconHeader(CNvgEngine& aNvgEngine, HBufC8* aNVGData)
+ {
+ TAknIconHeader iconheader = GetNvgIconHeader(aNVGData);
+
+ // Set preserve aspect ratio according to the header info
+ TNvgAlignStatusType alignTypeValue = ENvgPreserveAspectRatio_XmidYmid;
+ TNvgMeetOrSliceType meetOrSliceTypeValue = ENvgMeet;
+
+ switch ( iconheader.GetScaleMode() )
+ {
+ case EAspectRatioPreserved: // Fall through
+ {
+ // Use default
+ break;
+ }
+
+ // Ensures NVG content fully covers
+ // the area of the icon whilst preserving aspect ratio.
+ case EAspectRatioPreservedSlice:
+ {
+ // alignTypeValue use default
+ meetOrSliceTypeValue = ENvgSlice;
+ break;
+ }
+
+ // EAspectRatioPreservedAndUnusedSpaceRemoved is mapped to the same
+ // values as EAspectRatioNotPreserved because we already have a
+ // frame buffer with the dimensions that preserves the aspect ratio.
+ // This mapping ensures that NVG engine does not calculate aspect
+ // ratio twice and potentially resulting in precision loss.
+ case EAspectRatioPreservedAndUnusedSpaceRemoved:
+ case EAspectRatioNotPreserved:
+ {
+ alignTypeValue = ENvgPreserveAspectRatio_None;
+ // meetOrSliceTypeValue used default
+ break;
+ }
+ }
+ aNvgEngine.SetPreserveAspectRatio(alignTypeValue, meetOrSliceTypeValue);
+ aNvgEngine.Rotate(iconheader.GetRotation(),Size().iWidth >>1, Size().iHeight >>1);
+ }
+
+TSize CHuiVg10Texture::ApplyMargin(VGImage aImage, TSize aSize, EGLDisplay aDisplay, EGLSurface aSurface, EGLContext aContext)
+ {
+ HUI_VG_INVARIANT();
+ // If the icon is also a current EGL surface, the getImageSubData
+ // won't succeed and return "image in use" -error..
+ if ( eglMakeCurrent( aDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ) == EGL_FALSE )
+ {
+ HUI_DEBUG1(_L("CHuiVg10Texture::ApplyMargin() - EGL NO_Surface could not be made current, eglErr: %04x"), eglGetError());
+ return aSize;
+ }
+
+#ifndef __WINS__ // Should possibly query the supported mode instead?
+ VGImageFormat imageInternalFormat = VG_sARGB_8888_PRE;
+#else
+ // This doesn't work in the Emulator anyways.. => remove?
+ VGImageFormat imageInternalFormat = VG_sARGB_8888;
+#endif
+
+ TInt stride = aSize.iWidth * 4; // VG_sARGB_8888(_PRE) is four bytes long (8888)
+ HBufC8* buf = HBufC8::New(stride);
+ if (!buf)
+ {
+ HUI_DEBUG(_L("CHuiVg10Texture::ApplyMargin() - Ran out of memory!"));
+ return aSize;
+ }
+ TUint32* ptr = (TUint32*)(buf->Des()).Ptr();
+
+ const TInt lValidMargin = aSize.iHeight * 12 / 100;
+
+ const TInt Ha = aSize.iHeight;
+ TInt hTa = 0;
+ TInt hNT = 0;
+ TInt C = 0;
+ TInt hNTN = Ha - 2.0 * 0.12 * Ha;
+ TReal R = 1.0;
+ TInt HaN = Ha;
+
+ const TInt lastColumn = aSize.iHeight - 1;
+ for (TInt curRow = 0; curRow < lValidMargin; curRow++)
+ {
+ const TInt y = (aSize.iHeight - 1) - curRow; // h - 1 is the last line
+ // Get just one stride at a time (iWidth wide, 1 pixel high)
+ vgGetImageSubData(aImage, ptr, stride, imageInternalFormat, 0, y, aSize.iWidth, 1);
+ for (TInt s = lastColumn; s >= 0; --s)
+ {
+ if (ptr[s] & 0xFF000000)
+ {
+ hTa = curRow;
+ hNT = Ha - 2 * hTa;
+ C = 2 * hTa;
+ R = ( ( (TReal)hNTN / (TReal)hNT ) > 1.0 ) ? 1 : (TReal)hNTN / (TReal)hNT;
+ HaN = Ha * R - C * R + C;
+ curRow = lValidMargin; // to exit the outer loop
+ break; // to exit the inner
+ }
+ }
+ }
+ delete buf;
+ HUI_VG_INVARIANT();
+
+ // Make the PBuffer surface current again
+ if ( eglMakeCurrent(aDisplay, aSurface, aSurface, aContext) == EGL_FALSE )
+ {
+ HUI_DEBUG1(_L("CHuiVg10Texture::ApplyMargin() - EGL aSurface could not be made current, eglErr: %04x"), eglGetError());
+ return aSize;
+ }
+
+ // If icon size has to be changed, clear out old area for new DrawNVG round!
+ if(aSize.iHeight > HaN)
+ {
+ vgLoadIdentity();
+
+ VGfloat color[4] = { 1.0f, 1.0f, 1.0f, 0.0f };
+ vgSetfv(VG_CLEAR_COLOR, 4, color);
+ vgClear(0, 0, aSize.iWidth, aSize.iHeight);
+ // Or should it be clearImage instead?
+ //vgClearImage(aImage, 0, 0, aSize.iWidth, aSize.iHeight);
+
+ VGfloat Hr = (VGfloat)HaN/(aSize.iHeight);
+ TInt WaN = aSize.iWidth*Hr;
+
+ VGfloat Tx = (aSize.iHeight-HaN)/2;
+ VGfloat Ty = (aSize.iWidth-WaN)/2;
+ vgTranslate(Tx,Ty);
+
+ HUI_VG_INVARIANT();
+ return(TSize(HaN,WaN));
+ }
+
+ HUI_VG_INVARIANT();
+ return aSize;
+ }
+
+void CHuiVg10Texture::SetIconColor(VGImage& aSrcImage, TSize aSize, TUint32 aColor)
+ {
+ // TODO: DOESN'T WORK IN EMULATOR FOR SOME REASON! Figure out why!
+ HUI_VG_INVARIANT();
+
+ vgSeti(VG_FILTER_FORMAT_LINEAR, VG_FALSE);
+
+#ifndef __WINS__ // Should possibly query the supported mode instead?
+ VGImageFormat imageInternalFormat = VG_sARGB_8888_PRE;
+ // TODO: !!! SHOULD FORMAT_PREMULTIPLIED BE APPLIED?? !!!
+ //vgSeti(VG_FILTER_FORMAT_PREMULTIPLIED, VG_TRUE);
+#else
+ // This doesn't work in the Emulator anyways.. => remove?
+ VGImageFormat imageInternalFormat = VG_sARGB_8888;
+#endif
+
+ // Rip the RGB components from the aColor param & scale to [0..1]
+ VGfloat red = (aColor&0xff)/255.0f;
+ VGfloat green = ((aColor>>8)&0xff)/255.0f;
+ VGfloat blue = ((aColor>>16)&0xff)/255.0f;
+
+ //vgSeti(VG_FILTER_CHANNEL_MASK, VG_ALPHA );
+ // This matrix will set all color components in the source image to 0,
+ // and replaces the RGB with the values from the iconheader
+ VGfloat matrix[20] = {
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,1, // <- Preserves the original alpha value
+ red, green, blue, 0};
+
+ // Create the destination image & start modifying colors
+ VGImage dstImg = vgCreateImage(imageInternalFormat, aSize.iWidth, aSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
+ vgColorMatrix(dstImg, aSrcImage, matrix);
+ HUI_VG_INVARIANT();
+
+ // Destroy the old source image and return the new image with changed colors
+ vgDestroyImage(aSrcImage);
+ aSrcImage = dstImg;
+
+ HUI_VG_INVARIANT();
+ }
+
+void CHuiVg10Texture::ReplaceVGImageAlphaChannelL(VGImage aImage, VGImage aMaskImage, TSize aSize)
+ {
+ HUI_VG_INVARIANT();
+
+#ifndef __WINS__ // Should possibly query the supported mode instead?
+ VGImageFormat imageInternalFormat = VG_sARGB_8888_PRE;
+#else
+ VGImageFormat imageInternalFormat = VG_sARGB_8888;
+#endif
+ TInt height = aSize.iHeight;
+ TInt width = aSize.iWidth;
+ const TInt colorDepth = 4; // VG_sARGB_8888(_PRE) 4 bytes long
+ TInt stride = width * colorDepth;
+
+ // Create the pointers to RAM in which the image data will be saved temporarily
+ HBufC8* imgBuf = HBufC8::NewL(width * height * colorDepth);
+ CleanupStack::PushL(imgBuf);
+ TUint32* imgPtr = (TUint32*)(imgBuf->Des()).Ptr();
+ const TUint32* imgSavePtr = (TUint32*)(imgBuf->Des()).Ptr();
+
+ HBufC8* maskBuf = HBufC8::NewL(width * height * colorDepth);
+ CleanupStack::PushL(maskBuf);
+ TUint32* maskPtr = (TUint32*)(maskBuf->Des()).Ptr();
+
+ // Get the image pixel data
+ vgGetImageSubData(aImage, imgPtr, stride, imageInternalFormat, 0, 0, width, height);
+ vgGetImageSubData(aMaskImage, maskPtr, stride, imageInternalFormat, 0, 0, width, height);
+
+ // Replace destination image's alpha values with mask image
+ for (TInt y = 0; y < height; y++)
+ {
+ for (TInt x = 0; x < width; x++)
+ {
+ *maskPtr &= 0xff000000; // Remove other than alpha component from source pixel
+ *imgPtr &= ~0xff000000; // Remove alpha channel value from destination pixel
+ *imgPtr++ |= *maskPtr++; // Bitwise OR the maskImg alpha info to destination image pixel
+ }
+ }
+
+ // Replace the destination image with combined alpha information from src image
+ vgImageSubData(aImage, imgSavePtr, stride, imageInternalFormat, 0, 0, width, height);
+
+ CleanupStack::PopAndDestroy(maskBuf);
+ CleanupStack::PopAndDestroy(imgBuf);
+
+ HUI_VG_INVARIANT();
+ }
+#endif
+
+
+void CHuiVg10Texture::PushEGLContext()
+ {
+ iPreviousEGLState.iContext= eglGetCurrentContext();
+ TEGLState& state = iRenderPlugin.GetUploadState();
+ if (state.iContext == KErrNotFound)
+ {
+ TEGLState& state = iRenderPlugin.GetUploadState();
+ // the first context used for uploading will be used for all texture uploads
+ state.iContext = iPreviousEGLState.iContext;
+ state.iDrawSurface = eglGetCurrentSurface(EGL_DRAW);
+ state.iReadSurface = eglGetCurrentSurface(EGL_READ);
+ state.iDisplay = eglGetCurrentDisplay();
+ }
+ else
+ {
+ // change context only if necessary
+ if (iPreviousEGLState.iContext != state.iContext)
+ {
+ iPreviousEGLState.iDrawSurface = eglGetCurrentSurface(EGL_DRAW);
+ iPreviousEGLState.iReadSurface = eglGetCurrentSurface(EGL_READ);
+ iPreviousEGLState.iDisplay = eglGetCurrentDisplay();
+ eglMakeCurrent(state.iDisplay, state.iDrawSurface, state.iReadSurface, state.iContext);
+ }
+ }
+ }
+
+void CHuiVg10Texture::PopEGLContext()
+ {
+ if (iPreviousEGLState.iContext != iRenderPlugin.GetUploadState().iContext)
+ {
+ eglMakeCurrent(iPreviousEGLState.iDisplay, iPreviousEGLState.iDrawSurface, iPreviousEGLState.iReadSurface,iPreviousEGLState.iContext);
+ }
+ }
+// End of file
+