libtxt: support right-to-left text (flutter/engine#4198)

This commit is contained in:
Jason Simmons 2017-10-11 16:15:57 -07:00 committed by GitHub
parent 948a60c83d
commit 0f67acda39
8 changed files with 58 additions and 74 deletions

View File

@ -16,7 +16,6 @@
#include "flutter/third_party/txt/src/txt/font_style.h"
#include "flutter/third_party/txt/src/txt/font_weight.h"
#include "flutter/third_party/txt/src/txt/paragraph_style.h"
#include "flutter/third_party/txt/src/txt/text_align.h"
#include "flutter/third_party/txt/src/txt/text_decoration.h"
#include "flutter/third_party/txt/src/txt/text_style.h"
#include "lib/fxl/tasks/task_runner.h"
@ -217,22 +216,21 @@ ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded,
if (mask & psTextAlignMask)
style.text_align = txt::TextAlign(encoded[psTextAlignIndex]);
if (mask & (psFontWeightMask | psFontStyleMask | psFontFamilyMask |
psFontSizeMask)) {
if (mask & psFontWeightMask)
style.font_weight =
static_cast<txt::FontWeight>(encoded[psFontWeightIndex]);
if (mask & psTextDirectionMask)
style.text_direction = txt::TextDirection(encoded[psTextDirectionIndex]);
if (mask & psFontStyleMask)
style.font_style =
static_cast<txt::FontStyle>(encoded[psFontStyleIndex]);
if (mask & psFontWeightMask)
style.font_weight =
static_cast<txt::FontWeight>(encoded[psFontWeightIndex]);
if (mask & psFontFamilyMask)
style.font_family = fontFamily;
if (mask & psFontStyleMask)
style.font_style = static_cast<txt::FontStyle>(encoded[psFontStyleIndex]);
if (mask & psFontSizeMask)
style.font_size = fontSize;
}
if (mask & psFontFamilyMask)
style.font_family = fontFamily;
if (mask & psFontSizeMask)
style.font_size = fontSize;
if (mask & psLineHeightMask)
style.line_height = lineHeight;

View File

@ -66,9 +66,9 @@ std::vector<TextBox> ParagraphImplTxt::getRectsForRange(unsigned start,
std::vector<TextBox> result;
std::vector<SkRect> rects = m_paragraph->GetRectsForRange(start, end);
for (size_t i = 0; i < rects.size(); ++i) {
result.push_back(TextBox(rects[i], m_paragraph->GetParagraphStyle().rtl
? TextDirection::RTL
: TextDirection::LTR));
result.push_back(TextBox(
rects[i], static_cast<TextDirection>(
m_paragraph->GetParagraphStyle().text_direction)));
}
return result;
}

View File

@ -89,7 +89,6 @@ source_set("txt") {
"src/txt/platform.h",
"src/txt/styled_runs.cc",
"src/txt/styled_runs.h",
"src/txt/text_align.h",
"src/txt/text_baseline.h",
"src/txt/text_decoration.cc",
"src/txt/text_decoration.h",

View File

@ -37,6 +37,8 @@ namespace {
const std::vector<SkUnichar> fallback_characters{
0x1f600, // emoji
0x4e00, // CJK
0x5d0, // Hebrew
0x627, // Arabic
};
} // anonymous namespace

View File

@ -307,7 +307,9 @@ void Paragraph::Layout(double width, bool force) {
size_t line_run_end = std::min(run.end, line_end);
uint16_t* text_ptr = text_.data() + line_run_start;
size_t text_count = line_run_end - line_run_start;
bool bidiFlags = paragraph_style_.rtl;
int bidiFlags = (paragraph_style_.text_direction == TextDirection::rtl)
? minikin::kBidi_RTL
: minikin::kBidi_LTR;
if (text_count == 0)
continue;
@ -366,7 +368,7 @@ void Paragraph::Layout(double width, bool force) {
blob_start += blob_len;
}
double current_x_position = 0;
double justify_x_offset = 0;
size_t code_unit_index = 0;
for (const Range& glyph_blob : glyph_blobs) {
@ -380,7 +382,8 @@ void Paragraph::Layout(double width, bool force) {
blob_buffer.glyphs[blob_index] = layout.getGlyphId(glyph_index);
size_t pos_index = blob_index * 2;
blob_buffer.pos[pos_index] = current_x_position;
double glyph_x_offset = layout.getX(glyph_index) + justify_x_offset;
blob_buffer.pos[pos_index] = glyph_x_offset;
blob_buffer.pos[pos_index + 1] = layout.getY(glyph_index);
float glyph_advance = layout.getCharAdvance(code_unit_index);
@ -403,7 +406,7 @@ void Paragraph::Layout(double width, bool force) {
float subglyph_advance =
glyph_advance / subglyph_code_unit_counts.size();
glyph_single_line_position_x.emplace_back(
run_x_offset + current_x_position, subglyph_advance,
run_x_offset + glyph_x_offset, subglyph_advance,
subglyph_code_unit_counts[0]);
// Compute positions for the additional characters in the ligature.
@ -413,11 +416,9 @@ void Paragraph::Layout(double width, bool force) {
subglyph_advance, subglyph_code_unit_counts[i]);
}
current_x_position += glyph_advance;
if (justify_line && word_index < words.size() &&
code_unit_index == words[word_index].end) {
current_x_position += word_gap_width;
justify_x_offset += word_gap_width;
word_index++;
}
}
@ -427,8 +428,8 @@ void Paragraph::Layout(double width, bool force) {
paint.getFontMetrics(&metrics);
paint_records.emplace_back(run.style, SkPoint::Make(run_x_offset, 0),
builder.make(), metrics, line_number,
current_x_position);
run_x_offset += current_x_position;
layout.getAdvance());
run_x_offset += layout.getAdvance();
}
double max_line_spacing = 0;
@ -477,7 +478,12 @@ double Paragraph::GetLineXOffset(size_t line) {
if (line >= breaks_count_)
return 0;
if (paragraph_style_.text_align == TextAlign::right) {
TextAlign align = paragraph_style_.text_align;
TextDirection direction = paragraph_style_.text_direction;
if (align == TextAlign::right ||
(align == TextAlign::start && direction == TextDirection::rtl) ||
(align == TextAlign::end && direction == TextDirection::ltr)) {
return width_ - breaker_.getWidths()[line];
} else if (paragraph_style_.text_align == TextAlign::center) {
return (width_ - breaker_.getWidths()[line]) / 2;

View File

@ -23,10 +23,23 @@
#include "font_style.h"
#include "font_weight.h"
#include "minikin/LineBreaker.h"
#include "text_align.h"
namespace txt {
enum class TextAlign {
left,
right,
center,
justify,
start,
end,
};
enum class TextDirection {
rtl,
ltr,
};
class ParagraphStyle {
public:
FontWeight font_weight = FontWeight::w400;
@ -34,7 +47,8 @@ class ParagraphStyle {
std::string font_family = "";
double font_size = 14;
TextAlign text_align = TextAlign::left;
TextAlign text_align = TextAlign::start;
TextDirection text_direction = TextDirection::ltr;
size_t max_lines = std::numeric_limits<size_t>::max();
double line_height = 1.0;
std::u16string ellipsis;
@ -44,9 +58,6 @@ class ParagraphStyle {
// kBreakStrategy_Balanced will balance between the two.
minikin::BreakStrategy break_strategy =
minikin::BreakStrategy::kBreakStrategy_Greedy;
// TODO(garyq): Implement right to left.
// Right to left (Arabic, Hebrew, etc).
bool rtl = false;
};
} // namespace txt

View File

@ -1,31 +0,0 @@
/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIB_TXT_SRC_TEXT_ALIGN_H_
#define LIB_TXT_SRC_TEXT_ALIGN_H_
namespace txt {
enum class TextAlign {
left,
right,
center,
justify,
};
} // namespace txt
#endif // LIB_TXT_SRC_TEXT_ALIGN_H_

View File

@ -22,7 +22,6 @@
#include "txt/font_weight.h"
#include "txt/paragraph.h"
#include "txt/paragraph_builder.h"
#include "txt/text_align.h"
#include "utils.h"
namespace txt {
@ -809,7 +808,7 @@ TEST_F(ParagraphTest, DISABLED_ArabicParagraph) {
txt::ParagraphStyle paragraph_style;
paragraph_style.max_lines = 14;
paragraph_style.text_align = TextAlign::right;
paragraph_style.rtl = true;
paragraph_style.text_direction = TextDirection::rtl;
txt::ParagraphBuilder builder(paragraph_style, GetTestFontCollection());
txt::TextStyle text_style;
@ -838,7 +837,7 @@ TEST_F(ParagraphTest, DISABLED_ArabicParagraph) {
ASSERT_TRUE(paragraph->runs_.styles_[1].equals(text_style));
ASSERT_EQ(paragraph->records_[0].style().color, text_style.color);
ASSERT_EQ(paragraph->records_.size(), 2ull);
ASSERT_EQ(paragraph->paragraph_style_.rtl, true);
ASSERT_EQ(paragraph->paragraph_style_.text_direction, TextDirection::rtl);
for (size_t i = 0; i < u16_text.length(); i++) {
ASSERT_EQ(paragraph->text_[i], u16_text[u16_text.length() - i]);
@ -978,7 +977,7 @@ TEST_F(ParagraphTest, GetRectsForRangeParagraph) {
EXPECT_EQ(rects.size(), 1ull);
EXPECT_FLOAT_EQ(rects[0].left(), 56.835938);
EXPECT_FLOAT_EQ(rects[0].top(), 0);
EXPECT_FLOAT_EQ(rects[0].right(), 177.97266);
EXPECT_FLOAT_EQ(rects[0].right(), 177.44922);
EXPECT_FLOAT_EQ(rects[0].bottom(), 59);
paint.setColor(SK_ColorGREEN);
@ -987,9 +986,9 @@ TEST_F(ParagraphTest, GetRectsForRangeParagraph) {
GetCanvas()->drawRect(rects[i], paint);
}
EXPECT_EQ(rects.size(), 1ull);
EXPECT_FLOAT_EQ(rects[0].left(), 177.97266);
EXPECT_FLOAT_EQ(rects[0].left(), 177);
EXPECT_FLOAT_EQ(rects[0].top(), 0);
EXPECT_FLOAT_EQ(rects[0].right(), 507.02344);
EXPECT_FLOAT_EQ(rects[0].right(), 506.08984);
EXPECT_FLOAT_EQ(rects[0].bottom(), 59);
paint.setColor(SK_ColorRED);
@ -998,9 +997,9 @@ TEST_F(ParagraphTest, GetRectsForRangeParagraph) {
GetCanvas()->drawRect(rects[i], paint);
}
EXPECT_EQ(rects.size(), 4ull);
EXPECT_FLOAT_EQ(rects[0].left(), 211.375);
EXPECT_FLOAT_EQ(rects[0].left(), 210.83594);
EXPECT_FLOAT_EQ(rects[0].top(), 59);
EXPECT_FLOAT_EQ(rects[0].right(), 463.61719);
EXPECT_FLOAT_EQ(rects[0].right(), 463.44922);
EXPECT_FLOAT_EQ(rects[0].bottom(), 118);
// TODO(garyq): The following set of vals are definetly wrong and
@ -1016,9 +1015,9 @@ TEST_F(ParagraphTest, GetRectsForRangeParagraph) {
GetCanvas()->drawRect(rects[i], paint);
}
EXPECT_EQ(rects.size(), 1ull);
EXPECT_FLOAT_EQ(rects[0].left(), 450.1875);
EXPECT_FLOAT_EQ(rects[0].left(), 449.25391);
EXPECT_FLOAT_EQ(rects[0].top(), 0);
EXPECT_FLOAT_EQ(rects[0].right(), 519.47266);
EXPECT_FLOAT_EQ(rects[0].right(), 519.44922);
EXPECT_FLOAT_EQ(rects[0].bottom(), 59);
paint.setColor(SK_ColorRED);