impl intercepts with fonts

Bug: skia:
Change-Id: Ib3958c61822716846e12647afdfef4ecd979b474
Reviewed-on: https://skia-review.googlesource.com/c/176581
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index c98e2b0..cd87eb0 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -1238,11 +1238,11 @@
     SkScalar measure_text(SkGlyphCache*, const char* text, size_t length,
                           int* count, SkRect* bounds) const;
 
-    int getTextIntercepts(const void* text, size_t length, SkScalar x, SkScalar y,
+    int getTextIntercepts(const SkFont&, const SkGlyphID[], int count, SkScalar x, SkScalar y,
                           const SkScalar bounds[2], SkScalar* intervals) const;
-    int getPosTextIntercepts(const void* text, size_t length, const SkPoint pos[],
+    int getPosTextIntercepts(const SkFont&, const SkGlyphID[], int count, const SkPoint pos[],
                              const SkScalar bounds[2], SkScalar* intervals) const;
-    int getPosTextHIntercepts(const void* text, size_t length, const SkScalar xpos[],
+    int getPosTextHIntercepts(const SkFont&, const SkGlyphID[], int count, const SkScalar xpos[],
                               SkScalar constY, const SkScalar bounds[2], SkScalar* intervals) const;
 
     /*
diff --git a/src/core/SkPaint_text.cpp b/src/core/SkPaint_text.cpp
index 4f42764..1d45b85 100644
--- a/src/core/SkPaint_text.cpp
+++ b/src/core/SkPaint_text.cpp
@@ -392,16 +392,12 @@
 }
 
 template <SkTextInterceptsIter::TextType TextType, typename Func>
-int GetTextIntercepts(const SkPaint& paint, const void* text, size_t length,
-                      const SkScalar bounds[2], SkScalar* array, Func posMaker) {
-    SkASSERT(length == 0 || text != nullptr);
-    if (!length) {
-        return 0;
-    }
+int GetTextIntercepts(const SkFont& font, const SkPaint& paint, const SkGlyphID glyphs[],
+                      int glyphCount, const SkScalar bounds[2], SkScalar* array, Func posMaker) {
+    SkASSERT(glyphCount == 0 || glyphs != nullptr);
 
     const SkPoint pos0 = posMaker(0);
-    SkTextInterceptsIter iter(static_cast<const char*>(text), length, paint, bounds,
-                              pos0.x(), pos0.y(), TextType);
+    SkTextInterceptsIter iter(glyphs, glyphCount, font, paint, bounds, pos0.x(), pos0.y(), TextType);
 
     int i = 0;
     int count = 0;
@@ -415,31 +411,32 @@
     return count;
 }
 
-int SkPaint::getTextIntercepts(const void* textData, size_t length,
+int SkPaint::getTextIntercepts(const SkFont& font, const SkGlyphID glyphs[], int count,
                                SkScalar x, SkScalar y, const SkScalar bounds[2],
                                SkScalar* array) const {
 
     return GetTextIntercepts<SkTextInterceptsIter::TextType::kText>(
-        *this, textData, length, bounds, array, [&x, &y] (int) -> SkPoint {
+        font, *this, glyphs, count, bounds, array, [&x, &y] (int) -> SkPoint {
             return SkPoint::Make(x, y);
         });
 }
 
-int SkPaint::getPosTextIntercepts(const void* textData, size_t length, const SkPoint pos[],
-                                  const SkScalar bounds[2], SkScalar* array) const {
+int SkPaint::getPosTextIntercepts(const SkFont& font, const SkGlyphID glyphs[], int count,
+                                  const SkPoint pos[], const SkScalar bounds[2],
+                                  SkScalar* array) const {
 
     return GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
-        *this, textData, length, bounds, array, [&pos] (int i) -> SkPoint {
+        font, *this, glyphs, count, bounds, array, [&pos] (int i) -> SkPoint {
             return pos[i];
         });
 }
 
-int SkPaint::getPosTextHIntercepts(const void* textData, size_t length, const SkScalar xpos[],
-                                   SkScalar constY, const SkScalar bounds[2],
+int SkPaint::getPosTextHIntercepts(const SkFont& font, const SkGlyphID glyphs[], int count,
+                                   const SkScalar xpos[], SkScalar constY, const SkScalar bounds[2],
                                    SkScalar* array) const {
 
     return GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
-        *this, textData, length, bounds, array, [&xpos, &constY] (int i) -> SkPoint {
+        font, *this, glyphs, count, bounds, array, [&xpos, &constY] (int i) -> SkPoint {
             return SkPoint::Make(xpos[i], constY);
         });
 }
@@ -447,27 +444,23 @@
 int SkPaint::getTextBlobIntercepts(const SkTextBlob* blob, const SkScalar bounds[2],
                                    SkScalar* intervals) const {
     int count = 0;
-    SkPaint runPaint(*this);
-
     SkTextBlobRunIterator it(blob);
+
     while (!it.done()) {
-        it.applyFontToPaint(&runPaint);
-        const size_t runByteCount = it.glyphCount() * sizeof(SkGlyphID);
         SkScalar* runIntervals = intervals ? intervals + count : nullptr;
 
         switch (it.positioning()) {
         case SkTextBlobRunIterator::kDefault_Positioning:
-            count += runPaint.getTextIntercepts(it.glyphs(), runByteCount, it.offset().x(),
-                                                it.offset().y(), bounds, runIntervals);
+            count += this->getTextIntercepts(it.font(), it.glyphs(), it.glyphCount(), it.offset().x(),
+                                             it.offset().y(), bounds, runIntervals);
             break;
         case SkTextBlobRunIterator::kHorizontal_Positioning:
-            count += runPaint.getPosTextHIntercepts(it.glyphs(), runByteCount, it.pos(),
-                                                    it.offset().y(), bounds, runIntervals);
+            count += this->getPosTextHIntercepts(it.font(), it.glyphs(), it.glyphCount(), it.pos(),
+                                                 it.offset().y(), bounds, runIntervals);
             break;
         case SkTextBlobRunIterator::kFull_Positioning:
-            count += runPaint.getPosTextIntercepts(it.glyphs(), runByteCount,
-                                                   reinterpret_cast<const SkPoint*>(it.pos()),
-                                                   bounds, runIntervals);
+            count += this->getPosTextIntercepts(it.font(), it.glyphs(), it.glyphCount(),
+                                                reinterpret_cast<const SkPoint*>(it.pos()), bounds, runIntervals);
             break;
         }
 
@@ -510,23 +503,19 @@
             paint.getStyle() != SkPaint::kFill_Style;
 }
 
-SkTextBaseIter::SkTextBaseIter(const char text[], size_t length,
-                                   const SkPaint& paint,
-                                   bool applyStrokeAndPathEffects)
-    : fPaint(paint) {
-    fGlyphCacheProc = SkFontPriv::GetGlyphCacheProc(paint.getTextEncoding(), true);
+SkTextBaseIter::SkTextBaseIter(const SkGlyphID glyphs[], int count, const SkFont& font,
+                               const SkPaint& paint)
+        : fFont(font), fPaint(paint)
+{
+    SkAssertResult(count >= 0);
 
-    fPaint.setLinearText(true);
+    fFont.setLinearMetrics(true);
     fPaint.setMaskFilter(nullptr);   // don't want this affecting our path-cache lookup
 
-    if (fPaint.getPathEffect() == nullptr && !has_thick_frame(fPaint)) {
-        applyStrokeAndPathEffects = false;
-    }
-
     // can't use our canonical size if we need to apply patheffects
     if (fPaint.getPathEffect() == nullptr) {
-        fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
-        fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
+        fScale = fFont.getSize() / SkPaint::kCanonicalTextSizeForPaths;
+        fFont.setSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
         // Note: fScale can be zero here (even if it wasn't before the divide). It can also
         // be very very small. We call sk_ieee_float_divide below to ensure IEEE divide behavior,
         // since downstream we will check for the resulting coordinates being non-finite anyway.
@@ -538,24 +527,13 @@
         fScale = SK_Scalar1;
     }
 
-    if (!applyStrokeAndPathEffects) {
-        fPaint.setStyle(SkPaint::kFill_Style);
-        fPaint.setPathEffect(nullptr);
-    }
+    fPaint.setStyle(SkPaint::kFill_Style);
+    fPaint.setPathEffect(nullptr);
 
-    // SRGBTODO: Is this correct?
-    const SkFont font = SkFont::LEGACY_ExtractFromPaint(fPaint);
-    fCache = SkStrikeCache::FindOrCreateStrikeWithNoDeviceExclusive(font, fPaint);
+    fCache = SkStrikeCache::FindOrCreateStrikeWithNoDeviceExclusive(fFont, fPaint);
 
-    SkPaint::Style  style = SkPaint::kFill_Style;
-    sk_sp<SkPathEffect> pe;
-
-    if (!applyStrokeAndPathEffects) {
-        style = paint.getStyle();       // restore
-        pe = paint.refPathEffect();     // restore
-    }
-    fPaint.setStyle(style);
-    fPaint.setPathEffect(pe);
+    fPaint.setStyle(paint.getStyle());
+    fPaint.setPathEffect(paint.refPathEffect());
     fPaint.setMaskFilter(paint.refMaskFilter());    // restore
 
     // now compute fXOffset if needed
@@ -564,41 +542,18 @@
     fXPos = xOffset;
     fPrevAdvance = 0;
 
-    fText = text;
-    fStop = text + length;
-}
-
-bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) {
-    if (fText < fStop) {
-        const SkGlyph& glyph = fGlyphCacheProc(fCache.get(), &fText, fStop);
-
-        fXPos += fPrevAdvance * fScale;
-        fPrevAdvance = advance(glyph);   // + fPaint.getTextTracking();
-
-        if (glyph.fWidth) {
-            if (path) {
-                *path = fCache->findPath(glyph);
-            }
-        } else {
-            if (path) {
-                *path = nullptr;
-            }
-        }
-        if (xpos) {
-            *xpos = fXPos;
-        }
-        return true;
-    }
-    return false;
+    fGlyphs = glyphs;
+    fStop = glyphs + count;
 }
 
 bool SkTextInterceptsIter::next(SkScalar* array, int* count) {
-    const SkGlyph& glyph = fGlyphCacheProc(fCache.get(), &fText, fStop);
+    SkASSERT(fGlyphs < fStop);
+    const SkGlyph& glyph = fCache->getGlyphIDMetrics(*fGlyphs++);
     fXPos += fPrevAdvance * fScale;
     fPrevAdvance = advance(glyph);   // + fPaint.getTextTracking();
     if (fCache->findPath(glyph)) {
         fCache->findIntercepts(fBounds, fScale, fXPos, false,
                 const_cast<SkGlyph*>(&glyph), array, count);
     }
-    return fText < fStop;
+    return fGlyphs < fStop;
 }
diff --git a/src/core/SkTextToPathIter.h b/src/core/SkTextToPathIter.h
index 92ddff2..6543543 100644
--- a/src/core/SkTextToPathIter.h
+++ b/src/core/SkTextToPathIter.h
@@ -13,35 +13,23 @@
 #include "SkStrikeCache.h"
 
 class SkTextBaseIter {
-protected:
-    SkTextBaseIter(const char text[], size_t length, const SkPaint& paint,
-                   bool applyStrokeAndPathEffects);
-
-    SkExclusiveStrikePtr fCache;
-    SkPaint              fPaint;
-    SkScalar             fScale;
-    SkScalar             fPrevAdvance;
-    const char*          fText;
-    const char*          fStop;
-    SkFontPriv::GlyphCacheProc fGlyphCacheProc;
-
-    SkScalar        fXPos;      // accumulated xpos, returned in next
-};
-
-class SkTextToPathIter : SkTextBaseIter {
 public:
-    SkTextToPathIter(const char text[], size_t length, const SkPaint& paint,
-                     bool applyStrokeAndPathEffects)
-                     : SkTextBaseIter(text, length, paint, applyStrokeAndPathEffects) {
-    }
-
+    const SkFont&   getFont() const { return fFont; }
     const SkPaint&  getPaint() const { return fPaint; }
     SkScalar        getPathScale() const { return fScale; }
 
-    /**
-     *  Returns false when all of the text has been consumed
-     */
-    bool next(const SkPath** path, SkScalar* xpos);
+protected:
+    SkTextBaseIter(const SkGlyphID glyphs[], int count, const SkFont&, const SkPaint& paint);
+
+    SkExclusiveStrikePtr fCache;
+    SkFont               fFont;
+    SkPaint              fPaint;
+    SkScalar             fScale;
+    SkScalar             fPrevAdvance;
+    const SkGlyphID*     fGlyphs;
+    const SkGlyphID*     fStop;
+
+    SkScalar        fXPos;      // accumulated xpos, returned in next
 };
 
 class SkTextInterceptsIter : SkTextBaseIter {
@@ -51,9 +39,10 @@
         kPosText
     };
 
-    SkTextInterceptsIter(const char text[], size_t length, const SkPaint& paint,
-                         const SkScalar bounds[2], SkScalar x, SkScalar y, TextType textType)
-         : SkTextBaseIter(text, length, paint, false)
+    SkTextInterceptsIter(const SkGlyphID glyphs[], int count, const SkFont& font,
+                         const SkPaint& paint, const SkScalar bounds[2], SkScalar x, SkScalar y,
+                         TextType textType)
+         : SkTextBaseIter(glyphs, count, font, paint)
     {
         fBoundsBase[0] = bounds[0];
         fBoundsBase[1] = bounds[1];