diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/coretoolkit/src/HuiImageVisual.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiacceltk/hitchcock/coretoolkit/src/HuiImageVisual.cpp Tue Feb 02 07:56:43 2010 +0200 @@ -0,0 +1,650 @@ +/* +* Copyright (c) 2006-2007 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 of CHuiImageVisual. CHuiImageVisual is a visual +* that is able to display images. +* +*/ + + + +#include "uiacceltk/HuiImageVisual.h" // Class definition +#include "uiacceltk/HuiStatic.h" +#include "HuiRenderPlugin.h" +#include "uiacceltk/HuiDrawing.h" +#include "uiacceltk/HuiControl.h" +#include "uiacceltk/HuiUtil.h" +#include "uiacceltk/huifixmath.h" +#include "HuiMatrixStack.h" + +#include "uiacceltk/huidropshadow.h" +#include "uiacceltk/HuiDisplay.h" + +#include "HuiRosterImpl.h" + + +EXPORT_C CHuiImageVisual* CHuiImageVisual::AddNewL(CHuiControl& aOwnerControl, + CHuiLayout* aParentLayout) + { + CHuiImageVisual* image = static_cast( + aOwnerControl.AppendVisualL(EHuiVisualTypeImage, aParentLayout)); + return image; + } + + +CHuiImageVisual::CHuiImageVisual(MHuiVisualOwner& aOwner) + : CHuiVisual(aOwner), iScaleMode(EScaleFit), + iStretchMode(CHuiGc::EStretchVertical), iColor(KRgbWhite), + iScale(1.f),iOffset(.5f,.5f),iDropShadow(0) + { + iSecondaryAlpha.SetStyle(EHuiTimedValueStyleLinear); + } + + +void CHuiImageVisual::ConstructL() + { + CHuiVisual::ConstructL(); + } + + +CHuiImageVisual::~CHuiImageVisual() + { + } + + +EXPORT_C void CHuiImageVisual::SetScaleMode(TScaleMode aScaleMode) + { + iScaleMode = aScaleMode; + SetChanged(); + } + + +EXPORT_C void CHuiImageVisual::SetStretch(TInt aTop, TInt aBottom) + { + iTopStretch = aTop; + iBottomStretch = aBottom; + SetChanged(); + } + + +EXPORT_C void CHuiImageVisual::SetStretchMode(CHuiGc::TStretchMode aStretchMode) + { + iStretchMode = aStretchMode; + SetChanged(); + } + +// deprecated +EXPORT_C void CHuiImageVisual::SetDropShadow(TInt aShadowDistance) + { + SetDropShadow(THuiXYMetric(aShadowDistance)); + } + +EXPORT_C void CHuiImageVisual::SetDropShadow(const THuiMetric& aShadowDistance) + { + SetDropShadow(THuiXYMetric(aShadowDistance)); + } + +EXPORT_C void CHuiImageVisual::SetDropShadow(const THuiXYMetric& aShadowDistance) + { + iDropShadow = aShadowDistance; + SetChanged(); + + if(!HuiUtil::RealCompare(iDropShadow.iX.iMagnitude,0.f) || !HuiUtil::RealCompare(iDropShadow.iY.iMagnitude,0.f)) + { + TRAP_IGNORE( EnableDropShadowL( ETrue ) ); + } + else + { + TRAP_IGNORE( EnableDropShadowL( EFalse ) ); + } + + } + + +EXPORT_C void CHuiImageVisual::SetImage(const THuiImage& aImage) + { + iImage = aImage; + SetChanged(); + } + + +EXPORT_C void CHuiImageVisual::SetSecondaryImage(const THuiImage& aImage) + { + iSecondaryImage = aImage; + SetChanged(); + } + + +EXPORT_C const THuiImage& CHuiImageVisual::Image() const + { + return iImage; + } + + +EXPORT_C void CHuiImageVisual::SetColor(const TRgb& aColor) + { + iColor = aColor; + SetChanged(); + } + + +EXPORT_C void CHuiImageVisual::SetColorMode(TColorMode aColorMode, TReal32 aParam) __SOFTFP + { + iColorMode = aColorMode; + iColorParam = aParam; + SetChanged(); + } + +TBool CHuiImageVisual::PrepareDrawL() + { + if (Flags() & EHuiVisualFlagDrawOnlyAsExternalContent) + { + // This is used only as external content visual. Return now if we are not currently drawing + // external content. + if (!Display() || !Display()->RosterImpl().IsDrawingExternalContent()) + { + return ETrue; + } + } + + if ( iImage.HasTexture() ) + { + CHuiDropShadow* shadowHandler = DropShadowHandler(); + if ( shadowHandler && shadowHandler->IsShadowVisible() ) + { + CHuiTexture* shadowTextureSource = shadowHandler->ShadowedTextureInstance( *iImage.ImageTexture() ); + if ( shadowTextureSource ) + { + const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*DropShadowHandler()->iRadius.Now() ); + shadowTextureSource->CreateShadowTextureL( requestedBlurredSize, EHuiTextureShadowStyleIcon ); + } + } + } + return ETrue; + } + +void CHuiImageVisual::DrawSelf(CHuiGc& aGc, const TRect& /*aDisplayRect*/) const + { + TReal32 effectiveOpacity = EffectiveOpacity(); + + THuiRealRect content = DisplayRect(); + content.Shrink(PaddingInPixels()); + + if(!iImage.HasTexture() || effectiveOpacity <= 0) + { + aGc.NotifyImagePreferredSize(iImage, content); + return; + } + + if(content.Width() <= 0 || content.Height() <= 0) + { + // Too small to see. + return; + } + + aGc.Enable(CHuiGc::EFeatureBlending); + + TReal32 turnAngle = iTurnAngle.Now(); + TReal32 xOffset = 0; + TReal32 yOffset = 0; + + TReal32 scale = HuiUtil::CalculateScaleFactorFromScaleMode( + content.Size(), + iImage.Texture().Size(), + iScaleMode, + iScale.Now() ); + + // Determine offset. + TSize imageSize = iImage.Texture().Size(); + TReal32 scaled = scale * imageSize.iWidth; + if(scaled > content.Width()) + { + xOffset = (scaled - content.Width()) * (iOffset.iX.Now() - 0.5f); + } + scaled = scale * imageSize.iHeight; + if(scaled > content.Height()) + { + yOffset = (scaled - content.Height()) * (iOffset.iY.Now() - 0.5f); + } + + if(turnAngle != 0 || scale != 1) + { + /** @todo GC must provide some support for transformations. */ + aGc.Push(EHuiGcMatrixModel); + + // Rotate around the midpoint of the visual. + THuiRealPoint mid = content.Center(); + + aGc.Translate(EHuiGcMatrixModel, mid.iX - xOffset, mid.iY - yOffset, 0.f); + if(turnAngle != 0) + { + aGc.Rotate(EHuiGcMatrixModel, turnAngle, 0.f, 0.f, -1.f); + } + if(scale != 1) + { + aGc.Scale(EHuiGcMatrixModel, scale, scale, 1.f); + } + aGc.Translate(EHuiGcMatrixModel, -mid.iX, -mid.iY, 0.f); + } + + // Use the appropriate alignment in the graphics context. + if(iScaleMode == EScaleFit) + { + aGc.SetAlign(EHuiAlignHLeft, EHuiAlignVTop); + } + else + { + aGc.SetAlign(EHuiAlignHCenter, EHuiAlignVCenter); + } + + // draw drop shadow + CHuiDropShadow* shadowHandler = DropShadowHandler(); + if ( shadowHandler && iImage.HasTexture() ) + { + CHuiTexture* shadowTextureSource = shadowHandler->ShadowedTextureInstance( *iImage.ImageTexture() ); + if ( iImage.ImageTexture() && + shadowTextureSource && + shadowHandler->IsShadowVisible() ) + { + const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*DropShadowHandler()->iRadius.Now() ); + + THuiTextureHandle shadow; + TBool haveShadowTexture = shadowTextureSource->GetShadowTexture( shadow,requestedBlurredSize ); + + if ( haveShadowTexture ) + { + THuiImage shadowImage( shadow ); + const THuiRealRect shadowDrawingRect = shadowHandler->ShadowDrawingRealRect( + content.iTl, + content.Size(), + shadow.Size(), + *this ); + + // set drawing parameters + aGc.SetPenAlpha(TInt(effectiveOpacity * shadowHandler->iOpacity.Now()*255.f)); + aGc.SetPenColor(shadowHandler->Color()); + const THuiQuality oldQuality = aGc.Quality(); // store the original quality + aGc.SetQuality(EHuiQualityFast); // draw always with 'fast' + + if(iScaleMode == EScaleFit) + { + aGc.DrawImage(shadowImage, shadowDrawingRect.iTl, shadowDrawingRect.Size() ); + } + else + { + THuiRealSize relativeShadowTextureSize = iImage.Texture().Size(); + relativeShadowTextureSize.iWidth *= ((TReal32)shadowDrawingRect.Width())/((TReal32)content.Size().iWidth); + relativeShadowTextureSize.iHeight *= ((TReal32)shadowDrawingRect.Height())/((TReal32)content.Size().iHeight); + + aGc.DrawImage( + shadowImage, + relativeShadowTextureSize, + THuiRealRect( shadowDrawingRect.iTl, shadowDrawingRect.Size() )); + + } + + aGc.SetQuality(oldQuality); // restore quality + } + } + } + + // Actual color of the image. + aGc.SetPenAlpha(TInt(effectiveOpacity * 255)); + aGc.SetPenColor(iColor); + + // Apply special color mode. + if(iColorMode == EColorDimmed) + { + aGc.Enable(CHuiGc::EFeatureFog); + aGc.SetDimmingFog(iColor, iColorParam); + } + + if(iTopStretch || iBottomStretch) + { + aGc.DrawStretchImage(iStretchMode, iImage, content, + iTopStretch, iBottomStretch); + } + else + { + if(aGc.TextureUnits() >= 2 && + CHuiStatic::Renderer().Allows(EHuiRenderPluginAllowTextureModeInterpolate) && + iImage.HasTexture() && iSecondaryImage.HasTexture() && + (iImage.SegmentCount() == iSecondaryImage.SegmentCount() && + (iImage.Texture().Size() == iSecondaryImage.Texture().Size() || iImage.SegmentCount() == 1))) + { + // Can use multitexturing to interpolate. + aGc.SetTextureUnits(2); + aGc.Enable(CHuiGc::EFeatureTexturing); + aGc.SetTextureMode(CHuiGc::ETextureModeInterpolate, + iSecondaryAlpha.Now()); + aGc.SetPenAlpha(TInt(effectiveOpacity * 255)); + + if(iScaleMode == EScaleFit) + { + // Scale both images to the content rectangle. + aGc.DrawImages(iImage, iSecondaryImage, + content.iTl, content.Size()); + } + else + { + // Draw both images by taking the size of the first one. + aGc.DrawImages(iImage, iSecondaryImage, + iImage.Texture().Size(), content); + } + + aGc.SetTextureUnits(1); + aGc.SetTextureMode(CHuiGc::ETextureModeNormal); + } + else + { + // Must draw using two passes. + TInt primaryAlpha = 0; + TInt secondaryAlpha = 0; + GetDualAlpha(effectiveOpacity, iSecondaryAlpha.Now(), + primaryAlpha, secondaryAlpha); + + // Draw both the primary and the secondary images. + if(primaryAlpha > 0) + { + aGc.SetPenAlpha(primaryAlpha); + if(iScaleMode == EScaleFit) + { + aGc.DrawImage(iImage, content.iTl, content.Size()); + } + else + { + aGc.DrawImage(iImage, content); + } + } + + if(secondaryAlpha > 0 && iSecondaryImage.HasTexture()) + { + aGc.SetPenAlpha(secondaryAlpha); + if(iScaleMode == EScaleFit) + { + aGc.DrawImage(iSecondaryImage, content.iTl, content.Size()); + } + else + { + aGc.DrawImage(iSecondaryImage, iImage.Texture().Size(), content); + } + } + else + { + // Notify preferred size even if image is not drawn (yet) + aGc.NotifyImagePreferredSize(iSecondaryImage, content); + } + } + } + + // Disable special color modes. + if(iColorMode == EColorDimmed) + { + aGc.Disable(CHuiGc::EFeatureFog); + } + + // Restore original transformation. + if(turnAngle != 0 || scale != 1) + { + aGc.Pop(EHuiGcMatrixModel); + } + } + + +TBool CHuiImageVisual::Changed() const + { + if(CHuiVisual::Changed()) + { + return ETrue; + } + + if(iImage.Changed()) + { + return ETrue; + } + + return (iTurnAngle.Changed() || iOffset.Changed() || iScale.Changed() || + iSecondaryAlpha.Changed()); + } + + +void CHuiImageVisual::ClearChanged() + { + CHuiVisual::ClearChanged(); + iImage.ClearChanged(); + iTurnAngle.ClearChanged(); + iOffset.ClearChanged(); + iScale.ClearChanged(); + iSecondaryAlpha.ClearChanged(); + } + +void DoRotateRect(THuiRealRect& aRect, TReal32 aAngle) + { + // Transform dirty rect and enlarge it if rotated. + THuiRealRect transformed(aRect); + + THuiRealPoint coords[4]; + coords[0].iX = transformed.iTl.iX; + coords[0].iY = transformed.iTl.iY; + coords[1].iX = transformed.iBr.iX; + coords[1].iY = transformed.iTl.iY; + coords[2].iX = transformed.iBr.iX; + coords[2].iY = transformed.iBr.iY; + coords[3].iX = transformed.iTl.iX; + coords[3].iY = transformed.iBr.iY; + + + TInt radians = HuiFixMath::FixMul(HuiFixMath::FloatToFix(aAngle),KFixPi)/180; + if (aAngle < 0) + { + radians = -radians; + } + + TInt sin = HuiFixMath::FixSin(radians); + TInt cos = HuiFixMath::FixCos(radians); + + + CHuiMatrixStack::TMatrix rotation; + rotation.iMatrix[0] = HuiFixMath::FixToFloat(cos); + rotation.iMatrix[1] = HuiFixMath::FixToFloat(sin); + rotation.iMatrix[3] = HuiFixMath::FixToFloat(-sin); + rotation.iMatrix[4] = HuiFixMath::FixToFloat(cos); + rotation.iMatrix[8] = 1.0f; + rotation.iIsIdentity = EFalse; + + for (TInt count = 0; count < 4; count++) + { + rotation.Multiply(coords[count]); + } + + // rotate only if there is really rotation, not mirroring + + if ( !HuiUtil::RealCompare(coords[2].iY, coords[3].iY) ) + { + // rotation has been applied + THuiRealPoint minPoint = coords[0]; + THuiRealPoint maxPoint = coords[0]; + for (TInt count = 1; count < 4; count++) + { + if (coords[count].iX < minPoint.iX) + { + minPoint.iX = coords[count].iX; + } + if (coords[count].iY < minPoint.iY) + { + minPoint.iY = coords[count].iY; + } + if (coords[count].iX > maxPoint.iX) + { + maxPoint.iX = coords[count].iX; + } + if (coords[count].iY > maxPoint.iY) + { + maxPoint.iY = coords[count].iY; + } + } + + transformed.iTl = minPoint; + transformed.iBr = maxPoint; + } + else + { + transformed.iTl = coords[0]; + transformed.iBr = coords[2]; + } + + aRect = transformed; + } + + +void CHuiImageVisual::ExpandRectWithContent(TRect& aRect) const + { + if(!Clipping()) + { + if( iImage.HasTexture() ) + { + TSize imageSize = iImage.Texture().Size(); + + // Handle scale mode + if (iScaleMode == EScaleNormal && + ( imageSize.iWidth > aRect.Width() || imageSize.iHeight > aRect.Height())) + { + const TInt growX = Max( 0, ((imageSize.iWidth - aRect.Width()) + 1) / 2 ); + const TInt growY = Max( 0, ((imageSize.iHeight - aRect.Height()) + 1) / 2 ); + aRect.Grow( growX, growY ); + } + else if (iScaleMode == EScaleFitWidth) + { + TReal32 scale = HuiUtil::CalculateScaleFactorFromScaleMode( + aRect.Size(), + imageSize, + iScaleMode, + 1.f ); + TInt scaled = (TReal32)imageSize.iHeight*scale+0.5f; + if (scaled > aRect.Height()) + { + aRect.Grow(0,(((scaled-aRect.Height()) +1)/2)); + } + } + else if (iScaleMode == EScaleFitHeight) + { + TReal32 scale = HuiUtil::CalculateScaleFactorFromScaleMode( + aRect.Size(), + imageSize, + iScaleMode, + 1.f ); + TInt scaled = (TReal32)imageSize.iWidth*scale+0.5f; + if (scaled > aRect.Width()) + { + aRect.Grow((((scaled-aRect.Width()) +1)/2),0); + } + } + else if (iScaleMode == EScaleCover || iScaleMode == EScaleFitInside) + { + TReal32 scale = HuiUtil::CalculateScaleFactorFromScaleMode( + aRect.Size(), + imageSize, + iScaleMode, + 1.f ); + TInt scaledW = (TReal32)imageSize.iWidth*scale+0.5f; + TInt scaledH = (TReal32)imageSize.iHeight*scale+0.5f; + + if (scaledW > aRect.Width()) + { + aRect.Grow((((scaledW-aRect.Width()) +1)/2),0); + } + if (scaledH > aRect.Height()) + { + aRect.Grow(0,(((scaledH-aRect.Height()) +1)/2)); + } + } + else + { + // For PC-lint + } + } + + // Calculate scaled rect. + // aRect and scaled rect has same center position. + TRect adjusted; + TReal32 scale = iScale.Now(); + TReal32 offsetX = TReal32(aRect.Width()) * scale / 2.f; + TReal32 offsetY = TReal32(aRect.Height()) * scale / 2.f; + + adjusted.iTl.iX = HUI_ROUND_FLOAT_TO_INT((aRect.iTl.iX + aRect.Width()/2.f) - offsetX); + adjusted.iTl.iY = HUI_ROUND_FLOAT_TO_INT((aRect.iTl.iY + aRect.Height()/2.f) - offsetY); + adjusted.iBr.iX = HUI_ROUND_FLOAT_TO_INT((aRect.iBr.iX - aRect.Width()/2.f) + offsetX); + adjusted.iBr.iY = HUI_ROUND_FLOAT_TO_INT((aRect.iBr.iY - aRect.Height()/2.f) + offsetY); + + // aRect must not become smaller. + aRect.BoundingRect( adjusted ); + + // calculate drop shadow + CHuiDropShadow* shadowHandler = DropShadowHandler(); + if ( iImage.HasTexture() && + shadowHandler && + shadowHandler->IsShadowVisible() ) + { + CHuiTexture* shadowTextureSource = shadowHandler->ShadowedTextureInstance( *iImage.ImageTexture() ); + if ( shadowTextureSource ) + { + + const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*shadowHandler->iRadius.Now() ); + + THuiTextureHandle shadow; + TBool haveShadowTexture = shadowTextureSource->GetShadowTexture( shadow,requestedBlurredSize ); + + if ( haveShadowTexture ) + { + const TRect shadowRect = shadowHandler->ShadowDrawingTRect( + aRect.iTl, + aRect.Size(), + shadow.Size(), + *this ); + + // aRect must not become smaller. + aRect.BoundingRect( shadowRect ); + } + } + } + + // add the turn angle effect + if ( iImage.HasTexture() && iTurnAngle.Now() ) + { + // Take turn angle into accout by rotating aRect. + THuiRealRect rotated( THuiRealPoint(0.f,0.f), aRect.Size() ); + rotated.Move( -rotated.Center().iX, -rotated.Center().iY ); + DoRotateRect( rotated, iTurnAngle.Now() ); + TSize rotatedSize = rotated.Size(); + // Size rounds down, compensate by increasing by one. + rotatedSize.iWidth++; + rotatedSize.iHeight++; + + // Define rotatedRect: same center point as aRect, different size + TRect rotatedRect( rotatedSize ); + rotatedRect.Move( + aRect.Center() - + TPoint( ( rotatedSize.iWidth + 1 )/2, ( rotatedSize.iHeight + 1 )/2 ) ); + rotatedRect.iBr += TPoint( 1, 1 ); // two possible center + + // aRect must not become smaller. + aRect.BoundingRect( rotatedRect ); + } + + // Apparently, there is two pixel error in above + // (occurs already before scaling, fit width/fit height cases). + aRect.Grow( 2, 2 ); + } + + CHuiVisual::ExpandRectWithContent(aRect); + }