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)
{