diff --git a/lib/stub_ui/lib/src/ui/text.dart b/lib/stub_ui/lib/src/ui/text.dart index 8f9d3bdfd8f25..64cc94600c4e7 100644 --- a/lib/stub_ui/lib/src/ui/text.dart +++ b/lib/stub_ui/lib/src/ui/text.dart @@ -298,7 +298,8 @@ class TextStyle { /// * `letterSpacing`: The amount of space (in logical pixels) to add between each letter. /// * `wordSpacing`: The amount of space (in logical pixels) to add at each sequence of white-space (i.e. between each word). /// * `textBaseline`: The common baseline that should be aligned between this text span and its parent text span, or, for the root text spans, with the line box. - /// * `height`: The height of this text span, as a multiple of the font size. + /// * `height`: The height of this text span, as a multiplier of the font size. Omitting `height` will allow the line height + /// to take the height as defined by the font, which may not be exactly the height of the fontSize. /// * `locale`: The locale used to select region-specific glyphs. /// * `background`: The paint drawn as a background for the text. /// * `foreground`: The paint used to draw the text. If this is specified, `color` must be null. @@ -623,13 +624,11 @@ class ParagraphStyle { /// * `fontSize`: The size of glyphs (in logical pixels) to use when painting /// the text. /// - /// * `height`: The minimum height of the line boxes, as a multiple of the - /// font size. The lines of the paragraph will be at least - /// `(height + leading) * fontSize` tall when fontSize - /// is not null. When fontSize is null, there is no minimum line height. Tall - /// glyphs due to baseline alignment or large [TextStyle.fontSize] may cause - /// the actual line height after layout to be taller than specified here. - /// [fontSize] must be provided for this property to take effect. + /// * `height`: The fallback height of the spans as a multiplier of the font + /// size. The fallback height is used when no height is provided through + /// [TextStyle.height]. Omitting `height` here and in [TextStyle] will allow + /// the line height to take the height as defined by the font, which may not + /// be exactly the height of the `fontSize`. /// /// * `fontWeight`: The typeface thickness to use when painting the text /// (e.g., bold). @@ -764,22 +763,24 @@ class StrutStyle { /// * `fontFamily`: The name of the font to use when painting the text (e.g., /// Roboto). /// - /// * `fontFamilyFallback`: An ordered list of font family names that will be searched for when - /// the font in `fontFamily` cannot be found. + /// * `fontFamilyFallback`: An ordered list of font family names that will be + /// searched for when the font in `fontFamily` cannot be found. /// /// * `fontSize`: The size of glyphs (in logical pixels) to use when painting /// the text. /// - /// * `lineHeight`: The minimum height of the line boxes, as a multiple of the + /// * `height`: The minimum height of the line boxes, as a multiplier of the /// font size. The lines of the paragraph will be at least - /// `(lineHeight + leading) * fontSize` tall when fontSize - /// is not null. When fontSize is null, there is no minimum line height. Tall - /// glyphs due to baseline alignment or large [TextStyle.fontSize] may cause - /// the actual line height after layout to be taller than specified here. - /// [fontSize] must be provided for this property to take effect. + /// `(height + leading) * fontSize` tall when `fontSize` is not null. Omitting + /// `height` will allow the minimum line height to take the height as defined + /// by the font, which may not be exactly the height of the `fontSize`. When + /// `fontSize` is null, there is no minimum line height. Tall glyphs due to + /// baseline alignment or large [TextStyle.fontSize] may cause the actual line + /// height after layout to be taller than specified here. The `fontSize` must + /// be provided for this property to take effect. /// /// * `leading`: The minimum amount of leading between lines as a multiple of - /// the font size. [fontSize] must be provided for this property to take effect. + /// the font size. `fontSize` must be provided for this property to take effect. /// /// * `fontWeight`: The typeface thickness to use when painting the text /// (e.g., bold). @@ -788,11 +789,11 @@ class StrutStyle { /// italics). /// /// * `forceStrutHeight`: When true, the paragraph will force all lines to be exactly - /// `(lineHeight + leading) * fontSize` tall from baseline to baseline. + /// `(height + leading) * fontSize` tall from baseline to baseline. /// [TextStyle] is no longer able to influence the line height, and any tall - /// glyphs may overlap with lines above. If a [fontFamily] is specified, the + /// glyphs may overlap with lines above. If a `fontFamily` is specified, the /// total ascent of the first line will be the min of the `Ascent + half-leading` - /// of the [fontFamily] and `(lineHeight + leading) * fontSize`. Otherwise, it + /// of the `fontFamily` and `(height + leading) * fontSize`. Otherwise, it /// will be determined by the Ascent + half-leading of the first text. StrutStyle({ String fontFamily, diff --git a/lib/ui/text.dart b/lib/ui/text.dart index bfdfd898e9c3b..bea3cbf616e22 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -527,7 +527,8 @@ class TextStyle { /// * `letterSpacing`: The amount of space (in logical pixels) to add between each letter. /// * `wordSpacing`: The amount of space (in logical pixels) to add at each sequence of white-space (i.e. between each word). /// * `textBaseline`: The common baseline that should be aligned between this text span and its parent text span, or, for the root text spans, with the line box. - /// * `height`: The height of this text span, as a multiplier of the font size. + /// * `height`: The height of this text span, as a multiplier of the font size. Omitting `height` will allow the line height + /// to take the height as defined by the font, which may not be exactly the height of the fontSize. /// * `locale`: The locale used to select region-specific glyphs. /// * `background`: The paint drawn as a background for the text. /// * `foreground`: The paint used to draw the text. If this is specified, `color` must be null. @@ -776,9 +777,11 @@ class ParagraphStyle { /// * `fontSize`: The fallback size of glyphs (in logical pixels) to /// use when painting the text. This is used when there is no [TextStyle]. /// - /// * `height`: The height of the spans as a multiplier of the font size. The - /// fallback height to use when no height is provided in through - /// [TextStyle.height]. + /// * `height`: The fallback height of the spans as a multiplier of the font + /// size. The fallback height is used when no height is provided through + /// [TextStyle.height]. Omitting `height` here and in [TextStyle] will allow + /// the line height to take the height as defined by the font, which may not + /// be exactly the height of the `fontSize`. /// /// * `fontWeight`: The typeface thickness to use when painting the text /// (e.g., bold). @@ -962,22 +965,24 @@ class StrutStyle { /// * `fontFamily`: The name of the font to use when painting the text (e.g., /// Roboto). /// - /// * `fontFamilyFallback`: An ordered list of font family names that will be searched for when - /// the font in `fontFamily` cannot be found. + /// * `fontFamilyFallback`: An ordered list of font family names that will be + /// searched for when the font in `fontFamily` cannot be found. /// /// * `fontSize`: The size of glyphs (in logical pixels) to use when painting /// the text. /// /// * `height`: The minimum height of the line boxes, as a multiplier of the - /// font size. The lines of the paragraph will be at least `(height + leading) - /// * fontSize` tall when fontSize is not null. When fontSize is null, there - /// is no minimum line height. Tall glyphs due to baseline alignment or large - /// [TextStyle.fontSize] may cause the actual line height after layout to be - /// taller than specified here. [fontSize] must be provided for this property - /// to take effect. + /// font size. The lines of the paragraph will be at least + /// `(height + leading) * fontSize` tall when `fontSize` is not null. Omitting + /// `height` will allow the minimum line height to take the height as defined + /// by the font, which may not be exactly the height of the `fontSize`. When + /// `fontSize` is null, there is no minimum line height. Tall glyphs due to + /// baseline alignment or large [TextStyle.fontSize] may cause the actual line + /// height after layout to be taller than specified here. The `fontSize` must + /// be provided for this property to take effect. /// /// * `leading`: The minimum amount of leading between lines as a multiple of - /// the font size. [fontSize] must be provided for this property to take effect. + /// the font size. `fontSize` must be provided for this property to take effect. /// /// * `fontWeight`: The typeface thickness to use when painting the text /// (e.g., bold). @@ -988,9 +993,9 @@ class StrutStyle { /// * `forceStrutHeight`: When true, the paragraph will force all lines to be exactly /// `(height + leading) * fontSize` tall from baseline to baseline. /// [TextStyle] is no longer able to influence the line height, and any tall - /// glyphs may overlap with lines above. If a [fontFamily] is specified, the + /// glyphs may overlap with lines above. If a `fontFamily` is specified, the /// total ascent of the first line will be the min of the `Ascent + half-leading` - /// of the [fontFamily] and `(height + leading) * fontSize`. Otherwise, it + /// of the `fontFamily` and `(height + leading) * fontSize`. Otherwise, it /// will be determined by the Ascent + half-leading of the first text. StrutStyle({ String fontFamily, diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc index 1682cbe41473c..bef66a700b98e 100644 --- a/lib/ui/text/paragraph_builder.cc +++ b/lib/ui/text/paragraph_builder.cc @@ -204,6 +204,7 @@ void decodeStrut(Dart_Handle strut_data, } if (mask & sHeightMask) { paragraph_style.strut_height = float_data[float_count++]; + paragraph_style.strut_has_height_override = true; } if (mask & sLeadingMask) { paragraph_style.strut_leading = float_data[float_count++]; @@ -261,6 +262,7 @@ ParagraphBuilder::ParagraphBuilder( if (mask & psHeightMask) { style.height = height; + style.has_height_override = true; } if (mask & psStrutStyleMask) { @@ -401,6 +403,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, if (mask & tsHeightMask) { style.height = height; + style.has_height_override = true; } if (mask & tsLocaleMask) { diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index 33712f77161ef..6acdc160bd30e 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -507,14 +507,30 @@ void Paragraph::ComputeStrut(StrutMetrics* strut, SkFont& font) { SkFontMetrics strut_metrics; font.getMetrics(&strut_metrics); - strut->ascent = paragraph_style_.strut_height * -strut_metrics.fAscent; - strut->descent = paragraph_style_.strut_height * strut_metrics.fDescent; - strut->leading = - // Use font's leading if there is no user specified strut leading. - paragraph_style_.strut_leading < 0 - ? strut_metrics.fLeading - : (paragraph_style_.strut_leading * - (strut_metrics.fDescent - strut_metrics.fAscent)); + if (paragraph_style_.strut_has_height_override) { + double metrics_height = -strut_metrics.fAscent + strut_metrics.fDescent; + strut->ascent = (-strut_metrics.fAscent / metrics_height) * + paragraph_style_.strut_height * + paragraph_style_.strut_font_size; + strut->descent = (strut_metrics.fDescent / metrics_height) * + paragraph_style_.strut_height * + paragraph_style_.strut_font_size; + strut->leading = + // Zero leading if there is no user specified strut leading. + paragraph_style_.strut_leading < 0 + ? 0 + : (paragraph_style_.strut_leading * + paragraph_style_.strut_font_size); + } else { + strut->ascent = -strut_metrics.fAscent; + strut->descent = strut_metrics.fDescent; + strut->leading = + // Use font's leading if there is no user specified strut leading. + paragraph_style_.strut_leading < 0 + ? strut_metrics.fLeading + : (paragraph_style_.strut_leading * + paragraph_style_.strut_font_size); + } strut->half_leading = strut->leading / 2; strut->line_height = strut->ascent + strut->descent + strut->leading; } @@ -1042,11 +1058,21 @@ void Paragraph::Layout(double width, bool force) { const TextStyle& style, PlaceholderRun* placeholder_run) { if (!strut_.force_strut) { - double ascent = - (-metrics.fAscent + metrics.fLeading / 2) * style.height; - double descent = - (metrics.fDescent + metrics.fLeading / 2) * style.height; - + double ascent; + double descent; + if (style.has_height_override) { + // Scale the ascent and descent such that the sum of ascent and + // descent is `fontsize * style.height * style.font_size`. + double metrics_height = -metrics.fAscent + metrics.fDescent; + ascent = (-metrics.fAscent / metrics_height) * style.height * + style.font_size; + descent = (metrics.fDescent / metrics_height) * style.height * + style.font_size; + } else { + // Use the font-provided ascent, descent, and leading directly. + ascent = (-metrics.fAscent + metrics.fLeading / 2); + descent = (metrics.fDescent + metrics.fLeading / 2); + } ComputePlaceholder(placeholder_run, ascent, descent); max_ascent = std::max(ascent, max_ascent); diff --git a/third_party/txt/src/txt/paragraph_style.cc b/third_party/txt/src/txt/paragraph_style.cc index 933a8db6d6123..06a4feca71c87 100644 --- a/third_party/txt/src/txt/paragraph_style.cc +++ b/third_party/txt/src/txt/paragraph_style.cc @@ -14,10 +14,10 @@ * limitations under the License. */ -#include - #include "paragraph_style.h" +#include + namespace txt { TextStyle ParagraphStyle::GetTextStyle() const { @@ -30,6 +30,7 @@ TextStyle ParagraphStyle::GetTextStyle() const { } result.locale = locale; result.height = height; + result.has_height_override = has_height_override; return result; } diff --git a/third_party/txt/src/txt/paragraph_style.h b/third_party/txt/src/txt/paragraph_style.h index 514037d41fd93..9ca5fae3ca9c4 100644 --- a/third_party/txt/src/txt/paragraph_style.h +++ b/third_party/txt/src/txt/paragraph_style.h @@ -50,6 +50,7 @@ class ParagraphStyle { std::string font_family = ""; double font_size = 14; double height = 1; + bool has_height_override = false; // Strut properties. strut_enabled must be set to true for the rest of the // properties to take effect. @@ -60,6 +61,7 @@ class ParagraphStyle { std::vector strut_font_families; double strut_font_size = 14; double strut_height = 1; + bool strut_has_height_override = false; double strut_leading = -1; // Negative to use font's default leading. [0,inf) // to use custom leading as a ratio of font size. bool force_strut_height = false; diff --git a/third_party/txt/src/txt/text_style.cc b/third_party/txt/src/txt/text_style.cc index 194dde47882e3..8ca0c42a1e4cb 100644 --- a/third_party/txt/src/txt/text_style.cc +++ b/third_party/txt/src/txt/text_style.cc @@ -15,6 +15,7 @@ */ #include "text_style.h" + #include "font_style.h" #include "font_weight.h" #include "third_party/skia/include/core/SkColor.h" @@ -46,6 +47,8 @@ bool TextStyle::equals(const TextStyle& other) const { return false; if (height != other.height) return false; + if (has_height_override != other.has_height_override) + return false; if (locale != other.locale) return false; if (foreground != other.foreground) diff --git a/third_party/txt/src/txt/text_style.h b/third_party/txt/src/txt/text_style.h index 83c814fd2027f..0d4a92a099814 100644 --- a/third_party/txt/src/txt/text_style.h +++ b/third_party/txt/src/txt/text_style.h @@ -51,6 +51,7 @@ class TextStyle { double letter_spacing = 0.0; double word_spacing = 0.0; double height = 1.0; + bool has_height_override = false; std::string locale; bool has_background = false; SkPaint background; diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc index 1a073080b5bb0..33201971003e9 100644 --- a/third_party/txt/tests/paragraph_unittests.cc +++ b/third_party/txt/tests/paragraph_unittests.cc @@ -1322,6 +1322,67 @@ TEST_F(ParagraphTest, BoldParagraph) { boxes[boxes.size() - 1].rect.right() - boxes[0].rect.left()); } +TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(HeightOverrideParagraph)) { + const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可"; + 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.max_lines = 10; + txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + text_style.font_families = std::vector(1, "Roboto"); + text_style.font_size = 20; + text_style.letter_spacing = 0; + text_style.word_spacing = 0; + text_style.color = SK_ColorBLACK; + text_style.height = 3.6345; + text_style.has_height_override = true; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = builder.Build(); + paragraph->Layout(550); + + paragraph->Paint(GetCanvas(), 0, 0); + + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setAntiAlias(true); + paint.setStrokeWidth(1); + + // Tests for GetRectsForRange() + Paragraph::RectHeightStyle rect_height_style = + Paragraph::RectHeightStyle::kIncludeLineSpacingMiddle; + Paragraph::RectWidthStyle rect_width_style = + Paragraph::RectWidthStyle::kTight; + paint.setColor(SK_ColorRED); + std::vector boxes = + paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); + for (size_t i = 0; i < boxes.size(); ++i) { + GetCanvas()->drawRect(boxes[i].rect, paint); + } + EXPECT_EQ(boxes.size(), 0ull); + + boxes = + paragraph->GetRectsForRange(0, 40, rect_height_style, rect_width_style); + for (size_t i = 0; i < boxes.size(); ++i) { + GetCanvas()->drawRect(boxes[i].rect, paint); + } + EXPECT_EQ(boxes.size(), 3ull); + EXPECT_FLOAT_EQ(boxes[1].rect.left(), 0); + EXPECT_NEAR(boxes[1].rect.top(), 92.805778503417969, 0.0001); + EXPECT_FLOAT_EQ(boxes[1].rect.right(), 43.84375); + EXPECT_NEAR(boxes[1].rect.bottom(), 165.49578857421875, 0.0001); + + ASSERT_TRUE(Snapshot()); +} + TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(LeftAlignParagraph)) { const char* text = "This is a very long sentence to test if the text will properly wrap " @@ -2389,9 +2450,6 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeTight)) { TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingMiddle)) { - // const char* text = - // "12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 - // 12345 " "67890 12345"; const char* text = "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" @@ -2407,13 +2465,13 @@ TEST_F(ParagraphTest, txt::TextStyle text_style; text_style.font_families = std::vector(1, "Roboto"); - // text_style.font_families = std::vector(1, "Roboto"); text_style.font_size = 50; text_style.letter_spacing = 0; text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; - text_style.height = 1.3; + text_style.height = 1.6; + text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -2451,9 +2509,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.958008); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305); paint.setColor(SK_ColorBLUE); boxes = @@ -2463,9 +2521,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.958008); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305); paint.setColor(SK_ColorGREEN); boxes = @@ -2475,9 +2533,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.958008); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473312); paint.setColor(SK_ColorRED); boxes = @@ -2487,34 +2545,34 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 82.786133); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 88.473312); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 158.95801); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 168.47331); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 82.786133); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 88.473312); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 158.95801); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 168.4733); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 158.78613); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 168.4733); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 234.95801); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 248.47331); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 158.78613); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 168.4733); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 234.95801); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 248.47331); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 234.78613); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 248.47331); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 310.95801); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 328.4733); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[5].rect.top(), 310.78613); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 328.47333); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 386.95801); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 408.4733); paint.setColor(SK_ColorBLUE); boxes = @@ -2524,9 +2582,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.958008); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 88.473305); paint.setColor(SK_ColorRED); boxes = @@ -2541,9 +2599,6 @@ TEST_F(ParagraphTest, TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingTop)) { - // const char* text = - // "12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 - // 12345 " "67890 12345"; const char* text = "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" @@ -2564,7 +2619,8 @@ TEST_F(ParagraphTest, text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; - text_style.height = 1.3; + text_style.height = 1.6; + text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -2602,9 +2658,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 76); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); paint.setColor(SK_ColorBLUE); boxes = @@ -2614,9 +2670,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 76); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); paint.setColor(SK_ColorGREEN); boxes = @@ -2626,9 +2682,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 76); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); paint.setColor(SK_ColorRED); boxes = @@ -2638,34 +2694,34 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 75.828125); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 80); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 152); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 160); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 75.828125); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 80); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 152); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 160); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 151.82812); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 160); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 228); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 240); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 151.82812); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 160); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 228); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 240); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 227.82812); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 240); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 304); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 320); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[5].rect.top(), 303.82812); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 320); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 380); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 400); paint.setColor(SK_ColorBLUE); boxes = @@ -2675,9 +2731,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 76); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 80); paint.setColor(SK_ColorRED); boxes = @@ -2692,9 +2748,6 @@ TEST_F(ParagraphTest, TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeIncludeLineSpacingBottom)) { - // const char* text = - // "12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 - // 12345 " "67890 12345"; const char* text = "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" @@ -2715,7 +2768,8 @@ TEST_F(ParagraphTest, text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; - text_style.height = 1.3; + text_style.height = 1.6; + text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -2753,9 +2807,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.916016); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609); paint.setColor(SK_ColorBLUE); boxes = @@ -2765,9 +2819,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.916016); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609); paint.setColor(SK_ColorGREEN); boxes = @@ -2777,9 +2831,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.916016); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609); paint.setColor(SK_ColorRED); boxes = @@ -2789,34 +2843,34 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 89.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 96.946617); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 165.91602); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 176.94661); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 89.744141); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 96.946617); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 165.91602); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 176.94661); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 165.74414); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 176.94661); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 241.91602); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 256.94662); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 165.74414); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 176.94661); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 241.91602); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 256.94662); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 241.74414); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 256.94662); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 317.91602); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 336.94662); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[5].rect.top(), 317.74414); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 336.94662); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 393.91602); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 416.94662); paint.setColor(SK_ColorBLUE); boxes = @@ -2826,9 +2880,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 16.946615); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.916016); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 96.946609); paint.setColor(SK_ColorRED); boxes = @@ -3365,6 +3419,7 @@ TEST_F(ParagraphTest, GetWordBoundaryParagraph) { text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; text_style.height = 1.5; + text_style.has_height_override = true; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -4194,6 +4249,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph1)) { paragraph_style.strut_font_families.push_back("ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.8; + paragraph_style.strut_has_height_override = true; paragraph_style.strut_leading = 0.1; paragraph_style.strut_enabled = true; @@ -4321,6 +4377,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph2)) { paragraph_style.strut_font_families = std::vector(1, "ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.6; + paragraph_style.strut_has_height_override = true; paragraph_style.strut_enabled = true; txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); @@ -4446,6 +4503,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutParagraph3)) { paragraph_style.strut_font_families = std::vector(1, "ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.2; + paragraph_style.strut_has_height_override = true; paragraph_style.strut_enabled = true; txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); @@ -4571,6 +4629,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutForceParagraph)) { paragraph_style.strut_font_families = std::vector(1, "ahem"); paragraph_style.strut_font_size = 50; paragraph_style.strut_height = 1.5; + paragraph_style.strut_has_height_override = true; paragraph_style.strut_leading = 0.1; paragraph_style.force_strut_height = true; paragraph_style.strut_enabled = true; @@ -4685,6 +4744,87 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutForceParagraph)) { ASSERT_TRUE(Snapshot()); } +// The height override is disabled for this test. Direct metrics from the font. +TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(StrutDefaultParagraph)) { + const char* text = "01234満毎冠行来昼本可\nabcd\n満毎冠行来昼本可"; + 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.max_lines = 10; + paragraph_style.strut_font_families = std::vector(1, "ahem"); + paragraph_style.strut_font_size = 50; + paragraph_style.strut_height = 1.5; + paragraph_style.strut_leading = 0.1; + paragraph_style.force_strut_height = false; + paragraph_style.strut_enabled = true; + txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + text_style.font_families = std::vector(1, "ahem"); + text_style.font_families.push_back("ahem"); + text_style.font_size = 20; + text_style.letter_spacing = 0; + text_style.word_spacing = 0; + text_style.color = SK_ColorBLACK; + text_style.height = 1; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = builder.Build(); + paragraph->Layout(550); + + paragraph->Paint(GetCanvas(), 0, 0); + + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + paint.setAntiAlias(true); + paint.setStrokeWidth(1); + + // Tests for GetRectsForRange() + Paragraph::RectHeightStyle rect_height_style = + Paragraph::RectHeightStyle::kTight; + Paragraph::RectHeightStyle rect_height_strut_style = + Paragraph::RectHeightStyle::kStrut; + Paragraph::RectWidthStyle rect_width_style = + Paragraph::RectWidthStyle::kTight; + paint.setColor(SK_ColorRED); + std::vector boxes = + paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style); + for (size_t i = 0; i < boxes.size(); ++i) { + GetCanvas()->drawRect(boxes[i].rect, paint); + } + EXPECT_EQ(boxes.size(), 0ull); + + boxes = + paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style); + for (size_t i = 0; i < boxes.size(); ++i) { + GetCanvas()->drawRect(boxes[i].rect, paint); + } + EXPECT_EQ(boxes.size(), 1ull); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); + EXPECT_NEAR(boxes[0].rect.top(), 26.5, 0.0001); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 20); + EXPECT_NEAR(boxes[0].rect.bottom(), 46.5, 0.0001); + + boxes = paragraph->GetRectsForRange(0, 2, rect_height_strut_style, + rect_width_style); + for (size_t i = 0; i < boxes.size(); ++i) { + GetCanvas()->drawRect(boxes[i].rect, paint); + } + EXPECT_EQ(boxes.size(), 1ull); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); + EXPECT_NEAR(boxes[0].rect.top(), 2.5, 0.0001); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 40); + EXPECT_NEAR(boxes[0].rect.bottom(), 52.5, 0.0001); + + ASSERT_TRUE(Snapshot()); +} + TEST_F(ParagraphTest, FontFeaturesParagraph) { const char* text = "12ab\n"; auto icu_text = icu::UnicodeString::fromUTF8(text);