impl SkFont::getPath

Replacement for SkPaint::getTextPath and getPosTextPath
- only works with glyphIDs
- doesn't try to do positioning
- doesn't force caller to consolidate all the glyphs into one giant path

Much of the time is spent transforming the path from the cache's size to the callers.
Might consider passing the raw path + matrix rather than scaling it for them???

Bug: skia:
Change-Id: Ie13015c61ebe410eaec084282d600338cfccb51a
Reviewed-on: https://skia-review.googlesource.com/c/170881
Reviewed-by: Ben Wagner <bungeman@google.com>
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2018-11-14 08:52:54 -08:00 committed by Skia Commit-Bot
parent f152130ef9
commit 07f93f2999
3 changed files with 110 additions and 4 deletions

View File

@ -8,7 +8,9 @@
#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkChecksum.h"
#include "SkFont.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkString.h"
#include "SkTemplates.h"
@ -139,10 +141,60 @@ protected:
private:
typedef Benchmark INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
DEF_BENCH( return new FontCacheBench(); )
// undefine this to run the efficiency test
//DEF_BENCH( return new FontCacheEfficiency(); )
///////////////////////////////////////////////////////////////////////////////
class FontPathBench : public Benchmark {
SkFont fFont;
uint16_t fGlyphs[100];
SkString fName;
const bool fOneAtATime;
public:
FontPathBench(bool oneAtATime) : fOneAtATime(oneAtATime) {
fName.printf("font-path-%s", oneAtATime ? "loop" : "batch");
}
protected:
const char* onGetName() override {
return fName.c_str();
}
bool isSuitableFor(Backend backend) override {
return backend == kNonRendering_Backend;
}
void onDelayedSetup() override {
fFont.setSize(32);
for (size_t i = 0; i < SK_ARRAY_COUNT(fGlyphs); ++i) {
fGlyphs[i] = i;
}
}
void onDraw(int loops, SkCanvas* canvas) override {
SkPath path;
for (int i = 0; i < loops; ++i) {
if (fOneAtATime) {
for (size_t i = 0; i < SK_ARRAY_COUNT(fGlyphs); ++i) {
fFont.getPath(fGlyphs[i], &path);
}
} else {
fFont.getPaths(fGlyphs, SK_ARRAY_COUNT(fGlyphs),
[](uint16_t, const SkPath* src, void* ctx) {
if (src) {
*static_cast<SkPath*>(ctx) = *src;
}
}, &path);
}
}
}
private:
typedef Benchmark INHERITED;
};
DEF_BENCH( return new FontPathBench(true); )
DEF_BENCH( return new FontPathBench(false); )

View File

@ -16,6 +16,7 @@
#define SK_SUPPORT_LEGACY_FONT_FLAGS
class SkPaint;
class SkPath;
struct SkFontMetrics;
class SK_API SkFont {
@ -152,7 +153,7 @@ public:
return fTypeface->unicharToGlyph(uni);
}
int countText(const void* text, size_t byteLength, SkTextEncoding encoding) {
int countText(const void* text, size_t byteLength, SkTextEncoding encoding) const {
return this->textToGlyphs(text, byteLength, encoding, nullptr, 0);
}
@ -162,6 +163,16 @@ public:
void getWidths(const uint16_t glyphs[], int count, SkScalar widths[],
SkRect bounds[] = nullptr) const;
/**
* Returns true if the glyph has an outline (even if its empty), and sets the path.
* If the glyph does not have an outline (e.g. it is a bitmap), this returns false
* and ignores the path parameter.
*/
bool getPath(uint16_t glyphID, SkPath* path) const;
void getPaths(const uint16_t glyphIDs[], int count,
void (*GlyphPathProc)(uint16_t glyphID, const SkPath* pathOrNull, void* ctx),
void* ctx) const;
SkScalar getMetrics(SkFontMetrics* metrics) const;
SkScalar getSpacing() const { return this->getMetrics(nullptr); }

View File

@ -9,6 +9,7 @@
#include "SkFontPriv.h"
#include "SkGlyphCache.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkScalerContext.h"
#include "SkStrikeCache.h"
#include "SkTo.h"
@ -334,6 +335,48 @@ void SkFont::getWidths(const uint16_t glyphs[], int count, SkScalar widths[], Sk
}
}
void SkFont::getPaths(const uint16_t glyphs[], int count,
void (*proc)(uint16_t, const SkPath*, void*), void* ctx) const {
SkFont font(*this);
SkScalar scale = font.setupForAsPaths(nullptr);
SkAutoDescriptor ad;
SkScalerContextEffects effects;
auto desc = SkScalerContext::CreateDescriptorAndEffectsUsingDefaultPaint(font,
SkSurfaceProps(0, kUnknown_SkPixelGeometry), SkScalerContextFlags::kNone,
SkMatrix::I(), &ad, &effects);
auto typeface = SkFontPriv::GetTypefaceOrDefault(font);
auto exclusive = SkStrikeCache::FindOrCreateStrikeExclusive(*desc, effects, *typeface);
auto cache = exclusive.get();
for (int i = 0; i < count; ++i) {
const SkPath* orig = cache->findPath(cache->getGlyphIDMetrics(glyphs[i]));
if (orig && scale) {
SkPath tmp;
orig->transform(SkMatrix::MakeScale(scale, scale), &tmp);
proc(glyphs[i], &tmp, ctx);
} else {
proc(glyphs[i], orig, ctx);
}
}
}
bool SkFont::getPath(uint16_t glyphID, SkPath* path) const {
struct Pair {
SkPath* fPath;
bool fWasSet;
} pair = { path, false };
this->getPaths(&glyphID, 1, [](uint16_t, const SkPath* orig, void* ctx) {
Pair* pair = static_cast<Pair*>(ctx);
if (orig) {
*pair->fPath = *orig;
pair->fWasSet = true;
}
}, &pair);
return pair.fWasSet;
}
SkScalar SkFont::getMetrics(SkFontMetrics* metrics) const {
SkCanonicalizeFont canon(*this);
const SkFont& font = canon.getFont();