Skip to content

Commit 25c6c1b

Browse files
authored
Add empty metrics to account for truncated whitespace for GetRectsForRange. (flutter#7164)
1 parent 9611d74 commit 25c6c1b

File tree

2 files changed

+256
-4
lines changed

2 files changed

+256
-4
lines changed

third_party/txt/src/txt/paragraph.cc

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -479,10 +479,6 @@ void Paragraph::Layout(double width, bool force) {
479479
}
480480
}
481481

482-
// TODO(garyq): Make GetRectsForRange return a zero-width box for the
483-
// excluded whitespace such that the caret placement is correct regardless
484-
// of the index being whitespace or not.
485-
486482
// Exclude trailing whitespace from right and center-justified lines so the
487483
// last visible character in the line will be flush with the right margin.
488484
size_t line_end_index =
@@ -740,6 +736,23 @@ void Paragraph::Layout(double width, bool force) {
740736
code_unit_runs_.insert(code_unit_runs_.end(), line_code_unit_runs.begin(),
741737
line_code_unit_runs.end());
742738

739+
// Add extra empty metrics for skipped whitespace at line end. This allows
740+
// GetRectsForRange to properly draw empty rects at the ends of lines with
741+
// truncated whitespace.
742+
if (line_end_index < line_range.end) {
743+
std::vector<GlyphPosition> empty_glyph_positions;
744+
double end_x = line_code_unit_runs.back().positions.back().x_pos.end;
745+
for (size_t index = line_end_index; index < line_range.end; ++index) {
746+
empty_glyph_positions.emplace_back(end_x, 0, index, 1);
747+
}
748+
code_unit_runs_.emplace_back(
749+
std::move(empty_glyph_positions),
750+
Range<size_t>(line_end_index, line_range.end),
751+
Range<double>(end_x, end_x), line_code_unit_runs.back().line_number,
752+
line_code_unit_runs.back().font_metrics,
753+
line_code_unit_runs.back().direction);
754+
}
755+
743756
double max_line_spacing = 0;
744757
double max_descent = 0;
745758
SkScalar max_unscaled_ascent = 0;

third_party/txt/tests/paragraph_unittests.cc

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,245 @@ TEST_F(ParagraphTest,
16131613
ASSERT_TRUE(Snapshot());
16141614
}
16151615

1616+
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraph)) {
1617+
const char* text = "01234   "; // includes ideographic space
1618+
// and english space.
1619+
auto icu_text = icu::UnicodeString::fromUTF8(text);
1620+
std::u16string u16_text(icu_text.getBuffer(),
1621+
icu_text.getBuffer() + icu_text.length());
1622+
1623+
txt::ParagraphStyle paragraph_style;
1624+
paragraph_style.max_lines = 10;
1625+
paragraph_style.text_align = TextAlign::center;
1626+
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
1627+
1628+
txt::TextStyle text_style;
1629+
text_style.font_family = "Roboto";
1630+
text_style.font_size = 50;
1631+
text_style.letter_spacing = 0;
1632+
text_style.font_weight = FontWeight::w500;
1633+
text_style.word_spacing = 0;
1634+
text_style.color = SK_ColorBLACK;
1635+
text_style.height = 1;
1636+
builder.PushStyle(text_style);
1637+
1638+
builder.AddText(u16_text);
1639+
1640+
builder.Pop();
1641+
1642+
auto paragraph = builder.Build();
1643+
paragraph->Layout(550);
1644+
1645+
paragraph->Paint(GetCanvas(), 0, 0);
1646+
1647+
SkPaint paint;
1648+
paint.setStyle(SkPaint::kStroke_Style);
1649+
paint.setAntiAlias(true);
1650+
paint.setStrokeWidth(1);
1651+
1652+
// Tests for GetRectsForRange()
1653+
Paragraph::RectHeightStyle rect_height_style =
1654+
Paragraph::RectHeightStyle::kMax;
1655+
Paragraph::RectWidthStyle rect_width_style =
1656+
Paragraph::RectWidthStyle::kTight;
1657+
paint.setColor(SK_ColorRED);
1658+
std::vector<txt::Paragraph::TextBox> boxes =
1659+
paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
1660+
for (size_t i = 0; i < boxes.size(); ++i) {
1661+
GetCanvas()->drawRect(boxes[i].rect, paint);
1662+
}
1663+
EXPECT_EQ(boxes.size(), 0ull);
1664+
1665+
boxes =
1666+
paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
1667+
for (size_t i = 0; i < boxes.size(); ++i) {
1668+
GetCanvas()->drawRect(boxes[i].rect, paint);
1669+
}
1670+
EXPECT_EQ(boxes.size(), 1ull);
1671+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
1672+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1673+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
1674+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
1675+
1676+
paint.setColor(SK_ColorBLUE);
1677+
boxes =
1678+
paragraph->GetRectsForRange(2, 4, rect_height_style, rect_width_style);
1679+
for (size_t i = 0; i < boxes.size(); ++i) {
1680+
GetCanvas()->drawRect(boxes[i].rect, paint);
1681+
}
1682+
EXPECT_EQ(boxes.size(), 1ull);
1683+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 260.79102);
1684+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1685+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317.62695);
1686+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
1687+
1688+
paint.setColor(SK_ColorGREEN);
1689+
boxes =
1690+
paragraph->GetRectsForRange(4, 6, rect_height_style, rect_width_style);
1691+
for (size_t i = 0; i < boxes.size(); ++i) {
1692+
GetCanvas()->drawRect(boxes[i].rect, paint);
1693+
}
1694+
EXPECT_EQ(boxes.size(), 2ull);
1695+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317.62695);
1696+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1697+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492);
1698+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
1699+
1700+
paint.setColor(SK_ColorBLACK);
1701+
boxes =
1702+
paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
1703+
for (size_t i = 0; i < boxes.size(); ++i) {
1704+
GetCanvas()->drawRect(boxes[i].rect, paint);
1705+
}
1706+
EXPECT_EQ(boxes.size(), 1ull);
1707+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 346.04492);
1708+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1709+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492);
1710+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
1711+
1712+
paint.setColor(SK_ColorRED);
1713+
boxes =
1714+
paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
1715+
for (size_t i = 0; i < boxes.size(); ++i) {
1716+
GetCanvas()->drawRect(boxes[i].rect, paint);
1717+
}
1718+
EXPECT_EQ(boxes.size(), 0ull);
1719+
1720+
ASSERT_TRUE(Snapshot());
1721+
}
1722+
1723+
TEST_F(ParagraphTest,
1724+
DISABLE_ON_WINDOWS(GetRectsForRangeCenterMultiLineParagraph)) {
1725+
const char* text = "01234   \n0123  "; // includes ideographic
1726+
// space and english space.
1727+
auto icu_text = icu::UnicodeString::fromUTF8(text);
1728+
std::u16string u16_text(icu_text.getBuffer(),
1729+
icu_text.getBuffer() + icu_text.length());
1730+
1731+
txt::ParagraphStyle paragraph_style;
1732+
paragraph_style.max_lines = 10;
1733+
paragraph_style.text_align = TextAlign::center;
1734+
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
1735+
1736+
txt::TextStyle text_style;
1737+
text_style.font_family = "Roboto";
1738+
text_style.font_size = 50;
1739+
text_style.letter_spacing = 0;
1740+
text_style.font_weight = FontWeight::w500;
1741+
text_style.word_spacing = 0;
1742+
text_style.color = SK_ColorBLACK;
1743+
text_style.height = 1;
1744+
builder.PushStyle(text_style);
1745+
1746+
builder.AddText(u16_text);
1747+
1748+
builder.Pop();
1749+
1750+
auto paragraph = builder.Build();
1751+
paragraph->Layout(550);
1752+
1753+
paragraph->Paint(GetCanvas(), 0, 0);
1754+
1755+
SkPaint paint;
1756+
paint.setStyle(SkPaint::kStroke_Style);
1757+
paint.setAntiAlias(true);
1758+
paint.setStrokeWidth(1);
1759+
1760+
// Tests for GetRectsForRange()
1761+
Paragraph::RectHeightStyle rect_height_style =
1762+
Paragraph::RectHeightStyle::kMax;
1763+
Paragraph::RectWidthStyle rect_width_style =
1764+
Paragraph::RectWidthStyle::kTight;
1765+
paint.setColor(SK_ColorRED);
1766+
std::vector<txt::Paragraph::TextBox> boxes =
1767+
paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
1768+
for (size_t i = 0; i < boxes.size(); ++i) {
1769+
GetCanvas()->drawRect(boxes[i].rect, paint);
1770+
}
1771+
EXPECT_EQ(boxes.size(), 0ull);
1772+
1773+
boxes =
1774+
paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
1775+
for (size_t i = 0; i < boxes.size(); ++i) {
1776+
GetCanvas()->drawRect(boxes[i].rect, paint);
1777+
}
1778+
EXPECT_EQ(boxes.size(), 1ull);
1779+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 203.95508);
1780+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1781+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305);
1782+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
1783+
1784+
paint.setColor(SK_ColorBLUE);
1785+
boxes =
1786+
paragraph->GetRectsForRange(2, 4, rect_height_style, rect_width_style);
1787+
for (size_t i = 0; i < boxes.size(); ++i) {
1788+
GetCanvas()->drawRect(boxes[i].rect, paint);
1789+
}
1790+
EXPECT_EQ(boxes.size(), 1ull);
1791+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 260.79102);
1792+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1793+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 317.62695);
1794+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
1795+
1796+
paint.setColor(SK_ColorGREEN);
1797+
boxes =
1798+
paragraph->GetRectsForRange(4, 6, rect_height_style, rect_width_style);
1799+
for (size_t i = 0; i < boxes.size(); ++i) {
1800+
GetCanvas()->drawRect(boxes[i].rect, paint);
1801+
}
1802+
EXPECT_EQ(boxes.size(), 2ull);
1803+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 317.62695);
1804+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1805+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492);
1806+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
1807+
1808+
paint.setColor(SK_ColorBLACK);
1809+
boxes =
1810+
paragraph->GetRectsForRange(5, 6, rect_height_style, rect_width_style);
1811+
for (size_t i = 0; i < boxes.size(); ++i) {
1812+
GetCanvas()->drawRect(boxes[i].rect, paint);
1813+
}
1814+
EXPECT_EQ(boxes.size(), 1ull);
1815+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 346.04492);
1816+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625);
1817+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 346.04492);
1818+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
1819+
1820+
paint.setColor(SK_ColorBLACK);
1821+
boxes =
1822+
paragraph->GetRectsForRange(10, 12, rect_height_style, rect_width_style);
1823+
for (size_t i = 0; i < boxes.size(); ++i) {
1824+
GetCanvas()->drawRect(boxes[i].rect, paint);
1825+
}
1826+
EXPECT_EQ(boxes.size(), 1ull);
1827+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 218.16406);
1828+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
1829+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275);
1830+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
1831+
1832+
paint.setColor(SK_ColorBLACK);
1833+
boxes =
1834+
paragraph->GetRectsForRange(14, 18, rect_height_style, rect_width_style);
1835+
for (size_t i = 0; i < boxes.size(); ++i) {
1836+
GetCanvas()->drawRect(boxes[i].rect, paint);
1837+
}
1838+
EXPECT_EQ(boxes.size(), 1ull);
1839+
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 331.83594);
1840+
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59.40625);
1841+
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 331.83594);
1842+
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 118);
1843+
1844+
paint.setColor(SK_ColorRED);
1845+
boxes =
1846+
paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style);
1847+
for (size_t i = 0; i < boxes.size(); ++i) {
1848+
GetCanvas()->drawRect(boxes[i].rect, paint);
1849+
}
1850+
EXPECT_EQ(boxes.size(), 0ull);
1851+
1852+
ASSERT_TRUE(Snapshot());
1853+
}
1854+
16161855
SkRect GetCoordinatesForGlyphPosition(const txt::Paragraph& paragraph,
16171856
size_t pos) {
16181857
std::vector<txt::Paragraph::TextBox> boxes =

0 commit comments

Comments
 (0)