Skip to content

Commit 058edef

Browse files
authored
Fix LibTxt/minikin text shifiting when breaking into multiple runs (flutter#6184)
1 parent 5f61056 commit 058edef

File tree

4 files changed

+90
-9
lines changed

4 files changed

+90
-9
lines changed

third_party/txt/src/minikin/Layout.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,9 @@ void Layout::appendLayout(Layout* src, size_t start, float extraAdvance) {
11321132
int font_ix = findFace(src->mFaces[i], NULL);
11331133
fontMap[i] = font_ix;
11341134
}
1135-
int x0 = mAdvance;
1135+
// LibTxt: Changed x0 from int to float to prevent rounding that causes text
1136+
// jitter.
1137+
float x0 = mAdvance;
11361138
for (size_t i = 0; i < src->mGlyphs.size(); i++) {
11371139
LayoutGlyph& srcGlyph = src->mGlyphs[i];
11381140
int font_ix = fontMap[srcGlyph.font_ix];

third_party/txt/src/txt/paint_record.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class PaintRecord {
6363

6464
size_t line() const { return line_; }
6565

66-
size_t GetRunWidth() const { return run_width_; }
66+
double GetRunWidth() const { return run_width_; }
6767

6868
private:
6969
TextStyle style_;

third_party/txt/src/txt/paragraph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ class Paragraph {
184184
FRIEND_TEST(ParagraphTest, HyphenBreakParagraph);
185185
FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph);
186186
FRIEND_TEST(ParagraphTest, Ellipsize);
187+
FRIEND_TEST(ParagraphTest, UnderlineShiftParagraph);
187188

188189
// Starting data to layout.
189190
std::vector<uint16_t> text_;

third_party/txt/tests/paragraph_unittests.cc

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
10071007
EXPECT_EQ(boxes.size(), 1ull);
10081008
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 56.835938);
10091009
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1010-
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 177.44922);
1010+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 177.97266);
10111011
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
10121012

10131013
paint.setColor(SK_ColorGREEN);
@@ -1016,9 +1016,9 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
10161016
GetCanvas()->drawRect(boxes[i].rect, paint);
10171017
}
10181018
EXPECT_EQ(boxes.size(), 1ull);
1019-
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 177);
1019+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 177.97266);
10201020
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1021-
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 506.08984);
1021+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 507.02344);
10221022
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
10231023

10241024
paint.setColor(SK_ColorRED);
@@ -1027,9 +1027,9 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
10271027
GetCanvas()->drawRect(boxes[i].rect, paint);
10281028
}
10291029
EXPECT_EQ(boxes.size(), 4ull);
1030-
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 210.83594);
1030+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 211.375);
10311031
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
1032-
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 463.44922);
1032+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 463.61719);
10331033
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
10341034

10351035
// TODO(garyq): The following set of vals are definetly wrong and
@@ -1045,9 +1045,9 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
10451045
GetCanvas()->drawRect(boxes[i].rect, paint);
10461046
}
10471047
EXPECT_EQ(boxes.size(), 1ull);
1048-
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 449.25391);
1048+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 450.1875);
10491049
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1050-
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 519.44922);
1050+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 519.47266);
10511051
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
10521052

10531053
paint.setColor(SK_ColorRED);
@@ -1569,4 +1569,82 @@ TEST_F(ParagraphTest, Ellipsize) {
15691569
ASSERT_EQ(paragraph->records_.size(), 1ull);
15701570
}
15711571

1572+
// Test for shifting when identical runs of text are built as multiple runs.
1573+
TEST_F(ParagraphTest, UnderlineShiftParagraph) {
1574+
const char* text1 = "fluttser ";
1575+
auto icu_text1 = icu::UnicodeString::fromUTF8(text1);
1576+
std::u16string u16_text1(icu_text1.getBuffer(),
1577+
icu_text1.getBuffer() + icu_text1.length());
1578+
const char* text2 = "mdje";
1579+
auto icu_text2 = icu::UnicodeString::fromUTF8(text2);
1580+
std::u16string u16_text2(icu_text2.getBuffer(),
1581+
icu_text2.getBuffer() + icu_text2.length());
1582+
const char* text3 = "fluttser mdje";
1583+
auto icu_text3 = icu::UnicodeString::fromUTF8(text3);
1584+
std::u16string u16_text3(icu_text3.getBuffer(),
1585+
icu_text3.getBuffer() + icu_text3.length());
1586+
1587+
// Construct multi-run paragraph.
1588+
txt::ParagraphStyle paragraph_style;
1589+
paragraph_style.max_lines = 2;
1590+
paragraph_style.text_align = TextAlign::left;
1591+
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
1592+
1593+
txt::TextStyle text_style1;
1594+
text_style1.color = SK_ColorBLACK;
1595+
text_style1.font_family = "Roboto";
1596+
builder.PushStyle(text_style1);
1597+
1598+
builder.AddText(u16_text1);
1599+
1600+
txt::TextStyle text_style2;
1601+
text_style2.color = SK_ColorBLACK;
1602+
text_style2.font_family = "Roboto";
1603+
text_style2.decoration = TextDecoration::kUnderline;
1604+
text_style2.decoration_color = SK_ColorBLACK;
1605+
builder.PushStyle(text_style2);
1606+
1607+
builder.AddText(u16_text2);
1608+
1609+
builder.Pop();
1610+
1611+
// Construct single run paragraph.
1612+
txt::ParagraphBuilder builder2(paragraph_style, GetTestFontCollection());
1613+
1614+
builder2.PushStyle(text_style1);
1615+
1616+
builder2.AddText(u16_text3);
1617+
1618+
builder2.Pop();
1619+
1620+
// Build multi-run paragraph
1621+
auto paragraph = builder.Build();
1622+
paragraph->Layout(GetTestCanvasWidth());
1623+
1624+
paragraph->Paint(GetCanvas(), 0, 0);
1625+
1626+
// Build single-run paragraph
1627+
auto paragraph2 = builder2.Build();
1628+
paragraph2->Layout(GetTestCanvasWidth());
1629+
1630+
paragraph2->Paint(GetCanvas(), 0, 25);
1631+
1632+
ASSERT_TRUE(Snapshot());
1633+
1634+
ASSERT_EQ(paragraph->records_[0].GetRunWidth() +
1635+
paragraph->records_[1].GetRunWidth(),
1636+
paragraph2->records_[0].GetRunWidth());
1637+
1638+
auto rects1 = paragraph->GetRectsForRange(0, 12);
1639+
auto rects2 = paragraph2->GetRectsForRange(0, 12);
1640+
1641+
for (size_t i = 0; i < 12; ++i) {
1642+
auto r1 = GetCoordinatesForGlyphPosition(*paragraph, i);
1643+
auto r2 = GetCoordinatesForGlyphPosition(*paragraph2, i);
1644+
1645+
ASSERT_EQ(r1.fLeft, r2.fLeft);
1646+
ASSERT_EQ(r1.fRight, r2.fRight);
1647+
}
1648+
}
1649+
15721650
} // namespace txt

0 commit comments

Comments
 (0)