From a32654c13a0f253d3d102e5c614140edad8af248 Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Fri, 4 Oct 2019 10:18:34 -0400 Subject: [PATCH] Simple iterator for textblobs bug: skia:9503 Change-Id: I5b4e2434c6085d048d6d0fc42b2b928439b1066b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/246296 Commit-Queue: Mike Reed Reviewed-by: Mike Klein --- RELEASE_NOTES.txt | 3 +++ include/core/SkTextBlob.h | 24 +++++++++++++++++++++++- src/core/SkTextBlob.cpp | 23 +++++++++++++++++++++++ src/core/SkTextBlobPriv.h | 2 ++ tests/TextBlobTest.cpp | 31 +++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 73e2ba552c..09212880c0 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -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.] diff --git a/include/core/SkTextBlob.h b/include/core/SkTextBlob.h index 2c120d9d7c..2eededd3ce 100644 --- a/include/core/SkTextBlob.h +++ b/include/core/SkTextBlob.h @@ -26,6 +26,9 @@ struct SkDeserialProcs; fonts and text rendering are used by run. */ class SK_API SkTextBlob final : public SkNVRefCnt { +private: + class RunRecord; + public: /** Returns conservative bounding box. Uses SkPaint associated with each glyph to @@ -186,9 +189,28 @@ public: static sk_sp 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; - class RunRecord; enum GlyphPositioning : uint8_t; diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp index aba9689bb9..207e8768d1 100644 --- a/src/core/SkTextBlob.cpp +++ b/src/core/SkTextBlob.cpp @@ -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; +} diff --git a/src/core/SkTextBlobPriv.h b/src/core/SkTextBlobPriv.h index fe4c92e959..5394b50d5d 100644 --- a/src/core/SkTextBlobPriv.h +++ b/src/core/SkTextBlobPriv.h @@ -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); diff --git a/tests/TextBlobTest.cpp b/tests/TextBlobTest.cpp index 351b8ee64f..30728f0cee 100644 --- a/tests/TextBlobTest.cpp +++ b/tests/TextBlobTest.cpp @@ -449,3 +449,34 @@ DEF_TEST(TextBlob_MakeAsDrawText, reporter) { REPORTER_ASSERT(reporter, runs == 1); } + +DEF_TEST(TextBlob_iter, reporter) { + sk_sp 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]); +}