Fix scaling issue with distance field text.

Picks the correct distance field size based on both the text size and
the max matrix scale. Adjusts the matrix scale if non-unity. Also adds
GM for verifying proper distance field scaling.

BUG=skia:2928
R=bsalomon@google.com, joshualitt@google.com

Author: jvanverth@google.com

Review URL: https://codereview.chromium.org/568843002
diff --git a/gm/dftext.cpp b/gm/dftext.cpp
new file mode 100755
index 0000000..65e64a9
--- /dev/null
+++ b/gm/dftext.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkSurface.h"
+#include "SkTypeface.h"
+
+namespace skiagm {
+
+class DFTextGM : public GM {
+public:
+    DFTextGM() {
+        this->setBGColor(0xFFFFFFFF);
+    }
+
+    virtual ~DFTextGM() {
+    }
+
+protected:
+    virtual uint32_t onGetFlags() const SK_OVERRIDE {
+        return kGPUOnly_Flag;
+    }
+
+    virtual SkString onShortName() {
+        return SkString("dftext");
+    }
+
+    virtual SkISize onISize() {
+        return SkISize::Make(1024, 768);
+    }
+
+    static void rotate_about(SkCanvas* canvas,
+        SkScalar degrees,
+        SkScalar px, SkScalar py) {
+        canvas->translate(px, py);
+        canvas->rotate(degrees);
+        canvas->translate(-px, -py);
+    }
+
+    virtual void onDraw(SkCanvas* inputCanvas) {
+        SkScalar textSizes[] = { 11.0f, 11.0f*2.0f, 11.0f*5.0f, 11.0f*2.0f*5.0f };
+        SkScalar scales[] = { 2.0f*5.0f, 5.0f, 2.0f, 1.0f };
+
+        // set up offscreen rendering with distance field text
+#if SK_SUPPORT_GPU
+        GrContext* ctx = inputCanvas->getGrContext();
+        SkImageInfo info = SkImageInfo::MakeN32Premul(onISize());
+        SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, info, 0,
+                                                        SkSurface::kDistanceField_TextRenderMode));
+        SkCanvas* canvas = surface->getCanvas();
+#else
+        SkCanvas* canvas = inputCanvas;
+#endif
+        canvas->clear(0xffffffff);
+
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setSubpixelText(true);
+#if !SK_SUPPORT_GPU
+        paint.setDistanceFieldTextTEMP(true);
+#endif
+        sk_tool_utils::set_portable_typeface(&paint, "Times New Roman", SkTypeface::kNormal);
+
+        const char* text = "Hamburgefons";
+        const size_t textLen = strlen(text);
+
+        // check scaling up
+        SkScalar x = SkIntToScalar(0);
+        SkScalar y = SkIntToScalar(78);
+        for (size_t i = 0; i < SK_ARRAY_COUNT(textSizes); ++i) {
+            SkAutoCanvasRestore acr(canvas, true);
+            canvas->translate(x, y);
+            canvas->scale(scales[i], scales[i]);
+            paint.setTextSize(textSizes[i]);
+            canvas->drawText(text, textLen, 0, 0, paint);
+            y += paint.getFontMetrics(NULL)*scales[i];
+        }
+
+        // check rotation
+        for (size_t i = 0; i < 5; ++i) {
+            SkScalar rotX = SkIntToScalar(10);
+            SkScalar rotY = y;
+
+            SkAutoCanvasRestore acr(canvas, true);
+            canvas->translate(SkIntToScalar(10 + i * 200), -80);
+            rotate_about(canvas, SkIntToScalar(i * 5), rotX, rotY);
+            for (int ps = 6; ps <= 32; ps += 3) {
+                paint.setTextSize(SkIntToScalar(ps));
+                canvas->drawText(text, textLen, rotX, rotY, paint);
+                rotY += paint.getFontMetrics(NULL);
+            }
+        }
+
+        // check scaling down
+        paint.setLCDRenderText(true);
+        x = SkIntToScalar(700);
+        y = SkIntToScalar(20);
+        size_t arraySize = SK_ARRAY_COUNT(textSizes);
+        for (size_t i = 0; i < arraySize; ++i) {
+            SkAutoCanvasRestore acr(canvas, true);
+            canvas->translate(x, y);
+            SkScalar scaleFactor = SkScalarInvert(scales[arraySize - i - 1]);
+            canvas->scale(scaleFactor, scaleFactor);
+            paint.setTextSize(textSizes[i]);
+            canvas->drawText(text, textLen, 0, 0, paint);
+            y += paint.getFontMetrics(NULL)*scaleFactor;
+        }
+
+        // check gamma-corrected blending
+        const SkColor fg[] = {
+            0xFFFFFFFF,
+            0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF,
+            0xFFFF0000, 0xFF00FF00, 0xFF0000FF,
+            0xFF000000,
+        };
+
+        paint.setColor(0xFFF1F1F1);
+        SkRect r = SkRect::MakeLTRB(690, 250, 840, 460);
+        canvas->drawRect(r, paint);
+
+        x = SkIntToScalar(700);
+        y = SkIntToScalar(270);
+        paint.setTextSize(SkIntToScalar(22));
+        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
+            paint.setColor(fg[i]);
+
+            canvas->drawText(text, textLen, x, y, paint);
+            y += paint.getFontMetrics(NULL);
+        }
+
+        paint.setColor(0xFF1F1F1F);
+        r = SkRect::MakeLTRB(840, 250, 990, 460);
+        canvas->drawRect(r, paint);
+
+        x = SkIntToScalar(850);
+        y = SkIntToScalar(270);
+        paint.setTextSize(SkIntToScalar(22));
+        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
+            paint.setColor(fg[i]);
+
+            canvas->drawText(text, textLen, x, y, paint);
+            y += paint.getFontMetrics(NULL);
+        }
+
+#if SK_SUPPORT_GPU
+        // render offscreen buffer
+        SkImage* image = surface->newImageSnapshot();
+        image->draw(inputCanvas, 0, 0, NULL);
+        image->unref();
+#endif
+    }
+
+private:
+    typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new DFTextGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/fontscaler.cpp b/gm/fontscaler.cpp
index 8aef8f0..eb38013 100644
--- a/gm/fontscaler.cpp
+++ b/gm/fontscaler.cpp
@@ -72,12 +72,10 @@
                     canvas->drawRect(r, p);
                 }
 
-                int index = 0;
                 for (int ps = 6; ps <= 22; ps++) {
                     paint.setTextSize(SkIntToScalar(ps));
                     canvas->drawText(text, textLen, x, y, paint);
                     y += paint.getFontMetrics(NULL);
-                    index += 1;
                 }
             }
             canvas->translate(0, SkIntToScalar(360));
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index f3d7b80..1ee94db 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -63,6 +63,7 @@
         '../gm/dashing.cpp',
         '../gm/deviceproperties.cpp',
         '../gm/distantclip.cpp',
+        '../gm/dftext.cpp',
         '../gm/displacement.cpp',
         '../gm/downsamplebitmap.cpp',
         '../gm/drawbitmaprect.cpp',
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index d32dcb9..18058be 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -127,9 +127,9 @@
     
     // set up any flags
     uint32_t flags = 0;
-    flags |= fContext->getMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
+    flags |= fTextMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
     flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
-    flags |= fUseLCDText && fContext->getMatrix().rectStaysRect() ?
+    flags |= fUseLCDText && fTextMatrix.rectStaysRect() ?
     kRectToRect_DistanceFieldEffectFlag : 0;
     bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
     fDeviceProperties.fGeometry.getLayout();
@@ -176,7 +176,8 @@
 
     GrDrawState* drawState = fDrawTarget->drawState();
     GrDrawState::AutoRestoreEffects are(drawState);
-    drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
+
+    drawState->setFromPaint(fPaint, fTextMatrix, fContext->getRenderTarget());
 
     if (fCurrVertex > 0) {
         // setup our sampler state for our text texture/atlas
@@ -443,18 +444,32 @@
 
     fStrike = NULL;
 
+    fTextMatrix = fContext->getMatrix();
+
+    // getMaxScale doesn't support perspective, so neither do we at the moment
+    SkASSERT(!fTextMatrix.hasPerspective());
+    SkScalar maxScale = fTextMatrix.getMaxScale();
+    SkScalar textSize = fSkPaint.getTextSize();
+    // if we have non-unity scale, we need to adjust our text size accordingly
+    // to avoid aliasing, and prescale the matrix by the inverse to end up with the same size
+    // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
+    if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
+        textSize *= maxScale;
+        fTextMatrix.preScale(SK_Scalar1 / maxScale, SK_Scalar1 / maxScale);
+    }
+
     fCurrVertex = 0;
 
     fVertices = NULL;
 
-    if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
-        fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
+    if (textSize <= kSmallDFFontLimit) {
+        fTextRatio = textSize / kSmallDFFontSize;
         fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
-    } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
-        fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
+    } else if (textSize <= kMediumDFFontLimit) {
+        fTextRatio = textSize / kMediumDFFontSize;
         fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
     } else {
-        fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
+        fTextRatio = textSize / kLargeDFFontSize;
         fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
     }
 
diff --git a/src/gpu/GrDistanceFieldTextContext.h b/src/gpu/GrDistanceFieldTextContext.h
index 75a13b3..15ff6d9 100644
--- a/src/gpu/GrDistanceFieldTextContext.h
+++ b/src/gpu/GrDistanceFieldTextContext.h
@@ -31,6 +31,7 @@
 
 private:
     GrTextStrike*           fStrike;
+    SkMatrix                fTextMatrix;
     SkScalar                fTextRatio;
     bool                    fUseLCDText;
     bool                    fEnableDFRendering;
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index ee7dd61..b689c8f 100755
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -34,7 +34,11 @@
     GrGLDistanceFieldTextureEffect(const GrBackendEffectFactory& factory,
                                    const GrDrawEffect& drawEffect)
         : INHERITED (factory)
-        , fTextureSize(SkISize::Make(-1,-1)) {}
+        , fTextureSize(SkISize::Make(-1,-1))
+#ifdef SK_GAMMA_APPLY_TO_A8
+        , fLuminance(-1.0f)
+#endif
+        {}
 
     virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
@@ -262,7 +266,8 @@
     GrGLDistanceFieldLCDTextureEffect(const GrBackendEffectFactory& factory,
                                       const GrDrawEffect& drawEffect)
     : INHERITED (factory)
-    , fTextureSize(SkISize::Make(-1,-1)) {}
+    , fTextureSize(SkISize::Make(-1,-1))
+    , fTextColor(GrColor_ILLEGAL) {}
 
     virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,