Round unresolved font blocks to grapheme edges

I had to stage the change with SK_PARAGRAPH_GRAPHEME_EDGES because of
some google3 tests.
Bug: skia:11196

Change-Id: Ic45e43e6c69f649c6bc0fedcc6f303891139b85e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/359566
Commit-Queue: Julia Lavrova <jlavrova@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
This commit is contained in:
Julia Lavrova 2021-01-21 17:06:44 -05:00 committed by Skia Commit-Bot
parent d6b26e5f06
commit d20a1097e8
4 changed files with 177 additions and 25 deletions

View File

@ -3268,6 +3268,116 @@ private:
using INHERITED = Sample;
};
class ParagraphView54 : public ParagraphView_Base {
protected:
SkString name() override { return SkString("Paragraph54"); }
void onDrawContent(SkCanvas* canvas) override {
canvas->drawColor(SK_ColorWHITE);
//std::string text("يَهْدِيْكُمُ اللَّهُ وَيُصْلِحُ بَالَكُمُ");
//auto text = "ד👨‍👩‍👧‍👦😀";
auto text = "👨‍👩‍👧‍👦😀";
//auto fontCollection = sk_make_sp<FontCollection>();
auto fontCollection = getFontCollection();
fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
fontCollection->enableFontFallback();
//fontCollection->disableFontFallback();
ParagraphStyle paragraph_style;
//paragraph_style.setTextDirection(TextDirection::kRtl);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
text_style.setFontSize(36);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text);
auto paragraph = builder.Build();
paragraph->layout(/*360*/width());
paragraph->paint(canvas, 0, 0);
}
private:
using INHERITED = Sample;
};
class ParagraphView55 : public ParagraphView_Base {
protected:
SkString name() override { return SkString("Paragraph55"); }
void onDrawContent(SkCanvas* canvas) override {
canvas->drawColor(SK_ColorWHITE);
std::string text("يَهْدِيْكُمُ اللَّهُ وَيُصْلِحُ بَالَكُمُ");
//auto fontCollection = sk_make_sp<FontCollection>();
//fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
//fontCollection->enableFontFallback();
auto fontCollection = getFontCollection();
fontCollection->disableFontFallback();
ParagraphStyle paragraph_style;
paragraph_style.setTextDirection(TextDirection::kRtl);
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
text_style.setFontSize(64);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text.substr(0, 10).data());
text_style.setColor(SK_ColorRED);
builder.pushStyle(text_style);
builder.addText(text.substr(10, 20).data());
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text.substr(30, 50).data());
auto paragraph = builder.Build();
paragraph->layout(/*360*/width());
paragraph->paint(canvas, 0, 0);
}
private:
using INHERITED = Sample;
};
class ParagraphView56 : public ParagraphView_Base {
protected:
SkString name() override { return SkString("Paragraph56"); }
void onDrawContent(SkCanvas* canvas) override {
canvas->drawColor(SK_ColorWHITE);
auto text = "BAM BAM BAM by Jade Baraldo\n"
"Now on Top 100 Music Videos United States";
auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false);
fontCollection->addFontFromFile("music/Roboto-Regular.ttf", "roboto");
fontCollection->addFontFromFile("music/NotoSansCJK-Regular.ttc", "noto");
fontCollection->addFontFromFile("music/NotoColorEmoji.ttf", "emoji");
ParagraphStyle paragraph_style;
ParagraphBuilderImpl builder(paragraph_style, fontCollection);
TextStyle text_style;
//text_style.setFontFamilies({SkString("Noto Naskh Arabic")});
text_style.setFontFamilies({SkString("roboto"),
SkString("noto"),
SkString("emoji")});
text_style.setFontSize(20);
text_style.setColor(SK_ColorBLACK);
builder.pushStyle(text_style);
builder.addText(text);
auto paragraph = builder.Build();
paragraph->layout(width());
paragraph->paint(canvas, 0, 0);
}
private:
using INHERITED = Sample;
};
} // namespace
//////////////////////////////////////////////////////////////////////////////
@ -3322,3 +3432,6 @@ DEF_SAMPLE(return new ParagraphView50();)
DEF_SAMPLE(return new ParagraphView51();)
DEF_SAMPLE(return new ParagraphView52();)
DEF_SAMPLE(return new ParagraphView53();)
DEF_SAMPLE(return new ParagraphView54();)
DEF_SAMPLE(return new ParagraphView55();)
DEF_SAMPLE(return new ParagraphView56();)

View File

@ -19,7 +19,12 @@ void OneLineShaper::commitRunBuffer(const RunInfo&) {
fCurrentRun->commit();
auto oldUnresolvedCount = fUnresolvedBlocks.size();
/*
SkDebugf("Run [%d:%d)\n", fCurrentRun->fTextRange.start, fCurrentRun->fTextRange.end);
for (size_t i = 0; i < fCurrentRun->size(); ++i) {
SkDebugf("[%d] %d %d %f\n", i, fCurrentRun->fGlyphs[i], fCurrentRun->fClusterIndexes[i], fCurrentRun->fPositions[i].fX);
}
*/
// Find all unresolved blocks
sortOutGlyphs([&](GlyphRange block){
if (block.width() == 0) {
@ -291,6 +296,60 @@ void OneLineShaper::addUnresolvedWithRun(GlyphRange glyphRange) {
// Glue whitespaces to the next/prev unresolved blocks
// (so we don't have chinese text with english whitespaces broken into millions of tiny runs)
#ifndef SK_PARAGRAPH_GRAPHEME_EDGES
void OneLineShaper::sortOutGlyphs(std::function<void(GlyphRange)>&& sortOutUnresolvedBLock) {
size_t unresolvedGlyphs = 0;
GlyphRange block = EMPTY_RANGE;
bool graphemeResolved = false;
TextIndex graphemeStart = EMPTY_INDEX;
for (size_t i = 0; i < fCurrentRun->size(); ++i) {
ClusterIndex ci = clusterIndex(i);
// Removing all pretty optimizations for whitespaces
// because they get in a way of grapheme rounding
// Inspect the glyph
auto glyph = fCurrentRun->fGlyphs[i];
GraphemeIndex gi = fParagraph->findPreviousGraphemeBoundary(ci);
if ((fCurrentRun->leftToRight() ? gi > graphemeStart : gi < graphemeStart) || graphemeStart == EMPTY_INDEX) {
// We only count glyph resolved if all the glyphs in its grapheme are resolved
graphemeResolved = glyph != 0;
graphemeStart = gi;
} else if (glyph == 0) {
// Found unresolved glyph - the entire grapheme is unresolved now
graphemeResolved = false;
}
if (!graphemeResolved) { // Unresolved glyph and not control codepoint
++unresolvedGlyphs;
if (block.start == EMPTY_INDEX) {
// Start new unresolved block
block.start = i;
block.end = EMPTY_INDEX;
} else {
// Keep skipping unresolved block
}
} else { // Resolved glyph or control codepoint
if (block.start == EMPTY_INDEX) {
// Keep skipping resolved code points
} else {
// This is the end of unresolved block
block.end = i;
sortOutUnresolvedBLock(block);
block = EMPTY_RANGE;
}
}
}
// One last block could have been left
if (block.start != EMPTY_INDEX) {
block.end = fCurrentRun->size();
sortOutUnresolvedBLock(block);
}
}
#else
void OneLineShaper::sortOutGlyphs(std::function<void(GlyphRange)>&& sortOutUnresolvedBLock) {
auto text = fCurrentRun->fOwner->text();
@ -353,6 +412,7 @@ void OneLineShaper::sortOutGlyphs(std::function<void(GlyphRange)>&& sortOutUnres
sortOutUnresolvedBLock(block);
}
}
#endif
void OneLineShaper::iterateThroughFontStyles(TextRange textRange,
SkSpan<Block> styleSpan,

View File

@ -45,7 +45,6 @@
struct GrContextOptions;
#define VeryLongCanvasWidth 1000000
#define TestCanvasWidth 1000
#define TestCanvasHeight 600
@ -1239,11 +1238,7 @@ DEF_TEST(SkParagraph_HeightOverrideParagraph, reporter) {
paragraph->layout(550);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
#ifdef SK_PARAGRAPH_LIBTXT_SPACES_RESOLUTION
REPORTER_ASSERT(reporter, impl->runs().size() == 5);
#else
REPORTER_ASSERT(reporter, impl->runs().size() == 4);
#endif
REPORTER_ASSERT(reporter, impl->styles().size() == 1); // paragraph style does not count
REPORTER_ASSERT(reporter, impl->styles()[0].fStyle.equals(text_style));
@ -3990,13 +3985,8 @@ DEF_TEST(SkParagraph_FontFallbackParagraph, reporter) {
paragraph->layout(TestCanvasWidth);
paragraph->paint(canvas.get(), 10.0, 15.0);
#ifdef SK_PARAGRAPH_LIBTXT_SPACES_RESOLUTION
size_t spaceRun = 1;
REPORTER_ASSERT(reporter, paragraph->unresolvedGlyphs() == 2); // From the text1 ("字典" - excluding the last space)
#else
size_t spaceRun = 0;
REPORTER_ASSERT(reporter, paragraph->unresolvedGlyphs() == 3); // From the text1 ("字典 " - including the last space)
#endif
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
@ -4009,9 +3999,7 @@ DEF_TEST(SkParagraph_FontFallbackParagraph, reporter) {
// [Apple + Han] 5, 6
auto robotoAdvance = impl->runs()[0].advance().fX +
impl->runs()[1].advance().fX;
#ifdef SK_PARAGRAPH_LIBTXT_SPACES_RESOLUTION
robotoAdvance += impl->runs()[2].advance().fX;
#endif
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(robotoAdvance, 64.199f, EPSILON50));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(impl->runs()[2 + spaceRun].advance().fX, 139.125f, EPSILON100));
@ -5503,11 +5491,7 @@ DEF_TEST(SkParagraph_FontResolutionInRTL, reporter) {
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
#ifdef SK_PARAGRAPH_LIBTXT_SPACES_RESOLUTION
REPORTER_ASSERT(reporter, impl->runs().size() == (10 + 11));
#else
REPORTER_ASSERT(reporter, impl->runs().size() == 1);
#endif
}
DEF_TEST(SkParagraph_FontResolutionInLTR, reporter) {
@ -5534,20 +5518,12 @@ DEF_TEST(SkParagraph_FontResolutionInLTR, reporter) {
paragraph->paint(canvas.get(), 0, 0);
auto impl = static_cast<ParagraphImpl*>(paragraph.get());
#ifdef SK_PARAGRAPH_LIBTXT_SPACES_RESOLUTION
REPORTER_ASSERT(reporter, impl->runs().size() == 5);
REPORTER_ASSERT(reporter, impl->runs()[0].textRange().width() == 4); // "abc "
REPORTER_ASSERT(reporter, impl->runs()[1].textRange().width() == 2); // "{unresolved}"
REPORTER_ASSERT(reporter, impl->runs()[2].textRange().width() == 1); // " "
REPORTER_ASSERT(reporter, impl->runs()[3].textRange().width() == 2); // "{unresolved}"
REPORTER_ASSERT(reporter, impl->runs()[4].textRange().width() == 4); // " def"
#else
REPORTER_ASSERT(reporter, impl->runs().size() == 3);
REPORTER_ASSERT(reporter, impl->runs()[0].textRange().width() == 4); // "abc "
REPORTER_ASSERT(reporter, impl->runs()[1].textRange().width() == 5); // "{unresolved} {unresolved}"
REPORTER_ASSERT(reporter, impl->runs()[2].textRange().width() == 4); // " def"
#endif
}
DEF_TEST(SkParagraph_Intrinsic, reporter) {
@ -5818,3 +5794,5 @@ DEF_TEST(SkParagraph_PlaceholderWidth, reporter) {
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(len1, 300.0f));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(len2, 250.0f));
}
// "\u05D3\u{1F468}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F466}\uD83D\uDE00"

View File

@ -723,6 +723,7 @@ def base_defines(os_conditions):
# Google3 probably doesn't want this feature yet
"SK_DISABLE_REDUCE_OPLIST_SPLITTING",
# Staging flags for API changes
"SK_PARAGRAPH_GRAPHEME_EDGES",
# Should remove after we update golden images
"SK_WEBP_ENCODER_USE_DEFAULT_METHOD",
# Experiment to diagnose image diffs in Google3