--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uiacceltk/hitchcock/coretoolkit/rendervg10/src/HuiVg10CurvePath.cpp Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,398 @@
+/*
+* 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: ?Description
+*
+* Note that we do not use OpenVG's line/arc rendering directly, since the
+* curves we are dealing with may have variable widths, which is not supported
+* by OpenVG yet. Also, only one opacity factor per path is supported.
+*
+*/
+
+#include "HuiVg10CurvePath.h"
+#include "HuiVg10Gc.h"
+#include "uiacceltk/HuiRealPoint.h"
+#include "uiacceltk/HuiUtil.h"
+
+CHuiVg10CurvePath::CHuiVg10CurvePath()
+ : CHuiCurvePath()
+ {
+ }
+
+
+void CHuiVg10CurvePath::ConstructL()
+ {
+ iPathCommands = 0;
+ iLastOpacityFactor = -1.0;
+ iMaxTupleCount = 0;
+ iUsedTupleCount = 0;
+ iPathCoords = 0;
+
+ iPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0f, 0.0f, 32, 32, VG_PATH_CAPABILITY_APPEND_TO);
+ HUI_VG_INVARIANT();
+ }
+
+
+CHuiVg10CurvePath::~CHuiVg10CurvePath()
+ {
+ Reset();
+ vgDestroyPath(iPath);
+ iPath = 0;
+ HUI_VG_INVARIANT();
+ }
+
+
+void CHuiVg10CurvePath::Reset()
+ {
+ CHuiCurvePath::Reset();
+ ResetPath();
+ }
+
+void CHuiVg10CurvePath::ResetPath()
+ {
+ ResetTuples();
+ vgClearPath(iPath, VG_PATH_CAPABILITY_APPEND_TO);
+ HUI_VG_INVARIANT();
+ }
+
+void CHuiVg10CurvePath::ResetTuples()
+ {
+ delete[] iPathCoords;
+ delete[] iPathCommands;
+ iPathCoords = 0;
+ iPathCommands = 0;
+ iMaxTupleCount = 0;
+ iUsedTupleCount = 0;
+ }
+
+TInt CHuiVg10CurvePath::SegmentTuples(const TSegment& aSegment) const
+ {
+ if(aSegment.iType == ESegmentTypeLine)
+ {
+ return 2;
+ }
+ else if(aSegment.iType == ESegmentTypeArc)
+ {
+ const TReal32 KAnglePerSegment = 5;
+ TInt tuples = Abs(aSegment.iAngleDelta) / KAnglePerSegment + 1;
+ if(tuples < 2)
+ {
+ tuples = 2;
+ }
+ return tuples;
+ }
+ ASSERT(0);
+ return 0;
+ }
+
+void CHuiVg10CurvePath::Update(TReal32 aStartPos, TReal32 aEndPos,
+ TReal32 aAlphaFactor,
+ MHuiMappingFunction* aAlphaFunction,
+ MHuiMappingFunction* aWidthFunction) __SOFTFP
+ {
+ const TReal32 KEpsilon = .001;
+ if(!GetVisual() && !NeedUpdate() && Abs(iLastOpacityFactor - aAlphaFactor) < KEpsilon)
+ {
+ // No need to update every time the path is drawn.
+ return;
+ }
+
+ iLastOpacityFactor = aAlphaFactor;
+
+ // Allocate enough memory for the path coordinates and commands. This is
+ // the maximum number of path nodes that can be. If aStartPos and aEndPos are
+ // somewhere in the middle, a smaller amount of data is generated.
+ TInt tuples = 0;
+ TInt i = 0;
+ for(i = 0; i < SegmentCount(); ++i)
+ {
+ tuples += SegmentTuples(Segment(i)) - 1;
+ }
+
+ // One extra tuple for the end.
+ tuples++;
+
+ TRAPD(err, SetTupleCountL(tuples));
+ if(err != KErrNone)
+ {
+ ResetPath();
+ return;
+ }
+
+ // Generate commands for the entire path, starting from aStartPos
+ // and stopping at aEndPos.
+ TReal32 pos = 0;
+ iUsedTupleCount = 0;
+
+ for(i = 0; i < SegmentCount(); ++i)
+ {
+ const TSegment& segment = Segment(i);
+ TReal32 segmentEnd = pos + segment.iLength;
+
+ if(aStartPos > segmentEnd)
+ {
+ // The start is past the end of the segment.
+ continue;
+ }
+ if(aEndPos < pos)
+ {
+ // We're past the end!
+ break;
+ }
+
+ TReal32 start = pos;
+ TReal32 end = segmentEnd;
+ TBool isFinal = EFalse;
+
+ if(start < aStartPos)
+ {
+ start = aStartPos;
+ }
+ if(end >= aEndPos || i == SegmentCount() - 1)
+ {
+ end = aEndPos;
+ isFinal = ETrue;
+ }
+ else
+ {
+ isFinal = EFalse;
+ }
+
+ // Normalize.
+ start -= pos;
+ end -= pos;
+
+ MakeSegmentTuples(segment, start, end, isFinal, aAlphaFactor,
+ aAlphaFunction, aWidthFunction);
+
+ pos += segment.iLength;
+ }
+ ASSERT(iUsedTupleCount <= iMaxTupleCount);
+ ASSERT(iUsedTupleCount > 0);
+
+ // First traverse the curve from start to end
+ vgAppendPathData(iPath, iUsedTupleCount, iPathCommands, iPathCoords);
+ HUI_VG_INVARIANT();
+
+ // And then back again on the other side
+ TInt tailIndex = 2 * iMaxTupleCount - iUsedTupleCount;
+ vgAppendPathData(iPath, iUsedTupleCount, &iPathCommands[tailIndex], &iPathCoords[2 * tailIndex]);
+ HUI_VG_INVARIANT();
+
+ // We do not need the tuple arrays anymore so we can free them
+ ResetTuples();
+
+ CHuiCurvePath::Update(aStartPos, aEndPos, aAlphaFactor,
+ aAlphaFunction, aWidthFunction);
+ }
+
+void CHuiVg10CurvePath::SetTupleCountL(TInt aTupleCount)
+ {
+ if(iMaxTupleCount != aTupleCount)
+ {
+ ResetPath();
+
+ // Allocate new arrays.
+ iMaxTupleCount = aTupleCount;
+
+ if(iMaxTupleCount > 0)
+ {
+ iPathCoords = new (ELeave) VGfloat[2 * iMaxTupleCount * 2];
+ iPathCommands = new (ELeave) VGubyte[iMaxTupleCount * 2];
+
+ // Since every path command is the same, we can do this at
+ // allocation time
+ for (TInt i = 0; i < iMaxTupleCount * 2; i++)
+ {
+ iPathCommands[i] = VG_LINE_TO;
+ }
+ }
+ }
+ }
+
+void CHuiVg10CurvePath::MakeSegmentTuples(const TSegment& aSegment,
+ TReal32 aStart, TReal32 aEnd,
+ TBool aIsFinal,
+ TReal32 aAlphaFactor,
+ MHuiMappingFunction* aAlphaFunction,
+ MHuiMappingFunction* aWidthFunction)
+ {
+ // aStart and aEnd are in range [0,length].
+ THuiRealPoint point;
+ THuiRealPoint normal;
+ TReal32 normStart = (aStart + aSegment.iTotalPos) / Length();
+ TReal32 normEnd = (aEnd + aSegment.iTotalPos) / Length();
+
+ if(aSegment.iType == ESegmentTypeLine)
+ {
+ EvaluateSegment(aStart, aSegment, point, &normal);
+ TReal32 width = 1;
+ if(aWidthFunction)
+ {
+ width = aWidthFunction->MapValue(normStart, 0);
+ }
+ TReal32 alpha = 1;
+ if(aAlphaFunction)
+ {
+ alpha = aAlphaFunction->MapValue(normStart, 0);
+ }
+ AddTuple(point, normal, width, alpha * aAlphaFactor);
+
+ if(aIsFinal)
+ {
+ // Does not reach the end, so we must also make an end tuple.
+ EvaluateSegment(aEnd, aSegment, point, &normal);
+ if(aWidthFunction)
+ {
+ width = aWidthFunction->MapValue(normEnd, 0);
+ }
+ else
+ {
+ width = 1;
+ }
+ if(aAlphaFunction)
+ {
+ alpha = aAlphaFunction->MapValue(normEnd, 0);
+ }
+ else
+ {
+ alpha = 1;
+ }
+ AddTuple(point, normal, width, alpha * aAlphaFactor);
+ }
+ }
+
+ if(aSegment.iType == ESegmentTypeArc)
+ {
+ // Make a set of tuples.
+ TInt count = SegmentTuples(aSegment);
+ TInt endCount = count;
+ if(aIsFinal)
+ {
+ endCount = count - 1;
+ }
+ else
+ {
+ count--;
+ endCount--;
+ }
+
+ for(TInt i = 0; i < count; ++i)
+ {
+ TReal32 off = i / TReal32(endCount);
+ EvaluateSegment(aStart + (aEnd - aStart) * off, aSegment, point,
+ &normal);
+ TReal32 width = 1;
+ if(aWidthFunction)
+ {
+ width = aWidthFunction->MapValue(normStart +
+ (normEnd - normStart) * off, 0);
+ }
+ TReal32 alpha = 1;
+ if(aAlphaFunction)
+ {
+ alpha = aAlphaFunction->MapValue(normStart +
+ (normEnd - normStart) * off, 0);
+ }
+ AddTuple(point, normal, width, alpha * aAlphaFactor);
+ }
+ }
+ }
+
+void CHuiVg10CurvePath::AddTuple(const THuiRealPoint& aPoint,
+ const THuiRealPoint& aNormal,
+ TReal32 aWidth, TReal32 /*aAlpha*/)
+ {
+ ASSERT(iUsedTupleCount < iMaxTupleCount);
+
+ // Make a pair of vertices. Normal is to the left.
+ //
+ // The first half of the path goes from the beginning of the curve
+ // to the end, while the second half traverses the same route
+ // backwards:
+ //
+ // 0 iUsedTupleCount
+ // >--->--->---> ... >---v
+ // | |
+ // ^---<---<---< ... <---<
+ // iMaxTupleCount - iMaxtupleCount
+ // iUsedTupleCount
+ //
+ // The coordinate array looks like this:
+ //
+ // +---+---+---+---+---+---+---+---+ N: tuple N left vertex
+ // | 0 | 1 | 2 | X | X | 2'| 1'| 0'| N': tuple N right vertex
+ // +---+---+---+---+---+---+---+---+ X: unused
+ //
+ VGfloat* vertex1 = &iPathCoords[2 * iUsedTupleCount];
+ VGfloat* vertex2 = &iPathCoords[2 * (2 * iMaxTupleCount - iUsedTupleCount - 1)];
+ const CHuiVisual* visual = GetVisual();
+
+ if (visual)
+ {
+ THuiRealPoint point1(aPoint.iX + aNormal.iX * aWidth/2,aPoint.iY + aNormal.iY * aWidth/2);
+ THuiRealPoint point2(aPoint.iX - aNormal.iX * aWidth/2,aPoint.iY - aNormal.iY * aWidth/2);
+ point1 = visual->LocalPointInPixels(point1);
+ point2 = visual->LocalPointInPixels(point2);
+ vertex1[0] = point1.iX;
+ vertex1[1] = point1.iY;
+ vertex2[0] = point2.iX;
+ vertex2[1] = point2.iY;
+ }
+ else
+ {
+ vertex1[0] = aPoint.iX + aNormal.iX * aWidth/2;
+ vertex1[1] = aPoint.iY + aNormal.iY * aWidth/2;
+ vertex2[0] = aPoint.iX - aNormal.iX * aWidth/2;
+ vertex2[1] = aPoint.iY - aNormal.iY * aWidth/2;
+ }
+
+ iUsedTupleCount++;
+ }
+
+void CHuiVg10CurvePath::Draw(const TPoint& aOrigin, CHuiGc* aGc) const
+ {
+ CHuiVg10Gc* gc = static_cast<CHuiVg10Gc*>(aGc);
+ ASSERT(gc);
+ gc->UpdateColor();
+
+ VGPaint paint = vgGetPaint(VG_FILL_PATH);
+ VGfloat color[4], modifiedColor[4];
+
+ if (paint != VG_INVALID_HANDLE)
+ {
+ vgGetParameterfv(paint, VG_PAINT_COLOR, 4, color);
+ modifiedColor[0] = color[0];
+ modifiedColor[1] = color[1];
+ modifiedColor[2] = color[2];
+ modifiedColor[3] = iLastOpacityFactor;
+ vgSetParameterfv(paint, VG_PAINT_COLOR, 4, modifiedColor);
+ HUI_VG_INVARIANT();
+ }
+
+ gc->UpdateMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgTranslate(aOrigin.iX, aOrigin.iY);
+ vgDrawPath(iPath, VG_FILL_PATH);
+ vgTranslate(-aOrigin.iX, -aOrigin.iY);
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+
+ HUI_VG_INVARIANT();
+
+ if (paint != VG_INVALID_HANDLE)
+ {
+ vgSetParameterfv(paint, VG_PAINT_COLOR, 4, color);
+ HUI_VG_INVARIANT();
+ }
+ }