Skip to content

Commit 10b4540

Browse files
authored
Implement ParagraphStyle.line_height and add tests for line_height and baselines. (flutter#6417)
1 parent 7e3b41d commit 10b4540

File tree

4 files changed

+158
-4
lines changed

4 files changed

+158
-4
lines changed

third_party/txt/src/txt/paragraph.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -729,14 +729,15 @@ void Paragraph::Layout(double width, bool force) {
729729
auto update_line_metrics = [&](const SkPaint::FontMetrics& metrics,
730730
const TextStyle& style) {
731731
double line_spacing =
732-
(line_number == 0)
733-
? -metrics.fAscent * style.height
734-
: (-metrics.fAscent + metrics.fLeading) * style.height;
732+
(line_number == 0) ? -metrics.fAscent * style.height
733+
: (-metrics.fAscent + metrics.fLeading) *
734+
style.height * paragraph_style_.line_height;
735735
if (line_spacing > max_line_spacing) {
736736
max_line_spacing = line_spacing;
737737
if (line_number == 0) {
738738
alphabetic_baseline_ = line_spacing;
739-
// TODO(garyq): Properly implement ideographic_baseline_.
739+
// TODO(garyq): Properly implement ideographic_baseline_ and update
740+
// tests.
740741
ideographic_baseline_ =
741742
(metrics.fUnderlinePosition - metrics.fAscent) * style.height;
742743
}

third_party/txt/src/txt/paragraph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ class Paragraph {
206206
FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph);
207207
FRIEND_TEST(ParagraphTest, Ellipsize);
208208
FRIEND_TEST(ParagraphTest, UnderlineShiftParagraph);
209+
FRIEND_TEST(ParagraphTest, LineHeightsParagraph);
209210

210211
// Starting data to layout.
211212
std::vector<uint16_t> text_;

third_party/txt/src/txt/styled_runs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class StyledRuns {
7979
FRIEND_TEST(ParagraphTest, HyphenBreakParagraph);
8080
FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph);
8181
FRIEND_TEST(ParagraphTest, Ellipsize);
82+
FRIEND_TEST(ParagraphTest, LineHeightsParagraph);
8283

8384
struct IndexedRun {
8485
size_t style_index = 0;

third_party/txt/tests/paragraph_unittests.cc

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,4 +1731,155 @@ TEST_F(ParagraphTest, UnderlineShiftParagraph) {
17311731
}
17321732
}
17331733

1734+
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(LineHeightsParagraph)) {
1735+
const char* text =
1736+
"This is a very long sentence to test if the text will properly wrap "
1737+
"around and go to the next line. Sometimes, short sentence. Longer "
1738+
"sentences are okay too because they are nessecary. Very short. "
1739+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1740+
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1741+
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1742+
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1743+
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1744+
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1745+
"mollit anim id est laborum. "
1746+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
1747+
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
1748+
"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
1749+
"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
1750+
"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
1751+
"occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
1752+
"mollit anim id est laborum.";
1753+
auto icu_text = icu::UnicodeString::fromUTF8(text);
1754+
std::u16string u16_text(icu_text.getBuffer(),
1755+
icu_text.getBuffer() + icu_text.length());
1756+
1757+
txt::ParagraphStyle paragraph_style;
1758+
paragraph_style.max_lines = 14;
1759+
paragraph_style.text_align = TextAlign::left;
1760+
double line_height = 2.0;
1761+
paragraph_style.line_height = line_height;
1762+
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
1763+
1764+
txt::TextStyle text_style;
1765+
text_style.font_family = "Roboto";
1766+
text_style.font_size = 26;
1767+
text_style.letter_spacing = 1;
1768+
text_style.word_spacing = 5;
1769+
text_style.color = SK_ColorBLACK;
1770+
text_style.height = 1;
1771+
text_style.decoration = TextDecoration::kUnderline;
1772+
text_style.decoration_color = SK_ColorBLACK;
1773+
builder.PushStyle(text_style);
1774+
1775+
builder.AddText(u16_text);
1776+
1777+
builder.Pop();
1778+
1779+
auto paragraph = builder.Build();
1780+
paragraph->Layout(GetTestCanvasWidth() - 100);
1781+
1782+
paragraph->Paint(GetCanvas(), 0, 0);
1783+
1784+
ASSERT_TRUE(Snapshot());
1785+
1786+
ASSERT_EQ(paragraph->text_.size(), std::string{text}.length());
1787+
for (size_t i = 0; i < u16_text.length(); i++) {
1788+
ASSERT_EQ(paragraph->text_[i], u16_text[i]);
1789+
}
1790+
ASSERT_EQ(paragraph->runs_.runs_.size(), 1ull);
1791+
ASSERT_EQ(paragraph->runs_.styles_.size(), 2ull);
1792+
ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
1793+
ASSERT_EQ(paragraph->records_.size(), paragraph_style.max_lines);
1794+
double expected_y = 24;
1795+
1796+
ASSERT_TRUE(paragraph->records_[0].style().equals(text_style));
1797+
ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().y(), expected_y);
1798+
expected_y += 27.5 * line_height;
1799+
ASSERT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
1800+
1801+
ASSERT_TRUE(paragraph->records_[1].style().equals(text_style));
1802+
ASSERT_DOUBLE_EQ(paragraph->records_[1].offset().y(), expected_y);
1803+
expected_y += 27.5 * line_height;
1804+
ASSERT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0);
1805+
1806+
ASSERT_TRUE(paragraph->records_[2].style().equals(text_style));
1807+
ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().y(), expected_y);
1808+
expected_y += 27.5 * line_height;
1809+
ASSERT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0);
1810+
1811+
ASSERT_TRUE(paragraph->records_[3].style().equals(text_style));
1812+
ASSERT_DOUBLE_EQ(paragraph->records_[3].offset().y(), expected_y);
1813+
expected_y += 27.5 * 10 * line_height;
1814+
ASSERT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0);
1815+
1816+
ASSERT_TRUE(paragraph->records_[13].style().equals(text_style));
1817+
ASSERT_DOUBLE_EQ(paragraph->records_[13].offset().y(), expected_y);
1818+
ASSERT_DOUBLE_EQ(paragraph->records_[13].offset().x(), 0);
1819+
1820+
ASSERT_EQ(paragraph_style.text_align,
1821+
paragraph->GetParagraphStyle().text_align);
1822+
1823+
// Tests for GetGlyphPositionAtCoordinate()
1824+
ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(0, 0).position, 0ull);
1825+
ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 1).position, 0ull);
1826+
ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 35).position, 68ull);
1827+
ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 70).position, 68ull);
1828+
ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(2000, 35).position, 134ull);
1829+
1830+
ASSERT_TRUE(Snapshot());
1831+
}
1832+
1833+
TEST_F(ParagraphTest, BaselineParagraph) {
1834+
const char* text =
1835+
"左線読設Byg後碁給能上目秘使約。満毎冠行来昼本可必図将発確年。今属場育"
1836+
"図情闘陰野高備込制詩西校客。審対江置講今固残必託地集済決維駆年策。立得";
1837+
auto icu_text = icu::UnicodeString::fromUTF8(text);
1838+
std::u16string u16_text(icu_text.getBuffer(),
1839+
icu_text.getBuffer() + icu_text.length());
1840+
1841+
txt::ParagraphStyle paragraph_style;
1842+
paragraph_style.max_lines = 14;
1843+
paragraph_style.text_align = TextAlign::justify;
1844+
paragraph_style.line_height = 1.5;
1845+
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
1846+
1847+
txt::TextStyle text_style;
1848+
text_style.color = SK_ColorBLACK;
1849+
text_style.font_size = 55;
1850+
text_style.letter_spacing = 2;
1851+
text_style.font_family = "Source Han Serif CN";
1852+
text_style.decoration_style = txt::TextDecorationStyle::kSolid;
1853+
text_style.decoration_color = SK_ColorBLACK;
1854+
builder.PushStyle(text_style);
1855+
1856+
builder.AddText(u16_text);
1857+
1858+
builder.Pop();
1859+
1860+
auto paragraph = builder.Build();
1861+
paragraph->Layout(GetTestCanvasWidth() - 100);
1862+
1863+
paragraph->Paint(GetCanvas(), 0, 0);
1864+
1865+
SkPaint paint;
1866+
paint.setStyle(SkPaint::kStroke_Style);
1867+
paint.setAntiAlias(true);
1868+
paint.setStrokeWidth(1);
1869+
paint.setColor(SK_ColorRED);
1870+
GetCanvas()->drawLine(0, paragraph->GetIdeographicBaseline(),
1871+
paragraph->GetMaxWidth(),
1872+
paragraph->GetIdeographicBaseline(), paint);
1873+
1874+
paint.setColor(SK_ColorGREEN);
1875+
1876+
GetCanvas()->drawLine(0, paragraph->GetAlphabeticBaseline(),
1877+
paragraph->GetMaxWidth(),
1878+
paragraph->GetAlphabeticBaseline(), paint);
1879+
ASSERT_DOUBLE_EQ(paragraph->GetIdeographicBaseline(), 70.180000305175781);
1880+
ASSERT_DOUBLE_EQ(paragraph->GetAlphabeticBaseline(), 63.305000305175781);
1881+
1882+
ASSERT_TRUE(Snapshot());
1883+
}
1884+
17341885
} // namespace txt

0 commit comments

Comments
 (0)