Simple iterator for textblobs

bug: skia:9503

Change-Id: I5b4e2434c6085d048d6d0fc42b2b928439b1066b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/246296
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Reed 2019-10-04 10:18:34 -04:00 committed by Skia Commit-Bot
parent 48de6fdef5
commit a32654c13a
5 changed files with 82 additions and 1 deletions

View File

@ -4,6 +4,9 @@ This file includes a list of high level updates for each milestone release.
* * *
* SkTextBlob::Iter to discover the glyph indices and typefaces in each run
https://skia-review.googlesource.com/246296
Milestone 79
[Insert new notes here.]

View File

@ -26,6 +26,9 @@ struct SkDeserialProcs;
fonts and text rendering are used by run.
*/
class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
private:
class RunRecord;
public:
/** Returns conservative bounding box. Uses SkPaint associated with each glyph to
@ -186,9 +189,28 @@ public:
static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size,
const SkDeserialProcs& procs);
class Iter {
public:
struct Run {
SkTypeface* fTypeface;
int fGlyphCount;
const uint16_t* fGlyphIndices;
};
Iter(const SkTextBlob&);
/**
* Returns true for each "run" inside the textblob, setting the Run fields (if not null).
* If this returns false, there are no more runs, and the Run parameter will be ignored.
*/
bool next(Run*);
private:
const RunRecord* fRunRecord;
};
private:
friend class SkNVRefCnt<SkTextBlob>;
class RunRecord;
enum GlyphPositioning : uint8_t;

View File

@ -919,3 +919,26 @@ int SkTextBlob::getIntercepts(const SkScalar bounds[2], SkScalar intervals[],
return intervalCount;
}
////////
SkTextBlob::Iter::Iter(const SkTextBlob& blob) {
fRunRecord = RunRecord::First(&blob);
}
bool SkTextBlob::Iter::next(Run* rec) {
if (fRunRecord) {
if (rec) {
rec->fTypeface = fRunRecord->font().getTypeface();
rec->fGlyphCount = fRunRecord->glyphCount();
rec->fGlyphIndices = fRunRecord->glyphBuffer();
}
if (fRunRecord->isLastRun()) {
fRunRecord = nullptr;
} else {
fRunRecord = RunRecord::Next(fRunRecord);
}
return true;
}
return false;
}

View File

@ -150,6 +150,8 @@ public:
: nullptr;
}
bool isLastRun() const { return SkToBool(fFlags & kLast_Flag); }
static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
SkTextBlob::GlyphPositioning positioning,
SkSafeMath* safe);

View File

@ -449,3 +449,34 @@ DEF_TEST(TextBlob_MakeAsDrawText, reporter) {
REPORTER_ASSERT(reporter, runs == 1);
}
DEF_TEST(TextBlob_iter, reporter) {
sk_sp<SkTypeface> tf = SkTypeface::MakeFromName(nullptr, SkFontStyle::BoldItalic());
SkTextBlobBuilder builder;
add_run(&builder, "Hello", 10, 20, nullptr);
add_run(&builder, "World", 10, 40, tf);
auto blob = builder.make();
SkTextBlob::Iter::Run expected[] = {
{ nullptr, 5, nullptr },
{ tf.get(), 5, nullptr },
};
SkTextBlob::Iter iter(*blob);
SkTextBlob::Iter::Run run;
for (auto exp : expected) {
REPORTER_ASSERT(reporter, iter.next(&run));
REPORTER_ASSERT(reporter, run.fTypeface == exp.fTypeface);
REPORTER_ASSERT(reporter, run.fGlyphCount == exp.fGlyphCount);
for (int i = 0; i < run.fGlyphCount; ++i) {
REPORTER_ASSERT(reporter, run.fGlyphIndices[i] != 0);
}
}
REPORTER_ASSERT(reporter, !iter.next(&run)); // we're done
SkTextBlob::Iter iter2(*blob);
REPORTER_ASSERT(reporter, iter2.next(&run));
// Hello should have the same glyph repeated for the 'l'
REPORTER_ASSERT(reporter, run.fGlyphIndices[2] == run.fGlyphIndices[3]);
}