Simplify nvpr text

- Drops device-space glyphs in favor of perf/simplicity.

- Removes residual complexities that would flip glyphs vertically for
  compatibility with nvpr glyph loading, which is no longer used.

- Drops hairline support since they required new paths for every draw
  matrix, and could only be supported under certain circumstances.

- Quits checking for color bitmap fonts in canDrawText since the
  normal color emoji fallback will handle them anyway.

BUG=skia:

Review URL: https://codereview.chromium.org/1380973002
diff --git a/src/gpu/GrPathRendering.cpp b/src/gpu/GrPathRendering.cpp
index d98d9d2..0287eb0 100644
--- a/src/gpu/GrPathRendering.cpp
+++ b/src/gpu/GrPathRendering.cpp
@@ -19,9 +19,7 @@
 #ifdef SK_DEBUG
         , fDesc(desc.copy())
 #endif
-    {
-        fFlipMatrix.setScale(1, -1);
-    }
+    {}
 
     virtual ~GlyphGenerator() {
 #ifdef SK_DEBUG
@@ -39,7 +37,6 @@
         fScalerContext->getMetrics(&skGlyph);
 
         fScalerContext->getPath(skGlyph, out);
-        out->transform(fFlipMatrix); // Load glyphs with the inverted y-direction.
     }
 #ifdef SK_DEBUG
     bool isEqualTo(const SkDescriptor& desc) const override {
@@ -48,7 +45,6 @@
 #endif
 private:
     const SkAutoTDelete<SkScalerContext> fScalerContext;
-    SkMatrix fFlipMatrix;
 #ifdef SK_DEBUG
     SkDescriptor* const fDesc;
 #endif
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index fbd32fc..9c0fc2a 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -58,18 +58,8 @@
             return false;
         }
     }
-
-    // No hairlines unless we can map the 1 px width to the object space.
-    if (skPaint.getStyle() == SkPaint::kStroke_Style
-        && skPaint.getStrokeWidth() == 0
-        && viewMatrix.hasPerspective()) {
-        return false;
-    }
-
-    // No color bitmap fonts.
-    SkScalerContext::Rec    rec;
-    SkScalerContext::MakeRec(skPaint, &fSurfaceProps, nullptr, &rec);
-    return rec.getFormat() != SkMask::kARGB32_Format;
+    // No hairlines. They would require new paths with customized strokes for every new draw matrix.
+    return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrokeWidth();
 }
 
 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt,
@@ -87,31 +77,7 @@
         return;
     }
 
-    // This is the slow path, mainly used by Skia unit tests.  The other
-    // backends (8888, gpu, ...) use device-space dependent glyph caches. In
-    // order to match the glyph positions that the other code paths produce, we
-    // must also use device-space dependent glyph cache. This has the
-    // side-effect that the glyph shape outline will be in device-space,
-    // too. This in turn has the side-effect that NVPR can not stroke the paths,
-    // as the stroke in NVPR is defined in object-space.
-    // NOTE: here we have following coincidence that works at the moment:
-    // - When using the device-space glyphs, the transforms we pass to NVPR
-    // instanced drawing are the global transforms, and the view transform is
-    // identity. NVPR can not use non-affine transforms in the instanced
-    // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it
-    // will turn off the use of device-space glyphs when perspective transforms
-    // are in use.
-
-    this->init(rt, clip, paint, skPaint, byteLength, kMaxAccuracy_RenderMode, viewMatrix,
-               regionClipBounds);
-
-    // Transform our starting point.
-    if (fUsingDeviceSpaceGlyphs) {
-        SkPoint loc;
-        fContextInitialMatrix.mapXY(x, y, &loc);
-        x = loc.fX;
-        y = loc.fY;
-    }
+    this->init(rt, clip, paint, skPaint, byteLength, viewMatrix, regionClipBounds);
 
     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
 
@@ -184,16 +150,7 @@
         return;
     }
 
-    // This is the fast path.  Here we do not bake in the device-transform to
-    // the glyph outline or the advances. This is because we do not need to
-    // position the glyphs at all, since the caller has done the positioning.
-    // The positioning is based on SkPaint::measureText of individual
-    // glyphs. That already uses glyph cache without device transforms. Device
-    // transform is not part of SkPaint::measureText API, and thus we use the
-    // same glyphs as what were measured.
-
-    this->init(rt, clip, paint, skPaint, byteLength, kMaxPerformance_RenderMode, viewMatrix,
-               regionClipBounds);
+    this->init(rt, clip, paint, skPaint, byteLength, viewMatrix, regionClipBounds);
 
     SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
 
@@ -251,7 +208,6 @@
                                         const GrPaint& paint,
                                         const SkPaint& skPaint,
                                         size_t textByteLength,
-                                        RenderMode renderMode,
                                         const SkMatrix& viewMatrix,
                                         const SkIRect& regionClipBounds) {
     fClip = clip;
@@ -264,147 +220,69 @@
     fPaint = paint;
     fSkPaint = skPaint;
 
-    fContextInitialMatrix = viewMatrix;
-    fViewMatrix = viewMatrix;
-    fLocalMatrix = SkMatrix::I();
+    // Don't bake strokes into the glyph outlines. We will stroke the glyphs using the GPU instead.
+    fStroke = GrStrokeInfo(fSkPaint);
+    fSkPaint.setStyle(SkPaint::kFill_Style);
 
-    const bool otherBackendsWillDrawAsPaths =
-        SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix);
+    SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported.
 
-    fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths &&
-                              kMaxAccuracy_RenderMode == renderMode &&
-                              SkToBool(fContextInitialMatrix.getType() &
-                                       (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask));
+    if (fSkPaint.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
+        // Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
+        SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
+                                                    kStdFakeBoldInterpKeys,
+                                                    kStdFakeBoldInterpValues,
+                                                    kStdFakeBoldInterpLength);
+        SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
+        fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
+                               true /*strokeAndFill*/);
 
-    if (fUsingDeviceSpaceGlyphs) {
-        // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms.
-        SkASSERT(!fContextInitialMatrix.hasPerspective());
+        fSkPaint.setFakeBoldText(false);
+    }
 
-        // The whole shape (including stroke) will be baked into the glyph outlines. Make
-        // NVPR just fill the baked shapes.
-        fStroke = GrStrokeInfo(SkStrokeRec::kFill_InitStyle);
+    bool canUseRawPaths;
+    if (!fStroke.isDashed()) {
+        // We can draw the glyphs from canonically sized paths.
+        fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
+        fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
 
+        // Compensate for the glyphs being scaled by fTextRatio.
+        if (!fStroke.isFillStyle()) {
+            fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
+                                   SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
+        }
+
+        fSkPaint.setLinearText(true);
+        fSkPaint.setLCDRenderText(false);
+        fSkPaint.setAutohinted(false);
+        fSkPaint.setHinting(SkPaint::kNo_Hinting);
+        fSkPaint.setSubpixelText(true);
+        fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
+
+        canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
+                         0 == fSkPaint.getTextSkewX() &&
+                         !fSkPaint.isFakeBoldText() &&
+                         !fSkPaint.isVerticalText();
+    } else {
         fTextRatio = fTextInverseRatio = 1.0f;
+        canUseRawPaths = false;
+    }
 
-        // Glyphs loaded by GPU path rendering have an inverted y-direction.
-        SkMatrix m;
-        m.setScale(1, -1);
-        fViewMatrix = m;
+    fViewMatrix = viewMatrix;
+    fViewMatrix.preScale(fTextRatio, fTextRatio);
+    fLocalMatrix.setScale(fTextRatio, fTextRatio);
 
-        // Post-flip the initial matrix so we're left with just the flip after
-        // the paint preConcats the inverse.
-        m = fContextInitialMatrix;
-        m.postScale(1, -1);
-        if (!m.invert(&fLocalMatrix)) {
-            SkDebugf("Not invertible!\n");
-            return;
-        }
-
-        fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, &fContextInitialMatrix,
-                                           true /*ignoreGamma*/);
-        fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
+    fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, nullptr, true /*ignoreGamma*/);
+    fGlyphs = canUseRawPaths ?
+                  get_gr_glyphs(fContext, fSkPaint.getTypeface(), nullptr, fStroke) :
+                  get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
                                 &fGlyphCache->getDescriptor(), fStroke);
-    } else {
-        // Don't bake strokes into the glyph outlines. We will stroke the glyphs
-        // using the GPU instead. This is the fast path.
-        fStroke = GrStrokeInfo(fSkPaint);
-        fSkPaint.setStyle(SkPaint::kFill_Style);
-
-        if (fStroke.isHairlineStyle()) {
-            // Approximate hairline stroke.
-            SkScalar strokeWidth = SK_Scalar1 /
-                (SkVector::Make(fContextInitialMatrix.getScaleX(),
-                                fContextInitialMatrix.getSkewY()).length());
-            fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/);
-
-        } else if (fSkPaint.isFakeBoldText() &&
-#ifdef SK_USE_FREETYPE_EMBOLDEN
-                   kMaxPerformance_RenderMode == renderMode &&
-#endif
-                   SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
-
-            // Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
-            SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
-                                                        kStdFakeBoldInterpKeys,
-                                                        kStdFakeBoldInterpValues,
-                                                        kStdFakeBoldInterpLength);
-            SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
-            fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
-                                   true /*strokeAndFill*/);
-
-            fSkPaint.setFakeBoldText(false);
-        }
-
-        bool canUseRawPaths;
-        if (!fStroke.isDashed() && (otherBackendsWillDrawAsPaths ||
-                                    kMaxPerformance_RenderMode == renderMode)) {
-            // We can draw the glyphs from canonically sized paths.
-            fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
-            fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
-
-            // Compensate for the glyphs being scaled by fTextRatio.
-            if (!fStroke.isFillStyle()) {
-                fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
-                                       SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
-            }
-
-            fSkPaint.setLinearText(true);
-            fSkPaint.setLCDRenderText(false);
-            fSkPaint.setAutohinted(false);
-            fSkPaint.setHinting(SkPaint::kNo_Hinting);
-            fSkPaint.setSubpixelText(true);
-            fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
-
-            canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
-                             0 == fSkPaint.getTextSkewX() &&
-                             !fSkPaint.isFakeBoldText() &&
-                             !fSkPaint.isVerticalText();
-        } else {
-            fTextRatio = fTextInverseRatio = 1.0f;
-            canUseRawPaths = false;
-        }
-
-        SkMatrix textMatrix;
-        // Glyphs loaded by GPU path rendering have an inverted y-direction.
-        textMatrix.setScale(fTextRatio, -fTextRatio);
-        fViewMatrix.preConcat(textMatrix);
-        fLocalMatrix = textMatrix;
-
-        fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, nullptr, true /*ignoreGamma*/);
-        fGlyphs = canUseRawPaths ?
-                      get_gr_glyphs(fContext, fSkPaint.getTypeface(), nullptr, fStroke) :
-                      get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
-                                    &fGlyphCache->getDescriptor(), fStroke);
-    }
-
-}
-
-bool GrStencilAndCoverTextContext::mapToFallbackContext(SkMatrix* inverse) {
-    // The current view matrix is flipped because GPU path rendering glyphs have an
-    // inverted y-direction. Unflip the view matrix for the fallback context. If using
-    // device-space glyphs, we'll also need to restore the original view matrix since
-    // we moved that transfomation into our local glyph cache for this scenario. Also
-    // track the inverse operation so the caller can unmap the paint and glyph positions.
-    if (fUsingDeviceSpaceGlyphs) {
-        fViewMatrix = fContextInitialMatrix;
-        if (!fContextInitialMatrix.invert(inverse)) {
-            return false;
-        }
-        inverse->preScale(1, -1);
-    } else {
-        inverse->setScale(1, -1);
-        const SkMatrix& unflip = *inverse; // unflip is equal to its own inverse.
-        fViewMatrix.preConcat(unflip);
-    }
-    return true;
 }
 
 inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) {
     // Stick the glyphs we can't draw into the fallback arrays.
     if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
         fFallbackIndices.push_back(glyph.getGlyphID());
-        fFallbackPositions.push_back().set(fTextInverseRatio * pos.x(),
-                                           -fTextInverseRatio * pos.y());
+        fFallbackPositions.push_back(pos);
     } else {
         // TODO: infer the reserve count from the text length.
         if (!fDraw) {
@@ -412,18 +290,11 @@
                                             GrPathRendering::kTranslate_PathTransformType,
                                             64);
         }
-        float translate[] = { fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y() };
+        float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y() };
         fDraw->append(glyph.getGlyphID(), translate);
     }
 }
 
-static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) {
-    GR_STATIC_ASSERT(2 * sizeof(SkScalar) == sizeof(SkPoint));
-    GR_STATIC_ASSERT(0 == offsetof(SkPoint, fX));
-
-    return &pointArray[0].fX;
-}
-
 void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) {
     if (fDraw) {
         SkASSERT(fDraw->count());
@@ -452,25 +323,27 @@
 
     if (fFallbackIndices.count()) {
         SkASSERT(fFallbackPositions.count() == fFallbackIndices.count());
-        GrPaint paintFallback(fPaint);
 
-        SkPaint skPaintFallback(fSkPaint);
-        if (!fUsingDeviceSpaceGlyphs) {
-            fStroke.applyToPaint(&skPaintFallback);
+        SkPaint fallbackSkPaint(fSkPaint);
+        fStroke.applyToPaint(&fallbackSkPaint);
+        if (!fStroke.isFillStyle()) {
+            fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
         }
-        skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
-        skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        fallbackSkPaint.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
+        fallbackSkPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non-bitmap color
+        // glyphs show up and https://code.google.com/p/skia/issues/detail?id=4408 gets resolved.
+        fallbackSkPaint.setSubpixelText(false);
+        fallbackSkPaint.setTextSize(fSkPaint.getTextSize() * fTextRatio);
 
-        SkMatrix inverse;
-        if (this->mapToFallbackContext(&inverse)) {
-            inverse.mapPoints(fFallbackPositions.begin(), fFallbackPositions.count());
-        }
+        SkMatrix fallbackMatrix(fViewMatrix);
+        fallbackMatrix.preScale(fTextInverseRatio, fTextInverseRatio);
 
-        fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, paintFallback, skPaintFallback,
-                                          fViewMatrix, (char*)fFallbackIndices.begin(),
+        fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, fPaint, fallbackSkPaint,
+                                          fallbackMatrix, (char*)fFallbackIndices.begin(),
                                           sizeof(uint16_t) * fFallbackIndices.count(),
-                                          get_xy_scalar_array(fFallbackPositions.begin()),
-                                          2, SkPoint::Make(0, 0), fRegionClipBounds);
+                                          fFallbackPositions[0].asScalars(), 2, SkPoint::Make(0, 0),
+                                          fRegionClipBounds);
         fFallbackIndices.reset();
         fFallbackPositions.reset();
     }
@@ -488,6 +361,4 @@
 
     SkGlyphCache::AttachCache(fGlyphCache);
     fGlyphCache = nullptr;
-
-    fViewMatrix = fContextInitialMatrix;
 }
diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h
index 4c57d3c..44b33a5 100644
--- a/src/gpu/GrStencilAndCoverTextContext.h
+++ b/src/gpu/GrStencilAndCoverTextContext.h
@@ -30,27 +30,6 @@
     virtual ~GrStencilAndCoverTextContext();
 
 private:
-    enum RenderMode {
-        /**
-         * This is the render mode used by drawText(), which is mainly used by
-         * the Skia unit tests. It tries match the other text backends exactly,
-         * with the exception of not implementing LCD text, and doing anti-
-         * aliasing with the built-in MSAA.
-         */
-        kMaxAccuracy_RenderMode,
-
-        /**
-         * This is the render mode used by drawPosText(). It ignores hinting and
-         * LCD text, even if the client provided positions for hinted glyphs,
-         * and renders from a canonically-sized, generic set of paths for the
-         * given typeface. In the future we should work out a system for the
-         * client to know it should not provide hinted glyph positions. This
-         * render mode also tries to use GPU stroking for fake bold, even when
-         * SK_USE_FREETYPE_EMBOLDEN is set.
-         */
-        kMaxPerformance_RenderMode,
-    };
-
     SkScalar                                            fTextRatio;
     float                                               fTextInverseRatio;
     SkGlyphCache*                                       fGlyphCache;
@@ -61,10 +40,8 @@
     SkSTArray<32, uint16_t, true>                       fFallbackIndices;
     SkSTArray<32, SkPoint, true>                        fFallbackPositions;
 
-    SkMatrix                                            fContextInitialMatrix;
     SkMatrix                                            fViewMatrix;
     SkMatrix                                            fLocalMatrix;
-    bool                                                fUsingDeviceSpaceGlyphs;
     SkAutoTUnref<GrRenderTarget>                        fRenderTarget;
     GrClip                                              fClip;
     SkIRect                                             fClipRect;
@@ -88,10 +65,8 @@
                        const SkScalar pos[], int scalarsPerPosition,
                        const SkPoint& offset, const SkIRect& regionClipBounds) override;
 
-    void init(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
-              size_t textByteLength, RenderMode, const SkMatrix& viewMatrix,
-              const SkIRect& regionClipBounds);
-    bool mapToFallbackContext(SkMatrix* inverse);
+    void init(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, size_t textByteLength,
+              const SkMatrix& viewMatrix, const SkIRect& regionClipBounds);
     void appendGlyph(const SkGlyph&, const SkPoint&);
     void flush(GrDrawContext* dc);
     void finish(GrDrawContext* dc);