Fix text-as-path with skshader on gpu

Review URL: http://codereview.appspot.com/4576057/



git-svn-id: http://skia.googlecode.com/svn/trunk@1575 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 37c3ee3..bd9eba0 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -26,6 +26,10 @@
 class Iter {
 public:
     Iter() {
+        this->reset();
+    }
+
+    void reset() {
         fReg = GMRegistry::Head();
     }
 
@@ -475,15 +479,22 @@
       return -1;
     }
 
+    int maxW = -1;
+    int maxH = -1;
+    Iter iter;
+    GM* gm;
+    while ((gm = iter.next()) != NULL) {
+        SkISize size = gm->getISize();
+        maxW = SkMax32(size.width(), maxW);
+        maxH = SkMax32(size.height(), maxH);
+    }
     // setup a GL context for drawing offscreen
     GrContext* context = NULL;
     SkEGLContext eglContext;
-    if (eglContext.init(1024, 1024)) {
+    if (eglContext.init(maxW, maxH)) {
         context = GrContext::CreateGLShaderContext();
     }
 
-    Iter iter;
-    GM* gm;
 
     if (readPath) {
         fprintf(stderr, "reading from %s\n", readPath);
@@ -493,6 +504,7 @@
 
     // Accumulate success of all tests so we can flag error in any
     // one with the return value.
+    iter.reset();
     bool overallSuccess = true;
     while ((gm = iter.next()) != NULL) {
         SkISize size = gm->getISize();
diff --git a/gm/shadertext.cpp b/gm/shadertext.cpp
index ea87823..dac75ae 100644
--- a/gm/shadertext.cpp
+++ b/gm/shadertext.cpp
@@ -110,7 +110,7 @@
         return SkString("shadertext");
     }
 
-	SkISize onISize() { return make_isize(950, 500); }
+	SkISize onISize() { return make_isize(1450, 500); }
 
     void drawBG(SkCanvas* canvas) {
         canvas->drawColor(0xFFDDDDDD);
@@ -121,7 +121,7 @@
 
         const char text[] = "Shaded Text";
         const int textLen = SK_ARRAY_COUNT(text) - 1;
-        const int pointSize = 48;
+        const int pointSize = 36;
 
         int w = pointSize * textLen;
         int h = pointSize;
@@ -169,19 +169,32 @@
         canvas->save();
         canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
 
+        SkPath path;
+        path.arcTo(SkRect::MakeXYWH(-40, 15, 300, 90), 
+                   SK_Scalar1 * 225,  SK_Scalar1 * 90, false);
+        path.close();
+
         static const int testsPerCol = 8;
         static const int rowHeight = 60;
         static const int colWidth = 300;
         canvas->save();
         for (size_t s = 0; s < SK_ARRAY_COUNT(shaders); s++) {
             canvas->save();
-            canvas->translate(SkIntToScalar((s / testsPerCol) * colWidth),
-                              SkIntToScalar((s % testsPerCol) * rowHeight));
-                              paint.setShader(shaders[s])->ref();
+            int i = 2*s;
+            canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
+                              SkIntToScalar((i % testsPerCol) * rowHeight));
+            paint.setShader(shaders[s])->unref();
             canvas->drawText(text, textLen, 0, textBase, paint);
             canvas->restore();
+            canvas->save();
+            ++i;
+            canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
+                              SkIntToScalar((i % testsPerCol) * rowHeight));
+            canvas->drawTextOnPath(text, textLen, path, NULL, paint);
+            canvas->restore();
         }
         canvas->restore();
+
     }
 
 private:
diff --git a/gpu/include/GrTextContext.h b/gpu/include/GrTextContext.h
index b7a690e..c4181c6 100644
--- a/gpu/include/GrTextContext.h
+++ b/gpu/include/GrTextContext.h
@@ -51,6 +51,7 @@
     GrTextStrike*   fStrike;
 
     inline void flushGlyphs();
+    void setupDrawTarget();
 
     enum {
         kMinRequestedGlyphs      = 1,
diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp
index 2aacfa2..41e4a85 100644
--- a/gpu/src/GrTextContext.cpp
+++ b/gpu/src/GrTextContext.cpp
@@ -115,6 +115,34 @@
     fOrigViewMatrix = fContext->getMatrix();
     fContext->setMatrix(fExtMatrix);
 
+    /*
+     We need to call preConcatMatrix with our viewmatrix's inverse, for each
+     texture and mask in the paint. However, computing the inverse can be 
+     expensive, and its possible we may not have any textures or masks, so these
+     two loops are written such that we only compute the inverse (once) if we
+     need it. We do this on our copy of the paint rather than directly on the 
+     draw target because we re-provide the paint to the context when we have
+     to flush our glyphs or draw a glyph as a path midstream.
+    */
+    bool invVMComputed = false;
+    GrMatrix invVM;
+    for (int t = 0; t < GrPaint::kMaxTextures; ++t) {
+        if (NULL != fPaint.getTexture(t)) {
+            if (invVMComputed || fOrigViewMatrix.invert(&invVM)) {
+                invVMComputed = true;
+                fPaint.getTextureSampler(t)->preConcatMatrix(invVM);
+            }
+        }
+    }
+    for (int m = 0; m < GrPaint::kMaxMasks; ++m) {
+        if (NULL != fPaint.getMask(m)) {
+            if (invVMComputed || fOrigViewMatrix.invert(&invVM)) {
+                invVMComputed = true;
+                fPaint.getMaskSampler(m)->preConcatMatrix(invVM);
+            }
+        }
+    }
+
     fDrawTarget = fContext->getTextTarget(fPaint);
 
     fVertices = NULL;
@@ -126,11 +154,6 @@
 
     int stageMask = paint.getActiveStageMask();
     if (stageMask) {
-        GrMatrix inverseViewMatrix;
-        if (fOrigViewMatrix.invert(&inverseViewMatrix)) {
-            fDrawTarget->preConcatSamplerMatrices(stageMask, 
-                                                  inverseViewMatrix);
-        }
         for (int i = 0; i < GrPaint::kTotalStages; ++i) {
             if ((1 << i) & stageMask) {
                 fVertexLayout |= 
@@ -139,7 +162,6 @@
             }
         }
     }
-
 }
 
 GrTextContext::~GrTextContext() {
diff --git a/samplecode/SampleShaderText.cpp b/samplecode/SampleShaderText.cpp
index 2748b55..dedf04d 100644
--- a/samplecode/SampleShaderText.cpp
+++ b/samplecode/SampleShaderText.cpp
@@ -118,7 +118,7 @@
     virtual void onDrawContent(SkCanvas* canvas) {
         const char text[] = "Shaded Text";
         const int textLen = SK_ARRAY_COUNT(text) - 1;
-        static int pointSize = 48;
+        static int pointSize = 36;
 
         int w = pointSize * textLen;
         int h = pointSize;
@@ -166,17 +166,29 @@
         canvas->save();
         canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
 
+        SkPath path;
+        path.arcTo(SkRect::MakeXYWH(-40, 15, 300, 90), 
+                   SK_Scalar1 * 225,  SK_Scalar1 * 90, false);
+        path.close();
+
         static const int testsPerCol = 8;
         static const int rowHeight = 60;
         static const int colWidth = 300;
         canvas->save();
         for (size_t s = 0; s < SK_ARRAY_COUNT(shaders); s++) {
             canvas->save();
-            canvas->translate(SkIntToScalar((s / testsPerCol) * colWidth),
-                              SkIntToScalar((s % testsPerCol) * rowHeight));
+            int i = 2*s;
+            canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
+                              SkIntToScalar((i % testsPerCol) * rowHeight));
             paint.setShader(shaders[s])->unref();
             canvas->drawText(text, textLen, 0, textBase, paint);
             canvas->restore();
+            canvas->save();
+            ++i;
+            canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
+                              SkIntToScalar((i % testsPerCol) * rowHeight));
+            canvas->drawTextOnPath(text, textLen, path, NULL, paint);
+            canvas->restore();
         }
         canvas->restore();