add gm calling textblob intercepts with spacing

Bug: skia:
Change-Id: Ibff3d2ee6375ef4db2235a5c3f0714b02bdb3d74
Reviewed-on: https://skia-review.googlesource.com/c/177025
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/gm/texteffects.cpp b/gm/texteffects.cpp
index 49956a9..d5ab92a 100644
--- a/gm/texteffects.cpp
+++ b/gm/texteffects.cpp
@@ -287,3 +287,116 @@
         canvas->translate(0, textSize * 1.3f);
     }
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static sk_sp<SkTextBlob> make_text(const SkFont& font, const SkGlyphID glyphs[], int count) {
+    return SkTextBlob::MakeFromText(glyphs, count * sizeof(SkGlyphID), font,
+                                    kGlyphID_SkTextEncoding);
+}
+
+static sk_sp<SkTextBlob> make_posh(const SkFont& font, const SkGlyphID glyphs[], int count,
+                                   SkScalar spacing) {
+    SkAutoTArray<SkScalar> xpos(count);
+    font.getXPos(glyphs, count, xpos.get());
+    for (int i = 1; i < count; ++i) {
+        xpos[i] += spacing * i;
+    }
+    return SkTextBlob::MakeFromPosTextH(glyphs, count * sizeof(SkGlyphID), xpos.get(), 0, font,
+                                        kGlyphID_SkTextEncoding);
+}
+
+static sk_sp<SkTextBlob> make_pos(const SkFont& font, const SkGlyphID glyphs[], int count,
+                                  SkScalar spacing) {
+    SkAutoTArray<SkPoint> pos(count);
+    font.getPos(glyphs, count, pos.get());
+    for (int i = 1; i < count; ++i) {
+        pos[i].fX += spacing * i;
+    }
+    return SkTextBlob::MakeFromPosText(glyphs, count * sizeof(SkGlyphID), pos.get(), font,
+                                       kGlyphID_SkTextEncoding);
+}
+
+// widen the gaps with a margin (on each side of the gap), elimnating segments that go away
+static int trim_with_halo(SkScalar intervals[], int count, SkScalar margin) {
+    SkASSERT(count > 0 && (count & 1) == 0);
+
+    int n = count;
+    SkScalar* stop = intervals + count;
+    *intervals++ -= margin;
+    while (intervals < stop - 1) {
+        intervals[0] += margin;
+        intervals[1] -= margin;
+        if (intervals[0] >= intervals[1]) { // went away
+            int remaining = stop - intervals - 2;
+            SkASSERT(remaining >= 0 && (remaining & 1) == 1);
+            if (remaining > 0) {
+                memmove(intervals, intervals + 2, remaining * sizeof(SkScalar));
+            }
+            stop -= 2;
+            n -= 2;
+        } else {
+            intervals += 2;
+        }
+    }
+    *intervals += margin;
+    return n;
+}
+
+static void draw_blob_adorned(SkCanvas* canvas, sk_sp<SkTextBlob> blob) {
+    SkPaint paint;
+
+    canvas->drawTextBlob(blob.get(), 0, 0, paint);
+
+    const SkScalar yminmax[] = { 8, 16 };
+    int count = blob->getIntercepts(yminmax, nullptr);
+    if (!count) {
+        return;
+    }
+
+    SkAutoTArray<SkScalar> intervals(count);
+    blob->getIntercepts(yminmax, intervals.get());
+    count = trim_with_halo(intervals.get(), count, SkScalarHalf(yminmax[1] - yminmax[0]) * 1.5f);
+    SkASSERT(count >= 2);
+
+    const SkScalar y = SkScalarAve(yminmax[0], yminmax[1]);
+    SkScalar end = 900;
+    SkPath path;
+    path.moveTo({0, y});
+    for (int i = 0; i < count; i += 2) {
+        path.lineTo(intervals[i], y).moveTo(intervals[i+1], y);
+    }
+    if (intervals[count - 1] < end) {
+        path.lineTo(end, y);
+    }
+
+    paint.setAntiAlias(true);
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setStrokeWidth(yminmax[1] - yminmax[0]);
+    canvas->drawPath(path, paint);
+}
+
+DEF_SIMPLE_GM(textblob_intercepts, canvas, 940, 800) {
+    const char text[] = "Hyjay {worlp}.";
+    const size_t length = strlen(text);
+    SkFont font;
+    font.setTypeface(sk_tool_utils::create_portable_typeface());
+    font.setSize(100);
+    font.setEdging(SkFont::Edging::kAntiAlias);
+    const int count = font.countText(text, length, kUTF8_SkTextEncoding);
+    SkAutoTArray<SkGlyphID> glyphs(count);
+    font.textToGlyphs(text, length, kUTF8_SkTextEncoding, glyphs.get(), count);
+
+    auto b0 = make_text(font, glyphs.get(), count);
+
+    canvas->translate(20, 120);
+    draw_blob_adorned(canvas, b0);
+    for (SkScalar spacing = 0; spacing < 30; spacing += 20) {
+        auto b1 = make_posh(font, glyphs.get(), count, spacing);
+        auto b2 = make_pos( font, glyphs.get(), count, spacing);
+        canvas->translate(0, 150);
+        draw_blob_adorned(canvas, b1);
+        canvas->translate(0, 150);
+        draw_blob_adorned(canvas, b2);
+    }
+}
diff --git a/src/core/SkPaint_text.cpp b/src/core/SkPaint_text.cpp
index 4382592..a82af19 100644
--- a/src/core/SkPaint_text.cpp
+++ b/src/core/SkPaint_text.cpp
@@ -430,12 +430,16 @@
 }
 
 SkTextBaseIter::SkTextBaseIter(const SkGlyphID glyphs[], int count, const SkFont& font,
-                               const SkPaint& paint)
-        : fFont(font), fPaint(paint)
+                               const SkPaint* paint)
+        : fFont(font)
 {
     SkAssertResult(count >= 0);
 
     fFont.setLinearMetrics(true);
+
+    if (paint) {
+        fPaint = *paint;
+    }
     fPaint.setMaskFilter(nullptr);   // don't want this affecting our path-cache lookup
 
     // can't use our canonical size if we need to apply patheffects
@@ -453,14 +457,17 @@
         fScale = SK_Scalar1;
     }
 
+    SkPaint::Style prevStyle = fPaint.getStyle();
+    auto prevPE = fPaint.refPathEffect();
+    auto prevMF = fPaint.refMaskFilter();
     fPaint.setStyle(SkPaint::kFill_Style);
     fPaint.setPathEffect(nullptr);
 
     fCache = SkStrikeCache::FindOrCreateStrikeWithNoDeviceExclusive(fFont, fPaint);
 
-    fPaint.setStyle(paint.getStyle());
-    fPaint.setPathEffect(paint.refPathEffect());
-    fPaint.setMaskFilter(paint.refMaskFilter());    // restore
+    fPaint.setStyle(prevStyle);
+    fPaint.setPathEffect(std::move(prevPE));
+    fPaint.setMaskFilter(std::move(prevMF));
 
     // now compute fXOffset if needed
 
diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp
index df647af..3edfe09 100644
--- a/src/core/SkTextBlob.cpp
+++ b/src/core/SkTextBlob.cpp
@@ -589,7 +589,7 @@
 #include "SkTextToPathIter.h"
 
 template <SkTextInterceptsIter::TextType TextType, typename Func>
-int GetTextIntercepts(const SkFont& font, const SkPaint& paint, const SkGlyphID glyphs[],
+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);
 
@@ -624,7 +624,7 @@
             case SkTextBlobRunIterator::kDefault_Positioning: {
                 SkPoint loc = it.offset();
                 count += GetTextIntercepts<SkTextInterceptsIter::TextType::kText>(
-                          font, *paint, glyphs, glyphCount, bounds, runIntervals, [loc] (int) {
+                          font, paint, glyphs, glyphCount, bounds, runIntervals, [loc] (int) {
                     return loc;
                 });
             } break;
@@ -632,14 +632,14 @@
                 const SkScalar* xpos = it.pos();
                 const SkScalar constY = it.offset().fY;
                 count += GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
-                 font, *paint, glyphs, glyphCount, bounds, runIntervals, [xpos, constY] (int i) {
+                 font, paint, glyphs, glyphCount, bounds, runIntervals, [xpos, constY] (int i) {
                     return SkPoint::Make(xpos[i], constY);
                 });
             } break;
             case SkTextBlobRunIterator::kFull_Positioning: {
                 const SkPoint* pos = reinterpret_cast<const SkPoint*>(it.pos());
                 count += GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
-                             font, *paint, glyphs, glyphCount, bounds, runIntervals, [pos] (int i) {
+                             font, paint, glyphs, glyphCount, bounds, runIntervals, [pos] (int i) {
                     return pos[i];
                 });
             } break;
diff --git a/src/core/SkTextToPathIter.h b/src/core/SkTextToPathIter.h
index 6543543..0b15cce 100644
--- a/src/core/SkTextToPathIter.h
+++ b/src/core/SkTextToPathIter.h
@@ -19,7 +19,7 @@
     SkScalar        getPathScale() const { return fScale; }
 
 protected:
-    SkTextBaseIter(const SkGlyphID glyphs[], int count, const SkFont&, const SkPaint& paint);
+    SkTextBaseIter(const SkGlyphID glyphs[], int count, const SkFont&, const SkPaint*);
 
     SkExclusiveStrikePtr fCache;
     SkFont               fFont;
@@ -40,7 +40,7 @@
     };
 
     SkTextInterceptsIter(const SkGlyphID glyphs[], int count, const SkFont& font,
-                         const SkPaint& paint, const SkScalar bounds[2], SkScalar x, SkScalar y,
+                         const SkPaint* paint, const SkScalar bounds[2], SkScalar x, SkScalar y,
                          TextType textType)
          : SkTextBaseIter(glyphs, count, font, paint)
     {