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);
diff --git a/samplecode/SampleTextBox.cpp b/samplecode/SampleTextBox.cpp
index 3b67af4..8c1c66e 100644
--- a/samplecode/SampleTextBox.cpp
+++ b/samplecode/SampleTextBox.cpp
@@ -79,7 +79,7 @@
paint.setColor(fg);
for (int i = 9; i < 24; i += 2) {
- SkTextBlobBuilderRunHandler builder;
+ SkTextBlobBuilderRunHandler builder(gText);
SkFont font(nullptr, SkIntToScalar(i));
font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
diff --git a/src/pdf/SkClusterator.cpp b/src/pdf/SkClusterator.cpp
index 2827810..6a75015 100644
--- a/src/pdf/SkClusterator.cpp
+++ b/src/pdf/SkClusterator.cpp
@@ -30,10 +30,10 @@
, fUtf8Text(run.text().data())
, fGlyphCount(SkToU32(run.glyphsIDs().size()))
, fTextByteLength(SkToU32(run.text().size()))
+ , fReversedChars(fClusters ? is_reversed(fClusters, fGlyphCount) : false)
{
if (fClusters) {
SkASSERT(fUtf8Text && fTextByteLength > 0 && fGlyphCount > 0);
- fReversedChars = is_reversed(fClusters, fGlyphCount);
} else {
SkASSERT(!fUtf8Text && fTextByteLength == 0);
}
diff --git a/src/pdf/SkClusterator.h b/src/pdf/SkClusterator.h
index 40d9994..ec87d4d 100644
--- a/src/pdf/SkClusterator.h
+++ b/src/pdf/SkClusterator.h
@@ -35,12 +35,12 @@
Cluster next();
private:
- const uint32_t* fClusters;
- const char* fUtf8Text;
- uint32_t fGlyphCount;
- uint32_t fTextByteLength;
+ uint32_t const * const fClusters;
+ char const * const fUtf8Text;
+ uint32_t const fGlyphCount;
+ uint32_t const fTextByteLength;
+ bool const fReversedChars;
uint32_t fCurrentGlyphIndex = 0;
- bool fReversedChars = false;
};
diff --git a/src/utils/SkLua.cpp b/src/utils/SkLua.cpp
index a7e978a..a6057c9 100644
--- a/src/utils/SkLua.cpp
+++ b/src/utils/SkLua.cpp
@@ -1882,7 +1882,7 @@
#else
SkFont font;
#endif
- SkTextBlobBuilderRunHandler builder;
+ SkTextBlobBuilderRunHandler builder(text);
SkPoint end = shaper.shape(&builder, font, text, strlen(text), true,
{ bounds.left(), bounds.top() }, bounds.width());
diff --git a/tools/using_skia_and_harfbuzz.cpp b/tools/using_skia_and_harfbuzz.cpp
index b739218..8ca76f2 100644
--- a/tools/using_skia_and_harfbuzz.cpp
+++ b/tools/using_skia_and_harfbuzz.cpp
@@ -139,7 +139,7 @@
}
void WriteLine(const SkShaper& shaper, const char *text, size_t textBytes) {
- SkTextBlobBuilderRunHandler textBlobBuilder;
+ SkTextBlobBuilderRunHandler textBlobBuilder(text);
SkPoint endPoint = shaper.shape(&textBlobBuilder, font, text, textBytes, true,
SkPoint{0, 0},
config->page_width.value - 2*config->left_margin.value);