diff --git a/lib/stub_ui/lib/src/ui/text.dart b/lib/stub_ui/lib/src/ui/text.dart index 979657ff9e3d2..899ee591c0188 100644 --- a/lib/stub_ui/lib/src/ui/text.dart +++ b/lib/stub_ui/lib/src/ui/text.dart @@ -1235,6 +1235,8 @@ enum BoxHeightStyle { /// entire paragraph. The top edge of each line will align with the bottom /// edge of the previous line. It is possible for glyphs to extend outside /// these boxes. + /// + /// Will fall back to tight bounds if the strut is disabled or invalid. strut, } diff --git a/lib/ui/text.dart b/lib/ui/text.dart index 2c74f877bd215..e48e16d771687 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -1429,6 +1429,8 @@ enum BoxHeightStyle { /// entire paragraph. The top edge of each line will align with the bottom /// edge of the previous line. It is possible for glyphs to extend outside /// these boxes. + /// + /// Will fall back to tight bounds if the strut is disabled or invalid. strut, } diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index d6534311a11c2..449b0d13dff1c 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -425,6 +425,12 @@ bool Paragraph::ComputeBidiRuns(std::vector* result) { return true; } +bool Paragraph::IsStrutValid() const { + // Font size must be positive. + return (paragraph_style_.strut_enabled && + paragraph_style_.strut_font_size >= 0); +} + void Paragraph::ComputeStrut(StrutMetrics* strut, SkFont& font) { strut->ascent = 0; strut->descent = 0; @@ -433,15 +439,12 @@ void Paragraph::ComputeStrut(StrutMetrics* strut, SkFont& font) { strut->line_height = 0; strut->force_strut = false; - // Font size must be positive. - bool valid_strut = - paragraph_style_.strut_enabled && paragraph_style_.strut_font_size >= 0; - if (!valid_strut) { + if (!IsStrutValid()) return; - } + // force_strut makes all lines have exactly the strut metrics, and ignores all // actual metrics. We only force the strut if the strut is non-zero and valid. - strut->force_strut = paragraph_style_.force_strut_height && valid_strut; + strut->force_strut = paragraph_style_.force_strut_height; minikin::FontStyle minikin_font_style( 0, GetWeight(paragraph_style_.strut_font_weight), paragraph_style_.strut_font_style == FontStyle::italic); @@ -1458,12 +1461,18 @@ std::vector Paragraph::GetRectsForRange( box.direction); } } else if (rect_height_style == RectHeightStyle::kStrut) { - for (const Paragraph::TextBox& box : kv.second.boxes) { - boxes.emplace_back( - SkRect::MakeLTRB( - box.rect.fLeft, line_baselines_[kv.first] - strut_.ascent, - box.rect.fRight, line_baselines_[kv.first] + strut_.descent), - box.direction); + if (IsStrutValid()) { + for (const Paragraph::TextBox& box : kv.second.boxes) { + boxes.emplace_back( + SkRect::MakeLTRB( + box.rect.fLeft, line_baselines_[kv.first] - strut_.ascent, + box.rect.fRight, line_baselines_[kv.first] + strut_.descent), + box.direction); + } + } else { + // Fall back to tight bounds if the strut is invalid. + boxes.insert(boxes.end(), kv.second.boxes.begin(), + kv.second.boxes.end()); } } } diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index a1ebc0da18794..ef16c20f91aab 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -405,6 +405,8 @@ class Paragraph { // Calculates and populates strut based on paragraph_style_ strut info. void ComputeStrut(StrutMetrics* strut, SkFont& font); + bool IsStrutValid() const; + // Calculate the starting X offset of a line based on the line's width and // alignment. double GetLineXOffset(double line_total_advance); diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc index 7c92de6f4800d..93590753ce0a5 100644 --- a/third_party/txt/tests/paragraph_unittests.cc +++ b/third_party/txt/tests/paragraph_unittests.cc @@ -2259,6 +2259,41 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeStrut)) { ASSERT_TRUE(Snapshot()); } +TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeStrutFallback)) { + const char* text = "Chinese 字典"; + + auto icu_text = icu::UnicodeString::fromUTF8(text); + std::u16string u16_text(icu_text.getBuffer(), + icu_text.getBuffer() + icu_text.length()); + + txt::ParagraphStyle paragraph_style; + paragraph_style.strut_enabled = false; + txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + text_style.font_families.push_back("Noto Sans CJK JP"); + text_style.font_size = 20; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = builder.Build(); + paragraph->Layout(550); + + std::vector strut_boxes = + paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kStrut, + Paragraph::RectWidthStyle::kMax); + std::vector tight_boxes = + paragraph->GetRectsForRange(0, 10, Paragraph::RectHeightStyle::kTight, + Paragraph::RectWidthStyle::kMax); + + ASSERT_EQ(strut_boxes.size(), 1ull); + ASSERT_EQ(tight_boxes.size(), 1ull); + ASSERT_EQ(strut_boxes.front().rect, tight_boxes.front().rect); +} + SkRect GetCoordinatesForGlyphPosition(const txt::Paragraph& paragraph, size_t pos) { std::vector boxes =