Chromium Code Reviews| 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..24692ffa77cf3392d428cf6f5e5926724d583616 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,10 @@ unsigned NextSafeToBreakBefore(const UChar* text, |
| return offset; |
| } |
| +LayoutUnit FlipRtl(LayoutUnit value, TextDirection direction) { |
| + return direction == TextDirection::kRtl ? -value : value; |
| +} |
| + |
| } // namespace |
| // Shapes a line of text by finding a valid and appropriate break opportunity |
| @@ -86,35 +89,52 @@ PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeLine( |
| unsigned start, |
| LayoutUnit available_space, |
| unsigned* break_offset) { |
| + unsigned range_start = result_->CharacterStartIndex(); |
| + unsigned range_end = range_start + result_->NumCharacters(); |
| + 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); |
| + LayoutUnit start_position = LayoutUnit::FromFloatFloor(start_position_float); |
| TextDirection direction = result_->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 = LayoutUnit::FromFloatCeil(start_position_float) + |
| + FlipRtl(available_space, direction); |
| + unsigned candidate_break = |
| + result_->OffsetForPosition(end_position, |
| + ShapeResult::kOutsideAsStartOrEnd) + |
| + range_start; |
| + DCHECK_GE(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 |
| // available space adjusted to take the reshaping into account. |
| 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. |
|
eae
2017/05/12 18:45:49
I considered this case and wanted to fix it but fa
kojii
2017/05/12 19:08:13
Yes, the Han character in your ShapeLineArabicThai
|
| + // 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(result_->SnappedEndPositionForOffset(first_safe - range_start) - |
| + 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 +145,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) { |
| + result_->SnappedStartPositionForOffset(previous_safe - range_start); |
| + 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 +175,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 +189,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(); |
| } |