Add proper aliased support for SDF text

Previously, when asked to render aliased text with distance fields,
we would get the aliased glyph from the cache and then try to
anti-alias the edge. This change instead grabs the anti-aliased glyph,
then deliberately aliases the edge.

Bug: chromium:707979
Change-Id: I05766af17d7ae58bca27aaffd9e08e5c586e789c
Reviewed-on: https://skia-review.googlesource.com/21728
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index f0f4ec4..c8dd4eb 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -77,6 +77,8 @@
         bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
         bool isGammaCorrect =
             SkToBool(dfTexEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag);
+        bool isAliased =
+            SkToBool(dfTexEffect.getFlags() & kAliased_DistanceFieldEffectFlag);
         varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
         vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName);
 
@@ -158,10 +160,12 @@
             fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
         }
 
-        // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
-        // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance
-        // mapped linearly to coverage, so use a linear step:
-        if (isGammaCorrect) {
+        if (isAliased) {
+            fragBuilder->codeAppend("float val = distance > 0 ? 1.0 : 0.0;");
+        } else if (isGammaCorrect) {
+            // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
+            // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want
+            // distance mapped linearly to coverage, so use a linear step:
             fragBuilder->codeAppend(
                 "float val = clamp((distance + afwidth) / (2.0 * afwidth), 0.0, 1.0);");
         } else {
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h
index 3f616e9..344ac4a 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.h
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.h
@@ -23,6 +23,7 @@
     kBGR_DistanceFieldEffectFlag          = 0x08, // lcd display has bgr order
     kPortrait_DistanceFieldEffectFlag     = 0x10, // lcd display is in portrait mode (not used yet)
     kGammaCorrect_DistanceFieldEffectFlag = 0x20, // assume gamma-correct output (linear blending)
+    kAliased_DistanceFieldEffectFlag      = 0x40, // monochrome output
 
     kInvalid_DistanceFieldEffectFlag    = 0x80,   // invalid state (for initialization)
 
@@ -31,7 +32,8 @@
     // The subset of the flags relevant to GrDistanceFieldA8TextGeoProc
     kNonLCD_DistanceFieldEffectMask       = kSimilarity_DistanceFieldEffectFlag |
                                             kScaleOnly_DistanceFieldEffectFlag |
-                                            kGammaCorrect_DistanceFieldEffectFlag,
+                                            kGammaCorrect_DistanceFieldEffectFlag |
+                                            kAliased_DistanceFieldEffectFlag,
     // The subset of the flags relevant to GrDistanceFieldLCDTextGeoProc
     kLCD_DistanceFieldEffectMask          = kSimilarity_DistanceFieldEffectFlag |
                                             kScaleOnly_DistanceFieldEffectFlag |
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 20a5b4f..9c4172c 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -47,12 +47,14 @@
         color->setToConstant(fColor);
     }
     switch (fMaskType) {
-        case kGrayscaleDistanceField_MaskType:
         case kGrayscaleCoverageMask_MaskType:
+        case kAliasedDistanceField_MaskType:
+        case kGrayscaleDistanceField_MaskType:
             *coverage = GrProcessorAnalysisCoverage::kSingleChannel;
             break;
         case kLCDCoverageMask_MaskType:
         case kLCDDistanceField_MaskType:
+        case kLCDBGRDistanceField_MaskType:
             *coverage = GrProcessorAnalysisCoverage::kLCD;
             break;
         case kColorBitmapMask_MaskType:
@@ -174,10 +176,6 @@
         if (fLuminanceColor != that->fLuminanceColor) {
             return false;
         }
-
-        if (fUseBGR != that->fUseBGR) {
-            return false;
-        }
     }
 
     fNumGlyphs += that->numGlyphs();
@@ -221,11 +219,12 @@
     uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
     flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
     flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
+    flags |= (kAliasedDistanceField_MaskType == fMaskType) ? kAliased_DistanceFieldEffectFlag : 0;
 
     // see if we need to create a new effect
     if (isLCD) {
         flags |= kUseLCD_DistanceFieldEffectFlag;
-        flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
+        flags |= (kLCDBGRDistanceField_MaskType == fMaskType) ? kBGR_DistanceFieldEffectFlag : 0;
 
         float redCorrection = fDistanceAdjustTable->getAdjustment(
                 SkColorGetR(luminanceColor) >> kDistanceAdjustLumShift,
@@ -245,9 +244,12 @@
                                                    this->usesLocalCoords());
     } else {
 #ifdef SK_GAMMA_APPLY_TO_A8
-        U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, luminanceColor);
-        float correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
-                                                               fUseGammaCorrectDistanceTable);
+        float correction = 0;
+        if (kAliasedDistanceField_MaskType != fMaskType) {
+            U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, luminanceColor);
+            correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
+                                                             fUseGammaCorrectDistanceTable);
+        }
         return GrDistanceFieldA8TextGeoProc::Make(color,
                                                   viewMatrix, std::move(proxy),
                                                   params, correction, flags,
diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h
index fcb3db1..24166a1 100644
--- a/src/gpu/ops/GrAtlasTextOp.h
+++ b/src/gpu/ops/GrAtlasTextOp.h
@@ -57,22 +57,24 @@
         op->fGeoCount = 1;
         op->fLuminanceColor = 0;
         op->fFontCache = fontCache;
-        op->fUseBGR = false;
         return op;
     }
 
     static std::unique_ptr<GrAtlasTextOp> MakeDistanceField(
             int glyphCount, GrAtlasGlyphCache* fontCache,
             const GrDistanceFieldAdjustTable* distanceAdjustTable,
-            bool useGammaCorrectDistanceTable, SkColor luminanceColor, bool isLCD, bool useBGR) {
+            bool useGammaCorrectDistanceTable, SkColor luminanceColor, bool isLCD, bool useBGR,
+            bool isAntiAliased) {
         std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp);
 
         op->fFontCache = fontCache;
-        op->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType;
+        op->fMaskType = !isAntiAliased ? kAliasedDistanceField_MaskType
+                                       : isLCD ? (useBGR ? kLCDBGRDistanceField_MaskType
+                                                         : kLCDDistanceField_MaskType)
+                                               : kGrayscaleDistanceField_MaskType;
         op->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable));
         op->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable;
         op->fLuminanceColor = luminanceColor;
-        op->fUseBGR = useBGR;
         op->fNumGlyphs = glyphCount;
         op->fGeoCount = 1;
         return op;
@@ -122,20 +124,26 @@
             case kColorBitmapMask_MaskType:
                 return kARGB_GrMaskFormat;
             case kGrayscaleCoverageMask_MaskType:
+            case kAliasedDistanceField_MaskType:
             case kGrayscaleDistanceField_MaskType:
             case kLCDDistanceField_MaskType:
+            case kLCDBGRDistanceField_MaskType:
                 return kA8_GrMaskFormat;
         }
         return kA8_GrMaskFormat;  // suppress warning
     }
 
     bool usesDistanceFields() const {
-        return kGrayscaleDistanceField_MaskType == fMaskType ||
-               kLCDDistanceField_MaskType == fMaskType;
+        return kAliasedDistanceField_MaskType == fMaskType ||
+               kGrayscaleDistanceField_MaskType == fMaskType ||
+               kLCDDistanceField_MaskType == fMaskType ||
+               kLCDBGRDistanceField_MaskType == fMaskType;
     }
 
     bool isLCD() const {
-        return kLCDCoverageMask_MaskType == fMaskType || kLCDDistanceField_MaskType == fMaskType;
+        return kLCDCoverageMask_MaskType == fMaskType ||
+               kLCDDistanceField_MaskType == fMaskType ||
+               kLCDBGRDistanceField_MaskType == fMaskType;
     }
 
     inline void flush(GrLegacyMeshDrawOp::Target* target, FlushInfo* flushInfo) const;
@@ -164,10 +172,11 @@
         kGrayscaleCoverageMask_MaskType,
         kLCDCoverageMask_MaskType,
         kColorBitmapMask_MaskType,
+        kAliasedDistanceField_MaskType,
         kGrayscaleDistanceField_MaskType,
         kLCDDistanceField_MaskType,
+        kLCDBGRDistanceField_MaskType,
     } fMaskType;
-    bool fUseBGR;  // fold this into the enum?
 
     GrAtlasGlyphCache* fFontCache;
 
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index a68f6f9..10b1c81 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -270,7 +270,7 @@
         bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
         op = GrAtlasTextOp::MakeDistanceField(glyphCount, cache, distanceAdjustTable,
                                               useGammaCorrectDistanceTable, luminanceColor,
-                                              info.hasUseLCDText(), useBGR);
+                                              info.hasUseLCDText(), useBGR, info.isAntiAliased());
     } else {
         op = GrAtlasTextOp::MakeBitmap(format, glyphCount, cache);
     }
diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h
index 470d26f..12fe68b 100644
--- a/src/gpu/text/GrAtlasTextBlob.h
+++ b/src/gpu/text/GrAtlasTextBlob.h
@@ -126,10 +126,11 @@
     }
 
     // sets the last subrun of runIndex to use distance field text
-    void setSubRunHasDistanceFields(int runIndex, bool hasLCD) {
+    void setSubRunHasDistanceFields(int runIndex, bool hasLCD, bool isAntiAlias) {
         Run& run = fRuns[runIndex];
         Run::SubRunInfo& subRun = run.fSubRunInfo.back();
         subRun.setUseLCDText(hasLCD);
+        subRun.setAntiAliased(isAntiAlias);
         subRun.setDrawAsDistanceFields();
     }
 
@@ -358,8 +359,7 @@
                     , fGlyphEndIndex(0)
                     , fColor(GrColor_ILLEGAL)
                     , fMaskFormat(kA8_GrMaskFormat)
-                    , fDrawAsDistanceFields(false)
-                    , fUseLCDText(false) {
+                    , fFlags(0) {
                 fVertexBounds.setLargestInverted();
             }
             SubRunInfo(const SubRunInfo& that)
@@ -376,8 +376,7 @@
                 , fY(that.fY)
                 , fColor(that.fColor)
                 , fMaskFormat(that.fMaskFormat)
-                , fDrawAsDistanceFields(that.fDrawAsDistanceFields)
-                , fUseLCDText(that.fUseLCDText) {
+                , fFlags(that.fFlags) {
             }
 
             // TODO when this object is more internal, drop the privacy
@@ -432,12 +431,24 @@
                                     SkScalar*transX, SkScalar* transY);
 
             // df properties
-            void setUseLCDText(bool useLCDText) { fUseLCDText = useLCDText; }
-            bool hasUseLCDText() const { return fUseLCDText; }
-            void setDrawAsDistanceFields() { fDrawAsDistanceFields = true; }
-            bool drawAsDistanceFields() const { return fDrawAsDistanceFields; }
+            void setDrawAsDistanceFields() { fFlags |= kDrawAsSDF_Flag; }
+            bool drawAsDistanceFields() const { return SkToBool(fFlags & kDrawAsSDF_Flag); }
+            void setUseLCDText(bool useLCDText) {
+                fFlags = useLCDText ? fFlags | kUseLCDText_Flag : fFlags & ~kUseLCDText_Flag;
+            }
+            bool hasUseLCDText() const { return SkToBool(fFlags & kUseLCDText_Flag); }
+            void setAntiAliased(bool antiAliased) {
+                fFlags = antiAliased ? fFlags | kAntiAliased_Flag : fFlags & ~kAntiAliased_Flag;
+            }
+            bool isAntiAliased() const { return SkToBool(fFlags & kAntiAliased_Flag); }
 
         private:
+            enum Flag {
+                kDrawAsSDF_Flag = 0x1,
+                kUseLCDText_Flag = 0x2,
+                kAntiAliased_Flag = 0x4
+            };
+
             GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
             sk_sp<GrAtlasTextStrike> fStrike;
             SkMatrix fCurrentViewMatrix;
@@ -451,8 +462,7 @@
             SkScalar fY;
             GrColor fColor;
             GrMaskFormat fMaskFormat;
-            bool fDrawAsDistanceFields; // df property
-            bool fUseLCDText; // df property
+            uint32_t fFlags;
         };
 
         SubRunInfo& push_back() {
diff --git a/src/gpu/text/GrTextUtils.cpp b/src/gpu/text/GrTextUtils.cpp
index 20d5aaf..7ef7eb8 100644
--- a/src/gpu/text/GrTextUtils.cpp
+++ b/src/gpu/text/GrTextUtils.cpp
@@ -283,6 +283,7 @@
     SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil);
     blob->setMinAndMaxScale(dfMaskScaleFloor / scaledTextSize, dfMaskScaleCeil / scaledTextSize);
 
+    skPaint->setAntiAlias(true);
     skPaint->setLCDRenderText(false);
     skPaint->setAutohinted(false);
     skPaint->setHinting(SkPaint::kNormal_Hinting);
@@ -386,7 +387,8 @@
     SkPaint dfPaint(paint);
     GrTextUtils::InitDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix);
     blob->setHasDistanceField();
-    blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText());
+    blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText(),
+                                     paint.skPaint().isAntiAlias());
 
     GrAtlasTextStrike* currStrike = nullptr;