Skip to content

Commit

Permalink
Fix cursor jumping when typing some special characters. (flutter#7964)
Browse files Browse the repository at this point in the history
  • Loading branch information
HelloCore authored and GaryQian committed Mar 1, 2019
1 parent fe15149 commit 302e2e9
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
10 changes: 10 additions & 0 deletions third_party/txt/src/txt/paragraph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,7 @@ std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(
// Lines that are actually in the requested range.
size_t max_line = 0;
size_t min_line = INT_MAX;
size_t glyph_length = 0;

// Generate initial boxes and calculate metrics.
for (const CodeUnitRun& run : code_unit_runs_) {
Expand Down Expand Up @@ -1276,6 +1277,15 @@ std::vector<Paragraph::TextBox> Paragraph::GetRectsForRange(
if (gp.code_units.start >= start && gp.code_units.end <= end) {
left = std::min(left, static_cast<SkScalar>(gp.x_pos.start));
right = std::max(right, static_cast<SkScalar>(gp.x_pos.end));
} else if (gp.code_units.end == end) {
// Calculate left and right when we are at
// the last position of a combining character.
glyph_length = (gp.code_units.end - gp.code_units.start) - 1;
if (gp.code_units.start ==
std::max<size_t>(0, (start - glyph_length))) {
left = std::min(left, static_cast<SkScalar>(gp.x_pos.start));
right = std::max(right, static_cast<SkScalar>(gp.x_pos.end));
}
}
}
if (left == SK_ScalarMax || right == SK_ScalarMin)
Expand Down
86 changes: 86 additions & 0 deletions third_party/txt/tests/paragraph_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1673,6 +1673,92 @@ TEST_F(ParagraphTest,
ASSERT_TRUE(Snapshot());
}

TEST_F(ParagraphTest, GetRectsForRangeIncludeCombiningCharacter) {
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_families = std::vector<std::string>(1, "Roboto");
text_style.font_size = 50;
text_style.letter_spacing = 1;
text_style.word_spacing = 5;
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(GetTestCanvasWidth() - 100);

paragraph->Paint(GetCanvas(), 0, 0);

Paragraph::RectHeightStyle rect_height_style =
Paragraph::RectHeightStyle::kTight;
Paragraph::RectWidthStyle rect_width_style =
Paragraph::RectWidthStyle::kTight;

std::vector<txt::Paragraph::TextBox> boxes =
paragraph->GetRectsForRange(0, 0, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 0ull);

// Case when the sentence starts with a combining character
// We should get 0 box for ด because it's already been combined to ดี
boxes =
paragraph->GetRectsForRange(0, 1, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 0ull);

boxes =
paragraph->GetRectsForRange(1, 2, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 1ull);

boxes =
paragraph->GetRectsForRange(0, 2, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 1ull);

// Case when the sentence contains a combining character
// We should get 0 box for ว because it's already been combined to วั
boxes =
paragraph->GetRectsForRange(3, 4, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 0ull);

boxes =
paragraph->GetRectsForRange(4, 5, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 1ull);

boxes =
paragraph->GetRectsForRange(3, 5, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 1ull);

// Case when the sentence contains a combining character that contain 3
// characters We should get 0 box for ท and ที because it's already been
// combined to ที่
boxes =
paragraph->GetRectsForRange(14, 15, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 0ull);

boxes =
paragraph->GetRectsForRange(15, 16, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 0ull);

boxes =
paragraph->GetRectsForRange(16, 17, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 1ull);

boxes =
paragraph->GetRectsForRange(14, 17, rect_height_style, rect_width_style);
EXPECT_EQ(boxes.size(), 1ull);
}

TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeCenterParagraph)) {
const char* text = "01234   "; // includes ideographic space
// and english space.
Expand Down

0 comments on commit 302e2e9

Please sign in to comment.