bug 624359 - iterate by clusters for mozTextAlongPath; r=vlad
authorJonathan Kew <jfkthame@gmail.com>
Tue, 22 Mar 2011 10:59:25 -0400
changeset 63634 92bc57f478c1503efe65690f1ab33c7ba3020f20
parent 63633 0c6c92d27f04ed21a5ad64c44cc6057f8a4a5051
child 63635 8f679b9e32eb5fa50610729d2b900c37b765ee6f
push id19248
push usereakhgari@mozilla.com
push dateWed, 23 Mar 2011 23:19:35 +0000
treeherdermozilla-central@ab95ab9e389b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad
bugs624359
milestone2.0b13pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 624359 - iterate by clusters for mozTextAlongPath; r=vlad
content/canvas/src/nsCanvasRenderingContext2D.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -3008,60 +3008,67 @@ nsCanvasRenderingContext2D::MozTextAlong
     PathChar *cp = new PathChar[strLength];
 
     if (!cp) {
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     gfxPoint position(0.0,0.0);
     gfxFloat x = position.x;
-    for (PRUint32 i = 0; i < strLength; i++)
-    {
-        gfxFloat halfAdvance = textRun->GetAdvanceWidth(i, 1, nsnull) / (2.0 * aupdp);
-
-        // Check for end of path
-        if(x + halfAdvance > length)
+
+    gfxTextRun::ClusterIterator iter(textRun.get());
+    while (iter.NextCluster()) {
+        gfxFloat halfAdvance = iter.ClusterAdvance(nsnull) / (2.0 * aupdp);
+        if (x + halfAdvance > length) {
             break;
-
-        if(x + halfAdvance >= 0)
-        {
-            cp[i].draw = PR_TRUE;
-            gfxPoint pt = path->FindPoint(gfxPoint(x + halfAdvance, position.y), &(cp[i].angle));
-
-            cp[i].pos = pt - gfxPoint(cos(cp[i].angle), sin(cp[i].angle)) * halfAdvance;
         }
+
+        if (x + halfAdvance >= 0) {
+            cp[iter.Position()].draw = PR_TRUE;
+            gfxPoint pt = path->FindPoint(gfxPoint(x + halfAdvance, position.y),
+                                          &(cp[iter.Position()].angle));
+            cp[iter.Position()].pos =
+                pt - gfxPoint(cos(cp[iter.Position()].angle),
+                              sin(cp[iter.Position()].angle)) * halfAdvance;
+        }
+
         x += 2 * halfAdvance;
     }
 
     if (stroke) {
         ApplyStyle(STYLE_STROKE);
         mThebes->NewPath();
     } else {
         ApplyStyle(STYLE_FILL);
     }
 
-    for(PRUint32 i = 0; i < strLength; i++)
-    {
+    iter.Reset();
+    while (iter.NextCluster()) {
         // Skip non-visible characters
-        if(!cp[i].draw) continue;
+        if (!cp[iter.Position()].draw) {
+            continue;
+        }
 
         gfxMatrix matrix = mThebes->CurrentMatrix();
 
         gfxMatrix rot;
-        rot.Rotate(cp[i].angle);
+        rot.Rotate(cp[iter.Position()].angle);
         mThebes->Multiply(rot);
 
         rot.Invert();
         rot.Scale(aupdp,aupdp);
-        gfxPoint pt = rot.Transform(cp[i].pos);
-
-        if(stroke) {
-            textRun->DrawToPath(mThebes, pt, i, 1, nsnull, nsnull);
+        gfxPoint pt = rot.Transform(cp[iter.Position()].pos);
+
+        if (stroke) {
+            textRun->DrawToPath(mThebes, pt,
+                                iter.Position(), iter.ClusterLength(),
+                                nsnull, nsnull);
         } else {
-            textRun->Draw(mThebes, pt, i, 1, nsnull, nsnull);
+            textRun->Draw(mThebes, pt, iter.Position(), iter.ClusterLength(),
+                          nsnull, nsnull);
         }
         mThebes->SetMatrix(matrix);
     }
 
     if (stroke)
         mThebes->Stroke();
 
     delete [] cp;
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -4267,16 +4267,69 @@ gfxTextRun::FetchGlyphExtents(gfxContext
                         font->SetupGlyphExtents(aRefContext, glyphIndex, PR_TRUE, extents);
                     }
                 }
             }
         }
     }
 }
 
+
+gfxTextRun::ClusterIterator::ClusterIterator(gfxTextRun *aTextRun)
+    : mTextRun(aTextRun), mCurrentChar(PRUint32(-1))
+{
+}
+
+void
+gfxTextRun::ClusterIterator::Reset()
+{
+    mCurrentChar = PRUint32(-1);
+}
+
+PRBool
+gfxTextRun::ClusterIterator::NextCluster()
+{
+    while (++mCurrentChar < mTextRun->GetLength()) {
+        if (mTextRun->IsClusterStart(mCurrentChar)) {
+            return PR_TRUE;
+        }
+    }
+
+    mCurrentChar = PRUint32(-1);
+    return PR_FALSE;
+}
+
+PRUint32
+gfxTextRun::ClusterIterator::ClusterLength() const
+{
+    if (mCurrentChar == PRUint32(-1)) {
+        return 0;
+    }
+
+    PRUint32 i = mCurrentChar;
+    while (++i < mTextRun->GetLength()) {
+        if (mTextRun->IsClusterStart(i)) {
+            break;
+        }
+    }
+
+    return i - mCurrentChar;
+}
+
+gfxFloat
+gfxTextRun::ClusterIterator::ClusterAdvance(PropertyProvider *aProvider) const
+{
+    if (mCurrentChar == PRUint32(-1)) {
+        return 0;
+    }
+
+    return mTextRun->GetAdvanceWidth(mCurrentChar, ClusterLength(), aProvider);
+}
+
+
 #ifdef DEBUG
 void
 gfxTextRun::Dump(FILE* aOutput) {
     if (!aOutput) {
         aOutput = stdout;
     }
 
     PRUint32 i;
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1460,16 +1460,37 @@ public:
          * inside clusters. In other words, if character i is not
          * CLUSTER_START, then character i-1 must have zero after-spacing and
          * character i must have zero before-spacing.
          */
         virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength,
                                 Spacing *aSpacing) = 0;
     };
 
+    class ClusterIterator {
+    public:
+        ClusterIterator(gfxTextRun *aTextRun);
+
+        void Reset();
+
+        PRBool NextCluster();
+
+        PRUint32 Position() const {
+            return mCurrentChar;
+        }
+
+        PRUint32 ClusterLength() const;
+
+        gfxFloat ClusterAdvance(PropertyProvider *aProvider) const;
+
+    private:
+        gfxTextRun *mTextRun;
+        PRUint32    mCurrentChar;
+    };
+
     /**
      * Draws a substring. Uses only GetSpacing from aBreakProvider.
      * The provided point is the baseline origin on the left of the string
      * for LTR, on the right of the string for RTL.
      * @param aAdvanceWidth if non-null, the advance width of the substring
      * is returned here.
      * 
      * Drawing should respect advance widths in the sense that for LTR runs,