From 73b016b75b3542c7c10998350f0e4877e42c923e Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Wed, 15 Apr 2020 17:19:38 -0700 Subject: [PATCH 1/4] Adjust newline rectangles to reflect paragraph alignment GetRectsForRange inserts empty rectangles that represent newline characters within the specified range of text positions. The x coordinate of these rectangles needs to account for left/right/center alignment. Fixes https://github.com/flutter/flutter/issues/53057 --- third_party/txt/src/txt/paragraph_txt.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/third_party/txt/src/txt/paragraph_txt.cc b/third_party/txt/src/txt/paragraph_txt.cc index efbe2df0fbc7a..5deed1da89abb 100644 --- a/third_party/txt/src/txt/paragraph_txt.cc +++ b/third_party/txt/src/txt/paragraph_txt.cc @@ -1730,11 +1730,12 @@ std::vector ParagraphTxt::GetRectsForRange( if (line_box_metrics.find(line_number) == line_box_metrics.end()) { if (line.end_index != line.end_including_newline && line.end_index >= start && line.end_including_newline <= end) { - SkScalar x = line_widths_[line_number]; - // Move empty box to center if center aligned and is an empty line. - if (x == 0 && !isinf(width_) && - paragraph_style_.effective_align() == TextAlign::center) { - x = width_ / 2; + SkScalar x; + const GlyphLine& glyph_line = glyph_lines_[line_number]; + if (glyph_lines_[line_number].positions.empty()) { + x = GetLineXOffset(0, line_number, false); + } else { + x = glyph_line.positions.back().x_pos.end; } SkScalar top = (line_number > 0) ? line_metrics_[line_number - 1].height : 0; From 2d1b23b0761c5c2b8bc31cc8e21b0fa1387b8267 Mon Sep 17 00:00:00 2001 From: Ali Mahdiyar Date: Thu, 16 Apr 2020 10:35:42 +0430 Subject: [PATCH 2/4] handle direction in newline rectangles --- third_party/txt/src/txt/paragraph_txt.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/third_party/txt/src/txt/paragraph_txt.cc b/third_party/txt/src/txt/paragraph_txt.cc index 5deed1da89abb..76079605066dc 100644 --- a/third_party/txt/src/txt/paragraph_txt.cc +++ b/third_party/txt/src/txt/paragraph_txt.cc @@ -1650,6 +1650,10 @@ std::vector ParagraphTxt::GetRectsForRange( // RectWidthStyle::kMax. TextDirection first_line_dir = TextDirection::ltr; + // Text direction of the last run of each line so we can determine + // line end positions + std::map line_last_run_directions; + // Lines that are actually in the requested range. size_t max_line = 0; size_t min_line = INT_MAX; @@ -1660,6 +1664,9 @@ std::vector ParagraphTxt::GetRectsForRange( // Check to see if we are finished. if (run.code_units.start >= end) break; + + line_last_run_directions[run.line_number] = run.direction; + if (run.code_units.end <= start) continue; @@ -1735,7 +1742,9 @@ std::vector ParagraphTxt::GetRectsForRange( if (glyph_lines_[line_number].positions.empty()) { x = GetLineXOffset(0, line_number, false); } else { - x = glyph_line.positions.back().x_pos.end; + x = line_last_run_directions[line_number] == TextDirection::ltr + ? glyph_line.positions.back().x_pos.end + : glyph_line.positions.front().x_pos.start; } SkScalar top = (line_number > 0) ? line_metrics_[line_number - 1].height : 0; From 9c8e684833f527453f4283de6dd4518ba4c9f0a6 Mon Sep 17 00:00:00 2001 From: Ali Mahdiyar Date: Thu, 16 Apr 2020 16:51:24 +0430 Subject: [PATCH 3/4] newline rectangles unit tests --- third_party/txt/tests/paragraph_unittests.cc | 215 ++++++++++++++++++- 1 file changed, 214 insertions(+), 1 deletion(-) diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc index 6122be579929b..9776036b6da29 100644 --- a/third_party/txt/tests/paragraph_unittests.cc +++ b/third_party/txt/tests/paragraph_unittests.cc @@ -3943,9 +3943,202 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraph)) { ASSERT_TRUE(Snapshot()); } +TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeParagraphNewlineLeftAligned)) { + const char* text = "01234\n\nab\nعلی\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.text_align = TextAlign::left; + txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + 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; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = BuildParagraph(builder); + 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::kMax; + 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_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 28.417969); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorGREEN); + boxes = + paragraph->GetRectsForRange(6, 7, 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_FLOAT_EQ(boxes[0].rect.right(), 0); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), + 75); // TODO(garyq): This value can be improved... Should be + // taller, but we need a good way to obtain a height + // without any glyphs on the line. + + boxes = + paragraph->GetRectsForRange(9, 10, 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(), 55.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 55.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); + + boxes = + paragraph->GetRectsForRange(13, 14, 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_FLOAT_EQ(boxes[0].rect.right(), 0); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); + + ASSERT_TRUE(Snapshot()); +} + +TEST_F(ParagraphTest, + LINUX_ONLY(GetRectsForRangeParagraphNewlineRightAligned)) { + const char* text = "01234\n\nab\nعلی\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.text_align = TextAlign::right; + txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + 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; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = BuildParagraph(builder); + 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::kMax; + 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(), 407.91016); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 436.32812); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorGREEN); + boxes = + paragraph->GetRectsForRange(6, 7, 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(), 550); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), + 75); // TODO(garyq): This value can be improved... Should be + // taller, but we need a good way to obtain a height + // without any glyphs on the line. + + boxes = + paragraph->GetRectsForRange(9, 10, 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(), 550); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); + + boxes = + paragraph->GetRectsForRange(13, 14, 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(), 483.49609); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 483.49609); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); + + ASSERT_TRUE(Snapshot()); +} + TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeCenterParagraphNewlineCentered)) { - const char* text = "01234\n"; + const char* text = "01234\n\nab\nعلی\n"; auto icu_text = icu::UnicodeString::fromUTF8(text); std::u16string u16_text(icu_text.getBuffer(), icu_text.getBuffer() + icu_text.length()); @@ -4017,6 +4210,26 @@ TEST_F(ParagraphTest, // taller, but we need a good way to obtain a height // without any glyphs on the line. + boxes = + paragraph->GetRectsForRange(9, 10, 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(), 302.59961); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 302.59961); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); + + boxes = + paragraph->GetRectsForRange(13, 14, 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(), 241.74805); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 241.74805); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); + ASSERT_TRUE(Snapshot()); } From cdcf7cd6d2abe1c6d8634258c898a6d815ed0f7b Mon Sep 17 00:00:00 2001 From: Ali Mahdiyar Date: Thu, 16 Apr 2020 19:27:53 +0430 Subject: [PATCH 4/4] Get newline rectangles in line with multiple bidi runs --- third_party/txt/src/txt/paragraph_txt.cc | 19 +- third_party/txt/tests/paragraph_unittests.cc | 339 +++++++++++++++++-- 2 files changed, 325 insertions(+), 33 deletions(-) diff --git a/third_party/txt/src/txt/paragraph_txt.cc b/third_party/txt/src/txt/paragraph_txt.cc index 76079605066dc..fe50b789378da 100644 --- a/third_party/txt/src/txt/paragraph_txt.cc +++ b/third_party/txt/src/txt/paragraph_txt.cc @@ -1649,10 +1649,7 @@ std::vector ParagraphTxt::GetRectsForRange( // Text direction of the first line so we can extend the correct side for // RectWidthStyle::kMax. TextDirection first_line_dir = TextDirection::ltr; - - // Text direction of the last run of each line so we can determine - // line end positions - std::map line_last_run_directions; + std::map newline_x_positions; // Lines that are actually in the requested range. size_t max_line = 0; @@ -1665,7 +1662,9 @@ std::vector ParagraphTxt::GetRectsForRange( if (run.code_units.start >= end) break; - line_last_run_directions[run.line_number] = run.direction; + // Update new line x position with the ending of last bidi run on the line + newline_x_positions[run.line_number] = + run.direction == TextDirection::ltr ? run.x_pos.end : run.x_pos.start; if (run.code_units.end <= start) continue; @@ -1738,13 +1737,11 @@ std::vector ParagraphTxt::GetRectsForRange( if (line.end_index != line.end_including_newline && line.end_index >= start && line.end_including_newline <= end) { SkScalar x; - const GlyphLine& glyph_line = glyph_lines_[line_number]; - if (glyph_lines_[line_number].positions.empty()) { - x = GetLineXOffset(0, line_number, false); + auto it = newline_x_positions.find(line_number); + if (it != newline_x_positions.end()) { + x = it->second; } else { - x = line_last_run_directions[line_number] == TextDirection::ltr - ? glyph_line.positions.back().x_pos.end - : glyph_line.positions.front().x_pos.start; + x = GetLineXOffset(0, false); } SkScalar top = (line_number > 0) ? line_metrics_[line_number - 1].height : 0; diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc index 9776036b6da29..1626510008bbc 100644 --- a/third_party/txt/tests/paragraph_unittests.cc +++ b/third_party/txt/tests/paragraph_unittests.cc @@ -3943,14 +3943,15 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraph)) { ASSERT_TRUE(Snapshot()); } -TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeParagraphNewlineLeftAligned)) { - const char* text = "01234\n\nab\nعلی\n"; +TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeParagraphNewlineLeftAlign)) { + const char* text = "01234\n\nعab\naعلی\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.text_direction = TextDirection::ltr; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); @@ -4017,37 +4018,37 @@ TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeParagraphNewlineLeftAligned)) { // without any glyphs on the line. boxes = - paragraph->GetRectsForRange(9, 10, rect_height_style, rect_width_style); + paragraph->GetRectsForRange(10, 11, 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(), 55.199219); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 55.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 77); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 77); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); boxes = - paragraph->GetRectsForRange(13, 14, rect_height_style, rect_width_style); + paragraph->GetRectsForRange(15, 16, 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_FLOAT_EQ(boxes[0].rect.right(), 0); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 27); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 27); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); ASSERT_TRUE(Snapshot()); } -TEST_F(ParagraphTest, - LINUX_ONLY(GetRectsForRangeParagraphNewlineRightAligned)) { - const char* text = "01234\n\nab\nعلی\n"; +TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeParagraphNewlineRightAlign)) { + const char* text = "01234\n\nعab\naعلی\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.text_direction = TextDirection::ltr; paragraph_style.text_align = TextAlign::right; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); @@ -4114,7 +4115,7 @@ TEST_F(ParagraphTest, // without any glyphs on the line. boxes = - paragraph->GetRectsForRange(9, 10, rect_height_style, rect_width_style); + paragraph->GetRectsForRange(10, 11, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } @@ -4124,13 +4125,13 @@ TEST_F(ParagraphTest, EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); boxes = - paragraph->GetRectsForRange(13, 14, rect_height_style, rect_width_style); + paragraph->GetRectsForRange(15, 16, 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(), 483.49609); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 483.49609); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 483); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 483); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); ASSERT_TRUE(Snapshot()); @@ -4138,13 +4139,14 @@ TEST_F(ParagraphTest, TEST_F(ParagraphTest, LINUX_ONLY(GetRectsForRangeCenterParagraphNewlineCentered)) { - const char* text = "01234\n\nab\nعلی\n"; + const char* text = "01234\n\nعab\naعلی\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.text_direction = TextDirection::ltr; paragraph_style.text_align = TextAlign::center; txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); @@ -4211,23 +4213,316 @@ TEST_F(ParagraphTest, // without any glyphs on the line. boxes = - paragraph->GetRectsForRange(9, 10, rect_height_style, rect_width_style); + paragraph->GetRectsForRange(10, 11, 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(), 313); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 313); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); + + boxes = + paragraph->GetRectsForRange(15, 16, 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(), 255); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 255); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); + + ASSERT_TRUE(Snapshot()); +} +TEST_F(ParagraphTest, + LINUX_ONLY(GetRectsForRangeParagraphNewlineRTLLeftAlign)) { + const char* text = "01234\n\nعab\naعلی\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.text_direction = TextDirection::rtl; + paragraph_style.text_align = TextAlign::left; + txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + 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; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = BuildParagraph(builder); + 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::kMax; + 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_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 28.417969); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorGREEN); + boxes = + paragraph->GetRectsForRange(6, 7, 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_FLOAT_EQ(boxes[0].rect.right(), 0); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), + 75); // TODO(garyq): This value can be improved... Should be + // taller, but we need a good way to obtain a height + // without any glyphs on the line. + + boxes = + paragraph->GetRectsForRange(10, 11, 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(), 302.59961); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 302.59961); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 55); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 55); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); boxes = - paragraph->GetRectsForRange(13, 14, rect_height_style, rect_width_style); + paragraph->GetRectsForRange(15, 16, 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_FLOAT_EQ(boxes[0].rect.right(), 0); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); + + ASSERT_TRUE(Snapshot()); +} + +TEST_F(ParagraphTest, + LINUX_ONLY(GetRectsForRangeParagraphNewlineRTLRightAlign)) { + const char* text = "01234\n\nعab\naعلی\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.text_direction = TextDirection::rtl; + paragraph_style.text_align = TextAlign::right; + txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + 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; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = BuildParagraph(builder); + 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::kMax; + 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(), 407.91016); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 436.32812); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorGREEN); + boxes = + paragraph->GetRectsForRange(6, 7, 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(), 550); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 550); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), + 75); // TODO(garyq): This value can be improved... Should be + // taller, but we need a good way to obtain a height + // without any glyphs on the line. + + boxes = + paragraph->GetRectsForRange(10, 11, 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(), 527); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 527); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); + + boxes = + paragraph->GetRectsForRange(15, 16, 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(), 456); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 456); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); + + ASSERT_TRUE(Snapshot()); +} + +TEST_F(ParagraphTest, + LINUX_ONLY(GetRectsForRangeCenterParagraphNewlineRTLCentered)) { + const char* text = "01234\n\nعab\naعلی\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.text_direction = TextDirection::rtl; + paragraph_style.text_align = TextAlign::center; + txt::ParagraphBuilderTxt builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + 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; + builder.PushStyle(text_style); + + builder.AddText(u16_text); + + builder.Pop(); + + auto paragraph = BuildParagraph(builder); + 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::kMax; + 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(), 203.95508); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 232.37305); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorGREEN); + boxes = + paragraph->GetRectsForRange(6, 7, 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(), 275); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 275); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), + 75); // TODO(garyq): This value can be improved... Should be + // taller, but we need a good way to obtain a height + // without any glyphs on the line. + + boxes = + paragraph->GetRectsForRange(10, 11, 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(), 291); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 291); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 134); + + boxes = + paragraph->GetRectsForRange(15, 16, 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(), 241.74805); - EXPECT_FLOAT_EQ(boxes[0].rect.right(), 241.74805); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 228); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 228); EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 193); ASSERT_TRUE(Snapshot());