未验证 提交 3a9c22af 编写于 作者: G Gary Qian 提交者: GitHub

Allow GetRectsForRange to provide more detailed/nuanced metrics through RectStyle enum. (#6335)

* Let GetRectsForRange provide more detailed/nuanced metrics through RectStyle enum.
上级 b59c8649
......@@ -85,7 +85,8 @@ void Paragraph::paint(Canvas* canvas, double x, double y) {
}
std::vector<TextBox> Paragraph::getRectsForRange(unsigned start, unsigned end) {
return m_paragraphImpl->getRectsForRange(start, end);
return m_paragraphImpl->getRectsForRange(start, end,
txt::Paragraph::RectStyle::kTight);
}
Dart_Handle Paragraph::getPositionForOffset(double dx, double dy) {
......
......@@ -7,6 +7,7 @@
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/text/text_box.h"
#include "flutter/third_party/txt/src/txt/paragraph.h"
namespace blink {
......@@ -32,8 +33,10 @@ class ParagraphImpl {
virtual void paint(Canvas* canvas, double x, double y) = 0;
virtual std::vector<TextBox> getRectsForRange(unsigned start,
unsigned end) = 0;
virtual std::vector<TextBox> getRectsForRange(
unsigned start,
unsigned end,
txt::Paragraph::RectStyle rect_style) = 0;
virtual Dart_Handle getPositionForOffset(double dx, double dy) = 0;
......
......@@ -61,11 +61,13 @@ void ParagraphImplTxt::paint(Canvas* canvas, double x, double y) {
m_paragraph->Paint(sk_canvas, x, y);
}
std::vector<TextBox> ParagraphImplTxt::getRectsForRange(unsigned start,
unsigned end) {
std::vector<TextBox> ParagraphImplTxt::getRectsForRange(
unsigned start,
unsigned end,
txt::Paragraph::RectStyle rect_style) {
std::vector<TextBox> result;
std::vector<txt::Paragraph::TextBox> boxes =
m_paragraph->GetRectsForRange(start, end);
m_paragraph->GetRectsForRange(start, end, rect_style);
for (const txt::Paragraph::TextBox& box : boxes) {
result.emplace_back(box.rect,
static_cast<blink::TextDirection>(box.direction));
......
......@@ -8,7 +8,6 @@
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/text/paragraph_impl.h"
#include "flutter/lib/ui/text/text_box.h"
#include "flutter/third_party/txt/src/txt/paragraph.h"
namespace blink {
......@@ -29,7 +28,10 @@ class ParagraphImplTxt : public ParagraphImpl {
void layout(double width) override;
void paint(Canvas* canvas, double x, double y) override;
std::vector<TextBox> getRectsForRange(unsigned start, unsigned end) override;
std::vector<TextBox> getRectsForRange(
unsigned start,
unsigned end,
txt::Paragraph::RectStyle rect_style) override;
Dart_Handle getPositionForOffset(double dx, double dy) override;
Dart_Handle getWordBoundary(unsigned offset) override;
......
......@@ -674,11 +674,10 @@ void Paragraph::Layout(double width, bool force) {
word_start_position = std::numeric_limits<double>::quiet_NaN();
}
}
}
} // for each in glyph_blob
if (glyph_positions.empty())
continue;
SkPaint::FontMetrics metrics;
paint.getFontMetrics(&metrics);
paint_records.emplace_back(run.style(), SkPoint::Make(run_x_offset, 0),
......@@ -701,10 +700,10 @@ void Paragraph::Layout(double width, bool force) {
Range<double>(glyph_positions.front().x_pos.start,
glyph_positions.back().x_pos.end),
line_number, metrics, run.direction());
}
} // for each in glyph_blobs
run_x_offset += layout.getAdvance();
}
} // for each in line_runs
// Adjust the glyph positions based on the alignment of the line.
double line_x_offset = GetLineXOffset(run_x_offset);
......@@ -772,7 +771,7 @@ void Paragraph::Layout(double width, bool force) {
SkPoint::Make(paint_record.offset().x() + line_x_offset, y_offset));
records_.emplace_back(std::move(paint_record));
}
}
} // for each line_number
if (paragraph_style_.max_lines == 1 ||
(paragraph_style_.unlimited_lines() && paragraph_style_.ellipsized())) {
......@@ -1067,8 +1066,10 @@ void Paragraph::PaintBackground(SkCanvas* canvas,
canvas->drawRect(rect, record.style().background);
}
std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(size_t start,
size_t end) const {
std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(
size_t start,
size_t end,
RectStyle rect_style) const {
std::map<size_t, std::vector<Paragraph::TextBox>> line_boxes;
for (const CodeUnitRun& run : code_unit_runs_) {
......@@ -1123,7 +1124,23 @@ std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(size_t start,
std::vector<Paragraph::TextBox> boxes;
for (const auto& kv : line_boxes) {
boxes.insert(boxes.end(), kv.second.begin(), kv.second.end());
if (rect_style & RectStyle::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;
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);
}
for (const Paragraph::TextBox& box : kv.second) {
boxes.emplace_back(SkRect::MakeLTRB(box.rect.fLeft, min_top,
box.rect.fRight, max_bottom),
box.direction);
}
}
}
return boxes;
}
......
......@@ -55,6 +55,25 @@ class Paragraph {
enum Affinity { UPSTREAM, DOWNSTREAM };
// TODO(garyq): Implement kIncludeLineSpacing and kExtendEndOfLine
// 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
};
struct PositionWithAffinity {
const size_t position;
const Affinity affinity;
......@@ -137,7 +156,9 @@ class Paragraph {
// Returns a vector of bounding boxes that enclose all text between start and
// end glyph indexes, including start and excluding end.
std::vector<TextBox> GetRectsForRange(size_t start, size_t end) const;
std::vector<TextBox> GetRectsForRange(size_t start,
size_t end,
RectStyle rect_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.
......
......@@ -983,13 +983,13 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
// are adjusted.
paint.setColor(SK_ColorRED);
std::vector<txt::Paragraph::TextBox> boxes =
paragraph->GetRectsForRange(0, 0);
paragraph->GetRectsForRange(0, 0, Paragraph::RectStyle::kNone);
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);
boxes = paragraph->GetRectsForRange(0, 1, Paragraph::RectStyle::kNone);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
......@@ -1000,7 +1000,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
paint.setColor(SK_ColorBLUE);
boxes = paragraph->GetRectsForRange(2, 8);
boxes = paragraph->GetRectsForRange(2, 8, Paragraph::RectStyle::kNone);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
......@@ -1011,7 +1011,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
paint.setColor(SK_ColorGREEN);
boxes = paragraph->GetRectsForRange(8, 21);
boxes = paragraph->GetRectsForRange(8, 21, Paragraph::RectStyle::kNone);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
......@@ -1022,7 +1022,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
paint.setColor(SK_ColorRED);
boxes = paragraph->GetRectsForRange(30, 100);
boxes = paragraph->GetRectsForRange(30, 100, Paragraph::RectStyle::kNone);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
......@@ -1040,7 +1040,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
EXPECT_FLOAT_EQ(boxes[3].rect.bottom(), 295);
paint.setColor(SK_ColorBLUE);
boxes = paragraph->GetRectsForRange(19, 22);
boxes = paragraph->GetRectsForRange(19, 22, Paragraph::RectStyle::kNone);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
......@@ -1051,7 +1051,7 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 59);
paint.setColor(SK_ColorRED);
boxes = paragraph->GetRectsForRange(21, 21);
boxes = paragraph->GetRectsForRange(21, 21, Paragraph::RectStyle::kNone);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
......@@ -1060,10 +1060,93 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
ASSERT_TRUE(Snapshot());
}
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeTight)) {
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.text_align = TextAlign::left;
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
txt::TextStyle text_style;
text_style.font_family = "Noto Sans CJK JP";
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.
paint.setColor(SK_ColorRED);
std::vector<txt::Paragraph::TextBox> boxes =
paragraph->GetRectsForRange(0, 0, Paragraph::RectStyle::kTight);
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);
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);
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 16.898438);
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
paint.setColor(SK_ColorBLUE);
boxes = paragraph->GetRectsForRange(2, 8, Paragraph::RectStyle::kTight);
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.top(), 0);
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 264.09375);
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
paint.setColor(SK_ColorGREEN);
boxes = paragraph->GetRectsForRange(8, 21, Paragraph::RectStyle::kTight);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
EXPECT_EQ(boxes.size(), 2ull);
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 264.09375);
EXPECT_FLOAT_EQ(boxes[0].rect.top(), 0);
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 595.08594);
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 74);
ASSERT_TRUE(Snapshot());
}
SkRect GetCoordinatesForGlyphPosition(const txt::Paragraph& paragraph,
size_t pos) {
std::vector<txt::Paragraph::TextBox> boxes =
paragraph.GetRectsForRange(pos, pos + 1);
paragraph.GetRectsForRange(pos, pos + 1, Paragraph::RectStyle::kNone);
return !boxes.empty() ? boxes.front().rect : SkRect::MakeEmpty();
}
......@@ -1635,8 +1718,9 @@ TEST_F(ParagraphTest, UnderlineShiftParagraph) {
paragraph->records_[1].GetRunWidth(),
paragraph2->records_[0].GetRunWidth());
auto rects1 = paragraph->GetRectsForRange(0, 12);
auto rects2 = paragraph2->GetRectsForRange(0, 12);
auto rects1 = paragraph->GetRectsForRange(0, 12, Paragraph::RectStyle::kNone);
auto rects2 =
paragraph2->GetRectsForRange(0, 12, Paragraph::RectStyle::kNone);
for (size_t i = 0; i < 12; ++i) {
auto r1 = GetCoordinatesForGlyphPosition(*paragraph, i);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册