New plan -- aa and lcd DO belong on SkFont

edging settings are needed for metrics calls, as well as drawing, hence
we really have to include them in almost every SkFont call/usage, so I
guess we can just accept them as real.

This seems to imply that we have to document what happens in drawTextBlob,
since it has a bunch of SkFonts (runs) AND a paint. This is the situation
today of course, and I had hoped to simplify it, but I think I've failed.

Proposal dox for drawTextBlob.

drawTextBlob respects the paint when drawing the blog, but it IGNORES the
paint's antialias (and lcdrender) flags, as these are already specified in
the blob's runs.

Bug: skia:2664, skia:8494
Change-Id: I8f69186c9c337d98d058919f53b7901ff830a16e
Reviewed-on: https://skia-review.googlesource.com/c/170352
Auto-Submit: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Mike Reed <reed@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
diff --git a/gm/textblob.cpp b/gm/textblob.cpp
index e813aff..867e6cd 100644
--- a/gm/textblob.cpp
+++ b/gm/textblob.cpp
@@ -128,7 +128,8 @@
         SkTextBlobBuilder builder;
 
         SkFont font;
-        font.setFlags(font.getFlags() | SkFont::kSubpixel_Flag|SkFont::kDEPRECATED_Antialias_Flag);
+        font.setSubpixel(true);
+        font.setEdging(SkFont::Edging::kAntiAlias);
         font.setTypeface(fTypeface);
 
         for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) {
diff --git a/gm/textblobshader.cpp b/gm/textblobshader.cpp
index fcebadf..779b5b9 100644
--- a/gm/textblobshader.cpp
+++ b/gm/textblobshader.cpp
@@ -31,7 +31,8 @@
 
     void onOnceBeforeDraw() override {
         SkFont font;
-        font.setFlags(font.getFlags() | SkFont::kSubpixel_Flag | SkFont::kDEPRECATED_Antialias_Flag);
+        font.setSubpixel(true);
+        font.setEdging(SkFont::Edging::kAntiAlias);
         font.setSize(30);
         font.setTypeface(sk_tool_utils::create_portable_typeface());
 
diff --git a/include/core/SkFont.h b/include/core/SkFont.h
index 6b31ece..13cfaa1 100644
--- a/include/core/SkFont.h
+++ b/include/core/SkFont.h
@@ -12,11 +12,15 @@
 #include "SkScalar.h"
 #include "SkTypeface.h"
 
+// TODO: remove this, and opt in/out per client
+#define SK_SUPPORT_LEGACY_FONT_FLAGS
+
 class SkPaint;
 struct SkFontMetrics;
 
 class SK_API SkFont {
 public:
+#ifdef SK_SUPPORT_LEGACY_FONT_FLAGS
     enum Flags {
         /**
          *  Use the system's automatic hinting mechanism to hint the typeface.
@@ -37,6 +41,13 @@
         kDEPRECATED_Antialias_Flag  = 1 << 5,
         kDEPRECATED_LCDRender_Flag  = 1 << 6,
     };
+#endif
+
+    enum class Edging {
+        kAlias,
+        kAntiAlias,
+        kSubpixelAntiAlias,
+    };
 
     enum Hinting : uint8_t {
         kNo_Hinting     = 0, //!< glyph outlines unchanged
@@ -46,17 +57,18 @@
     };
 
     SkFont();
+    SkFont(sk_sp<SkTypeface>, SkScalar size);
+    SkFont(sk_sp<SkTypeface>, SkScalar size, SkScalar scaleX, SkScalar skewX);
+#ifdef SK_SUPPORT_LEGACY_FONT_FLAGS
     SkFont(sk_sp<SkTypeface>, SkScalar size, uint32_t flags);
     SkFont(sk_sp<SkTypeface>, SkScalar size, SkScalar scaleX, SkScalar skewX, uint32_t flags);
+#endif
 
-    bool isForceAutoHinting() const { return SkToBool(fFlags & kForceAutoHinting_Flag); }
-    bool isEmbeddedBitmaps() const { return SkToBool(fFlags & kEmbeddedBitmaps_Flag); }
-    bool isSubpixel() const { return SkToBool(fFlags & kSubpixel_Flag); }
-    bool isLinearMetrics() const { return SkToBool(fFlags & kLinearMetrics_Flag); }
-    bool isEmbolden() const { return SkToBool(fFlags & kEmbolden_Flag); }
-
-    bool DEPRECATED_isAntiAlias() const { return SkToBool(fFlags & kDEPRECATED_Antialias_Flag); }
-    bool DEPRECATED_isLCDRender() const { return SkToBool(fFlags & kDEPRECATED_LCDRender_Flag); }
+    bool isForceAutoHinting() const { return SkToBool(fFlags & kForceAutoHinting_PrivFlag); }
+    bool isEmbeddedBitmaps() const { return SkToBool(fFlags & kEmbeddedBitmaps_PrivFlag); }
+    bool isSubpixel() const { return SkToBool(fFlags & kSubpixel_PrivFlag); }
+    bool isLinearMetrics() const { return SkToBool(fFlags & kLinearMetrics_PrivFlag); }
+    bool isEmbolden() const { return SkToBool(fFlags & kEmbolden_PrivFlag); }
 
     void setForceAutoHinting(bool);
     void setEmbeddedBitmaps(bool);
@@ -64,8 +76,8 @@
     void setLinearMetrics(bool);
     void setEmbolden(bool);
 
-    void DEPRECATED_setAntiAlias(bool);
-    void DEPRECATED_setLCDRender(bool);
+    Edging getEdging() const { return (Edging)fEdging; }
+    void setEdging(Edging);
 
     void setHinting(SkFontHinting);
 
@@ -84,16 +96,25 @@
      */
     SkFont makeWithSize(SkScalar size) const;
 
+#ifdef SK_SUPPORT_LEGACY_FONT_FLAGS
+    bool DEPRECATED_isAntiAlias() const { return SkToBool(fFlags & kDEPRECATED_Antialias_Flag); }
+    bool DEPRECATED_isLCDRender() const { return SkToBool(fFlags & kDEPRECATED_LCDRender_Flag); }
+
+    void DEPRECATED_setAntiAlias(bool);
+    void DEPRECATED_setLCDRender(bool);
+
     /**
      *  Return a font with the same attributes of this font, but with the flags.
      */
     SkFont makeWithFlags(uint32_t newFlags) const;
+    uint32_t    getFlags() const { return fFlags; }
+    void setFlags(uint32_t);
+#endif
 
     SkTypeface* getTypeface() const { return fTypeface.get(); }
     SkScalar    getSize() const { return fSize; }
     SkScalar    getScaleX() const { return fScaleX; }
     SkScalar    getSkewX() const { return fSkewX; }
-    uint32_t    getFlags() const { return fFlags; }
 
     sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
 
@@ -101,7 +122,6 @@
     void setSize(SkScalar);
     void setScaleX(SkScalar);
     void setSkewX(SkScalar);
-    void setFlags(uint32_t);
 
     /** Converts text into glyph indices.
         Returns the number of glyph indices represented by text.
@@ -149,6 +169,14 @@
     static SkFont LEGACY_ExtractFromPaint(const SkPaint&);
 
 private:
+    enum PrivFlags {
+        kForceAutoHinting_PrivFlag      = 1 << 0,
+        kEmbeddedBitmaps_PrivFlag       = 1 << 1,
+        kSubpixel_PrivFlag              = 1 << 2,
+        kLinearMetrics_PrivFlag         = 1 << 3,
+        kEmbolden_PrivFlag              = 1 << 4,
+    };
+
     static constexpr unsigned kAllFlags = 0x07F;
 
     sk_sp<SkTypeface> fTypeface;
@@ -156,6 +184,7 @@
     SkScalar    fScaleX;
     SkScalar    fSkewX;
     uint8_t     fFlags;
+    uint8_t     fEdging;
     uint8_t     fHinting;
 
     SkScalar setupForAsPaths(SkPaint*);
diff --git a/src/core/SkFont.cpp b/src/core/SkFont.cpp
index 300a8d2..b04226a 100644
--- a/src/core/SkFont.cpp
+++ b/src/core/SkFont.cpp
@@ -18,27 +18,38 @@
 
 #define kDefault_Size       12
 #define kDefault_Flags      0
+#define kDefault_Edging     SkFont::Edging::kAntiAlias
 #define kDefault_Hinting    kNormal_SkFontHinting
 
 static inline SkScalar valid_size(SkScalar size) {
     return SkTMax<SkScalar>(0, size);
 }
 
-SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size, SkScalar scaleX, SkScalar skewX,
-               uint32_t flags)
+SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size, SkScalar scaleX, SkScalar skewX)
     : fTypeface(face ? std::move(face) : SkTypeface::MakeDefault())
     , fSize(valid_size(size))
     , fScaleX(scaleX)
     , fSkewX(skewX)
-    , fFlags(flags & kAllFlags)
+    , fFlags(kDefault_Flags)
+    , fEdging(static_cast<unsigned>(kDefault_Edging))
     , fHinting(static_cast<unsigned>(kDefault_Hinting))
 {}
 
-SkFont::SkFont() : SkFont(nullptr, kDefault_Size, 1, 0, kDefault_Flags)
-{}
+SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size) : SkFont(std::move(face), size, 1, 0) {}
 
-SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size, uint32_t flags)
-    : SkFont(std::move(face), size, 1, 0, flags) {}
+SkFont::SkFont() : SkFont(nullptr, kDefault_Size) {}
+
+#ifdef SK_SUPPORT_LEGACY_FONT_FLAGS
+SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size, SkScalar scaleX, SkScalar skewX,
+               uint32_t legacy_flags) : SkFont(std::move(face), size, scaleX, skewX) {
+    this->setFlags(legacy_flags);
+}
+
+SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size, uint32_t legacy_flags)
+    : SkFont(std::move(face), size) {
+    this->setFlags(legacy_flags);
+}
+#endif
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -47,27 +58,59 @@
 }
 
 void SkFont::setForceAutoHinting(bool predicate) {
-    fFlags = set_clear_mask(fFlags, predicate, kForceAutoHinting_Flag);
+    fFlags = set_clear_mask(fFlags, predicate, kForceAutoHinting_PrivFlag);
 }
 void SkFont::setEmbeddedBitmaps(bool predicate) {
-    fFlags = set_clear_mask(fFlags, predicate, kEmbeddedBitmaps_Flag);
+    fFlags = set_clear_mask(fFlags, predicate, kEmbeddedBitmaps_PrivFlag);
 }
 void SkFont::setSubpixel(bool predicate) {
-    fFlags = set_clear_mask(fFlags, predicate, kSubpixel_Flag);
+    fFlags = set_clear_mask(fFlags, predicate, kSubpixel_PrivFlag);
 }
 void SkFont::setLinearMetrics(bool predicate) {
-    fFlags = set_clear_mask(fFlags, predicate, kLinearMetrics_Flag);
+    fFlags = set_clear_mask(fFlags, predicate, kLinearMetrics_PrivFlag);
 }
 void SkFont::setEmbolden(bool predicate) {
-    fFlags = set_clear_mask(fFlags, predicate, kEmbolden_Flag);
+    fFlags = set_clear_mask(fFlags, predicate, kEmbolden_PrivFlag);
 }
 
-void SkFont::DEPRECATED_setAntiAlias(bool predicate) {
-    fFlags = set_clear_mask(fFlags, predicate, kDEPRECATED_Antialias_Flag);
+#ifdef SK_SUPPORT_LEGACY_FONT_FLAGS
+void SkFont::DEPRECATED_setAntiAlias(bool doAA) {
+    if (!doAA) {
+        this->setEdging(Edging::kAlias);
+    } else {
+        if (this->getEdging() == Edging::kAlias) {
+            this->setEdging(Edging::kAntiAlias);
+        }
+        // else leave the current fEdging as is
+    }
 }
 
-void SkFont::DEPRECATED_setLCDRender(bool predicate) {
-    fFlags = set_clear_mask(fFlags, predicate, kDEPRECATED_LCDRender_Flag);
+void SkFont::DEPRECATED_setLCDRender(bool doLCD) {
+    if (doLCD) {
+        this->setEdging(Edging::kSubpixelAntiAlias);
+    } else {
+        if (this->getEdging() == Edging::kSubpixelAntiAlias) {
+            this->setEdging(Edging::kAntiAlias);
+        }
+        // else leave the current fEdging as is
+    }
+}
+
+void SkFont::setFlags(uint32_t legacy_flags) {
+    fFlags = legacy_flags & 0x1F;   // the first 5 flags are fine
+    this->DEPRECATED_setAntiAlias(SkToBool(legacy_flags & kDEPRECATED_Antialias_Flag));
+    this->DEPRECATED_setLCDRender(SkToBool(legacy_flags & kDEPRECATED_LCDRender_Flag));
+}
+
+SkFont SkFont::makeWithFlags(uint32_t newFlags) const {
+    SkFont font = *this;
+    font.setFlags(newFlags);
+    return font;
+}
+#endif
+
+void SkFont::setEdging(Edging e) {
+    fEdging = SkToU8(e);
 }
 
 void SkFont::setHinting(SkFontHinting h) {
@@ -83,33 +126,25 @@
 void SkFont::setSkewX(SkScalar skew) {
     fSkewX = skew;
 }
-void SkFont::setFlags(uint32_t flags) {
-    fFlags = flags & kAllFlags;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
 
 SkFont SkFont::makeWithSize(SkScalar newSize) const {
-    return {this->refTypeface(), newSize, this->getScaleX(), this->getSkewX(), this->getFlags()};
+    SkFont font = *this;
+    font.setSize(newSize);
+    return font;
 }
 
-SkFont SkFont::makeWithFlags(uint32_t newFlags) const {
-    return {this->refTypeface(), this->getSize(), this->getScaleX(), this->getSkewX(), newFlags};
-}
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 SkScalar SkFont::setupForAsPaths(SkPaint* paint) {
-    constexpr uint32_t flagsToIgnore =  kLinearMetrics_Flag        |
-                                        kDEPRECATED_LCDRender_Flag |
-                                        kEmbeddedBitmaps_Flag      |
-                                        kForceAutoHinting_Flag;
+    constexpr uint32_t flagsToIgnore = kLinearMetrics_PrivFlag        |
+                                       kEmbeddedBitmaps_PrivFlag      |
+                                       kForceAutoHinting_PrivFlag;
 
-    uint32_t flags = (this->getFlags() & ~flagsToIgnore) | kSubpixel_Flag;
-
-    this->setFlags(flags);
+    fFlags = (fFlags & ~flagsToIgnore) | kSubpixel_PrivFlag;
     this->setHinting(kNo_SkFontHinting);
+
     if (paint) {
-       paint->setStyle(SkPaint::kFill_Style);
+        paint->setStyle(SkPaint::kFill_Style);
         paint->setPathEffect(nullptr);
     }
     SkScalar textSize = fSize;
@@ -337,13 +372,21 @@
     paint->setTextScaleX(fScaleX);
     paint->setTextSkewX(fSkewX);
 
-    paint->setEmbeddedBitmapText(SkToBool(fFlags & kEmbeddedBitmaps_Flag));
-    paint->setFakeBoldText(SkToBool(fFlags & kEmbolden_Flag));
-    paint->setAutohinted(SkToBool(fFlags & kForceAutoHinting_Flag));
-    paint->setSubpixelText(SkToBool(fFlags & kSubpixel_Flag));
-    paint->setLinearText(SkToBool(fFlags & kLinearMetrics_Flag));
-    paint->setAntiAlias(SkToBool(fFlags & kDEPRECATED_Antialias_Flag));
-    paint->setLCDRenderText(SkToBool(fFlags & kDEPRECATED_LCDRender_Flag));
+    paint->setEmbeddedBitmapText(SkToBool(fFlags & kEmbeddedBitmaps_PrivFlag));
+    paint->setFakeBoldText(SkToBool(fFlags & kEmbolden_PrivFlag));
+    paint->setAutohinted(SkToBool(fFlags & kForceAutoHinting_PrivFlag));
+    paint->setSubpixelText(SkToBool(fFlags & kSubpixel_PrivFlag));
+    paint->setLinearText(SkToBool(fFlags & kLinearMetrics_PrivFlag));
+
+    bool doAA = false,
+         doLCD = false;
+    switch (this->getEdging()) {
+        case Edging::kAlias:                                        break;
+        case Edging::kAntiAlias:         doAA = true;               break;
+        case Edging::kSubpixelAntiAlias: doAA = true; doLCD = true; break;
+    }
+    paint->setAntiAlias(doAA);
+    paint->setLCDRenderText(doLCD);
 
     paint->setHinting((SkFontHinting)this->getHinting());
 }
@@ -351,30 +394,33 @@
 SkFont SkFont::LEGACY_ExtractFromPaint(const SkPaint& paint) {
     uint32_t flags = 0;
     if (paint.isEmbeddedBitmapText()) {
-        flags |= kEmbeddedBitmaps_Flag;
+        flags |= kEmbeddedBitmaps_PrivFlag;
     }
     if (paint.isFakeBoldText()) {
-        flags |= kEmbolden_Flag;
+        flags |= kEmbolden_PrivFlag;
     }
     if (paint.isAutohinted()) {
-        flags |= kForceAutoHinting_Flag;
+        flags |= kForceAutoHinting_PrivFlag;
     }
     if (paint.isSubpixelText()) {
-        flags |= kSubpixel_Flag;
+        flags |= kSubpixel_PrivFlag;
     }
     if (paint.isLinearText()) {
-        flags |= kLinearMetrics_Flag;
+        flags |= kLinearMetrics_PrivFlag;
     }
 
+    Edging edging = Edging::kAlias;
     if (paint.isAntiAlias()) {
-        flags |= kDEPRECATED_Antialias_Flag;
+        edging = Edging::kAntiAlias;
     }
     if (paint.isLCDRenderText()) {
-        flags |= kDEPRECATED_LCDRender_Flag;
+        edging = Edging::kSubpixelAntiAlias;
     }
 
     SkFont font(sk_ref_sp(paint.getTypeface()), paint.getTextSize(), paint.getTextScaleX(),
-                paint.getTextSkewX(), flags);
+                paint.getTextSkewX());
+    font.fFlags = flags;
+    font.setEdging(edging);
     font.setHinting((SkFontHinting)paint.getHinting());
     return font;
 }
diff --git a/tests/FontMgrTest.cpp b/tests/FontMgrTest.cpp
index 2f63a2a..502c1ca 100644
--- a/tests/FontMgrTest.cpp
+++ b/tests/FontMgrTest.cpp
@@ -18,8 +18,7 @@
 #include <vector>
 
 static void test_font(skiatest::Reporter* reporter) {
-    uint32_t flags = 0;
-    SkFont font(nullptr, 24, flags);
+    SkFont font(nullptr, 24);
 
     REPORTER_ASSERT(reporter, font.getTypeface());
     REPORTER_ASSERT(reporter, 24 == font.getSize());