提交 8a9034c0 编写于 作者: J Jason Simmons 提交者: GitHub

libtxt: handle newlines during invocation of the minikin line breaker (#4237)

minikin::LineBreaker does not convert newline characters into line breaks
in its output.  Previously libtxt's version of LineBreaker container a patch
that added a large width offset for a newline in order to force wrapping to
the next line.  This works if the offset exceeds the paragraph's width
constraint.  But if the paragraph is laid out with infinite width, then the
text after the newline will continue on the current output line.

This change separates the paragraph's text into newline delimited blocks and
feeds each block separately to the minikin LineBreaker.

Also, libtxt was breaking the input styled text runs at newline boundaries.
This is no longer necessary.
上级 1ce6f0e5
...@@ -402,8 +402,7 @@ static void BM_ParagraphMinikinAddStyleRun(benchmark::State& state) { ...@@ -402,8 +402,7 @@ static void BM_ParagraphMinikinAddStyleRun(benchmark::State& state) {
for (int i = 0; i < 20; ++i) { for (int i = 0; i < 20; ++i) {
breaker.addStyleRun( breaker.addStyleRun(
&paint, font_collection->GetMinikinFontCollectionForFamily("Roboto"), &paint, font_collection->GetMinikinFontCollectionForFamily("Roboto"),
font, state.range(0) / 20 * i, state.range(0) / 20 * (i + 1), false, font, state.range(0) / 20 * i, state.range(0) / 20 * (i + 1), false);
0);
} }
} }
state.SetComplexityN(state.range(0)); state.SetComplexityN(state.range(0));
......
...@@ -120,8 +120,7 @@ float LineBreaker::addStyleRun(MinikinPaint* paint, ...@@ -120,8 +120,7 @@ float LineBreaker::addStyleRun(MinikinPaint* paint,
FontStyle style, FontStyle style,
size_t start, size_t start,
size_t end, size_t end,
bool isRtl, bool isRtl) {
double letterSpacing) {
float width = 0.0f; float width = 0.0f;
int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
...@@ -169,8 +168,6 @@ float LineBreaker::addStyleRun(MinikinPaint* paint, ...@@ -169,8 +168,6 @@ float LineBreaker::addStyleRun(MinikinPaint* paint,
if (isWordSpace(c)) if (isWordSpace(c))
mSpaceCount += 1; mSpaceCount += 1;
mWidth += mCharWidths[i]; mWidth += mCharWidths[i];
if (c == '\n')
mWidth += INT_MAX;
if (!isLineEndSpace(c)) { if (!isLineEndSpace(c)) {
postBreak = mWidth; postBreak = mWidth;
postSpaceCount = mSpaceCount; postSpaceCount = mSpaceCount;
...@@ -367,7 +364,7 @@ void LineBreaker::pushBreak(int offset, float width, uint8_t hyphenEdit) { ...@@ -367,7 +364,7 @@ void LineBreaker::pushBreak(int offset, float width, uint8_t hyphenEdit) {
void LineBreaker::addReplacement(size_t start, size_t end, float width) { void LineBreaker::addReplacement(size_t start, size_t end, float width) {
mCharWidths[start] = width; mCharWidths[start] = width;
std::fill(&mCharWidths[start + 1], &mCharWidths[end], 0.0f); std::fill(&mCharWidths[start + 1], &mCharWidths[end], 0.0f);
addStyleRun(nullptr, nullptr, FontStyle(), start, end, false, 0); addStyleRun(nullptr, nullptr, FontStyle(), start, end, false);
} }
// Get the width of a space. May return 0 if there are no spaces. // Get the width of a space. May return 0 if there are no spaces.
......
...@@ -169,8 +169,7 @@ class LineBreaker { ...@@ -169,8 +169,7 @@ class LineBreaker {
FontStyle style, FontStyle style,
size_t start, size_t start,
size_t end, size_t end,
bool isRtl, bool isRtl);
double letterSpacing = 0);
void addReplacement(size_t start, size_t end, float width); void addReplacement(size_t start, size_t end, float width);
......
...@@ -144,13 +144,8 @@ void FindWords(const std::vector<uint16_t>& text, ...@@ -144,13 +144,8 @@ void FindWords(const std::vector<uint16_t>& text,
static const float kDoubleDecorationSpacing = 3.0f; static const float kDoubleDecorationSpacing = 3.0f;
Paragraph::GlyphLine::GlyphLine(std::vector<GlyphPosition>&& p) Paragraph::GlyphLine::GlyphLine(std::vector<GlyphPosition>&& p, size_t tcu)
: positions(std::move(p)), : positions(std::move(p)), total_code_units(tcu) {}
total_code_units(std::accumulate(
positions.begin(),
positions.end(),
0,
[](size_t a, const auto& b) { return a + b.code_units; })) {}
const Paragraph::GlyphPosition& Paragraph::GlyphLine::GetGlyphPosition( const Paragraph::GlyphPosition& Paragraph::GlyphLine::GetGlyphPosition(
size_t pos) const { size_t pos) const {
...@@ -168,7 +163,9 @@ const Paragraph::GlyphPosition& Paragraph::GlyphLine::GetGlyphPosition( ...@@ -168,7 +163,9 @@ const Paragraph::GlyphPosition& Paragraph::GlyphLine::GetGlyphPosition(
return positions.back(); return positions.back();
} }
Paragraph::Paragraph() = default; Paragraph::Paragraph() {
breaker_.setLocale(icu::Locale(), nullptr);
}
Paragraph::~Paragraph() = default; Paragraph::~Paragraph() = default;
...@@ -180,31 +177,80 @@ void Paragraph::SetText(std::vector<uint16_t> text, StyledRuns runs) { ...@@ -180,31 +177,80 @@ void Paragraph::SetText(std::vector<uint16_t> text, StyledRuns runs) {
runs_ = std::move(runs); runs_ = std::move(runs);
} }
void Paragraph::InitBreaker() { bool Paragraph::ComputeLineBreaks() {
breaker_.setLocale(icu::Locale(), nullptr); line_ranges_.clear();
breaker_.resize(text_.size()); line_widths_.clear();
memcpy(breaker_.buffer(), text_.data(), text_.size() * sizeof(text_[0]));
breaker_.setText(); std::vector<size_t> newline_positions;
} for (size_t i = 0; i < text_.size(); ++i) {
ULineBreak ulb = static_cast<ULineBreak>(
bool Paragraph::AddRunsToLineBreaker( u_getIntPropertyValue(text_[i], UCHAR_LINE_BREAK));
std::unordered_map<std::string, std::shared_ptr<minikin::FontCollection>>& if (ulb == U_LB_LINE_FEED || ulb == U_LB_MANDATORY_BREAK)
collection_map /* TODO: Cache the font collection here. */) { newline_positions.push_back(i);
minikin::FontStyle font; }
minikin::MinikinPaint paint; newline_positions.push_back(text_.size());
for (size_t i = 0; i < runs_.size(); ++i) {
auto run = runs_.GetRun(i); size_t run_index = 0;
GetFontAndMinikinPaint(run.style, &font, &paint); for (size_t newline_index = 0; newline_index < newline_positions.size();
auto collection = font_collection_->GetMinikinFontCollectionForFamily( ++newline_index) {
run.style.font_family); size_t block_start =
if (collection == nullptr) { (newline_index > 0) ? newline_positions[newline_index - 1] + 1 : 0;
FXL_LOG(INFO) << "Could not find font collection for family \"" size_t block_end = newline_positions[newline_index];
<< run.style.font_family << "\"."; size_t block_size = block_end - block_start;
return false;
if (block_size == 0) {
line_ranges_.emplace_back(block_start, block_start, true);
line_widths_.push_back(0);
continue;
} }
breaker_.addStyleRun(&paint, collection, font, run.start, run.end, false,
run.style.letter_spacing); breaker_.setLineWidths(0.0f, 0, width_);
breaker_.setJustified(paragraph_style_.text_align == TextAlign::justify);
breaker_.setStrategy(paragraph_style_.break_strategy);
breaker_.resize(block_size);
memcpy(breaker_.buffer(), text_.data() + block_start,
block_size * sizeof(text_[0]));
breaker_.setText();
// Add the runs that include this line to the LineBreaker.
while (run_index < runs_.size()) {
StyledRuns::Run run = runs_.GetRun(run_index);
if (run.start >= block_end)
break;
minikin::FontStyle font;
minikin::MinikinPaint paint;
GetFontAndMinikinPaint(run.style, &font, &paint);
std::shared_ptr<minikin::FontCollection> collection =
font_collection_->GetMinikinFontCollectionForFamily(
run.style.font_family);
if (collection == nullptr) {
FXL_LOG(INFO) << "Could not find font collection for family \""
<< run.style.font_family << "\".";
return false;
}
size_t run_start = std::max(run.start, block_start) - block_start;
size_t run_end = std::min(run.end, block_end) - block_start;
bool isRtl = (paragraph_style_.text_direction == TextDirection::rtl);
breaker_.addStyleRun(&paint, collection, font, run_start, run_end, isRtl);
if (run.end > block_end)
break;
run_index++;
}
size_t breaks_count = breaker_.computeBreaks();
const int* breaks = breaker_.getBreaks();
for (size_t i = 0; i < breaks_count; ++i) {
size_t break_start = (i > 0) ? breaks[i - 1] : 0;
line_ranges_.emplace_back(break_start + block_start,
breaks[i] + block_start, i == breaks_count - 1);
line_widths_.push_back(breaker_.getWidths()[i]);
}
breaker_.finish();
} }
return true; return true;
} }
...@@ -217,31 +263,10 @@ void Paragraph::Layout(double width, bool force) { ...@@ -217,31 +263,10 @@ void Paragraph::Layout(double width, bool force) {
width_ = width; width_ = width;
std::unordered_map<std::string, std::shared_ptr<minikin::FontCollection>> if (!ComputeLineBreaks()) {
collection_map;
breaker_.setLineWidths(0.0f, 0, width_);
// TODO(garyq): Get hyphenator working. Hyphenator should be created with
// a pattern binary dataset. Should be something along these lines:
//
// minikin::Hyphenator* hyph =
// minikin::Hyphenator::loadBinary(<paramsgohere>);
// breaker_.setLocale(icu::Locale::getRoot(), &hyph);
//
// TODO: Maybe create a new breaker altogether.
InitBreaker();
if (!AddRunsToLineBreaker(collection_map)) {
return; return;
} }
breaker_.setJustified(paragraph_style_.text_align == TextAlign::justify);
breaker_.setStrategy(paragraph_style_.break_strategy);
breaks_count_ = breaker_.computeBreaks();
const int* breaks = breaker_.getBreaks();
SkPaint paint; SkPaint paint;
paint.setAntiAlias(true); paint.setAntiAlias(true);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
...@@ -253,28 +278,29 @@ void Paragraph::Layout(double width, bool force) { ...@@ -253,28 +278,29 @@ void Paragraph::Layout(double width, bool force) {
minikin::Layout layout; minikin::Layout layout;
SkTextBlobBuilder builder; SkTextBlobBuilder builder;
size_t line_limit = std::min(paragraph_style_.max_lines, breaks_count_);
size_t run_index = 0; size_t run_index = 0;
double y_offset = 0; double y_offset = 0;
double prev_max_descent = 0; double prev_max_descent = 0;
double max_word_width = 0; double max_word_width = 0;
size_t line_limit = std::min(paragraph_style_.max_lines, line_ranges_.size());
did_exceed_max_lines_ = (line_ranges_.size() > paragraph_style_.max_lines);
for (size_t line_number = 0; line_number < line_limit; ++line_number) { for (size_t line_number = 0; line_number < line_limit; ++line_number) {
size_t line_start = (line_number > 0) ? breaks[line_number - 1] : 0; const LineRange& line_range = line_ranges_[line_number];
size_t line_end = breaks[line_number];
// Break the line into words if justification should be applied. // Break the line into words if justification should be applied.
std::vector<Range> words; std::vector<Range> words;
double word_gap_width = 0; double word_gap_width = 0;
size_t word_index = 0; size_t word_index = 0;
bool justify_line = bool justify_line = (paragraph_style_.text_align == TextAlign::justify &&
(paragraph_style_.text_align == TextAlign::justify && line_number != line_limit - 1 &&
line_number != line_limit - 1 && text_[line_end - 1] != '\n'); !line_ranges_[line_number].hard_break);
FindWords(text_, line_start, line_end, &words); FindWords(text_, line_range.start, line_range.end, &words);
if (justify_line) { if (justify_line) {
if (words.size() > 1) { if (words.size() > 1) {
word_gap_width = word_gap_width =
(width_ - breaker_.getWidths()[line_number]) / (words.size() - 1); (width_ - line_widths_[line_number]) / (words.size() - 1);
} }
} }
...@@ -282,10 +308,10 @@ void Paragraph::Layout(double width, bool force) { ...@@ -282,10 +308,10 @@ void Paragraph::Layout(double width, bool force) {
std::vector<StyledRuns::Run> line_runs; std::vector<StyledRuns::Run> line_runs;
while (run_index < runs_.size()) { while (run_index < runs_.size()) {
StyledRuns::Run run = runs_.GetRun(run_index); StyledRuns::Run run = runs_.GetRun(run_index);
if (run.start >= line_end) if (run.start >= line_range.end)
break; break;
line_runs.push_back(run); line_runs.push_back(run);
if (run.end > line_end) if (run.end > line_range.end)
break; break;
run_index++; run_index++;
} }
...@@ -305,24 +331,19 @@ void Paragraph::Layout(double width, bool force) { ...@@ -305,24 +331,19 @@ void Paragraph::Layout(double width, bool force) {
run.style.font_family); run.style.font_family);
// Lay out this run. // Lay out this run.
size_t line_run_start = std::max(run.start, line_start); size_t line_run_start = std::max(run.start, line_range.start);
size_t line_run_end = std::min(run.end, line_end); size_t line_run_end = std::min(run.end, line_range.end);
uint16_t* text_ptr = text_.data() + line_run_start; uint16_t* text_ptr = text_.data() + line_run_start;
size_t text_count = line_run_end - line_run_start; size_t text_count = line_run_end - line_run_start;
int bidiFlags = (paragraph_style_.text_direction == TextDirection::rtl) int bidiFlags = (paragraph_style_.text_direction == TextDirection::rtl)
? minikin::kBidi_RTL ? minikin::kBidi_RTL
: minikin::kBidi_LTR; : minikin::kBidi_LTR;
if (text_count == 0)
continue;
if (text_ptr[text_count - 1] == '\n')
text_count--;
// Apply ellipsizing if the run was not completely laid out and this // Apply ellipsizing if the run was not completely laid out and this
// is the last line (or lines are unlimited). // is the last line (or lines are unlimited).
const std::u16string& ellipsis = paragraph_style_.ellipsis; const std::u16string& ellipsis = paragraph_style_.ellipsis;
std::vector<uint16_t> ellipsized_text; std::vector<uint16_t> ellipsized_text;
if (ellipsis.length() && !isinf(width_) && run.end > line_end && if (ellipsis.length() && !isinf(width_) && !line_range.hard_break &&
(line_number == line_limit - 1 || (line_number == line_limit - 1 ||
paragraph_style_.max_lines == std::numeric_limits<size_t>::max())) { paragraph_style_.max_lines == std::numeric_limits<size_t>::max())) {
float ellipsis_width = layout.measureText( float ellipsis_width = layout.measureText(
...@@ -355,8 +376,10 @@ void Paragraph::Layout(double width, bool force) { ...@@ -355,8 +376,10 @@ void Paragraph::Layout(double width, bool force) {
// If there is no line limit, then skip all lines after the ellipsized // If there is no line limit, then skip all lines after the ellipsized
// line. // line.
if (paragraph_style_.max_lines == std::numeric_limits<size_t>::max()) if (paragraph_style_.max_lines == std::numeric_limits<size_t>::max()) {
line_limit = line_number + 1; line_limit = line_number + 1;
did_exceed_max_lines_ = true;
}
} }
layout.doLayout(text_ptr, 0, text_count, text_count, bidiFlags, font, layout.doLayout(text_ptr, 0, text_count, text_count, bidiFlags, font,
...@@ -484,20 +507,22 @@ void Paragraph::Layout(double width, bool force) { ...@@ -484,20 +507,22 @@ void Paragraph::Layout(double width, bool force) {
records_.emplace_back(std::move(paint_record)); records_.emplace_back(std::move(paint_record));
} }
glyph_position_x_.emplace_back(std::move(glyph_single_line_position_x)); size_t next_line_start = (line_number < line_ranges_.size() - 1)
? line_ranges_[line_number + 1].start
: text_.size();
glyph_position_x_.emplace_back(std::move(glyph_single_line_position_x),
next_line_start - line_range.start);
} }
max_intrinsic_width_ = 0; max_intrinsic_width_ = 0;
for (size_t i = 0; i < breaks_count_; ++i) { for (double line_width : line_widths_) {
max_intrinsic_width_ += breaker_.getWidths()[i]; max_intrinsic_width_ += line_width;
} }
min_intrinsic_width_ = std::min(max_word_width, max_intrinsic_width_); min_intrinsic_width_ = std::min(max_word_width, max_intrinsic_width_);
breaker_.finish();
} }
double Paragraph::GetLineXOffset(size_t line) { double Paragraph::GetLineXOffset(size_t line) {
if (line >= breaks_count_ || isinf(width_)) if (line >= line_widths_.size() || isinf(width_))
return 0; return 0;
TextAlign align = paragraph_style_.text_align; TextAlign align = paragraph_style_.text_align;
...@@ -506,9 +531,9 @@ double Paragraph::GetLineXOffset(size_t line) { ...@@ -506,9 +531,9 @@ double Paragraph::GetLineXOffset(size_t line) {
if (align == TextAlign::right || if (align == TextAlign::right ||
(align == TextAlign::start && direction == TextDirection::rtl) || (align == TextAlign::start && direction == TextDirection::rtl) ||
(align == TextAlign::end && direction == TextDirection::ltr)) { (align == TextAlign::end && direction == TextDirection::ltr)) {
return width_ - breaker_.getWidths()[line]; return width_ - line_widths_[line];
} else if (paragraph_style_.text_align == TextAlign::center) { } else if (paragraph_style_.text_align == TextAlign::center) {
return (width_ - breaker_.getWidths()[line]) / 2; return (width_ - line_widths_[line]) / 2;
} else { } else {
return 0; return 0;
} }
...@@ -843,9 +868,7 @@ size_t Paragraph::GetLineCount() const { ...@@ -843,9 +868,7 @@ size_t Paragraph::GetLineCount() const {
} }
bool Paragraph::DidExceedMaxLines() const { bool Paragraph::DidExceedMaxLines() const {
if (GetLineCount() > paragraph_style_.max_lines) return did_exceed_max_lines_;
return true;
return false;
} }
void Paragraph::SetDirty(bool dirty) { void Paragraph::SetDirty(bool dirty) {
......
...@@ -71,7 +71,6 @@ class Paragraph { ...@@ -71,7 +71,6 @@ class Paragraph {
// //
// Layout calculates the positioning of all the glyphs. Must call this method // Layout calculates the positioning of all the glyphs. Must call this method
// before Painting and getting any statistics from this class. // before Painting and getting any statistics from this class.
void OldLayout(double width, bool force = false);
void Layout(double width, bool force = false); void Layout(double width, bool force = false);
// Paints the Laid out text onto the supplied SkCanvas at (x, y) offset from // Paints the Laid out text onto the supplied SkCanvas at (x, y) offset from
...@@ -181,12 +180,20 @@ class Paragraph { ...@@ -181,12 +180,20 @@ class Paragraph {
std::shared_ptr<FontCollection> font_collection_; std::shared_ptr<FontCollection> font_collection_;
minikin::LineBreaker breaker_; minikin::LineBreaker breaker_;
size_t breaks_count_ = 0;
struct LineRange {
LineRange(size_t s, size_t e, bool h) : start(s), end(e), hard_break(h) {}
size_t start, end;
bool hard_break;
};
std::vector<LineRange> line_ranges_;
std::vector<double> line_widths_;
// Stores the result of Layout(). // Stores the result of Layout().
std::vector<PaintRecord> records_; std::vector<PaintRecord> records_;
std::vector<double> line_heights_; std::vector<double> line_heights_;
bool did_exceed_max_lines_;
struct GlyphPosition { struct GlyphPosition {
const double start; const double start;
...@@ -203,7 +210,7 @@ class Paragraph { ...@@ -203,7 +210,7 @@ class Paragraph {
const std::vector<GlyphPosition> positions; const std::vector<GlyphPosition> positions;
const size_t total_code_units; const size_t total_code_units;
GlyphLine(std::vector<GlyphPosition>&& p); GlyphLine(std::vector<GlyphPosition>&& p, size_t tcu);
// Return the GlyphPosition containing the given code unit index within // Return the GlyphPosition containing the given code unit index within
// the line. // the line.
...@@ -237,18 +244,12 @@ class Paragraph { ...@@ -237,18 +244,12 @@ class Paragraph {
// into breaker_ in InitBreaker(), which is called in Layout(). // into breaker_ in InitBreaker(), which is called in Layout().
void SetText(std::vector<uint16_t> text, StyledRuns runs); void SetText(std::vector<uint16_t> text, StyledRuns runs);
// Sets up breaker_ with the contents of text_ and runs_. This is called every
// Layout() call to allow for different widths to be used.
void InitBreaker();
void SetParagraphStyle(const ParagraphStyle& style); void SetParagraphStyle(const ParagraphStyle& style);
void SetFontCollection(std::shared_ptr<FontCollection> font_collection); void SetFontCollection(std::shared_ptr<FontCollection> font_collection);
FXL_WARN_UNUSED_RESULT // Break the text into lines.
bool AddRunsToLineBreaker( bool ComputeLineBreaks();
std::unordered_map<std::string, std::shared_ptr<minikin::FontCollection>>&
collection_map);
// Calculate the starting X offset of a line based on the line's width and // Calculate the starting X offset of a line based on the line's width and
// alignment. // alignment.
......
...@@ -85,22 +85,9 @@ void ParagraphBuilder::AddText(const char* text) { ...@@ -85,22 +85,9 @@ void ParagraphBuilder::AddText(const char* text) {
AddText(u16_text); AddText(u16_text);
} }
void ParagraphBuilder::SplitNewlineRuns() {
std::list<size_t> newline_positions;
for (size_t i = 0; i < text_.size(); ++i) {
if (text_[i] == '\n') {
newline_positions.push_back(i);
}
}
if (newline_positions.size() > 0)
runs_.SplitNewlineRuns(newline_positions);
}
std::unique_ptr<Paragraph> ParagraphBuilder::Build() { std::unique_ptr<Paragraph> ParagraphBuilder::Build() {
runs_.EndRunIfNeeded(text_.size()); runs_.EndRunIfNeeded(text_.size());
SplitNewlineRuns();
std::unique_ptr<Paragraph> paragraph = std::make_unique<Paragraph>(); std::unique_ptr<Paragraph> paragraph = std::make_unique<Paragraph>();
paragraph->SetText(std::move(text_), std::move(runs_)); paragraph->SetText(std::move(text_), std::move(runs_));
paragraph->SetParagraphStyle(paragraph_style_); paragraph->SetParagraphStyle(paragraph_style_);
......
...@@ -79,10 +79,6 @@ class ParagraphBuilder { ...@@ -79,10 +79,6 @@ class ParagraphBuilder {
StyledRuns runs_; StyledRuns runs_;
ParagraphStyle paragraph_style_; ParagraphStyle paragraph_style_;
// Break any newline '\n' characters into their own runs. This allows
// Paragraph::Layout to cleanly discover and handle newlines.
void SplitNewlineRuns();
FXL_DISALLOW_COPY_AND_ASSIGN(ParagraphBuilder); FXL_DISALLOW_COPY_AND_ASSIGN(ParagraphBuilder);
}; };
......
...@@ -71,40 +71,4 @@ StyledRuns::Run StyledRuns::GetRun(size_t index) const { ...@@ -71,40 +71,4 @@ StyledRuns::Run StyledRuns::GetRun(size_t index) const {
return Run{styles_[run.style_index], run.start, run.end}; return Run{styles_[run.style_index], run.start, run.end};
} }
void StyledRuns::SplitNewlineRuns(std::list<size_t> newline_positions) {
std::vector<IndexedRun> result;
for (size_t i = 0; i < runs_.size(); ++i) {
if (runs_[i].end <= newline_positions.front() ||
newline_positions.empty()) {
result.push_back(runs_[i]);
} else {
size_t start = runs_[i].start;
size_t end = runs_[i].end;
while (end > newline_positions.front() && !newline_positions.empty() &&
start < end) {
IndexedRun temp_run;
temp_run.style_index = runs_[i].style_index;
temp_run.start = start;
temp_run.end = newline_positions.front();
newline_positions.pop_front();
result.push_back(temp_run);
temp_run.start = temp_run.end;
temp_run.end = temp_run.end + 1;
result.push_back(temp_run);
start = temp_run.end;
}
if (start < end) {
IndexedRun temp_run;
temp_run.style_index = runs_[i].style_index;
temp_run.start = start;
temp_run.end = end;
result.push_back(temp_run);
}
}
}
runs_ = result;
}
} // namespace txt } // namespace txt
...@@ -60,9 +60,6 @@ class StyledRuns { ...@@ -60,9 +60,6 @@ class StyledRuns {
Run GetRun(size_t index) const; Run GetRun(size_t index) const;
// Break any newline '\n' characters into their own runs.
void SplitNewlineRuns(std::list<size_t> newline_positions);
private: private:
FRIEND_TEST(ParagraphTest, SimpleParagraph); FRIEND_TEST(ParagraphTest, SimpleParagraph);
FRIEND_TEST(ParagraphTest, SimpleRedParagraph); FRIEND_TEST(ParagraphTest, SimpleRedParagraph);
......
...@@ -1332,32 +1332,16 @@ TEST_F(ParagraphTest, NewlineParagraph) { ...@@ -1332,32 +1332,16 @@ TEST_F(ParagraphTest, NewlineParagraph) {
ASSERT_TRUE(Snapshot()); ASSERT_TRUE(Snapshot());
ASSERT_EQ(paragraph->runs_.size(), 9ull); ASSERT_EQ(paragraph->records_.size(), 7ull);
ASSERT_EQ(paragraph->runs_.GetRun(1).end - paragraph->runs_.GetRun(1).start,
1ull);
ASSERT_EQ(paragraph->runs_.GetRun(3).end - paragraph->runs_.GetRun(3).start,
1ull);
ASSERT_EQ(paragraph->runs_.GetRun(5).end - paragraph->runs_.GetRun(5).start,
1ull);
ASSERT_EQ(paragraph->runs_.GetRun(7).end - paragraph->runs_.GetRun(7).start,
1ull);
ASSERT_EQ(paragraph->records_.size(), 10ull);
EXPECT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[0].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 127.69921875); EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().y(), EXPECT_DOUBLE_EQ(paragraph->records_[1].offset().y(), 126);
paragraph->records_[0].offset().y());
EXPECT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[2].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 586.9921875); EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().y(), EXPECT_DOUBLE_EQ(paragraph->records_[3].offset().y(), 266);
paragraph->records_[4].offset().y());
EXPECT_DOUBLE_EQ(paragraph->records_[5].offset().x(), 0); EXPECT_DOUBLE_EQ(paragraph->records_[5].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[6].offset().x(), 127.69921875); EXPECT_DOUBLE_EQ(paragraph->records_[6].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[7].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[8].offset().x(), 0);
EXPECT_DOUBLE_EQ(paragraph->records_[7].offset().y(), 336);
EXPECT_DOUBLE_EQ(paragraph->records_[8].offset().y(), 406);
} }
TEST_F(ParagraphTest, EmojiParagraph) { TEST_F(ParagraphTest, EmojiParagraph) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册