Make SkShaper an interface.

The interface here is not ideal, but there will need to be some build
clean-up before it can be changed.

Change-Id: Ic4d55634405f4c8d9c194e4e6f368287c9669dcd
Reviewed-on: https://skia-review.googlesource.com/c/193036
Reviewed-by: Hal Canary <halcanary@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
diff --git a/modules/skottie/src/SkottieAdapter.cpp b/modules/skottie/src/SkottieAdapter.cpp
index 648a811..140a026 100644
--- a/modules/skottie/src/SkottieAdapter.cpp
+++ b/modules/skottie/src/SkottieAdapter.cpp
@@ -421,12 +421,12 @@
     BlobMaker blobMaker(fText.fAlign);
 
     const auto& push_line = [&](const char* start, const char* end) {
-        SkShaper shaper;
-        if (!shaper.good()) {
+        std::unique_ptr<SkShaper> shaper = SkShaper::Make();
+        if (!shaper) {
             return;
         }
 
-        shaper.shape(&blobMaker, font, start, SkToSizeT(end - start), true, { 0, 0 }, SK_ScalarMax);
+        shaper->shape(&blobMaker, font, start, SkToSizeT(end - start), true, { 0, 0 }, SK_ScalarMax);
     };
 
     const auto& is_line_break = [](SkUnichar uch) {
diff --git a/modules/skshaper/BUILD.gn b/modules/skshaper/BUILD.gn
index 3db1b91d..468b40e 100644
--- a/modules/skshaper/BUILD.gn
+++ b/modules/skshaper/BUILD.gn
@@ -8,6 +8,10 @@
 config("public_config") {
   if (skia_enable_skshaper) {
     include_dirs = [ "include" ]
+    defines = []
+    if (skia_use_icu) {
+      defines += [ "SK_SHAPER_HARFBUZZ_AVAILABLE" ]
+    }
   }
 }
 
@@ -19,10 +23,9 @@
     deps = [
       "../..:skia",
     ]
-    if (!skia_use_icu) {
-      sources = skia_shaper_primitive_sources
-    } else {
-      sources = skia_shaper_harfbuzz_sources
+    sources = skia_shaper_primitive_sources
+    if (skia_use_icu) {
+      sources += skia_shaper_harfbuzz_sources
       deps += [
         "//third_party/harfbuzz",
         "//third_party/icu",
diff --git a/modules/skshaper/include/SkShaper.h b/modules/skshaper/include/SkShaper.h
index ce7b54f..854c368 100644
--- a/modules/skshaper/include/SkShaper.h
+++ b/modules/skshaper/include/SkShaper.h
@@ -25,8 +25,15 @@
  */
 class SkShaper {
 public:
+    static std::unique_ptr<SkShaper> MakePrimitive();
+    #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
+    static std::unique_ptr<SkShaper> MakeHarfBuzz();
+    #endif
+
+    static std::unique_ptr<SkShaper> Make();
+
     SkShaper();
-    ~SkShaper();
+    virtual ~SkShaper();
 
     class RunHandler {
     public:
@@ -55,21 +62,17 @@
         virtual void commitLine() = 0;
     };
 
-    bool good() const;
-    SkPoint shape(RunHandler* handler,
-                  const SkFont& srcFont,
-                  const char* utf8text,
-                  size_t textBytes,
-                  bool leftToRight,
-                  SkPoint point,
-                  SkScalar width) const;
+    virtual SkPoint shape(RunHandler* handler,
+                          const SkFont& srcFont,
+                          const char* utf8text,
+                          size_t textBytes,
+                          bool leftToRight,
+                          SkPoint point,
+                          SkScalar width) const = 0;
 
 private:
     SkShaper(const SkShaper&) = delete;
     SkShaper& operator=(const SkShaper&) = delete;
-
-    struct Impl;
-    std::unique_ptr<Impl> fImpl;
 };
 
 /**
diff --git a/modules/skshaper/skshaper.gni b/modules/skshaper/skshaper.gni
index c0f5fd0..ed66e92 100644
--- a/modules/skshaper/skshaper.gni
+++ b/modules/skshaper/skshaper.gni
@@ -9,12 +9,8 @@
 
 skia_shaper_public = [ "$_include/SkShaper.h" ]
 
-skia_shaper_harfbuzz_sources = [
-  "$_src/SkShaper.cpp",
-  "$_src/SkShaper_harfbuzz.cpp",
-]
-
 skia_shaper_primitive_sources = [
   "$_src/SkShaper.cpp",
   "$_src/SkShaper_primitive.cpp",
 ]
+skia_shaper_harfbuzz_sources = [ "$_src/SkShaper_harfbuzz.cpp" ]
diff --git a/modules/skshaper/src/SkShaper.cpp b/modules/skshaper/src/SkShaper.cpp
index f476d21..f3e3929 100644
--- a/modules/skshaper/src/SkShaper.cpp
+++ b/modules/skshaper/src/SkShaper.cpp
@@ -9,6 +9,19 @@
 #include "SkSpan.h"
 #include "SkTextBlobPriv.h"
 
+std::unique_ptr<SkShaper> SkShaper::Make() {
+#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
+    std::unique_ptr<SkShaper> shaper = SkShaper::MakeHarfBuzz();
+    if (shaper) {
+        return shaper;
+    }
+#endif
+    return SkShaper::MakePrimitive();
+}
+
+SkShaper::SkShaper() {}
+SkShaper::~SkShaper() {}
+
 SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::newRunBuffer(const RunInfo&,
                                                                        const SkFont& font,
                                                                        int glyphCount,
diff --git a/modules/skshaper/src/SkShaper_harfbuzz.cpp b/modules/skshaper/src/SkShaper_harfbuzz.cpp
index 99553da..b2e7116 100644
--- a/modules/skshaper/src/SkShaper_harfbuzz.cpp
+++ b/modules/skshaper/src/SkShaper_harfbuzz.cpp
@@ -10,6 +10,7 @@
 #include "SkFontArguments.h"
 #include "SkFontMetrics.h"
 #include "SkFontMgr.h"
+#include "SkMakeUnique.h"
 #include "SkMalloc.h"
 #include "SkPoint.h"
 #include "SkRefCnt.h"
@@ -786,12 +787,24 @@
 
 }  // namespace
 
-struct SkShaper::Impl {
+class SkShaperHarfBuzz : public SkShaper {
+public:
+    SkShaperHarfBuzz();
+    bool good() const;
+private:
     HBBuffer fBuffer;
     ICUBrk fLineBreakIterator;
     ICUBrk fGraphemeBreakIterator;
 
-    SkPoint shapeCorrect(RunHandler* handler,
+    SkPoint shape(SkShaper::RunHandler* handler,
+                  const SkFont& srcFont,
+                  const char* utf8text,
+                  size_t textBytes,
+                  bool leftToRight,
+                  SkPoint point,
+                  SkScalar width) const override;
+
+    SkPoint shapeCorrect(SkShaper::RunHandler* handler,
                          const char* utf8,
                          size_t utf8Bytes,
                          SkPoint point,
@@ -802,7 +815,7 @@
                          const ScriptRunIterator* script,
                          const FontRunIterator* font) const;
 
-    SkPoint shapeOk(RunHandler* handler,
+    SkPoint shapeOk(SkShaper::RunHandler* handler,
                     const char* utf8,
                     size_t utf8Bytes,
                     SkPoint point,
@@ -823,24 +836,29 @@
                     const FontRunIterator* font) const;
 };
 
-SkShaper::SkShaper() : fImpl(new Impl) {
+std::unique_ptr<SkShaper> SkShaper::MakeHarfBuzz() {
+    auto hb = skstd::make_unique<SkShaperHarfBuzz>();
+    return hb->good() ? std::move(hb) : nullptr;
+}
+
+SkShaperHarfBuzz::SkShaperHarfBuzz() {
 #if defined(SK_USING_THIRD_PARTY_ICU)
     if (!SkLoadICU()) {
         SkDebugf("SkLoadICU() failed!\n");
         return;
     }
 #endif
-    fImpl->fBuffer.reset(hb_buffer_create());
-    SkASSERT(fImpl->fBuffer);
+    fBuffer.reset(hb_buffer_create());
+    SkASSERT(fBuffer);
 
     UErrorCode status = U_ZERO_ERROR;
-    fImpl->fLineBreakIterator.reset(ubrk_open(UBRK_LINE, "th", nullptr, 0, &status));
+    fLineBreakIterator.reset(ubrk_open(UBRK_LINE, "th", nullptr, 0, &status));
     if (U_FAILURE(status)) {
         SkDebugf("Could not create line break iterator: %s", u_errorName(status));
         SK_ABORT("");
     }
 
-    fImpl->fGraphemeBreakIterator.reset(ubrk_open(UBRK_CHARACTER, "th", nullptr, 0, &status));
+    fGraphemeBreakIterator.reset(ubrk_open(UBRK_CHARACTER, "th", nullptr, 0, &status));
     if (U_FAILURE(status)) {
         SkDebugf("Could not create grapheme break iterator: %s", u_errorName(status));
         SK_ABORT("");
@@ -848,21 +866,19 @@
 
 }
 
-SkShaper::~SkShaper() {}
-
-bool SkShaper::good() const {
-    return fImpl->fBuffer &&
-           fImpl->fLineBreakIterator &&
-           fImpl->fGraphemeBreakIterator;
+bool SkShaperHarfBuzz::good() const {
+    return fBuffer &&
+           fLineBreakIterator &&
+           fGraphemeBreakIterator;
 }
 
-SkPoint SkShaper::shape(RunHandler* handler,
-                        const SkFont& srcFont,
-                        const char* utf8,
-                        size_t utf8Bytes,
-                        bool leftToRight,
-                        SkPoint point,
-                        SkScalar width) const
+SkPoint SkShaperHarfBuzz::shape(SkShaper::RunHandler* handler,
+                                const SkFont& srcFont,
+                                const char* utf8,
+                                size_t utf8Bytes,
+                                bool leftToRight,
+                                SkPoint point,
+                                SkScalar width) const
 {
     SkASSERT(handler);
     sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
@@ -884,7 +900,7 @@
     }
     runSegmenter.insert(language);
 
-    hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fImpl->fBuffer.get());
+    hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fBuffer.get());
     SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
     ScriptRunIterator* script = maybeScript.getMaybeNull();
     if (!script) {
@@ -901,24 +917,24 @@
     runSegmenter.insert(font);
 
     if (true) {
-        return fImpl->shapeCorrect(handler, utf8, utf8Bytes, point, width,
+        return shapeCorrect(handler, utf8, utf8Bytes, point, width,
                                    runSegmenter, bidi, language, script, font);
     } else {
-        return fImpl->shapeOk(handler, utf8, utf8Bytes, point, width,
+        return shapeOk(handler, utf8, utf8Bytes, point, width,
                               runSegmenter, bidi, language, script, font);
     }
 }
 
-SkPoint SkShaper::Impl::shapeCorrect(RunHandler* handler,
-                                     const char* utf8,
-                                     size_t utf8Bytes,
-                                     SkPoint point,
-                                     SkScalar width,
-                                     RunIteratorQueue& runSegmenter,
-                                     const BiDiRunIterator* bidi,
-                                     const LanguageRunIterator* language,
-                                     const ScriptRunIterator* script,
-                                     const FontRunIterator* font) const
+SkPoint SkShaperHarfBuzz::shapeCorrect(RunHandler* handler,
+                                       const char* utf8,
+                                       size_t utf8Bytes,
+                                       SkPoint point,
+                                       SkScalar width,
+                                       RunIteratorQueue& runSegmenter,
+                                       const BiDiRunIterator* bidi,
+                                       const LanguageRunIterator* language,
+                                       const ScriptRunIterator* script,
+                                       const FontRunIterator* font) const
 {
     ShapedLine line;
     SkPoint currentPoint = point;
@@ -1064,16 +1080,16 @@
     return currentPoint;
 }
 
-SkPoint SkShaper::Impl::shapeOk(RunHandler* handler,
-                                const char* utf8,
-                                size_t utf8Bytes,
-                                SkPoint point,
-                                SkScalar width,
-                                RunIteratorQueue& runSegmenter,
-                                const BiDiRunIterator* bidi,
-                                const LanguageRunIterator* language,
-                                const ScriptRunIterator* script,
-                                const FontRunIterator* font) const
+SkPoint SkShaperHarfBuzz::shapeOk(RunHandler* handler,
+                                   const char* utf8,
+                                   size_t utf8Bytes,
+                                   SkPoint point,
+                                   SkScalar width,
+                                   RunIteratorQueue& runSegmenter,
+                                   const BiDiRunIterator* bidi,
+                                   const LanguageRunIterator* language,
+                                   const ScriptRunIterator* script,
+                                   const FontRunIterator* font) const
 {
     SkTArray<ShapedRun> runs;
 {
@@ -1288,14 +1304,14 @@
 }
 
 
-ShapedRun SkShaper::Impl::shape(const char* utf8,
-                                const size_t utf8Bytes,
-                                const char* utf8Start,
-                                const char* utf8End,
-                                const BiDiRunIterator* bidi,
-                                const LanguageRunIterator* language,
-                                const ScriptRunIterator* script,
-                                const FontRunIterator* font) const
+ShapedRun SkShaperHarfBuzz::shape(const char* utf8,
+                                   const size_t utf8Bytes,
+                                   const char* utf8Start,
+                                   const char* utf8End,
+                                   const BiDiRunIterator* bidi,
+                                   const LanguageRunIterator* language,
+                                   const ScriptRunIterator* script,
+                                   const FontRunIterator* font) const
 {
     ShapedRun run(SkSpan<const char>(), SkFont(), 0, nullptr, 0);
 
diff --git a/modules/skshaper/src/SkShaper_primitive.cpp b/modules/skshaper/src/SkShaper_primitive.cpp
index 9295a62..f69fecb 100644
--- a/modules/skshaper/src/SkShaper_primitive.cpp
+++ b/modules/skshaper/src/SkShaper_primitive.cpp
@@ -5,19 +5,30 @@
  * found in the LICENSE file.
  */
 
-#include "SkShaper.h"
 #include "SkFontMetrics.h"
+#include "SkMakeUnique.h"
+#include "SkShaper.h"
 #include "SkStream.h"
 #include "SkTo.h"
 #include "SkTypeface.h"
 #include "SkUTF.h"
 
-struct SkShaper::Impl {};
-SkShaper::SkShaper() : fImpl(nullptr) {}
+class SkShaperPrimitive : public SkShaper {
+public:
+    SkShaperPrimitive() {}
+private:
+    SkPoint shape(RunHandler* handler,
+                  const SkFont& srcFont,
+                  const char* utf8text,
+                  size_t textBytes,
+                  bool leftToRight,
+                  SkPoint point,
+                  SkScalar width) const override;
+};
 
-SkShaper::~SkShaper() {}
-
-bool SkShaper::good() const { return true; }
+std::unique_ptr<SkShaper> SkShaper::MakePrimitive() {
+    return skstd::make_unique<SkShaperPrimitive>();
+}
 
 static inline bool is_breaking_whitespace(SkUnichar c) {
     switch (c) {
@@ -129,13 +140,13 @@
     return text - start;
 }
 
-SkPoint SkShaper::shape(RunHandler* handler,
-                        const SkFont& font,
-                        const char* utf8text,
-                        size_t textBytes,
-                        bool leftToRight,
-                        SkPoint point,
-                        SkScalar width) const {
+SkPoint SkShaperPrimitive::shape(RunHandler* handler,
+                                 const SkFont& font,
+                                 const char* utf8text,
+                                 size_t textBytes,
+                                 bool leftToRight,
+                                 SkPoint point,
+                                 SkScalar width) const {
     sk_ignore_unused_variable(leftToRight);
 
     int glyphCount = font.countText(utf8text, textBytes, SkTextEncoding::kUTF8);
diff --git a/samplecode/SampleTextBox.cpp b/samplecode/SampleTextBox.cpp
index a0eb5b4..1d37b19 100644
--- a/samplecode/SampleTextBox.cpp
+++ b/samplecode/SampleTextBox.cpp
@@ -25,12 +25,6 @@
 #include "SkTypeface.h"
 #include "SkUTF.h"
 
-extern void skia_set_text_gamma(float blackGamma, float whiteGamma);
-
-#if defined(SK_BUILD_FOR_WIN) && defined(SK_FONTHOST_WIN_GDI)
-extern SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&);
-#endif
-
 static const char gText[] =
     "When in the Course of human events it becomes necessary for one people "
     "to dissolve the political bands which have connected them with another "
@@ -41,20 +35,7 @@
 
 class TextBoxView : public Sample {
 public:
-    TextBoxView() {
-#if defined(SK_BUILD_FOR_WIN) && defined(SK_FONTHOST_WIN_GDI)
-        LOGFONT lf;
-        sk_bzero(&lf, sizeof(lf));
-        lf.lfHeight = 9;
-        SkTypeface* tf0 = SkCreateTypefaceFromLOGFONT(lf);
-        lf.lfHeight = 12;
-        SkTypeface* tf1 = SkCreateTypefaceFromLOGFONT(lf);
-        // we assert that different sizes should not affect which face we get
-        SkASSERT(tf0 == tf1);
-        tf0->unref();
-        tf1->unref();
-#endif
-    }
+    TextBoxView() : fShaper(SkShaper::Make()) {}
 
 protected:
     bool onQuery(Sample::Event* evt) override {
@@ -71,8 +52,6 @@
         canvas->clipRect(SkRect::MakeWH(w, h));
         canvas->drawColor(bg);
 
-        SkShaper shaper;
-
         SkScalar margin = 20;
 
         SkPaint paint;
@@ -83,8 +62,8 @@
             SkFont font(nullptr, SkIntToScalar(i));
             font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
 
-            SkPoint end = shaper.shape(&builder, font, gText, strlen(gText), true,
-                                       { margin, margin }, w - margin);
+            SkPoint end = fShaper->shape(&builder, font, gText, strlen(gText), true,
+                                         { margin, margin }, w - margin);
             canvas->drawTextBlob(builder.makeBlob(), 0, 0, paint);
 
             canvas->translate(0, end.y());
@@ -103,6 +82,7 @@
     }
 
 private:
+    std::unique_ptr<SkShaper> fShaper;
     typedef Sample INHERITED;
 };
 
diff --git a/src/utils/SkLua.cpp b/src/utils/SkLua.cpp
index 303558e..1c7bff1 100644
--- a/src/utils/SkLua.cpp
+++ b/src/utils/SkLua.cpp
@@ -1873,7 +1873,7 @@
     SkRect bounds;
     lua2rect(L, 2, &bounds);
 
-    SkShaper shaper;
+    std::unique_ptr<SkShaper> shaper = SkShaper::Make();
 
     // TODO: restore this logic based on SkFont instead of SkPaint
 #if 0
@@ -1883,8 +1883,8 @@
     SkFont font;
 #endif
     SkTextBlobBuilderRunHandler builder(text);
-    SkPoint end = shaper.shape(&builder, font, text, strlen(text), true,
-                               { bounds.left(), bounds.top() }, bounds.width());
+    SkPoint end = shaper->shape(&builder, font, text, strlen(text), true,
+                                { bounds.left(), bounds.top() }, bounds.width());
 
     push_ref<SkTextBlob>(L, builder.makeBlob());
     SkLua(L).pushScalar(end.fY);
diff --git a/tools/using_skia_and_harfbuzz.cpp b/tools/using_skia_and_harfbuzz.cpp
index 586b9e8..37bc7b5 100644
--- a/tools/using_skia_and_harfbuzz.cpp
+++ b/tools/using_skia_and_harfbuzz.cpp
@@ -208,12 +208,12 @@
     if (font_file.size() > 0) {
         typeface = SkTypeface::MakeFromFile(font_file.c_str(), 0 /* index */);
     }
-    SkShaper shaper;
-    assert(shaper.good());
+    std::unique_ptr<SkShaper> shaper = SkShaper::Make();
+    assert(shaper);
     //SkString line("This is هذا هو الخط a line.");
     //SkString line("⁧This is a line هذا هو الخط.⁩");
     for (std::string line; std::getline(std::cin, line);) {
-        placement.WriteLine(shaper, line.c_str(), line.size());
+        placement.WriteLine(*shaper, line.c_str(), line.size());
     }
 
     doc->close();