diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/coretoolkit/rendervg10/src/HuiVg10Texture.cpp --- /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 +#include + +#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 + #include + #include + #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(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(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(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 +