| Index: third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
|
| diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
|
| index 5206620abd964b923089b5c2b7b48b99b87f3495..dafe8f19e9a07cc0bdc11a84600fe359ea0e06c8 100644
|
| --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
|
| +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
|
| @@ -12,16 +12,15 @@
|
|
|
| namespace blink {
|
|
|
| -ShapingLineBreaker::ShapingLineBreaker(const HarfBuzzShaper* shaper,
|
| - const Font* font,
|
| - const ShapeResult* result,
|
| - const AtomicString locale,
|
| - LineBreakType break_type)
|
| +ShapingLineBreaker::ShapingLineBreaker(
|
| + const HarfBuzzShaper* shaper,
|
| + const Font* font,
|
| + const ShapeResult* result,
|
| + const LazyLineBreakIterator* break_iterator)
|
| : shaper_(shaper),
|
| font_(font),
|
| result_(result),
|
| - locale_(locale),
|
| - break_type_(break_type) {
|
| + break_iterator_(break_iterator) {
|
| text_ = String(shaper->GetText(), shaper->TextLength());
|
| }
|
|
|
| @@ -51,6 +50,24 @@ unsigned NextSafeToBreakBefore(const UChar* text,
|
| return offset;
|
| }
|
|
|
| +// ShapingLineBreaker computes using visual positions. This function flips
|
| +// logical advance to visual, or vice versa.
|
| +LayoutUnit FlipRtl(LayoutUnit value, TextDirection direction) {
|
| + return direction != TextDirection::kRtl ? value : -value;
|
| +}
|
| +
|
| +// Snaps a visual position to the line start direction.
|
| +LayoutUnit SnapStart(float value, TextDirection direction) {
|
| + return direction != TextDirection::kRtl ? LayoutUnit::FromFloatFloor(value)
|
| + : LayoutUnit::FromFloatCeil(value);
|
| +}
|
| +
|
| +// Snaps a visual position to the line end direction.
|
| +LayoutUnit SnapEnd(float value, TextDirection direction) {
|
| + return direction != TextDirection::kRtl ? LayoutUnit::FromFloatCeil(value)
|
| + : LayoutUnit::FromFloatFloor(value);
|
| +}
|
| +
|
| } // namespace
|
|
|
| // Shapes a line of text by finding a valid and appropriate break opportunity
|
| @@ -86,9 +103,35 @@ PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeLine(
|
| unsigned start,
|
| LayoutUnit available_space,
|
| unsigned* break_offset) {
|
| + DCHECK_GE(available_space, LayoutUnit(0));
|
| + unsigned range_start = result_->StartIndexForResult();
|
| + unsigned range_end = result_->EndIndexForResult();
|
| + DCHECK_GE(start, range_start);
|
| + DCHECK_LT(start, range_end);
|
| +
|
| // The start position in the original shape results.
|
| - LayoutUnit start_position = result_->SnappedStartPositionForOffset(start);
|
| + float start_position_float = result_->PositionForOffset(start - range_start);
|
| TextDirection direction = result_->Direction();
|
| + LayoutUnit start_position = SnapStart(start_position_float, direction);
|
| +
|
| + // Find a candidate break opportunity by identifying the last offset before
|
| + // exceeding the available space and the determine the closest valid break
|
| + // preceding the candidate.
|
| + LayoutUnit end_position = SnapEnd(start_position_float, direction) +
|
| + FlipRtl(available_space, direction);
|
| + DCHECK_GE(FlipRtl(end_position - start_position, direction), LayoutUnit(0));
|
| + unsigned candidate_break =
|
| + result_->OffsetForPosition(end_position, false) + range_start;
|
| + // candidate_break should be >= start, but rounding errors can chime in when
|
| + // comparing floats. See ShapeLineZeroAvailableWidth on Linux/Mac.
|
| + candidate_break = std::max(candidate_break, start);
|
| + unsigned break_opportunity =
|
| + break_iterator_->PreviousBreakOpportunity(candidate_break, start);
|
| + if (break_opportunity <= start) {
|
| + break_opportunity = break_iterator_->NextBreakOpportunity(
|
| + std::max(candidate_break, start + 1));
|
| + }
|
| + DCHECK_GT(break_opportunity, start);
|
|
|
| // If the start offset is not at a safe-to-break boundary the content between
|
| // the start and the next safe-to-break boundary needs to be reshaped and the
|
| @@ -96,25 +139,19 @@ PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeLine(
|
| RefPtr<ShapeResult> line_start_result;
|
| unsigned first_safe =
|
| NextSafeToBreakBefore(shaper_->GetText(), shaper_->TextLength(), start);
|
| - if (first_safe != start) {
|
| + DCHECK_GE(first_safe, start);
|
| + // Reshape takes place only when first_safe is before the break opportunity.
|
| + // Otherwise reshape will be part of line_end_result.
|
| + if (first_safe != start && first_safe < break_opportunity) {
|
| LayoutUnit original_width =
|
| - result_->SnappedEndPositionForOffset(first_safe) - start_position;
|
| + FlipRtl(SnapEnd(result_->PositionForOffset(first_safe - range_start),
|
| + direction) -
|
| + start_position,
|
| + direction);
|
| line_start_result = shaper_->Shape(font_, direction, start, first_safe);
|
| available_space += line_start_result->SnappedWidth() - original_width;
|
| }
|
|
|
| - // Find a candidate break opportunity by identifying the last offset before
|
| - // exceeding the available space and the determine the closest valid break
|
| - // preceding the candidate.
|
| - LazyLineBreakIterator break_iterator(text_, locale_, break_type_);
|
| - LayoutUnit end_position = start_position + available_space;
|
| - unsigned candidate_break = result_->OffsetForPosition(end_position, false);
|
| - unsigned break_opportunity =
|
| - break_iterator.PreviousBreakOpportunity(candidate_break, start);
|
| - if (break_opportunity <= start) {
|
| - break_opportunity = break_iterator.NextBreakOpportunity(candidate_break);
|
| - }
|
| -
|
| RefPtr<ShapeResult> line_end_result;
|
| unsigned last_safe = break_opportunity;
|
| while (break_opportunity > start) {
|
| @@ -125,17 +162,26 @@ PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeLine(
|
| unsigned previous_safe = std::max(
|
| PreviousSafeToBreakAfter(shaper_->GetText(), start, break_opportunity),
|
| start);
|
| + DCHECK_LE(previous_safe, break_opportunity);
|
| if (previous_safe != break_opportunity) {
|
| - LayoutUnit safe_position =
|
| - result_->SnappedStartPositionForOffset(previous_safe);
|
| - while (break_opportunity > previous_safe && previous_safe > start) {
|
| + LayoutUnit safe_position = SnapStart(
|
| + result_->PositionForOffset(previous_safe - range_start), direction);
|
| + while (break_opportunity > previous_safe && previous_safe >= start) {
|
| line_end_result =
|
| - shaper_->Shape(font_, direction, previous_safe, break_opportunity);
|
| - if (safe_position + line_end_result->SnappedWidth() <= end_position)
|
| + shaper_->Shape(font_, direction, previous_safe,
|
| + std::min(break_opportunity, range_end));
|
| + if (line_end_result->SnappedWidth() <=
|
| + FlipRtl(end_position - safe_position, direction))
|
| break;
|
| + // Doesn't fit after the reshape. Try previous break opportunity, or
|
| + // overflow if there were none.
|
| + unsigned previous_break_opportunity =
|
| + break_iterator_->PreviousBreakOpportunity(break_opportunity - 1,
|
| + start);
|
| + if (previous_break_opportunity <= start)
|
| + break;
|
| + break_opportunity = previous_break_opportunity;
|
| line_end_result = nullptr;
|
| - break_opportunity = break_iterator.PreviousBreakOpportunity(
|
| - break_opportunity - 1, start);
|
| }
|
| }
|
|
|
| @@ -146,7 +192,7 @@ PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeLine(
|
|
|
| // No suitable break opportunity, not exceeding the available space,
|
| // found. Choose the next valid one even though it will overflow.
|
| - break_opportunity = break_iterator.NextBreakOpportunity(candidate_break);
|
| + break_opportunity = break_iterator_->NextBreakOpportunity(candidate_break);
|
| }
|
|
|
| // Create shape results for the line by copying from the re-shaped result (if
|
| @@ -160,6 +206,10 @@ PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeLine(
|
| if (line_end_result)
|
| line_end_result->CopyRange(last_safe, max_length, line_result.Get());
|
|
|
| + DCHECK_GT(break_opportunity, start);
|
| + DCHECK_EQ(std::min(break_opportunity, range_end) - start,
|
| + line_result->NumCharacters());
|
| +
|
| *break_offset = break_opportunity;
|
| return line_result.Release();
|
| }
|
|
|