Expose intercepts on SkFont

Already exposed (on TextBlob), so this makes it available for clients
that may use drawGlyphs directly. (including canvaskit/flutter)

Change-Id: I8b4bd51e13827dc3970d5a6d06f0e0d3031af13c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/408638
Reviewed-by: Julia Lavrova <jlavrova@google.com>
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2021-05-14 09:53:30 -04:00 committed by Skia Commit-Bot
parent c650cc05f8
commit 81e2f9355b
3 changed files with 70 additions and 1 deletions

View File

@ -12,6 +12,8 @@
#include "include/core/SkScalar.h" #include "include/core/SkScalar.h"
#include "include/core/SkTypeface.h" #include "include/core/SkTypeface.h"
#include <vector>
class SkMatrix; class SkMatrix;
class SkPaint; class SkPaint;
class SkPath; class SkPath;
@ -432,6 +434,20 @@ public:
*/ */
void getXPos(const SkGlyphID glyphs[], int count, SkScalar xpos[], SkScalar origin = 0) const; void getXPos(const SkGlyphID glyphs[], int count, SkScalar xpos[], SkScalar origin = 0) const;
/** Returns intervals [start, end] describing lines parallel to the advance that intersect
* with the glyphs.
*
* @param glyphs the glyphs to intersect
* @param count the number of glyphs and positions
* @param pos the position of each glyph
* @param top the top of the line intersecting
* @param bottom the bottom of the line intersecting
@return array of pairs of x values [start, end]. May be empty.
*/
std::vector<SkScalar> getIntercepts(const SkGlyphID glyphs[], int count, const SkPoint pos[],
SkScalar top, SkScalar bottom,
const SkPaint* = nullptr) const;
/** Modifies path to be the outline of the glyph. /** Modifies path to be the outline of the glyph.
If the glyph has an outline, modifies path to be the glyph's outline and returns true. If the glyph has an outline, modifies path to be the glyph's outline and returns true.
The glyph outline may be empty. Degenerate contours in the glyph outline will be skipped. The glyph outline may be empty. Degenerate contours in the glyph outline will be skipped.

View File

@ -99,6 +99,12 @@ protected:
p2.setColor(0xFFFF0000); p2.setColor(0xFFFF0000);
p2.setStrokeWidth(4); p2.setStrokeWidth(4);
p2.setStrokeCap(SkPaint::kSquare_Cap); p2.setStrokeCap(SkPaint::kSquare_Cap);
SkPaint underp;
underp.setStroke(true);
underp.setStrokeWidth(2);
underp.setAntiAlias(true);
underp.setColor(p.getColor());
const SkScalar GAP = 2;
para->visit([&](int, const skia::textlayout::Paragraph::VisitorInfo* info) { para->visit([&](int, const skia::textlayout::Paragraph::VisitorInfo* info) {
if (!info) { if (!info) {
@ -107,6 +113,31 @@ protected:
canvas->drawGlyphs(info->count, info->glyphs, info->positions, info->origin, canvas->drawGlyphs(info->count, info->glyphs, info->positions, info->origin,
info->font, p); info->font, p);
if (fFlags & kUseUnderline) {
// Need to modify positions to roll-in the orign
std::vector<SkPoint> pos;
for (int i = 0; i < info->count; ++i) {
pos.push_back({info->origin.fX + info->positions[i].fX,
info->origin.fY + info->positions[i].fY});
}
const SkScalar X0 = pos[0].fX;
const SkScalar X1 = X0 + info->advanceX;
const SkScalar Y = pos[0].fY;
auto sects = info->font.getIntercepts(info->glyphs, info->count, pos.data(),
Y+1, Y+3);
SkScalar x0 = X0;
for (size_t i = 0; i < sects.size(); i += 2) {
SkScalar x1 = sects[i] - GAP;
if (x0 < x1) {
canvas->drawLine(x0, Y+2, x1, Y+2, underp);
}
x0 = sects[i+1] + GAP;
}
canvas->drawLine(x0, Y+2, X1, Y+2, underp);
}
if (info->utf8Starts && false) { if (info->utf8Starts && false) {
SkString str; SkString str;
for (int i = 0; i < info->count; ++i) { for (int i = 0; i < info->count; ++i) {
@ -176,3 +207,4 @@ DEF_GM(return new ParagraphGM(0);)
DEF_GM(return new ParagraphGM(kTimeLayout);) DEF_GM(return new ParagraphGM(kTimeLayout);)
DEF_GM(return new ParagraphGM(kUseUnderline);) DEF_GM(return new ParagraphGM(kUseUnderline);)
DEF_GM(return new ParagraphGM(kShowVisitor);) DEF_GM(return new ParagraphGM(kShowVisitor);)
DEF_GM(return new ParagraphGM(kShowVisitor | kUseUnderline);)

View File

@ -922,7 +922,6 @@ int get_glyph_run_intercepts(const SkGlyphRun& glyphRun,
int SkTextBlob::getIntercepts(const SkScalar bounds[2], SkScalar intervals[], int SkTextBlob::getIntercepts(const SkScalar bounds[2], SkScalar intervals[],
const SkPaint* paint) const { const SkPaint* paint) const {
SkTLazy<SkPaint> defaultPaint; SkTLazy<SkPaint> defaultPaint;
if (paint == nullptr) { if (paint == nullptr) {
defaultPaint.init(); defaultPaint.init();
@ -944,6 +943,28 @@ int SkTextBlob::getIntercepts(const SkScalar bounds[2], SkScalar intervals[],
return intervalCount; return intervalCount;
} }
std::vector<SkScalar> SkFont::getIntercepts(const SkGlyphID glyphs[], int count,
const SkPoint positions[],
SkScalar top, SkScalar bottom,
const SkPaint* paintPtr) const {
if (count <= 0) {
return std::vector<SkScalar>();
}
const SkPaint paint(paintPtr ? *paintPtr : SkPaint());
const SkScalar bounds[] = {top, bottom};
const SkGlyphRun run(*this,
{positions, size_t(count)}, {glyphs, size_t(count)},
{nullptr, 0}, {nullptr, 0}, {nullptr, 0});
std::vector<SkScalar> result;
result.resize(count * 2); // worst case allocation
int intervalCount = 0;
intervalCount = get_glyph_run_intercepts(run, paint, bounds, result.data(), &intervalCount);
result.resize(intervalCount);
return result;
}
//////// ////////
SkTextBlob::Iter::Iter(const SkTextBlob& blob) { SkTextBlob::Iter::Iter(const SkTextBlob& blob) {