uiacceltk/hitchcock/coretoolkit/rendervg10/src/HuiVg10CurvePath.cpp
changeset 0 15bf7259bb7c
--- /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();
+        }
+    }