/*
* Copyright (c) 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:
*
*/
#include "HuiFxVg10Engine.h"
#include "HuiFxVg10OnscreenRenderbuffer.h"
#include "HuiFxVg10OffscreenRenderbuffer.h"
#include "HuiFxVg10BlurFilter.h"
#include "HuiFxVg10BrightnessContrastFilter.h"
#include "HuiFxVg10HSLFilter.h"
#include "HuiFxVg10ColorizeFilter.h"
#include "HuiFxVg10OutlineFilter.h"
#include "HuiFxVg10BevelFilter.h"
#include "HuiVg10Gc.h"
#include "uiacceltk/HuiEnv.h"
#include "uiacceltk/HuiDisplay.h"
#include "uiacceltk/HuiStatic.h"
CHuiFxVg10Engine* CHuiFxVg10Engine::NewL(CHuiVg10RenderPlugin& aPlugin)
{
CHuiFxVg10Engine* e = new (ELeave) CHuiFxVg10Engine();
CleanupStack::PushL(e);
e->ConstructL(aPlugin);
CleanupStack::Pop(e);
return e;
}
void CHuiFxVg10Engine::ConstructL(CHuiVg10RenderPlugin& aPlugin)
{
CHuiFxEngine::ConstructL(EHuiFxEngineVg10);
iPlugin = &aPlugin;
iDefaultBuffer = 0;
iCompPaint = vgCreatePaint();
}
CHuiFxVg10Engine::~CHuiFxVg10Engine()
{
delete iDefaultBuffer;
vgDestroyPaint(iCompPaint);
}
CHuiFxRenderbuffer* CHuiFxVg10Engine::AcquireNativeRenderbuffer(const TSize& aDesiredSize)
{
CHuiFxRenderbuffer* ret = NULL;
TRAP_IGNORE(ret = CHuiFxVg10OffscreenRenderbuffer::NewL(*iPlugin, aDesiredSize));
return ret;
}
void CHuiFxVg10Engine::ReleaseNativeRenderbuffer(CHuiFxRenderbuffer* aBuffer)
{
ASSERT(aBuffer);
ASSERT(aBuffer != iDefaultBuffer);
delete aBuffer;
aBuffer = 0;
}
CHuiFxRenderbuffer* CHuiFxVg10Engine::DefaultRenderbuffer()
{
if (!iDefaultBuffer)
{
TRAPD(err, RestoreL());
if(err != KErrNone)
{
return NULL;
}
}
return iDefaultBuffer;
}
void CHuiFxVg10Engine::Release()
{
delete iDefaultBuffer;
iDefaultBuffer = 0;
}
void CHuiFxVg10Engine::RestoreL()
{
if (!iDefaultBuffer)
{
CHuiVg10RenderSurface* surface = static_cast<CHuiVg10RenderSurface*>(CHuiStatic::CurrentRenderSurface());
if (surface)
{
iDefaultBuffer = CHuiFxVg10OnscreenRenderbuffer::NewL(*iPlugin, *surface);
}
}
}
CHuiFxFilter* CHuiFxVg10Engine::CreateFilterL(THuiFxFilterType aType)
{
switch (aType)
{
case EFilterTypeBrightnessContrast:
return CHuiFxVg10BrightnessContrastFilter::NewL();
// no break because we returned already
case EFilterTypeBlur:
return CHuiFxVg10BlurFilter::NewL();
// no break because we returned already
case EFilterTypeHSL:
case EFilterTypeDesaturate: // desaturate is generated by hsl filter
return CHuiFxVg10HSLFilter::NewL();
// no break because we returned already
case EFilterTypeColorize:
return CHuiFxVg10ColorizeFilter::NewL();
// no break because we returned already
case EFilterTypeOutline:
return CHuiFxVg10OutlineFilter::NewL();
// no break because we returned already
case EFilterTypeBevel:
return CHuiFxVg10BevelFilter::NewL();
// no break because we returned already
default: // unsupported
break;
}
return NULL;
}
void CHuiFxVg10Engine::Composite(CHuiFxRenderbuffer& aTarget, CHuiFxRenderbuffer& aSource,
const TRect& aTargetRect, const TRect& aSourceRect,
THuiFxBlendingMode aMode, TInt aAlpha)
{
const TInt VG_MATRIX_SIZE = 9;
CHuiGc& gc = aTarget.BindAsRenderTarget();
aSource.BindAsTexture(ERenderbufferUsageReadOnly);
#if 0 // render debug rectangle
VGint x = aTargetRect.iTl.iX;
VGint y = aTarget.Size().iHeight - aTargetRect.iBr.iY;
VGint w = aTargetRect.Size().iWidth;
VGint h = aTargetRect.Size().iHeight;
VGfloat color[] =
{
.2f, .4f, .6f, 1.0f
};
vgSetfv(VG_CLEAR_COLOR, 4, color);
vgClear(x, y, w, h);
HUIFX_VG_INVARIANT();
#else
VGImage image = (reinterpret_cast<CHuiFxVg10RenderbufferBase*>(&aSource))->AcquireSubImage(aSourceRect);
ASSERT(vgGeti(VG_MATRIX_MODE) == VG_MATRIX_IMAGE_USER_TO_SURFACE);
VGfloat oldMatrix[VG_MATRIX_SIZE];
vgGetMatrix(oldMatrix);
vgLoadIdentity();
vgSeti(VG_SCISSORING, VG_FALSE);
VGint blendMode = vgGeti(VG_BLEND_MODE);
// Choose a blending mode
switch (aMode)
{
case EBlendingModeReplace:
vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
break;
case EBlendingModeOver:
vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
break;
case EBlendingModeMultiply:
vgSeti(VG_BLEND_MODE, VG_BLEND_MULTIPLY);
break;
case EBlendingModeAdditive:
vgSeti(VG_BLEND_MODE, VG_BLEND_ADDITIVE);
break;
case EBlendingModeLighten:
vgSeti(VG_BLEND_MODE, VG_BLEND_LIGHTEN);
break;
case EBlendingModeDarken:
vgSeti(VG_BLEND_MODE, VG_BLEND_DARKEN);
break;
default:
ASSERT(0);
}
HUIFX_VG_INVARIANT();
// Update alpha
TBool mustRestorePaint = EFalse;
VGPaint userPaint = VG_INVALID_HANDLE;
if (aAlpha < 0xff)
{
if ( iCompPaint == VG_INVALID_HANDLE )
{
iCompPaint = vgCreatePaint();
}
if ( iCompPaint != VG_INVALID_HANDLE )
{
mustRestorePaint = ETrue;
userPaint = vgGetPaint( VG_FILL_PATH );
// if the original paint is not set, we'll get an error that must be cleared
vgSetPaint(iCompPaint, VG_FILL_PATH);
}
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY);
vgSetColor(iCompPaint, 0xffffff00 | aAlpha);
}
else
{
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
}
// we've taken childimage from source so no clipping or adjusting is needed
// by source rectangle.
if (aTarget.BufferType() == EBufferTypeOnscreen)
{
// we need to adjust our coordinates to screen coordinates. Hitchcock
// thinks origo is on top-left of screen. VG thinks origo is on
// bottom-left.
// We must take orientation if we access vg matrixes directly..
CHuiDisplay* display = &CHuiStatic::Env().PrimaryDisplay(); // TODO: should use CHuiEnv::CurrentDisplay() ?
if (display->Orientation() == CHuiGc::EOrientationCCW90)
{
// Rotate around origo and move back to displayarea
vgRotate(-90);
vgTranslate(aTargetRect.iTl.iX - aTarget.Size().iHeight , aTarget.Size().iWidth - aTargetRect.iBr.iY);
}
else if (display->Orientation() == CHuiGc::EOrientationCW90)
{
// Rotate around origo and move back to displayarea
vgRotate(90);
vgTranslate(aTargetRect.iTl.iX , - aTargetRect.iBr.iY);
}
else if (display->Orientation() == CHuiGc::EOrientation180)
{
// Rotate around origo and move back to displayarea
vgRotate(180);
vgTranslate(aTarget.Size().iWidth- aTargetRect.iTl.iX , - aTargetRect.iBr.iY);
}
else
{
vgTranslate(aTargetRect.iTl.iX, aTarget.Size().iHeight - aTargetRect.iBr.iY);
}
}
else
{
// offscreen renderbuffer --- we use VG coordinates
vgTranslate(aTargetRect.iTl.iX, aTargetRect.iTl.iY);
}
// slowpath
if(aTargetRect.Size() != aSourceRect.Size())
{
VGfloat scaleX = (VGfloat)aTargetRect.Width() / aSourceRect.Width();
VGfloat scaleY = (VGfloat)aTargetRect.Height() / aSourceRect.Height();
vgScale(scaleX, scaleY);
}
vgDrawImage(image);
// Restore default VG state
vgSeti(VG_SCISSORING, VG_TRUE);
// vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
vgSeti(VG_BLEND_MODE, blendMode);
vgLoadMatrix(oldMatrix);
HUIFX_VG_INVARIANT();
if ( mustRestorePaint )
{
vgSetPaint(userPaint, VG_FILL_PATH);
// if the original handle was invalid, this may produce an error
}
reinterpret_cast<CHuiFxVg10RenderbufferBase*>(&aSource)->ReleaseSubImage(image);
#endif // debug rectangle
aSource.UnbindAsTexture();
aTarget.UnbindAsRenderTarget();
}
void CHuiFxVg10Engine::Composite(CHuiGc& aGc, CHuiFxRenderbuffer& aSource, const TPoint& aTargetPoint,TBool aOpaque, TInt aAlpha)
{
// Directly to screen, overrides onscreen buffer. Always "over" blending mode, constant alpha.
const CHuiFxVg10OffscreenRenderbuffer* vg10RenderBuffer = (const CHuiFxVg10OffscreenRenderbuffer*) &aSource;
CHuiVg10Gc* vg10Gc = (CHuiVg10Gc*)&aGc;
if (vg10RenderBuffer->Image())
{
// For some reason color is weird at this point, so set our own.
TRgb oldPencolor = aGc.PenColor();
TInt oldPenAlpha = aGc.PenAlpha();
aGc.SetPenColor(KRgbWhite);
aGc.SetPenAlpha(aAlpha);
vg10Gc->UpdateColor();
// Push matrix
aGc.Push(EHuiGcMatrixModel);
// Take into account the screen relative position of the buffer
aGc.Translate(EHuiGcMatrixModel, aTargetPoint.iX, aTargetPoint.iY, 0);
// Flip the content (because of hitchcock/openvg coordinate differencies
aGc.Translate(EHuiGcMatrixModel, 0.0f, aSource.Size().iHeight, 0.0f);
aGc.Scale(EHuiGcMatrixModel, 1.0f, -1.0f, 1.0f);
// Do the drawing, handle opaque windows with writealpha, otherwise blend
if (aOpaque)
{
aGc.Disable(CHuiGc::EFeatureBlending);
}
else
{
aGc.Enable(CHuiGc::EFeatureBlending);
}
vgDrawImage(vg10RenderBuffer->Image());
// Restore pen color, matrix
aGc.Enable(CHuiGc::EFeatureBlending);
aGc.SetPenColor(oldPencolor);
aGc.SetPenAlpha(oldPenAlpha);
aGc.Pop(EHuiGcMatrixModel);
}
}