From 0f590c5e5a90cf9bbf60fac48e98f9908bb2f62c Mon Sep 17 00:00:00 2001 From: GaryQian Date: Wed, 17 Oct 2018 17:46:14 -0700 Subject: [PATCH 1/7] Support all combinations of GetRectsForRange styles --- lib/ui/text/paragraph.cc | 5 +- lib/ui/text/paragraph_impl.h | 3 +- lib/ui/text/paragraph_impl_txt.cc | 7 +- lib/ui/text/paragraph_impl_txt.h | 3 +- third_party/txt/src/txt/paragraph.cc | 137 ++++- third_party/txt/src/txt/paragraph.h | 46 +- third_party/txt/tests/paragraph_unittests.cc | 505 ++++++++++++++++++- 7 files changed, 655 insertions(+), 51 deletions(-) diff --git a/lib/ui/text/paragraph.cc b/lib/ui/text/paragraph.cc index 032ee1af4d9bd..1821bf9dd3a7a 100644 --- a/lib/ui/text/paragraph.cc +++ b/lib/ui/text/paragraph.cc @@ -85,8 +85,9 @@ void Paragraph::paint(Canvas* canvas, double x, double y) { } std::vector Paragraph::getRectsForRange(unsigned start, unsigned end) { - return m_paragraphImpl->getRectsForRange(start, end, - txt::Paragraph::RectStyle::kTight); + return m_paragraphImpl->getRectsForRange( + start, end, txt::Paragraph::RectHeightStyle::kTight, + txt::Paragraph::RectWidthStyle::kTight); } Dart_Handle Paragraph::getPositionForOffset(double dx, double dy) { diff --git a/lib/ui/text/paragraph_impl.h b/lib/ui/text/paragraph_impl.h index cf71897d250e4..30ce8a080070d 100644 --- a/lib/ui/text/paragraph_impl.h +++ b/lib/ui/text/paragraph_impl.h @@ -36,7 +36,8 @@ class ParagraphImpl { virtual std::vector getRectsForRange( unsigned start, unsigned end, - txt::Paragraph::RectStyle rect_style) = 0; + txt::Paragraph::RectHeightStyle rect_height_style, + txt::Paragraph::RectWidthStyle rect_width_style) = 0; virtual Dart_Handle getPositionForOffset(double dx, double dy) = 0; diff --git a/lib/ui/text/paragraph_impl_txt.cc b/lib/ui/text/paragraph_impl_txt.cc index cc55638db2680..9f31a3896985d 100644 --- a/lib/ui/text/paragraph_impl_txt.cc +++ b/lib/ui/text/paragraph_impl_txt.cc @@ -64,10 +64,11 @@ void ParagraphImplTxt::paint(Canvas* canvas, double x, double y) { std::vector ParagraphImplTxt::getRectsForRange( unsigned start, unsigned end, - txt::Paragraph::RectStyle rect_style) { + txt::Paragraph::RectHeightStyle rect_height_style, + txt::Paragraph::RectWidthStyle rect_width_style) { std::vector result; - std::vector boxes = - m_paragraph->GetRectsForRange(start, end, rect_style); + std::vector boxes = m_paragraph->GetRectsForRange( + start, end, rect_height_style, rect_width_style); for (const txt::Paragraph::TextBox& box : boxes) { result.emplace_back(box.rect, static_cast(box.direction)); diff --git a/lib/ui/text/paragraph_impl_txt.h b/lib/ui/text/paragraph_impl_txt.h index 665d65b15cce2..eabdcc114b198 100644 --- a/lib/ui/text/paragraph_impl_txt.h +++ b/lib/ui/text/paragraph_impl_txt.h @@ -31,7 +31,8 @@ class ParagraphImplTxt : public ParagraphImpl { std::vector getRectsForRange( unsigned start, unsigned end, - txt::Paragraph::RectStyle rect_style) override; + txt::Paragraph::RectHeightStyle rect_height_style, + txt::Paragraph::RectWidthStyle rect_width_style) override; Dart_Handle getPositionForOffset(double dx, double dy) override; Dart_Handle getWordBoundary(unsigned offset) override; diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index 2e324aa6e2b0d..67c7cfcd5c491 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -762,6 +762,8 @@ void Paragraph::Layout(double width, bool force) { update_line_metrics(metrics, style); } + // TODO(garyq): Remove rounding of line heights because it is irrelevant in + // a world of high DPI devices. line_heights_.push_back((line_heights_.empty() ? 0 : line_heights_.back()) + round(max_line_spacing + max_descent)); line_baselines_.push_back(line_heights_.back() - max_descent); @@ -1093,19 +1095,63 @@ void Paragraph::PaintShadow(SkCanvas* canvas, std::vector Paragraph::GetRectsForRange( size_t start, size_t end, - RectStyle rect_style) const { + RectHeightStyle rect_height_style, + RectWidthStyle rect_width_style) const { std::map> line_boxes; - + // Per-line min and max top/bottom edges over all runs in a given line. + std::vector min_tops; + std::vector max_bottoms; + + // Per-line metrics for max and min coordinates for left and right boxes. + std::vector max_rights; + std::vector min_lefts; + // Overall extremes of lines. + SkScalar max_right = 0; + SkScalar min_left = FLT_MAX; + // Text direction of the first line so we can extend the correct side for + // RectWidthStyle::kMax. + TextDirection first_line_dir = TextDirection::ltr; + + // Lines that are actually in the requested range. + size_t max_line = 0; + size_t min_line = INT_MAX; + + // Generate initial boxes and calculate metrics. for (const CodeUnitRun& run : code_unit_runs_) { - if (run.code_units.start >= end) - break; - if (run.code_units.end <= start) - continue; - double baseline = line_baselines_[run.line_number]; SkScalar top = baseline + run.font_metrics.fAscent; SkScalar bottom = baseline + run.font_metrics.fDescent; + // Calculate line height metrics. Not needed by RectHeightStyle::kTight. + if (rect_height_style != RectHeightStyle::kTight) { + // Init metrics vectors as needed. + while (run.line_number >= min_tops.size()) { + min_tops.push_back(FLT_MAX); + max_bottoms.push_back(FLT_MIN); + min_lefts.push_back(FLT_MAX); + max_rights.push_back(FLT_MIN); + } + min_tops[run.line_number] = std::min(min_tops[run.line_number], top); + max_bottoms[run.line_number] = + std::max(max_bottoms[run.line_number], bottom); + } + + // Check to see if we are finished. + if (run.code_units.start >= end) { + // We continue to store metrics of one additional line if available. + if (run.line_number <= max_line + 1) { + continue; + } else { + break; + } + } + if (run.code_units.end <= start) + continue; + + max_line = std::max(run.line_number, max_line); + min_line = std::min(run.line_number, min_line); + + // Calculate left and right. SkScalar left, right; if (run.code_units.start >= start && run.code_units.end <= end) { left = run.x_pos.start; @@ -1122,6 +1168,18 @@ std::vector Paragraph::GetRectsForRange( if (left == SK_ScalarMax || right == SK_ScalarMin) continue; } + // Keep track of the min and max horizontal coordinates over all lines. Not + // needed for kTight. + if (rect_width_style == RectWidthStyle::kMax) { + max_right = std::max(max_right, right); + min_left = std::min(min_left, left); + max_rights[run.line_number] = + std::max(max_rights[run.line_number], right); + min_lefts[run.line_number] = std::min(min_lefts[run.line_number], left); + if (min_line == run.line_number) { + first_line_dir = run.direction; + } + } line_boxes[run.line_number].emplace_back( SkRect::MakeLTRB(left, top, right, bottom), run.direction); } @@ -1147,22 +1205,69 @@ std::vector Paragraph::GetRectsForRange( } } + // "Post-process" metrics and aggregate final rects to return. std::vector boxes; for (const auto& kv : line_boxes) { - if (rect_style & RectStyle::kTight) { + // Handle rect_width_styles. We skip the last line because not everything is + // selected. + if (rect_width_style == RectWidthStyle::kMax && kv.first != max_line) { + if (min_lefts[kv.first] > min_left && + (kv.first != min_line || first_line_dir == TextDirection::rtl)) { + line_boxes[kv.first].emplace_back( + SkRect::MakeLTRB(min_left, min_tops[kv.first], min_lefts[kv.first], + max_bottoms[kv.first]), + TextDirection::rtl); + } + if (max_rights[kv.first] < max_right && + (kv.first != min_line || first_line_dir == TextDirection::ltr)) { + line_boxes[kv.first].emplace_back( + SkRect::MakeLTRB(max_rights[kv.first], min_tops[kv.first], + max_right, max_bottoms[kv.first]), + TextDirection::ltr); + } + } + + // Handle rect_height_styles + if (rect_height_style == RectHeightStyle::kTight) { // Ignore line max height and width and generate tight bounds. boxes.insert(boxes.end(), kv.second.begin(), kv.second.end()); - } else { - // Set each box to the max height of each line to ensure continuity. - float min_top = DBL_MAX; - float max_bottom = 0; + } else if (rect_height_style == RectHeightStyle::kMax) { + for (const Paragraph::TextBox& box : kv.second) { + boxes.emplace_back( + SkRect::MakeLTRB(box.rect.fLeft, min_tops[kv.first], + box.rect.fRight, max_bottoms[kv.first]), + box.direction); + } + } else if (rect_height_style == + RectHeightStyle::kIncludeLineSpacingMiddle) { + SkScalar adjusted_bottom = + kv.first >= max_bottoms.size() + ? max_bottoms[kv.first] + : (min_tops[kv.first + 1] + max_bottoms[kv.first]) / 2; + SkScalar adjusted_top = + kv.first == 0 ? min_tops[kv.first] + : (max_bottoms[kv.first - 1] + min_tops[kv.first]) / 2; + for (const Paragraph::TextBox& box : kv.second) { + boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, + box.rect.fRight, adjusted_bottom), + box.direction); + } + } else if (rect_height_style == RectHeightStyle::kIncludeLineSpacingTop) { for (const Paragraph::TextBox& box : kv.second) { - min_top = std::min(box.rect.fTop, min_top); - max_bottom = std::max(box.rect.fBottom, max_bottom); + SkScalar adjusted_top = + kv.first == 0 ? min_tops[kv.first] : max_bottoms[kv.first - 1]; + boxes.emplace_back( + SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, box.rect.fRight, + max_bottoms[kv.first]), + box.direction); } + } else { // kIncludeLineSpacingBottom for (const Paragraph::TextBox& box : kv.second) { - boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, min_top, - box.rect.fRight, max_bottom), + SkScalar adjusted_bottom = kv.first >= max_bottoms.size() + ? max_bottoms[kv.first] + : min_tops[kv.first + 1]; + boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, min_tops[kv.first], + box.rect.fRight, adjusted_bottom), box.direction); } } diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index 637f4e4723f3a..2f83f9caeacc9 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -59,19 +59,36 @@ class Paragraph { // Options for various types of bounding boxes provided by // GetRectsForRange(...). - // These options can be individually enabled, for example: - // - // (RectStyle::kTight | RectStyle::kExtendEndOfLine) - // - // provides tight bounding boxes and extends the last box per line to the end - // of the layout area. - enum RectStyle { - kNone = 0x0, // kNone cannot be combined with |. - - // Provide tight bounding boxes that fit heights per span. Otherwise, the - // heights of spans are the max of the heights of the line the span belongs - // in. - kTight = 0x1 + enum class RectHeightStyle { + // The height of the boxes will be the maximum height of all runs in the + // line. All rects in the same line will be the same height. + kMax, + + // Provide tight bounding boxes that fit heights per run. + kTight, + + // Extends the top and/or bottom edge of the bounds to fully cover any line + // spacing. The top edge of each line should be the same as the bottom edge + // of the line above. There should be no gaps in vertical coverage given any + // ParagraphStyle line_height. + // + // The top and bottom of each rect will cover half of the + // space above and half of the space below the line. + kIncludeLineSpacingMiddle, + // The line spacing will be added to the top of the rect. + kIncludeLineSpacingTop, + // The line spacing will be added to the bottom of the rect. + kIncludeLineSpacingBottom + }; + + enum class RectWidthStyle { + // Extends the width of the last rect of each line to match the position of + // the widest rect over all the lines. + kMax, + + // Provide tight bounding boxes that fit widths to the runs of each line + // independently. + kTight }; struct PositionWithAffinity { @@ -158,7 +175,8 @@ class Paragraph { // end glyph indexes, including start and excluding end. std::vector GetRectsForRange(size_t start, size_t end, - RectStyle rect_style) const; + RectHeightStyle rect_height_style, + RectWidthStyle rect_width_style) const; // Returns the index of the glyph that corresponds to the provided coordinate, // with the top left corner as the origin, and +y direction as down. diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc index 43243da4e97e8..24057c1d26bd9 100644 --- a/third_party/txt/tests/paragraph_unittests.cc +++ b/third_party/txt/tests/paragraph_unittests.cc @@ -981,15 +981,20 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) { // Tests for GetRectsForRange() // NOTE: The base truth values may still need adjustment as the specifics // are adjusted. + 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, Paragraph::RectStyle::kNone); + 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, Paragraph::RectStyle::kNone); + 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); } @@ -1000,7 +1005,8 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) { EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorBLUE); - boxes = paragraph->GetRectsForRange(2, 8, Paragraph::RectStyle::kNone); + boxes = + paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } @@ -1011,7 +1017,8 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) { EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorGREEN); - boxes = paragraph->GetRectsForRange(8, 21, Paragraph::RectStyle::kNone); + boxes = + paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } @@ -1022,7 +1029,8 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) { EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorRED); - boxes = paragraph->GetRectsForRange(30, 100, Paragraph::RectStyle::kNone); + boxes = + paragraph->GetRectsForRange(30, 100, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } @@ -1040,7 +1048,8 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) { EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 295); paint.setColor(SK_ColorBLUE); - boxes = paragraph->GetRectsForRange(19, 22, Paragraph::RectStyle::kNone); + boxes = + paragraph->GetRectsForRange(19, 22, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } @@ -1051,7 +1060,8 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) { EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); paint.setColor(SK_ColorRED); - boxes = paragraph->GetRectsForRange(21, 21, Paragraph::RectStyle::kNone); + boxes = + paragraph->GetRectsForRange(21, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } @@ -1101,15 +1111,20 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeTight)) { // Tests for GetRectsForRange() // NOTE: The base truth values may still need adjustment as the specifics // are adjusted. + Paragraph::RectHeightStyle rect_height_style = + Paragraph::RectHeightStyle::kTight; + Paragraph::RectWidthStyle rect_width_style = + Paragraph::RectWidthStyle::kTight; paint.setColor(SK_ColorRED); std::vector boxes = - paragraph->GetRectsForRange(0, 0, Paragraph::RectStyle::kTight); + 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, Paragraph::RectStyle::kTight); + 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); } @@ -1120,7 +1135,8 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeTight)) { EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74); paint.setColor(SK_ColorBLUE); - boxes = paragraph->GetRectsForRange(2, 8, Paragraph::RectStyle::kTight); + boxes = + paragraph->GetRectsForRange(2, 8, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } @@ -1130,7 +1146,8 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeTight)) { EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74); paint.setColor(SK_ColorGREEN); - boxes = paragraph->GetRectsForRange(8, 21, Paragraph::RectStyle::kTight); + boxes = + paragraph->GetRectsForRange(8, 21, rect_height_style, rect_width_style); for (size_t i = 0; i < boxes.size(); ++i) { GetCanvas()->drawRect(boxes[i].rect, paint); } @@ -1143,10 +1160,467 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeTight)) { ASSERT_TRUE(Snapshot()); } +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 = + "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" + " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" + " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)"; + 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.line_height = 2.0; + paragraph_style.text_align = TextAlign::left; + txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + text_style.font_family = "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 = 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() + // NOTE: The base truth values may still need adjustment as the specifics + // are adjusted. + Paragraph::RectHeightStyle rect_height_style = + Paragraph::RectHeightStyle::kIncludeLineSpacingMiddle; + Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax; + 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(), 17.429688); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.203125); + + paint.setColor(SK_ColorBLUE); + boxes = + paragraph->GetRectsForRange(2, 8, 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(), 67.429688); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.203125); + + paint.setColor(SK_ColorGREEN); + boxes = + paragraph->GetRectsForRange(8, 21, 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(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.203125); + + paint.setColor(SK_ColorRED); + boxes = + paragraph->GetRectsForRange(30, 100, 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(), 6ull); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 82.203125); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 187.20312); + + EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 82.203125); + EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 187.20312); + + EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 187.20312); + EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 292.20312); + + EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 187.20312); + EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 292.20312); + + EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 292.20312); + EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 397.20312); + + EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 397.20312); + EXPECT_FLOAT_EQ(boxes[5].rect.right(), 228.45703); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 502.20312); + + paint.setColor(SK_ColorBLUE); + boxes = + paragraph->GetRectsForRange(19, 22, 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(), 463.72656); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.203125); + + paint.setColor(SK_ColorRED); + boxes = + paragraph->GetRectsForRange(21, 21, 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); + + ASSERT_TRUE(Snapshot()); +} + +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 = + "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" + " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" + " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)"; + 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.line_height = 2.0; + paragraph_style.text_align = TextAlign::left; + txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + text_style.font_family = "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 = 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() + // NOTE: The base truth values may still need adjustment as the specifics + // are adjusted. + Paragraph::RectHeightStyle rect_height_style = + Paragraph::RectHeightStyle::kIncludeLineSpacingTop; + Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax; + 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(), 17.429688); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorBLUE); + boxes = + paragraph->GetRectsForRange(2, 8, 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(), 67.429688); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorGREEN); + boxes = + paragraph->GetRectsForRange(8, 21, 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(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorRED); + boxes = + paragraph->GetRectsForRange(30, 100, 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(), 6ull); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 164); + + EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 59); + EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 164); + + EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 164); + EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 269); + + EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 164); + EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 269); + + EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 269); + EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 374); + + EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 374); + EXPECT_FLOAT_EQ(boxes[5].rect.right(), 228.45703); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 479); + + paint.setColor(SK_ColorBLUE); + boxes = + paragraph->GetRectsForRange(19, 22, 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(), 463.72656); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + + paint.setColor(SK_ColorRED); + boxes = + paragraph->GetRectsForRange(21, 21, 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); + + ASSERT_TRUE(Snapshot()); +} + +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 = + "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" + " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)(" + " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)"; + 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.line_height = 2.0; + paragraph_style.text_align = TextAlign::left; + txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); + + txt::TextStyle text_style; + text_style.font_family = "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 = 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() + // NOTE: The base truth values may still need adjustment as the specifics + // are adjusted. + Paragraph::RectHeightStyle rect_height_style = + Paragraph::RectHeightStyle::kIncludeLineSpacingBottom; + Paragraph::RectWidthStyle rect_width_style = Paragraph::RectWidthStyle::kMax; + 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(), 17.429688); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 105.40625); + + paint.setColor(SK_ColorBLUE); + boxes = + paragraph->GetRectsForRange(2, 8, 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(), 67.429688); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 105.40625); + + paint.setColor(SK_ColorGREEN); + boxes = + paragraph->GetRectsForRange(8, 21, 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(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 105.40625); + + paint.setColor(SK_ColorRED); + boxes = + paragraph->GetRectsForRange(30, 150, 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(), 8ull); + EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 105.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 210.40625); + + EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 105.40625); + EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 210.40625); + + EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 210.40625); + EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 315.40625); + + EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 210.40625); + EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 315.40625); + + EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 315.40625); + EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 420.40625); + + EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 420.40625); + EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 525.40625); + + paint.setColor(SK_ColorBLUE); + boxes = + paragraph->GetRectsForRange(19, 22, 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(), 463.72656); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 105.40625); + + paint.setColor(SK_ColorRED); + boxes = + paragraph->GetRectsForRange(21, 21, 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); + + ASSERT_TRUE(Snapshot()); +} + SkRect GetCoordinatesForGlyphPosition(const txt::Paragraph& paragraph, size_t pos) { std::vector boxes = - paragraph.GetRectsForRange(pos, pos + 1, Paragraph::RectStyle::kNone); + paragraph.GetRectsForRange(pos, pos + 1, Paragraph::RectHeightStyle::kMax, + Paragraph::RectWidthStyle::kTight); return !boxes.empty() ? boxes.front().rect : SkRect::MakeEmpty(); } @@ -1718,9 +2192,12 @@ TEST_F(ParagraphTest, UnderlineShiftParagraph) { paragraph->records_[1].GetRunWidth(), paragraph2->records_[0].GetRunWidth()); - auto rects1 = paragraph->GetRectsForRange(0, 12, Paragraph::RectStyle::kNone); + auto rects1 = + paragraph->GetRectsForRange(0, 12, Paragraph::RectHeightStyle::kMax, + Paragraph::RectWidthStyle::kTight); auto rects2 = - paragraph2->GetRectsForRange(0, 12, Paragraph::RectStyle::kNone); + paragraph2->GetRectsForRange(0, 12, Paragraph::RectHeightStyle::kMax, + Paragraph::RectWidthStyle::kTight); for (size_t i = 0; i < 12; ++i) { auto r1 = GetCoordinatesForGlyphPosition(*paragraph, i); From bd7f2b3c508e0ac6fb29e44ba43639236a23cba4 Mon Sep 17 00:00:00 2001 From: GaryQian Date: Thu, 18 Oct 2018 15:13:36 -0700 Subject: [PATCH 2/7] Move cacheable rects metrics to Layout. --- third_party/txt/src/txt/paragraph.cc | 113 ++++++++-------- third_party/txt/src/txt/paragraph.h | 8 ++ third_party/txt/tests/paragraph_unittests.cc | 129 +++++++++---------- 3 files changed, 133 insertions(+), 117 deletions(-) diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index f53117357375a..ebe5e1070d93a 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -446,6 +446,10 @@ void Paragraph::Layout(double width, bool force) { line_baselines_.clear(); glyph_lines_.clear(); code_unit_runs_.clear(); + line_max_bottoms_.clear(); + line_min_tops_.clear(); + max_right_ = FLT_MIN; + min_left_ = FLT_MAX; minikin::Layout layout; SkTextBlobBuilder builder; @@ -458,6 +462,8 @@ void Paragraph::Layout(double width, bool force) { for (size_t line_number = 0; line_number < line_limit; ++line_number) { const LineRange& line_range = line_ranges_[line_number]; + line_max_bottoms_.push_back(0); + line_min_tops_.push_back(FLT_MAX); // Break the line into words if justification should be applied. std::vector> words; @@ -770,6 +776,21 @@ void Paragraph::Layout(double width, bool force) { y_offset += round(max_line_spacing + prev_max_descent); prev_max_descent = max_descent; + // Calcualte GetRectsForRange metrics. + for (CodeUnitRun& code_unit_run : line_code_unit_runs) { + code_unit_run.Shift(line_x_offset); + // Calcualte Rects Metrics: + SkScalar top = + line_baselines_[line_number] + code_unit_run.font_metrics.fAscent; + SkScalar bottom = + line_baselines_[line_number] + code_unit_run.font_metrics.fDescent; + line_min_tops_[line_number] = std::min(line_min_tops_[line_number], top); + line_max_bottoms_[line_number] = + std::max(line_max_bottoms_[line_number], bottom); + max_right_ = std::max(max_right_, code_unit_run.x_pos.end); + min_left_ = std::min(min_left_, code_unit_run.x_pos.start); + } + for (PaintRecord& paint_record : paint_records) { paint_record.SetOffset( SkPoint::Make(paint_record.offset().x() + line_x_offset, y_offset)); @@ -1098,16 +1119,12 @@ std::vector Paragraph::GetRectsForRange( RectHeightStyle rect_height_style, RectWidthStyle rect_width_style) const { std::map> line_boxes; - // Per-line min and max top/bottom edges over all runs in a given line. - std::vector min_tops; - std::vector max_bottoms; // Per-line metrics for max and min coordinates for left and right boxes. + // These metrics cannot be calculated in layout generically because of + // selections that do not cover the whole line. std::vector max_rights; std::vector min_lefts; - // Overall extremes of lines. - SkScalar max_right = 0; - SkScalar min_left = FLT_MAX; // Text direction of the first line so we can extend the correct side for // RectWidthStyle::kMax. TextDirection first_line_dir = TextDirection::ltr; @@ -1118,36 +1135,23 @@ std::vector Paragraph::GetRectsForRange( // Generate initial boxes and calculate metrics. for (const CodeUnitRun& run : code_unit_runs_) { - double baseline = line_baselines_[run.line_number]; - SkScalar top = baseline + run.font_metrics.fAscent; - SkScalar bottom = baseline + run.font_metrics.fDescent; - - // Calculate line height metrics. Not needed by RectHeightStyle::kTight. - if (rect_height_style != RectHeightStyle::kTight) { + if (rect_width_style == RectWidthStyle::kMax) { // Init metrics vectors as needed. - while (run.line_number >= min_tops.size()) { - min_tops.push_back(FLT_MAX); - max_bottoms.push_back(FLT_MIN); + while (run.line_number >= min_lefts.size()) { min_lefts.push_back(FLT_MAX); max_rights.push_back(FLT_MIN); } - min_tops[run.line_number] = std::min(min_tops[run.line_number], top); - max_bottoms[run.line_number] = - std::max(max_bottoms[run.line_number], bottom); } - // Check to see if we are finished. - if (run.code_units.start >= end) { - // We continue to store metrics of one additional line if available. - if (run.line_number <= max_line + 1) { - continue; - } else { - break; - } - } + if (run.code_units.start >= end) + break; if (run.code_units.end <= start) continue; + double baseline = line_baselines_[run.line_number]; + SkScalar top = baseline + run.font_metrics.fAscent; + SkScalar bottom = baseline + run.font_metrics.fDescent; + max_line = std::max(run.line_number, max_line); min_line = std::min(run.line_number, min_line); @@ -1171,8 +1175,11 @@ std::vector Paragraph::GetRectsForRange( // Keep track of the min and max horizontal coordinates over all lines. Not // needed for kTight. if (rect_width_style == RectWidthStyle::kMax) { - max_right = std::max(max_right, right); - min_left = std::min(min_left, left); + // Init metrics vectors as needed. + while (run.line_number >= min_lefts.size()) { + min_lefts.push_back(FLT_MAX); + max_rights.push_back(FLT_MIN); + } max_rights[run.line_number] = std::max(max_rights[run.line_number], right); min_lefts[run.line_number] = std::min(min_lefts[run.line_number], left); @@ -1211,18 +1218,18 @@ std::vector Paragraph::GetRectsForRange( // Handle rect_width_styles. We skip the last line because not everything is // selected. if (rect_width_style == RectWidthStyle::kMax && kv.first != max_line) { - if (min_lefts[kv.first] > min_left && + if (min_lefts[kv.first] > min_left_ && (kv.first != min_line || first_line_dir == TextDirection::rtl)) { line_boxes[kv.first].emplace_back( - SkRect::MakeLTRB(min_left, min_tops[kv.first], min_lefts[kv.first], - max_bottoms[kv.first]), + SkRect::MakeLTRB(min_left_, line_min_tops_[kv.first], + min_lefts[kv.first], line_max_bottoms_[kv.first]), TextDirection::rtl); } - if (max_rights[kv.first] < max_right && + if (max_rights[kv.first] < max_right_ && (kv.first != min_line || first_line_dir == TextDirection::ltr)) { line_boxes[kv.first].emplace_back( - SkRect::MakeLTRB(max_rights[kv.first], min_tops[kv.first], - max_right, max_bottoms[kv.first]), + SkRect::MakeLTRB(max_rights[kv.first], line_min_tops_[kv.first], + max_right_, line_max_bottoms_[kv.first]), TextDirection::ltr); } } @@ -1234,19 +1241,22 @@ std::vector Paragraph::GetRectsForRange( } else if (rect_height_style == RectHeightStyle::kMax) { for (const Paragraph::TextBox& box : kv.second) { boxes.emplace_back( - SkRect::MakeLTRB(box.rect.fLeft, min_tops[kv.first], - box.rect.fRight, max_bottoms[kv.first]), + SkRect::MakeLTRB(box.rect.fLeft, line_min_tops_[kv.first], + box.rect.fRight, line_max_bottoms_[kv.first]), box.direction); } } else if (rect_height_style == RectHeightStyle::kIncludeLineSpacingMiddle) { SkScalar adjusted_bottom = - kv.first >= max_bottoms.size() - ? max_bottoms[kv.first] - : (min_tops[kv.first + 1] + max_bottoms[kv.first]) / 2; + kv.first >= line_max_bottoms_.size() + ? line_max_bottoms_[kv.first] + : (line_min_tops_[kv.first + 1] + line_max_bottoms_[kv.first]) / + 2; SkScalar adjusted_top = - kv.first == 0 ? min_tops[kv.first] - : (max_bottoms[kv.first - 1] + min_tops[kv.first]) / 2; + kv.first == 0 + ? line_min_tops_[kv.first] + : (line_max_bottoms_[kv.first - 1] + line_min_tops_[kv.first]) / + 2; for (const Paragraph::TextBox& box : kv.second) { boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, box.rect.fRight, adjusted_bottom), @@ -1254,21 +1264,22 @@ std::vector Paragraph::GetRectsForRange( } } else if (rect_height_style == RectHeightStyle::kIncludeLineSpacingTop) { for (const Paragraph::TextBox& box : kv.second) { - SkScalar adjusted_top = - kv.first == 0 ? min_tops[kv.first] : max_bottoms[kv.first - 1]; + SkScalar adjusted_top = kv.first == 0 ? line_min_tops_[kv.first] + : line_max_bottoms_[kv.first - 1]; boxes.emplace_back( SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, box.rect.fRight, - max_bottoms[kv.first]), + line_max_bottoms_[kv.first]), box.direction); } } else { // kIncludeLineSpacingBottom for (const Paragraph::TextBox& box : kv.second) { - SkScalar adjusted_bottom = kv.first >= max_bottoms.size() - ? max_bottoms[kv.first] - : min_tops[kv.first + 1]; - boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, min_tops[kv.first], - box.rect.fRight, adjusted_bottom), - box.direction); + SkScalar adjusted_bottom = kv.first >= line_ranges_.size() - 1 + ? line_max_bottoms_[kv.first] + : line_min_tops_[kv.first + 1]; + boxes.emplace_back( + SkRect::MakeLTRB(box.rect.fLeft, line_min_tops_[kv.first], + box.rect.fRight, adjusted_bottom), + box.direction); } } } diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index 2f83f9caeacc9..be59ff13d3870 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -258,6 +258,14 @@ class Paragraph { std::vector line_baselines_; bool did_exceed_max_lines_; + // Metrics for use in GetRectsForRange(...); + // Per-line min and max top/bottom edges over all runs in a given line. + std::vector line_max_bottoms_; + std::vector line_min_tops_; + // Overall left and right extremes over all lines. + double max_right_; + double min_left_; + class BidiRun { public: BidiRun(size_t s, size_t e, TextDirection d, const TextStyle& st) diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc index 24057c1d26bd9..d13867b786274 100644 --- a/third_party/txt/tests/paragraph_unittests.cc +++ b/third_party/txt/tests/paragraph_unittests.cc @@ -1175,7 +1175,6 @@ TEST_F(ParagraphTest, txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; - paragraph_style.line_height = 2.0; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); @@ -1186,7 +1185,7 @@ TEST_F(ParagraphTest, text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; - text_style.height = 1; + text_style.height = 2.0; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -1224,9 +1223,9 @@ TEST_F(ParagraphTest, } 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.top(), 46.199219); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.203125); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 133.99609); paint.setColor(SK_ColorBLUE); boxes = @@ -1236,9 +1235,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.203125); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 133.99609); paint.setColor(SK_ColorGREEN); boxes = @@ -1248,9 +1247,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.203125); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 133.99609); paint.setColor(SK_ColorRED); boxes = @@ -1260,34 +1259,34 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 6ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 82.203125); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 133.99609); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 187.20312); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 250.99609); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 82.203125); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 133.99609); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 187.20312); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 250.99609); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 187.20312); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 250.99609); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 292.20312); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 367.99609); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 187.20312); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 250.99609); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 292.20312); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 367.99609); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 292.20312); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 367.99609); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 397.20312); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 484.99609); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[5].rect.top(), 397.20312); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 484.99609); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 228.45703); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 502.20312); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 601.99609); paint.setColor(SK_ColorBLUE); boxes = @@ -1297,9 +1296,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.203125); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 133.99609); paint.setColor(SK_ColorRED); boxes = @@ -1327,7 +1326,6 @@ TEST_F(ParagraphTest, txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; - paragraph_style.line_height = 2.0; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); @@ -1338,7 +1336,7 @@ TEST_F(ParagraphTest, text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; - text_style.height = 1; + text_style.height = 2.0; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -1376,9 +1374,9 @@ TEST_F(ParagraphTest, } 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.top(), 46.199219); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 104.79297); paint.setColor(SK_ColorBLUE); boxes = @@ -1388,9 +1386,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 104.79297); paint.setColor(SK_ColorGREEN); boxes = @@ -1400,9 +1398,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 104.79297); paint.setColor(SK_ColorRED); boxes = @@ -1412,34 +1410,34 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 6ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 59); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 104.79297); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 164); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 221.79297); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 59); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 104.79297); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 164); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 221.79297); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 164); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 221.79297); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 269); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 338.79297); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 164); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 221.79297); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 269); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 338.79297); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 269); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 338.79297); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 374); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 455.79297); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[5].rect.top(), 374); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 455.79297); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 228.45703); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 479); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 572.79297); paint.setColor(SK_ColorBLUE); boxes = @@ -1449,9 +1447,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 104.79297); paint.setColor(SK_ColorRED); boxes = @@ -1479,7 +1477,6 @@ TEST_F(ParagraphTest, txt::ParagraphStyle paragraph_style; paragraph_style.max_lines = 10; - paragraph_style.line_height = 2.0; paragraph_style.text_align = TextAlign::left; txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection()); @@ -1490,7 +1487,7 @@ TEST_F(ParagraphTest, text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; - text_style.height = 1; + text_style.height = 1.3; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -1528,9 +1525,9 @@ TEST_F(ParagraphTest, } 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.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 105.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.744141); paint.setColor(SK_ColorBLUE); boxes = @@ -1540,9 +1537,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 105.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.744141); paint.setColor(SK_ColorGREEN); boxes = @@ -1552,9 +1549,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 105.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.744141); paint.setColor(SK_ColorRED); boxes = @@ -1564,34 +1561,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(), 105.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 89.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 210.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 165.74414); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 105.40625); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 89.744141); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 210.40625); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 165.74414); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 210.40625); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 165.74414); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 315.40625); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 241.74414); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 210.40625); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 165.74414); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 315.40625); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 241.74414); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 315.40625); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 241.74414); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 420.40625); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 317.74414); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[5].rect.top(), 420.40625); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 317.74414); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 525.40625); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 393.74414); paint.setColor(SK_ColorBLUE); boxes = @@ -1601,9 +1598,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(), 0.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 105.40625); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.744141); paint.setColor(SK_ColorRED); boxes = From bbbfb7b87c3258e0521ada9437b632f634fe82f6 Mon Sep 17 00:00:00 2001 From: GaryQian Date: Fri, 19 Oct 2018 10:44:14 -0700 Subject: [PATCH 3/7] Reworked rects to use existing metrics --- third_party/txt/src/txt/paragraph.cc | 105 +++++++++------- third_party/txt/src/txt/paragraph.h | 7 +- third_party/txt/tests/paragraph_unittests.cc | 126 +++++++++---------- 3 files changed, 129 insertions(+), 109 deletions(-) diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index ebe5e1070d93a..0319786361859 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -446,8 +446,9 @@ void Paragraph::Layout(double width, bool force) { line_baselines_.clear(); glyph_lines_.clear(); code_unit_runs_.clear(); - line_max_bottoms_.clear(); - line_min_tops_.clear(); + line_max_spacings_.clear(); + line_max_descent_.clear(); + line_max_ascent_.clear(); max_right_ = FLT_MIN; min_left_ = FLT_MAX; @@ -462,8 +463,6 @@ void Paragraph::Layout(double width, bool force) { for (size_t line_number = 0; line_number < line_limit; ++line_number) { const LineRange& line_range = line_ranges_[line_number]; - line_max_bottoms_.push_back(0); - line_min_tops_.push_back(FLT_MAX); // Break the line into words if justification should be applied. std::vector> words; @@ -709,6 +708,9 @@ void Paragraph::Layout(double width, bool force) { Range(glyph_positions.front().x_pos.start, glyph_positions.back().x_pos.end), line_number, metrics, run.direction()); + + min_left_ = std::min(min_left_, glyph_positions.front().x_pos.start); + max_right_ = std::max(max_right_, glyph_positions.back().x_pos.end); } // for each in glyph_blobs run_x_offset += layout.getAdvance(); @@ -735,8 +737,12 @@ void Paragraph::Layout(double width, bool force) { double max_line_spacing = 0; double max_descent = 0; + SkScalar max_unscaled_ascent = 0; auto update_line_metrics = [&](const SkPaint::FontMetrics& metrics, const TextStyle& style) { + // TODO(garyq): Multipling in the style.height on the first line is + // probably wrong. Figure out how paragraph and line heights are supposed + // to work and fix it. double line_spacing = (line_number == 0) ? -metrics.fAscent * style.height @@ -753,6 +759,8 @@ void Paragraph::Layout(double width, bool force) { double descent = metrics.fDescent * style.height; max_descent = std::max(descent, max_descent); + + max_unscaled_ascent = std::max(-metrics.fAscent, max_unscaled_ascent); }; for (const PaintRecord& paint_record : paint_records) { update_line_metrics(paint_record.metrics(), paint_record.style()); @@ -776,20 +784,11 @@ void Paragraph::Layout(double width, bool force) { y_offset += round(max_line_spacing + prev_max_descent); prev_max_descent = max_descent; - // Calcualte GetRectsForRange metrics. - for (CodeUnitRun& code_unit_run : line_code_unit_runs) { - code_unit_run.Shift(line_x_offset); - // Calcualte Rects Metrics: - SkScalar top = - line_baselines_[line_number] + code_unit_run.font_metrics.fAscent; - SkScalar bottom = - line_baselines_[line_number] + code_unit_run.font_metrics.fDescent; - line_min_tops_[line_number] = std::min(line_min_tops_[line_number], top); - line_max_bottoms_[line_number] = - std::max(line_max_bottoms_[line_number], bottom); - max_right_ = std::max(max_right_, code_unit_run.x_pos.end); - min_left_ = std::min(min_left_, code_unit_run.x_pos.start); - } + // The max line spacing and ascent have been multiplied by -1 to make math + // in GetRectsForRange more logical/readable. + line_max_spacings_.push_back(max_line_spacing); + line_max_descent_.push_back(max_descent); + line_max_ascent_.push_back(max_unscaled_ascent); for (PaintRecord& paint_record : paint_records) { paint_record.SetOffset( @@ -1221,42 +1220,56 @@ std::vector Paragraph::GetRectsForRange( if (min_lefts[kv.first] > min_left_ && (kv.first != min_line || first_line_dir == TextDirection::rtl)) { line_boxes[kv.first].emplace_back( - SkRect::MakeLTRB(min_left_, line_min_tops_[kv.first], - min_lefts[kv.first], line_max_bottoms_[kv.first]), + SkRect::MakeLTRB( + min_left_, + line_baselines_[kv.first] - line_max_ascent_[kv.first], + min_lefts[kv.first], + line_baselines_[kv.first] + line_max_descent_[kv.first]), TextDirection::rtl); } if (max_rights[kv.first] < max_right_ && (kv.first != min_line || first_line_dir == TextDirection::ltr)) { line_boxes[kv.first].emplace_back( - SkRect::MakeLTRB(max_rights[kv.first], line_min_tops_[kv.first], - max_right_, line_max_bottoms_[kv.first]), + SkRect::MakeLTRB( + max_rights[kv.first], + line_baselines_[kv.first] - line_max_ascent_[kv.first], + max_right_, + line_baselines_[kv.first] + line_max_descent_[kv.first]), TextDirection::ltr); } } - // Handle rect_height_styles + // Handle rect_height_styles. The height metrics used are all positive to + // make the signage clear here. if (rect_height_style == RectHeightStyle::kTight) { // Ignore line max height and width and generate tight bounds. boxes.insert(boxes.end(), kv.second.begin(), kv.second.end()); } else if (rect_height_style == RectHeightStyle::kMax) { for (const Paragraph::TextBox& box : kv.second) { boxes.emplace_back( - SkRect::MakeLTRB(box.rect.fLeft, line_min_tops_[kv.first], - box.rect.fRight, line_max_bottoms_[kv.first]), + SkRect::MakeLTRB( + box.rect.fLeft, + line_baselines_[kv.first] - line_max_ascent_[kv.first], + box.rect.fRight, + line_baselines_[kv.first] + line_max_descent_[kv.first]), box.direction); } } else if (rect_height_style == RectHeightStyle::kIncludeLineSpacingMiddle) { SkScalar adjusted_bottom = - kv.first >= line_max_bottoms_.size() - ? line_max_bottoms_[kv.first] - : (line_min_tops_[kv.first + 1] + line_max_bottoms_[kv.first]) / - 2; + kv.first >= line_ranges_.size() - 1 + ? line_baselines_[kv.first] + line_max_descent_[kv.first] + : line_baselines_[kv.first] + line_max_descent_[kv.first] + + (line_max_spacings_[kv.first + 1] - + line_max_ascent_[kv.first + 1]) / + 2; SkScalar adjusted_top = kv.first == 0 - ? line_min_tops_[kv.first] - : (line_max_bottoms_[kv.first - 1] + line_min_tops_[kv.first]) / - 2; + ? line_baselines_[kv.first] - line_max_ascent_[kv.first] + : line_baselines_[kv.first] - line_max_ascent_[kv.first] - + (line_max_spacings_[kv.first] - + line_max_ascent_[kv.first]) / + 2; for (const Paragraph::TextBox& box : kv.second) { boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, box.rect.fRight, adjusted_bottom), @@ -1264,22 +1277,28 @@ std::vector Paragraph::GetRectsForRange( } } else if (rect_height_style == RectHeightStyle::kIncludeLineSpacingTop) { for (const Paragraph::TextBox& box : kv.second) { - SkScalar adjusted_top = kv.first == 0 ? line_min_tops_[kv.first] - : line_max_bottoms_[kv.first - 1]; + SkScalar adjusted_top = + kv.first == 0 + ? line_baselines_[kv.first] - line_max_ascent_[kv.first] + : line_baselines_[kv.first] - line_max_spacings_[kv.first]; boxes.emplace_back( - SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, box.rect.fRight, - line_max_bottoms_[kv.first]), + SkRect::MakeLTRB( + box.rect.fLeft, adjusted_top, box.rect.fRight, + line_baselines_[kv.first] + line_max_descent_[kv.first]), box.direction); } } else { // kIncludeLineSpacingBottom for (const Paragraph::TextBox& box : kv.second) { - SkScalar adjusted_bottom = kv.first >= line_ranges_.size() - 1 - ? line_max_bottoms_[kv.first] - : line_min_tops_[kv.first + 1]; - boxes.emplace_back( - SkRect::MakeLTRB(box.rect.fLeft, line_min_tops_[kv.first], - box.rect.fRight, adjusted_bottom), - box.direction); + SkScalar adjusted_bottom = + kv.first >= line_ranges_.size() - 1 + ? line_baselines_[kv.first] + line_max_descent_[kv.first] + : line_baselines_[kv.first] + line_max_descent_[kv.first] - + line_max_ascent_[kv.first] + line_max_spacings_[kv.first]; + boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, + line_baselines_[kv.first] - + line_max_ascent_[kv.first], + box.rect.fRight, adjusted_bottom), + box.direction); } } } diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index be59ff13d3870..a23237f57cbb6 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -259,9 +259,10 @@ class Paragraph { bool did_exceed_max_lines_; // Metrics for use in GetRectsForRange(...); - // Per-line min and max top/bottom edges over all runs in a given line. - std::vector line_max_bottoms_; - std::vector line_min_tops_; + // Per-line max metrics over all runs in a given line. + std::vector line_max_spacings_; + std::vector line_max_descent_; + std::vector line_max_ascent_; // Overall left and right extremes over all lines. double max_right_; double min_left_; diff --git a/third_party/txt/tests/paragraph_unittests.cc b/third_party/txt/tests/paragraph_unittests.cc index d13867b786274..b7589f7e211fd 100644 --- a/third_party/txt/tests/paragraph_unittests.cc +++ b/third_party/txt/tests/paragraph_unittests.cc @@ -892,7 +892,7 @@ TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateParagraph) { text_style.letter_spacing = 1; text_style.word_spacing = 5; text_style.color = SK_ColorBLACK; - text_style.height = 1.5; + text_style.height = 1; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -930,11 +930,11 @@ TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateParagraph) { 18ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(20, -80).position, 1ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 90).position, 18ull); - ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 180).position, 36ull); + ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 170).position, 36ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(10000, 180).position, - 54ull); - ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(70, 180).position, 38ull); - ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 270).position, 54ull); + 72ull); + ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(70, 180).position, 56ull); + ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(1, 270).position, 72ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(35, 90).position, 19ull); ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(10000, 10000).position, 77ull); @@ -1185,7 +1185,7 @@ TEST_F(ParagraphTest, text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; - text_style.height = 2.0; + text_style.height = 1.3; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -1223,9 +1223,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 133.99609); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.958008); paint.setColor(SK_ColorBLUE); boxes = @@ -1235,9 +1235,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(), 46.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 133.99609); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.958008); paint.setColor(SK_ColorGREEN); boxes = @@ -1247,46 +1247,46 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 133.99609); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.958008); paint.setColor(SK_ColorRED); boxes = - paragraph->GetRectsForRange(30, 100, rect_height_style, rect_width_style); + paragraph->GetRectsForRange(30, 150, 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(), 6ull); + EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 133.99609); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 82.786133); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 250.99609); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 158.95801); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 133.99609); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 82.786133); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 250.99609); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 158.95801); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 250.99609); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 158.78613); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 367.99609); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 234.95801); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 250.99609); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 158.78613); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 367.99609); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 234.95801); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 367.99609); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 234.78613); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 484.99609); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 310.95801); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[5].rect.top(), 484.99609); - EXPECT_FLOAT_EQ(boxes[5].rect.right(), 228.45703); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 601.99609); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 310.78613); + EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 386.95801); paint.setColor(SK_ColorBLUE); boxes = @@ -1296,9 +1296,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(), 46.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 133.99609); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 82.958008); paint.setColor(SK_ColorRED); boxes = @@ -1336,7 +1336,7 @@ TEST_F(ParagraphTest, text_style.font_weight = FontWeight::w500; text_style.word_spacing = 0; text_style.color = SK_ColorBLACK; - text_style.height = 2.0; + text_style.height = 1.3; builder.PushStyle(text_style); builder.AddText(u16_text); @@ -1374,9 +1374,9 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 104.79297); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 76); paint.setColor(SK_ColorBLUE); boxes = @@ -1386,9 +1386,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(), 46.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 104.79297); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 76); paint.setColor(SK_ColorGREEN); boxes = @@ -1398,46 +1398,46 @@ TEST_F(ParagraphTest, } EXPECT_EQ(boxes.size(), 1ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 46.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 104.79297); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 76); paint.setColor(SK_ColorRED); boxes = - paragraph->GetRectsForRange(30, 100, rect_height_style, rect_width_style); + paragraph->GetRectsForRange(30, 150, 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(), 6ull); + EXPECT_EQ(boxes.size(), 8ull); EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.top(), 104.79297); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 75.828125); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 221.79297); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 152); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); - EXPECT_FLOAT_EQ(boxes[1].rect.top(), 104.79297); + EXPECT_FLOAT_EQ(boxes[1].rect.top(), 75.828125); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 221.79297); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 152); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[2].rect.top(), 221.79297); + EXPECT_FLOAT_EQ(boxes[2].rect.top(), 151.82812); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 338.79297); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 228); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); - EXPECT_FLOAT_EQ(boxes[3].rect.top(), 221.79297); + EXPECT_FLOAT_EQ(boxes[3].rect.top(), 151.82812); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 338.79297); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 228); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[4].rect.top(), 338.79297); + EXPECT_FLOAT_EQ(boxes[4].rect.top(), 227.82812); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 455.79297); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 304); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); - EXPECT_FLOAT_EQ(boxes[5].rect.top(), 455.79297); - EXPECT_FLOAT_EQ(boxes[5].rect.right(), 228.45703); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 572.79297); + EXPECT_FLOAT_EQ(boxes[5].rect.top(), 303.82812); + EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 380); paint.setColor(SK_ColorBLUE); boxes = @@ -1447,9 +1447,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(), 46.199219); + EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 104.79297); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 76); paint.setColor(SK_ColorRED); boxes = @@ -1527,7 +1527,7 @@ TEST_F(ParagraphTest, EXPECT_FLOAT_EQ(boxes[0].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 17.429688); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.916016); paint.setColor(SK_ColorBLUE); boxes = @@ -1539,7 +1539,7 @@ TEST_F(ParagraphTest, EXPECT_FLOAT_EQ(boxes[0].rect.left(), 67.429688); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 190.00781); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.916016); paint.setColor(SK_ColorGREEN); boxes = @@ -1551,7 +1551,7 @@ TEST_F(ParagraphTest, EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 508.0625); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.916016); paint.setColor(SK_ColorRED); boxes = @@ -1563,32 +1563,32 @@ TEST_F(ParagraphTest, EXPECT_FLOAT_EQ(boxes[0].rect.left(), 190.00781); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 89.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 525.6875); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 165.74414); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 165.91602); EXPECT_FLOAT_EQ(boxes[1].rect.left(), 525.6875); EXPECT_FLOAT_EQ(boxes[1].rect.top(), 89.744141); EXPECT_FLOAT_EQ(boxes[1].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 165.74414); + EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 165.91602); EXPECT_FLOAT_EQ(boxes[2].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[2].rect.top(), 165.74414); EXPECT_FLOAT_EQ(boxes[2].rect.right(), 531.57422); - EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 241.74414); + EXPECT_FLOAT_EQ(boxes[2].rect.bottom(), 241.91602); EXPECT_FLOAT_EQ(boxes[3].rect.left(), 531.57422); EXPECT_FLOAT_EQ(boxes[3].rect.top(), 165.74414); EXPECT_FLOAT_EQ(boxes[3].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 241.74414); + EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 241.91602); EXPECT_FLOAT_EQ(boxes[4].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[4].rect.top(), 241.74414); EXPECT_FLOAT_EQ(boxes[4].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 317.74414); + EXPECT_FLOAT_EQ(boxes[4].rect.bottom(), 317.91602); EXPECT_FLOAT_EQ(boxes[5].rect.left(), 0); EXPECT_FLOAT_EQ(boxes[5].rect.top(), 317.74414); EXPECT_FLOAT_EQ(boxes[5].rect.right(), 570.02344); - EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 393.74414); + EXPECT_FLOAT_EQ(boxes[5].rect.bottom(), 393.91602); paint.setColor(SK_ColorBLUE); boxes = @@ -1600,7 +1600,7 @@ TEST_F(ParagraphTest, EXPECT_FLOAT_EQ(boxes[0].rect.left(), 463.72656); EXPECT_FLOAT_EQ(boxes[0].rect.top(), 13.744141); EXPECT_FLOAT_EQ(boxes[0].rect.right(), 530.23047); - EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.744141); + EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 89.916016); paint.setColor(SK_ColorRED); boxes = From 674a9128897b20a115c28fcf08f5d14b9245272a Mon Sep 17 00:00:00 2001 From: GaryQian Date: Fri, 19 Oct 2018 22:35:49 -0700 Subject: [PATCH 4/7] rects work --- lib/ui/text.dart | 53 ++++++++++++++++++++++ third_party/txt/src/txt/paragraph.cc | 67 +++++++++++++--------------- third_party/txt/src/txt/paragraph.h | 9 ++++ 3 files changed, 93 insertions(+), 36 deletions(-) diff --git a/lib/ui/text.dart b/lib/ui/text.dart index 664cbaedef276..5ad35dc34d95e 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -947,6 +947,59 @@ class ParagraphConstraints { String toString() => '$runtimeType(width: $width)'; } +/// Defines various ways to vertically bound the boxes returned by +/// [Paragraph.getBoxesForRange]. +enum RectHeightStyle { + /// The height of the boxes will be the maximum height of all runs in the + /// line. All boxes in the same line will be the same height. + max, + + /// Provide tight bounding boxes that fit heights per run. This style may result + /// in uneven bounding boxes that do not nicely connect with the lines above and + /// below. + tight, + + /// Extends the top and bottom edge of the bounds to fully cover any line + /// spacing. + /// + /// The top and bottom of each rect will cover half of the + /// space above and half of the space below the line. The text should be + /// centered vertically within the box. + /// + /// {@template flutter.dart:ui.rectHeightStyle.includeLineSpacing} + /// The top edge of each line should be the same as the bottom edge + /// of the line above. There should be no gaps in vertical coverage given any + /// amount of line spacing. Line spacing is not included above the first line + /// below the last line due to no additional space present there. + /// {@endtemplate} + includeLineSpacingMiddle, + /// Extends the top edge of the bounds to fully cover any line spacing. + /// + /// {@macro flutter.dart:ui.rectHeightStyle.includeLineSpacing} + /// + /// The line spacing will be added to the top of the rect. + includeLineSpacingTop, + /// Extends the bottom edge of the bounds to fully cover any line spacing. + /// + /// {@macro flutter.dart:ui.rectHeightStyle.includeLineSpacing} + /// + /// The line spacing will be added to the bottom of the rect. + includeLineSpacingBottom +} + +/// Defines various ways to horizontally bound the boxes returned by +/// [Paragraph.getBoxesForRange]. +enum RectWidthStyle { + /// Extends the width of the last rect of each line to match the position of + /// the widest rect over all the lines. This will add an additional box that + /// runs from the end of the last box in the line to the max width position + /// whenever the last box does not reach the max width. + max, + + // Provide tight bounding boxes that fit widths to the runs of each line + // independently. + tight +} /// A paragraph of text. /// /// A paragraph retains the size and position of each glyph in the text and can diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index 0319786361859..0104e6f782f39 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -1117,13 +1117,7 @@ std::vector Paragraph::GetRectsForRange( size_t end, RectHeightStyle rect_height_style, RectWidthStyle rect_width_style) const { - std::map> line_boxes; - - // Per-line metrics for max and min coordinates for left and right boxes. - // These metrics cannot be calculated in layout generically because of - // selections that do not cover the whole line. - std::vector max_rights; - std::vector min_lefts; + std::map line_metrics; // Text direction of the first line so we can extend the correct side for // RectWidthStyle::kMax. TextDirection first_line_dir = TextDirection::ltr; @@ -1134,13 +1128,13 @@ std::vector Paragraph::GetRectsForRange( // Generate initial boxes and calculate metrics. for (const CodeUnitRun& run : code_unit_runs_) { - if (rect_width_style == RectWidthStyle::kMax) { - // Init metrics vectors as needed. - while (run.line_number >= min_lefts.size()) { - min_lefts.push_back(FLT_MAX); - max_rights.push_back(FLT_MIN); - } - } + // if (rect_width_style == RectWidthStyle::kMax) { + // // Init metrics vectors as needed. + // while (run.line_number >= min_lefts.size()) { + // min_lefts.push_back(FLT_MAX); + // max_rights.push_back(FLT_MIN); + // } + // } // Check to see if we are finished. if (run.code_units.start >= end) break; @@ -1175,18 +1169,19 @@ std::vector Paragraph::GetRectsForRange( // needed for kTight. if (rect_width_style == RectWidthStyle::kMax) { // Init metrics vectors as needed. - while (run.line_number >= min_lefts.size()) { - min_lefts.push_back(FLT_MAX); - max_rights.push_back(FLT_MIN); - } - max_rights[run.line_number] = - std::max(max_rights[run.line_number], right); - min_lefts[run.line_number] = std::min(min_lefts[run.line_number], left); + // while (run.line_number >= min_lefts.size()) { + // min_lefts.push_back(FLT_MAX); + // max_rights.push_back(FLT_MIN); + // } + line_metrics[run.line_number].max_right = + std::max(line_metrics[run.line_number].max_right, right); + line_metrics[run.line_number].min_left = + std::min(line_metrics[run.line_number].min_left, left); if (min_line == run.line_number) { first_line_dir = run.direction; } } - line_boxes[run.line_number].emplace_back( + line_metrics[run.line_number].boxes.emplace_back( SkRect::MakeLTRB(left, top, right, bottom), run.direction); } @@ -1199,13 +1194,13 @@ std::vector Paragraph::GetRectsForRange( break; if (line.end_including_newline <= start) continue; - if (line_boxes.find(line_number) == line_boxes.end()) { + if (line_metrics.find(line_number) == line_metrics.end()) { if (line.end != line.end_including_newline && line.end >= start && line.end_including_newline <= end) { SkScalar x = line_widths_[line_number]; SkScalar top = (line_number > 0) ? line_heights_[line_number - 1] : 0; SkScalar bottom = line_heights_[line_number]; - line_boxes[line_number].emplace_back( + line_metrics[line_number].boxes.emplace_back( SkRect::MakeLTRB(x, top, x, bottom), TextDirection::ltr); } } @@ -1213,25 +1208,25 @@ std::vector Paragraph::GetRectsForRange( // "Post-process" metrics and aggregate final rects to return. std::vector boxes; - for (const auto& kv : line_boxes) { + for (const auto& kv : line_metrics) { // Handle rect_width_styles. We skip the last line because not everything is // selected. if (rect_width_style == RectWidthStyle::kMax && kv.first != max_line) { - if (min_lefts[kv.first] > min_left_ && + if (line_metrics[kv.first].min_left > min_left_ && (kv.first != min_line || first_line_dir == TextDirection::rtl)) { - line_boxes[kv.first].emplace_back( + line_metrics[kv.first].boxes.emplace_back( SkRect::MakeLTRB( min_left_, line_baselines_[kv.first] - line_max_ascent_[kv.first], - min_lefts[kv.first], + line_metrics[kv.first].min_left, line_baselines_[kv.first] + line_max_descent_[kv.first]), TextDirection::rtl); } - if (max_rights[kv.first] < max_right_ && + if (line_metrics[kv.first].max_right < max_right_ && (kv.first != min_line || first_line_dir == TextDirection::ltr)) { - line_boxes[kv.first].emplace_back( + line_metrics[kv.first].boxes.emplace_back( SkRect::MakeLTRB( - max_rights[kv.first], + line_metrics[kv.first].max_right, line_baselines_[kv.first] - line_max_ascent_[kv.first], max_right_, line_baselines_[kv.first] + line_max_descent_[kv.first]), @@ -1243,9 +1238,9 @@ std::vector Paragraph::GetRectsForRange( // make the signage clear here. if (rect_height_style == RectHeightStyle::kTight) { // Ignore line max height and width and generate tight bounds. - boxes.insert(boxes.end(), kv.second.begin(), kv.second.end()); + boxes.insert(boxes.end(), kv.second.boxes.begin(), kv.second.boxes.end()); } else if (rect_height_style == RectHeightStyle::kMax) { - for (const Paragraph::TextBox& box : kv.second) { + for (const Paragraph::TextBox& box : kv.second.boxes) { boxes.emplace_back( SkRect::MakeLTRB( box.rect.fLeft, @@ -1270,13 +1265,13 @@ std::vector Paragraph::GetRectsForRange( (line_max_spacings_[kv.first] - line_max_ascent_[kv.first]) / 2; - for (const Paragraph::TextBox& box : kv.second) { + for (const Paragraph::TextBox& box : kv.second.boxes) { boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, box.rect.fRight, adjusted_bottom), box.direction); } } else if (rect_height_style == RectHeightStyle::kIncludeLineSpacingTop) { - for (const Paragraph::TextBox& box : kv.second) { + for (const Paragraph::TextBox& box : kv.second.boxes) { SkScalar adjusted_top = kv.first == 0 ? line_baselines_[kv.first] - line_max_ascent_[kv.first] @@ -1288,7 +1283,7 @@ std::vector Paragraph::GetRectsForRange( box.direction); } } else { // kIncludeLineSpacingBottom - for (const Paragraph::TextBox& box : kv.second) { + for (const Paragraph::TextBox& box : kv.second.boxes) { SkScalar adjusted_bottom = kv.first >= line_ranges_.size() - 1 ? line_baselines_[kv.first] + line_max_descent_[kv.first] diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index a23237f57cbb6..46f835ee19ece 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -267,6 +267,15 @@ class Paragraph { double max_right_; double min_left_; + struct LineBoxMetrics { + std::vector boxes; + // Per-line metrics for max and min coordinates for left and right boxes. + // These metrics cannot be calculated in layout generically because of + // selections that do not cover the whole line. + SkScalar max_right = FLT_MAX; + SkScalar min_left = FLT_MIN; + }; + class BidiRun { public: BidiRun(size_t s, size_t e, TextDirection d, const TextStyle& st) From d08cbe7c6828e66cbf462bdea6abfecb8132b806 Mon Sep 17 00:00:00 2001 From: GaryQian Date: Mon, 22 Oct 2018 13:35:35 -0700 Subject: [PATCH 5/7] Fix init of max/min and improve kIncludeLineSpacingMiddle impl. --- lib/ui/text.dart | 53 ---------------------------- third_party/txt/src/txt/paragraph.cc | 35 ++++++------------ third_party/txt/src/txt/paragraph.h | 4 +-- 3 files changed, 13 insertions(+), 79 deletions(-) diff --git a/lib/ui/text.dart b/lib/ui/text.dart index 5ad35dc34d95e..664cbaedef276 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -947,59 +947,6 @@ class ParagraphConstraints { String toString() => '$runtimeType(width: $width)'; } -/// Defines various ways to vertically bound the boxes returned by -/// [Paragraph.getBoxesForRange]. -enum RectHeightStyle { - /// The height of the boxes will be the maximum height of all runs in the - /// line. All boxes in the same line will be the same height. - max, - - /// Provide tight bounding boxes that fit heights per run. This style may result - /// in uneven bounding boxes that do not nicely connect with the lines above and - /// below. - tight, - - /// Extends the top and bottom edge of the bounds to fully cover any line - /// spacing. - /// - /// The top and bottom of each rect will cover half of the - /// space above and half of the space below the line. The text should be - /// centered vertically within the box. - /// - /// {@template flutter.dart:ui.rectHeightStyle.includeLineSpacing} - /// The top edge of each line should be the same as the bottom edge - /// of the line above. There should be no gaps in vertical coverage given any - /// amount of line spacing. Line spacing is not included above the first line - /// below the last line due to no additional space present there. - /// {@endtemplate} - includeLineSpacingMiddle, - /// Extends the top edge of the bounds to fully cover any line spacing. - /// - /// {@macro flutter.dart:ui.rectHeightStyle.includeLineSpacing} - /// - /// The line spacing will be added to the top of the rect. - includeLineSpacingTop, - /// Extends the bottom edge of the bounds to fully cover any line spacing. - /// - /// {@macro flutter.dart:ui.rectHeightStyle.includeLineSpacing} - /// - /// The line spacing will be added to the bottom of the rect. - includeLineSpacingBottom -} - -/// Defines various ways to horizontally bound the boxes returned by -/// [Paragraph.getBoxesForRange]. -enum RectWidthStyle { - /// Extends the width of the last rect of each line to match the position of - /// the widest rect over all the lines. This will add an additional box that - /// runs from the end of the last box in the line to the max width position - /// whenever the last box does not reach the max width. - max, - - // Provide tight bounding boxes that fit widths to the runs of each line - // independently. - tight -} /// A paragraph of text. /// /// A paragraph retains the size and position of each glyph in the text and can diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index 0104e6f782f39..bf077db844e2b 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -1128,13 +1128,6 @@ std::vector Paragraph::GetRectsForRange( // Generate initial boxes and calculate metrics. for (const CodeUnitRun& run : code_unit_runs_) { - // if (rect_width_style == RectWidthStyle::kMax) { - // // Init metrics vectors as needed. - // while (run.line_number >= min_lefts.size()) { - // min_lefts.push_back(FLT_MAX); - // max_rights.push_back(FLT_MIN); - // } - // } // Check to see if we are finished. if (run.code_units.start >= end) break; @@ -1168,11 +1161,6 @@ std::vector Paragraph::GetRectsForRange( // Keep track of the min and max horizontal coordinates over all lines. Not // needed for kTight. if (rect_width_style == RectWidthStyle::kMax) { - // Init metrics vectors as needed. - // while (run.line_number >= min_lefts.size()) { - // min_lefts.push_back(FLT_MAX); - // max_rights.push_back(FLT_MIN); - // } line_metrics[run.line_number].max_right = std::max(line_metrics[run.line_number].max_right, right); line_metrics[run.line_number].min_left = @@ -1252,19 +1240,18 @@ std::vector Paragraph::GetRectsForRange( } else if (rect_height_style == RectHeightStyle::kIncludeLineSpacingMiddle) { SkScalar adjusted_bottom = - kv.first >= line_ranges_.size() - 1 - ? line_baselines_[kv.first] + line_max_descent_[kv.first] - : line_baselines_[kv.first] + line_max_descent_[kv.first] + - (line_max_spacings_[kv.first + 1] - - line_max_ascent_[kv.first + 1]) / - 2; + line_baselines_[kv.first] + line_max_descent_[kv.first]; + if (kv.first < line_ranges_.size() - 1) { + adjusted_bottom += (line_max_spacings_[kv.first + 1] - + line_max_ascent_[kv.first + 1]) / + 2; + } SkScalar adjusted_top = - kv.first == 0 - ? line_baselines_[kv.first] - line_max_ascent_[kv.first] - : line_baselines_[kv.first] - line_max_ascent_[kv.first] - - (line_max_spacings_[kv.first] - - line_max_ascent_[kv.first]) / - 2; + line_baselines_[kv.first] - line_max_ascent_[kv.first]; + if (kv.first != 0) { + adjusted_top -= + (line_max_spacings_[kv.first] - line_max_ascent_[kv.first]) / 2; + } for (const Paragraph::TextBox& box : kv.second.boxes) { boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, adjusted_top, box.rect.fRight, adjusted_bottom), diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index 46f835ee19ece..99008360d9c3e 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -272,8 +272,8 @@ class Paragraph { // Per-line metrics for max and min coordinates for left and right boxes. // These metrics cannot be calculated in layout generically because of // selections that do not cover the whole line. - SkScalar max_right = FLT_MAX; - SkScalar min_left = FLT_MIN; + SkScalar max_right = FLT_MIN; + SkScalar min_left = FLT_MAX; }; class BidiRun { From cfa9967501baf6672dd191bbbe92649167d786f3 Mon Sep 17 00:00:00 2001 From: GaryQian Date: Mon, 22 Oct 2018 14:58:13 -0700 Subject: [PATCH 6/7] Reorder RectStyle enums --- third_party/txt/src/txt/paragraph.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index 99008360d9c3e..43bc557fd181a 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -60,13 +60,13 @@ class Paragraph { // Options for various types of bounding boxes provided by // GetRectsForRange(...). enum class RectHeightStyle { + // Provide tight bounding boxes that fit heights per run. + kTight, + // The height of the boxes will be the maximum height of all runs in the // line. All rects in the same line will be the same height. kMax, - // Provide tight bounding boxes that fit heights per run. - kTight, - // Extends the top and/or bottom edge of the bounds to fully cover any line // spacing. The top edge of each line should be the same as the bottom edge // of the line above. There should be no gaps in vertical coverage given any @@ -82,13 +82,13 @@ class Paragraph { }; enum class RectWidthStyle { - // Extends the width of the last rect of each line to match the position of - // the widest rect over all the lines. - kMax, - // Provide tight bounding boxes that fit widths to the runs of each line // independently. - kTight + kTight, + + // Extends the width of the last rect of each line to match the position of + // the widest rect over all the lines. + kMax }; struct PositionWithAffinity { From dc13fc33e8d76e412ab7b3bff812f6a32058c4d5 Mon Sep 17 00:00:00 2001 From: GaryQian Date: Mon, 22 Oct 2018 17:45:53 -0700 Subject: [PATCH 7/7] Fix nits --- third_party/txt/src/txt/paragraph.cc | 19 +++++++++++++++---- third_party/txt/src/txt/paragraph.h | 9 --------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/third_party/txt/src/txt/paragraph.cc b/third_party/txt/src/txt/paragraph.cc index bf077db844e2b..270a094a0d947 100644 --- a/third_party/txt/src/txt/paragraph.cc +++ b/third_party/txt/src/txt/paragraph.cc @@ -1117,6 +1117,16 @@ std::vector Paragraph::GetRectsForRange( size_t end, RectHeightStyle rect_height_style, RectWidthStyle rect_width_style) const { + // Struct that holds calculated metrics for each line. + struct LineBoxMetrics { + std::vector boxes; + // Per-line metrics for max and min coordinates for left and right boxes. + // These metrics cannot be calculated in layout generically because of + // selections that do not cover the whole line. + SkScalar max_right = FLT_MIN; + SkScalar min_left = FLT_MAX; + }; + std::map line_metrics; // Text direction of the first line so we can extend the correct side for // RectWidthStyle::kMax. @@ -1272,10 +1282,11 @@ std::vector Paragraph::GetRectsForRange( } else { // kIncludeLineSpacingBottom for (const Paragraph::TextBox& box : kv.second.boxes) { SkScalar adjusted_bottom = - kv.first >= line_ranges_.size() - 1 - ? line_baselines_[kv.first] + line_max_descent_[kv.first] - : line_baselines_[kv.first] + line_max_descent_[kv.first] - - line_max_ascent_[kv.first] + line_max_spacings_[kv.first]; + line_baselines_[kv.first] + line_max_descent_[kv.first]; + if (kv.first < line_ranges_.size() - 1) { + adjusted_bottom += + -line_max_ascent_[kv.first] + line_max_spacings_[kv.first]; + } boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, line_baselines_[kv.first] - line_max_ascent_[kv.first], diff --git a/third_party/txt/src/txt/paragraph.h b/third_party/txt/src/txt/paragraph.h index 43bc557fd181a..708482aa628f1 100644 --- a/third_party/txt/src/txt/paragraph.h +++ b/third_party/txt/src/txt/paragraph.h @@ -267,15 +267,6 @@ class Paragraph { double max_right_; double min_left_; - struct LineBoxMetrics { - std::vector boxes; - // Per-line metrics for max and min coordinates for left and right boxes. - // These metrics cannot be calculated in layout generically because of - // selections that do not cover the whole line. - SkScalar max_right = FLT_MIN; - SkScalar min_left = FLT_MAX; - }; - class BidiRun { public: BidiRun(size_t s, size_t e, TextDirection d, const TextStyle& st)