Fix cluster reporting from shaper.
Bug: skia:8420
Change-Id: I7eea8c6b3af2153a1ac1189782fc6cbaaf9ee5c6
Reviewed-on: https://skia-review.googlesource.com/c/190821
Reviewed-by: Hal Canary <halcanary@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Ben Wagner <bungeman@google.com>
diff --git a/modules/skottie/src/SkottieAdapter.cpp b/modules/skottie/src/SkottieAdapter.cpp
index 1daac2b..9c04b9f 100644
--- a/modules/skottie/src/SkottieAdapter.cpp
+++ b/modules/skottie/src/SkottieAdapter.cpp
@@ -331,7 +331,7 @@
: fAlignFactor(AlignFactor(align)) {}
Buffer newRunBuffer(const RunInfo& info, const SkFont& font, int glyphCount,
- int utf8textCount) override {
+ SkSpan<const char> utf8) override {
fPendingLineAdvance += info.fAdvance;
auto& run = fPendingLineRuns.emplace_back(font, info, glyphCount);
@@ -340,10 +340,11 @@
run.fGlyphs .data(),
run.fPositions.data(),
nullptr,
- nullptr,
};
}
+ void commitRun() override { }
+
void commitLine() override {
SkScalar line_spacing = 0;
diff --git a/modules/skshaper/include/SkShaper.h b/modules/skshaper/include/SkShaper.h
index 06ffe68..a6fa72e 100644
--- a/modules/skshaper/include/SkShaper.h
+++ b/modules/skshaper/include/SkShaper.h
@@ -11,6 +11,7 @@
#include <memory>
#include "SkPoint.h"
+#include "SkSpan.h"
#include "SkTextBlob.h"
#include "SkTypeface.h"
@@ -41,14 +42,15 @@
struct Buffer {
SkGlyphID* glyphs; // required
SkPoint* positions; // required
- char* utf8text; // optional
uint32_t* clusters; // optional
};
// Callback per glyph run.
virtual Buffer newRunBuffer(const RunInfo&, const SkFont&, int glyphCount,
- int utf8textCount) = 0;
+ SkSpan<const char> utf8) = 0;
+ // Called after run information is filled out.
+ virtual void commitRun() = 0;
// Callback per line.
virtual void commitLine() = 0;
};
@@ -75,14 +77,19 @@
*/
class SkTextBlobBuilderRunHandler final : public SkShaper::RunHandler {
public:
+ SkTextBlobBuilderRunHandler(const char* utf8Text) : fUtf8Text(utf8Text) {}
sk_sp<SkTextBlob> makeBlob();
- SkShaper::RunHandler::Buffer newRunBuffer(const RunInfo&, const SkFont&, int, int) override;
-
+ SkShaper::RunHandler::Buffer newRunBuffer(const RunInfo&, const SkFont&, int, SkSpan<const char>) override;
+ void commitRun() override;
void commitLine() override {}
private:
SkTextBlobBuilder fBuilder;
+ char const * const fUtf8Text;
+ uint32_t* fClusters;
+ int fClusterOffset;
+ int fGlyphCount;
};
#endif // SkShaper_DEFINED
diff --git a/modules/skshaper/src/SkShaper.cpp b/modules/skshaper/src/SkShaper.cpp
index e08b7b3..1dd8c5c 100644
--- a/modules/skshaper/src/SkShaper.cpp
+++ b/modules/skshaper/src/SkShaper.cpp
@@ -6,21 +6,33 @@
*/
#include "SkShaper.h"
-
+#include "SkSpan.h"
#include "SkTextBlobPriv.h"
SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::newRunBuffer(const RunInfo&,
const SkFont& font,
int glyphCount,
- int textCount) {
+ SkSpan<const char> utf8) {
const auto& runBuffer = SkTextBlobBuilderPriv::AllocRunTextPos(&fBuilder, font, glyphCount,
- textCount, SkString());
+ utf8.size(), SkString());
+ if (runBuffer.utf8text && fUtf8Text) {
+ memcpy(runBuffer.utf8text, utf8.data(), utf8.size());
+ }
+ fClusters = runBuffer.clusters;
+ fGlyphCount = glyphCount;
+ fClusterOffset = utf8.data() - fUtf8Text;
+
return { runBuffer.glyphs,
runBuffer.points(),
- runBuffer.utf8text,
runBuffer.clusters };
}
+void SkTextBlobBuilderRunHandler::commitRun() {
+ for (int i = 0; i < fGlyphCount; ++i) {
+ fClusters[i] -= fClusterOffset;
+ }
+}
+
sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() {
return fBuilder.make();
}
diff --git a/modules/skshaper/src/SkShaper_harfbuzz.cpp b/modules/skshaper/src/SkShaper_harfbuzz.cpp
index 57f3df6..22a53a6 100644
--- a/modules/skshaper/src/SkShaper_harfbuzz.cpp
+++ b/modules/skshaper/src/SkShaper_harfbuzz.cpp
@@ -15,6 +15,7 @@
#include "SkRefCnt.h"
#include "SkScalar.h"
#include "SkShaper.h"
+#include "SkSpan.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkTArray.h"
@@ -455,18 +456,17 @@
bool fUnsafeToBreak;
};
struct ShapedRun {
- ShapedRun(const char* utf8Start, const char* utf8End, int numGlyphs, const SkFont& font,
- UBiDiLevel level, std::unique_ptr<ShapedGlyph[]> glyphs)
- : fUtf8Start(utf8Start), fUtf8End(utf8End), fNumGlyphs(numGlyphs), fFont(font)
- , fLevel(level), fGlyphs(std::move(glyphs))
+ ShapedRun(SkSpan<const char> utf8, const SkFont& font, UBiDiLevel level,
+ std::unique_ptr<ShapedGlyph[]> glyphs, int numGlyphs)
+ : fUtf8(utf8), fFont(font), fLevel(level)
+ , fGlyphs(std::move(glyphs)), fNumGlyphs(numGlyphs)
{}
- const char* fUtf8Start;
- const char* fUtf8End;
- int fNumGlyphs;
+ SkSpan<const char> fUtf8;
SkFont fFont;
UBiDiLevel fLevel;
std::unique_ptr<ShapedGlyph[]> fGlyphs;
+ int fNumGlyphs;
SkVector fAdvance = { 0, 0 };
};
struct ShapedLine {
@@ -481,16 +481,12 @@
static void append(SkShaper::RunHandler* handler, const SkShaper::RunHandler::RunInfo& runInfo,
const ShapedRun& run, int start, int end,
SkPoint* p) {
- unsigned len = end - start;
+ const unsigned len = end - start;
- const auto buffer = handler->newRunBuffer(runInfo, run.fFont, len, run.fUtf8End - run.fUtf8Start);
+ const auto buffer = handler->newRunBuffer(runInfo, run.fFont, len, run.fUtf8);
SkASSERT(buffer.glyphs);
SkASSERT(buffer.positions);
- if (buffer.utf8text) {
- memcpy(buffer.utf8text, run.fUtf8Start, run.fUtf8End - run.fUtf8Start);
- }
-
for (unsigned i = 0; i < len; i++) {
// Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
@@ -502,6 +498,7 @@
p->fX += glyph.fAdvance.fX;
p->fY += glyph.fAdvance.fY;
}
+ handler->commitRun();
}
static void emit(const ShapedLine& line, SkShaper::RunHandler* handler,
@@ -747,7 +744,7 @@
utf8Start = utf8End;
utf8End = runSegmenter.endOfCurrentRun();
- ShapedRun model(nullptr, nullptr, 0, SkFont(), 0, nullptr);
+ ShapedRun model(SkSpan<const char>(), SkFont(), 0, nullptr, 0);
bool modelNeedsRegenerated = true;
int modelOffset = 0;
@@ -805,7 +802,7 @@
}
}
- ShapedRun best(nullptr, nullptr, 0, SkFont(), 0, nullptr);
+ ShapedRun best(SkSpan<const char>(), SkFont(), 0, nullptr, 0);
best.fAdvance = { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity };
SkScalar widthLeft = width - line.fAdvance.fX;
@@ -817,15 +814,14 @@
// TODO: adjust breakIteratorCurrent by ignorable whitespace
ShapedRun candidate = modelText[breakIteratorCurrent + modelTextOffset].glyphLen
- ? ShapedRun(utf8Start, utf8Start + breakIteratorCurrent,
- modelText[breakIteratorCurrent + modelTextOffset].glyphLen - modelOffset,
- *font->currentFont(),
- bidi->currentLevel(),
- std::unique_ptr<ShapedGlyph[]>())
+ ? ShapedRun(SkSpan<const char>(utf8Start, breakIteratorCurrent),
+ *font->currentFont(), bidi->currentLevel(),
+ std::unique_ptr<ShapedGlyph[]>(),
+ modelText[breakIteratorCurrent + modelTextOffset].glyphLen - modelOffset)
: shape(utf8, utf8Bytes,
utf8Start, utf8Start + breakIteratorCurrent,
bidi, language, script, font);
- if (!candidate.fUtf8Start) {
+ if (!candidate.fUtf8.data()) {
//report error
return point;
}
@@ -834,10 +830,10 @@
}
auto score = [widthLeft](const ShapedRun& run) -> SkScalar {
if (run.fAdvance.fX < widthLeft) {
- if (run.fUtf8Start == nullptr) {
+ if (run.fUtf8.data() == nullptr) {
return SK_ScalarNegativeInfinity;
} else {
- return run.fUtf8End - run.fUtf8Start;
+ return run.fUtf8.size();
}
} else {
return widthLeft - run.fAdvance.fX;
@@ -859,12 +855,12 @@
memcpy(best.fGlyphs.get(), model.fGlyphs.get() + modelOffset,
best.fNumGlyphs * sizeof(ShapedGlyph));
modelOffset += best.fNumGlyphs;
- modelTextOffset += best.fUtf8End - best.fUtf8Start;
+ modelTextOffset += best.fUtf8.size();
modelTextAdvanceOffset += best.fAdvance;
} else {
modelNeedsRegenerated = true;
}
- utf8Start = best.fUtf8End;
+ utf8Start = best.fUtf8.end();
line.fAdvance += best.fAdvance;
line.runs.emplace_back(std::move(best));
@@ -1115,7 +1111,7 @@
const ScriptRunIterator* script,
const FontRunIterator* font) const
{
- ShapedRun run(nullptr, nullptr, 0, SkFont(), 0, nullptr);
+ ShapedRun run(SkSpan<const char>(), SkFont(), 0, nullptr, 0);
hb_buffer_t* buffer = fBuffer.get();
SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
@@ -1173,9 +1169,9 @@
return run;
}
- run = ShapedRun(utf8Start, utf8End, len, *font->currentFont(),
- bidi->currentLevel(),
- std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]));
+ run = ShapedRun(SkSpan<const char>(utf8Start, utf8runLength),
+ *font->currentFont(), bidi->currentLevel(),
+ std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]), len);
int scaleX, scaleY;
hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
double textSizeY = run.fFont.getSize() / scaleY;
diff --git a/modules/skshaper/src/SkShaper_primitive.cpp b/modules/skshaper/src/SkShaper_primitive.cpp
index 8980932..4b371c0 100644
--- a/modules/skshaper/src/SkShaper_primitive.cpp
+++ b/modules/skshaper/src/SkShaper_primitive.cpp
@@ -58,15 +58,12 @@
metrics.fDescent,
metrics.fLeading,
};
- const auto buffer = handler->newRunBuffer(info, font, glyphCount, textBytes);
+ const auto buffer = handler->newRunBuffer(info, font, glyphCount,
+ SkSpan<const char>(utf8text, textBytes));
SkAssertResult(font.textToGlyphs(utf8text, textBytes, SkTextEncoding::kUTF8, buffer.glyphs,
glyphCount) == glyphCount);
font.getPos(buffer.glyphs, glyphCount, buffer.positions, point);
- if (buffer.utf8text) {
- memcpy(buffer.utf8text, utf8text, textBytes);
- }
-
if (buffer.clusters) {
const char* txtPtr = utf8text;
for (int i = 0; i < glyphCount; ++i) {
@@ -76,7 +73,7 @@
SkASSERT(txtPtr <= utf8text + textBytes);
}
}
-
+ handler->commitRun();
handler->commitLine();
return point + SkVector::Make(0, metrics.fDescent + metrics.fLeading);