未验证 提交 8591bd32 编写于 作者: G Gary Qian 提交者: GitHub

Handle ambiguous directionality of final trailing whitespace in mixed bidi text (#9489)

上级 3aff2e35
......@@ -402,6 +402,33 @@ bool Paragraph::ComputeBidiRuns(std::vector<BidiRun>* result) {
if (!U_SUCCESS(status))
return false;
// Detect if final trailing run is a single ambiguous whitespace.
// We want to bundle the final ambiguous whitespace with the preceding
// run in order to maintain logical typing behavior when mixing RTL and LTR
// text. We do not want this to be a true ghost run since the contrasting
// directionality causes the trailing space to not render at the visual end of
// the paragraph.
//
// This only applies to the final whitespace at the end as other whitespace is
// no longer ambiguous when surrounded by additional text.
bool has_trailing_whitespace = false;
int32_t bidi_run_start, bidi_run_length;
if (bidi_run_count > 1) {
ubidi_getVisualRun(bidi.get(), bidi_run_count - 1, &bidi_run_start,
&bidi_run_length);
if (!U_SUCCESS(status))
return false;
if (bidi_run_length == 1) {
UChar32 last_char;
U16_GET(text_.data(), 0, bidi_run_start + bidi_run_length - 1,
static_cast<int>(text_.size()), last_char);
if (u_hasBinaryProperty(last_char, UCHAR_WHITE_SPACE)) {
has_trailing_whitespace = true;
bidi_run_count--;
}
}
}
// Build a map of styled runs indexed by start position.
std::map<size_t, StyledRuns::Run> styled_run_map;
for (size_t i = 0; i < runs_.size(); ++i) {
......@@ -411,7 +438,6 @@ bool Paragraph::ComputeBidiRuns(std::vector<BidiRun>* result) {
for (int32_t bidi_run_index = 0; bidi_run_index < bidi_run_count;
++bidi_run_index) {
int32_t bidi_run_start, bidi_run_length;
UBiDiDirection direction = ubidi_getVisualRun(
bidi.get(), bidi_run_index, &bidi_run_start, &bidi_run_length);
if (!U_SUCCESS(status))
......@@ -438,6 +464,11 @@ bool Paragraph::ComputeBidiRuns(std::vector<BidiRun>* result) {
if (bidi_run_length == 0)
continue;
// Attach the final trailing whitespace as part of this run.
if (has_trailing_whitespace && bidi_run_index == bidi_run_count - 1) {
bidi_run_length++;
}
size_t bidi_run_end = bidi_run_start + bidi_run_length;
TextDirection text_direction =
direction == UBIDI_RTL ? TextDirection::rtl : TextDirection::ltr;
......
......@@ -2100,6 +2100,137 @@ TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsParagraph)) {
ASSERT_TRUE(Snapshot());
}
// Trailing space at the end of the arabic rtl run should be at the left end of
// the arabic run.
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsLTRLeftAlignParagraph)) {
const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
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 = 14;
paragraph_style.text_align = TextAlign::left;
paragraph_style.text_direction = TextDirection::ltr;
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
txt::TextStyle text_style;
text_style.font_families = std::vector<std::string>(1, "Noto Naskh Arabic");
text_style.font_size = 26;
text_style.letter_spacing = 1;
text_style.word_spacing = 5;
text_style.color = SK_ColorBLACK;
text_style.height = 1;
text_style.decoration = TextDecoration::kUnderline;
text_style.decoration_color = SK_ColorBLACK;
builder.PushStyle(text_style);
builder.AddText(u16_text);
builder.Pop();
auto paragraph = builder.Build();
paragraph->Layout(GetTestCanvasWidth() - 100);
paragraph->Paint(GetCanvas(), 0, 0);
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
// Tests for GetRectsForRange()
Paragraph::RectHeightStyle rect_height_style =
Paragraph::RectHeightStyle::kMax;
Paragraph::RectWidthStyle rect_width_style =
Paragraph::RectWidthStyle::kTight;
paint.setColor(SK_ColorRED);
std::vector<txt::Paragraph::TextBox> boxes =
paragraph->GetRectsForRange(36, 40, rect_height_style, rect_width_style);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
EXPECT_EQ(boxes.size(), 1ull);
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 89.40625);
EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469);
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 121.87891);
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44);
ASSERT_EQ(paragraph_style.text_align,
paragraph->GetParagraphStyle().text_align);
ASSERT_TRUE(Snapshot());
}
// Trailing space at the end of the arabic rtl run should be at the left end of
// the arabic run and be a ghost space.
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(ArabicRectsLTRRightAlignParagraph)) {
const char* text = "Helloبمباركة التقليدية قام عن. تصفح يد ";
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 = 14;
paragraph_style.text_align = TextAlign::right;
paragraph_style.text_direction = TextDirection::ltr;
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
txt::TextStyle text_style;
text_style.font_families = std::vector<std::string>(1, "Noto Naskh Arabic");
text_style.font_size = 26;
text_style.letter_spacing = 1;
text_style.word_spacing = 5;
text_style.color = SK_ColorBLACK;
text_style.height = 1;
text_style.decoration = TextDecoration::kUnderline;
text_style.decoration_color = SK_ColorBLACK;
builder.PushStyle(text_style);
builder.AddText(u16_text);
builder.Pop();
auto paragraph = builder.Build();
paragraph->Layout(GetTestCanvasWidth() - 100);
paragraph->Paint(GetCanvas(), 0, 0);
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
// Tests for GetRectsForRange()
Paragraph::RectHeightStyle rect_height_style =
Paragraph::RectHeightStyle::kMax;
Paragraph::RectWidthStyle rect_width_style =
Paragraph::RectWidthStyle::kTight;
paint.setColor(SK_ColorRED);
std::vector<txt::Paragraph::TextBox> boxes =
paragraph->GetRectsForRange(36, 40, rect_height_style, rect_width_style);
for (size_t i = 0; i < boxes.size(); ++i) {
GetCanvas()->drawRect(boxes[i].rect, paint);
}
EXPECT_EQ(boxes.size(), 2ull);
EXPECT_FLOAT_EQ(boxes[0].rect.left(), 556.54688);
EXPECT_FLOAT_EQ(boxes[0].rect.top(), -0.26855469);
EXPECT_FLOAT_EQ(boxes[0].rect.right(), 577.78125);
EXPECT_FLOAT_EQ(boxes[0].rect.bottom(), 44);
EXPECT_FLOAT_EQ(boxes[1].rect.left(), 545.30859);
EXPECT_FLOAT_EQ(boxes[1].rect.top(), -0.26855469);
EXPECT_FLOAT_EQ(boxes[1].rect.right(), 557.04688);
EXPECT_FLOAT_EQ(boxes[1].rect.bottom(), 44);
ASSERT_EQ(paragraph_style.text_align,
paragraph->GetParagraphStyle().text_align);
ASSERT_TRUE(Snapshot());
}
TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateParagraph) {
const char* text =
"12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册