Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(817)

Side by Side Diff: third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp

Issue 2875933006: [LayoutNG] Misc fixes in ShapingLineBreaker (Closed)
Patch Set: clang build fix Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "platform/fonts/shaping/ShapingLineBreaker.h" 5 #include "platform/fonts/shaping/ShapingLineBreaker.h"
6 6
7 #include "platform/fonts/Font.h" 7 #include "platform/fonts/Font.h"
8 #include "platform/fonts/shaping/HarfBuzzShaper.h" 8 #include "platform/fonts/shaping/HarfBuzzShaper.h"
9 #include "platform/fonts/shaping/ShapeResult.h" 9 #include "platform/fonts/shaping/ShapeResult.h"
10 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" 10 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
11 #include "platform/text/TextBreakIterator.h" 11 #include "platform/text/TextBreakIterator.h"
12 12
13 namespace blink { 13 namespace blink {
14 14
15 ShapingLineBreaker::ShapingLineBreaker(const HarfBuzzShaper* shaper, 15 ShapingLineBreaker::ShapingLineBreaker(
16 const Font* font, 16 const HarfBuzzShaper* shaper,
17 const ShapeResult* result, 17 const Font* font,
18 const AtomicString locale, 18 const ShapeResult* result,
19 LineBreakType break_type) 19 const LazyLineBreakIterator* break_iterator)
20 : shaper_(shaper), 20 : shaper_(shaper),
21 font_(font), 21 font_(font),
22 result_(result), 22 result_(result),
23 locale_(locale), 23 break_iterator_(break_iterator) {
24 break_type_(break_type) {
25 text_ = String(shaper->GetText(), shaper->TextLength()); 24 text_ = String(shaper->GetText(), shaper->TextLength());
26 } 25 }
27 26
28 namespace { 27 namespace {
29 28
30 unsigned PreviousSafeToBreakAfter(const UChar* text, 29 unsigned PreviousSafeToBreakAfter(const UChar* text,
31 unsigned start, 30 unsigned start,
32 unsigned offset) { 31 unsigned offset) {
33 // TODO(eae): This is quite incorrect. It should be changed to use the 32 // TODO(eae): This is quite incorrect. It should be changed to use the
34 // HarfBuzzHarfBuzz safe to break info when available. 33 // HarfBuzzHarfBuzz safe to break info when available.
35 for (; offset > start; offset--) { 34 for (; offset > start; offset--) {
36 if (text[offset - 1] == kSpaceCharacter) 35 if (text[offset - 1] == kSpaceCharacter)
37 break; 36 break;
38 } 37 }
39 return offset; 38 return offset;
40 } 39 }
41 40
42 unsigned NextSafeToBreakBefore(const UChar* text, 41 unsigned NextSafeToBreakBefore(const UChar* text,
43 unsigned end, 42 unsigned end,
44 unsigned offset) { 43 unsigned offset) {
45 // TODO(eae): This is quite incorrect. It should be changed to use the 44 // TODO(eae): This is quite incorrect. It should be changed to use the
46 // HarfBuzzHarfBuzz safe to break info when available. 45 // HarfBuzzHarfBuzz safe to break info when available.
47 for (; offset < end; offset++) { 46 for (; offset < end; offset++) {
48 if (text[offset] == kSpaceCharacter) 47 if (text[offset] == kSpaceCharacter)
49 break; 48 break;
50 } 49 }
51 return offset; 50 return offset;
52 } 51 }
53 52
53 LayoutUnit FlipRtl(LayoutUnit value, TextDirection direction) {
54 return direction == TextDirection::kRtl ? -value : value;
55 }
56
54 } // namespace 57 } // namespace
55 58
56 // Shapes a line of text by finding a valid and appropriate break opportunity 59 // Shapes a line of text by finding a valid and appropriate break opportunity
57 // based on the shaping results for the entire paragraph. Re-shapes the start 60 // based on the shaping results for the entire paragraph. Re-shapes the start
58 // and end of the line as needed. 61 // and end of the line as needed.
59 // 62 //
60 // Definitions: 63 // Definitions:
61 // Candidate break opportunity: Ideal point to break, disregarding line 64 // Candidate break opportunity: Ideal point to break, disregarding line
62 // breaking rules. May be in the middle of a word 65 // breaking rules. May be in the middle of a word
63 // or inside a ligature. 66 // or inside a ligature.
(...skipping 15 matching lines...) Expand all
79 // The candidate (or ideal) break opportunity would be at an offset of 10 as 82 // The candidate (or ideal) break opportunity would be at an offset of 10 as
80 // the break would happen at exactly 100px in that case. 83 // the break would happen at exactly 100px in that case.
81 // The previous valid break opportunity though is at an offset of 5. 84 // The previous valid break opportunity though is at an offset of 5.
82 // If we further assume that the font kerns with space then even though it's a 85 // If we further assume that the font kerns with space then even though it's a
83 // valid break opportunity reshaping is required as the combined width of the 86 // valid break opportunity reshaping is required as the combined width of the
84 // two segments "Line " and "breaking" may be different from "Line breaking". 87 // two segments "Line " and "breaking" may be different from "Line breaking".
85 PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeLine( 88 PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeLine(
86 unsigned start, 89 unsigned start,
87 LayoutUnit available_space, 90 LayoutUnit available_space,
88 unsigned* break_offset) { 91 unsigned* break_offset) {
92 unsigned range_start = result_->CharacterStartIndex();
93 unsigned range_end = range_start + result_->NumCharacters();
94 DCHECK_GE(start, range_start);
95 DCHECK_LT(start, range_end);
96
89 // The start position in the original shape results. 97 // The start position in the original shape results.
90 LayoutUnit start_position = result_->SnappedStartPositionForOffset(start); 98 float start_position_float = result_->PositionForOffset(start - range_start);
99 LayoutUnit start_position = LayoutUnit::FromFloatFloor(start_position_float);
91 TextDirection direction = result_->Direction(); 100 TextDirection direction = result_->Direction();
92 101
102 // Find a candidate break opportunity by identifying the last offset before
103 // exceeding the available space and the determine the closest valid break
104 // preceding the candidate.
105 LayoutUnit end_position = LayoutUnit::FromFloatCeil(start_position_float) +
106 FlipRtl(available_space, direction);
107 unsigned candidate_break =
108 result_->OffsetForPosition(end_position,
109 ShapeResult::kOutsideAsStartOrEnd) +
110 range_start;
111 DCHECK_GE(candidate_break, start);
112 unsigned break_opportunity =
113 break_iterator_->PreviousBreakOpportunity(candidate_break, start);
114 if (break_opportunity <= start) {
115 break_opportunity = break_iterator_->NextBreakOpportunity(
116 std::max(candidate_break, start + 1));
117 }
118 DCHECK_GT(break_opportunity, start);
119
93 // If the start offset is not at a safe-to-break boundary the content between 120 // If the start offset is not at a safe-to-break boundary the content between
94 // the start and the next safe-to-break boundary needs to be reshaped and the 121 // the start and the next safe-to-break boundary needs to be reshaped and the
95 // available space adjusted to take the reshaping into account. 122 // available space adjusted to take the reshaping into account.
96 RefPtr<ShapeResult> line_start_result; 123 RefPtr<ShapeResult> line_start_result;
97 unsigned first_safe = 124 unsigned first_safe =
98 NextSafeToBreakBefore(shaper_->GetText(), shaper_->TextLength(), start); 125 NextSafeToBreakBefore(shaper_->GetText(), shaper_->TextLength(), start);
99 if (first_safe != start) { 126 DCHECK_GE(first_safe, start);
127 // 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
128 // Otherwise reshape will be part of line_end_result.
129 if (first_safe != start && first_safe < break_opportunity) {
100 LayoutUnit original_width = 130 LayoutUnit original_width =
101 result_->SnappedEndPositionForOffset(first_safe) - start_position; 131 FlipRtl(result_->SnappedEndPositionForOffset(first_safe - range_start) -
132 start_position,
133 direction);
102 line_start_result = shaper_->Shape(font_, direction, start, first_safe); 134 line_start_result = shaper_->Shape(font_, direction, start, first_safe);
103 available_space += line_start_result->SnappedWidth() - original_width; 135 available_space += line_start_result->SnappedWidth() - original_width;
104 } 136 }
105 137
106 // Find a candidate break opportunity by identifying the last offset before
107 // exceeding the available space and the determine the closest valid break
108 // preceding the candidate.
109 LazyLineBreakIterator break_iterator(text_, locale_, break_type_);
110 LayoutUnit end_position = start_position + available_space;
111 unsigned candidate_break = result_->OffsetForPosition(end_position, false);
112 unsigned break_opportunity =
113 break_iterator.PreviousBreakOpportunity(candidate_break, start);
114 if (break_opportunity <= start) {
115 break_opportunity = break_iterator.NextBreakOpportunity(candidate_break);
116 }
117
118 RefPtr<ShapeResult> line_end_result; 138 RefPtr<ShapeResult> line_end_result;
119 unsigned last_safe = break_opportunity; 139 unsigned last_safe = break_opportunity;
120 while (break_opportunity > start) { 140 while (break_opportunity > start) {
121 // If the previous valid break opportunity is not at a safe-to-break 141 // If the previous valid break opportunity is not at a safe-to-break
122 // boundary reshape between the safe-to-break offset and the valid break 142 // boundary reshape between the safe-to-break offset and the valid break
123 // offset. If the resulting width exceeds the available space the 143 // offset. If the resulting width exceeds the available space the
124 // preceding boundary is tried until the available space is sufficient. 144 // preceding boundary is tried until the available space is sufficient.
125 unsigned previous_safe = std::max( 145 unsigned previous_safe = std::max(
126 PreviousSafeToBreakAfter(shaper_->GetText(), start, break_opportunity), 146 PreviousSafeToBreakAfter(shaper_->GetText(), start, break_opportunity),
127 start); 147 start);
148 DCHECK_LE(previous_safe, break_opportunity);
128 if (previous_safe != break_opportunity) { 149 if (previous_safe != break_opportunity) {
129 LayoutUnit safe_position = 150 LayoutUnit safe_position =
130 result_->SnappedStartPositionForOffset(previous_safe); 151 result_->SnappedStartPositionForOffset(previous_safe - range_start);
131 while (break_opportunity > previous_safe && previous_safe > start) { 152 while (break_opportunity > previous_safe && previous_safe >= start) {
132 line_end_result = 153 line_end_result =
133 shaper_->Shape(font_, direction, previous_safe, break_opportunity); 154 shaper_->Shape(font_, direction, previous_safe,
134 if (safe_position + line_end_result->SnappedWidth() <= end_position) 155 std::min(break_opportunity, range_end));
156 if (line_end_result->SnappedWidth() <=
157 FlipRtl(end_position - safe_position, direction))
135 break; 158 break;
159 // Doesn't fit after the reshape. Try previous break opportunity, or
160 // overflow if there were none.
161 unsigned previous_break_opportunity =
162 break_iterator_->PreviousBreakOpportunity(break_opportunity - 1,
163 start);
164 if (previous_break_opportunity <= start)
165 break;
166 break_opportunity = previous_break_opportunity;
136 line_end_result = nullptr; 167 line_end_result = nullptr;
137 break_opportunity = break_iterator.PreviousBreakOpportunity(
138 break_opportunity - 1, start);
139 } 168 }
140 } 169 }
141 170
142 if (break_opportunity > start) { 171 if (break_opportunity > start) {
143 last_safe = previous_safe; 172 last_safe = previous_safe;
144 break; 173 break;
145 } 174 }
146 175
147 // No suitable break opportunity, not exceeding the available space, 176 // No suitable break opportunity, not exceeding the available space,
148 // found. Choose the next valid one even though it will overflow. 177 // found. Choose the next valid one even though it will overflow.
149 break_opportunity = break_iterator.NextBreakOpportunity(candidate_break); 178 break_opportunity = break_iterator_->NextBreakOpportunity(candidate_break);
150 } 179 }
151 180
152 // Create shape results for the line by copying from the re-shaped result (if 181 // Create shape results for the line by copying from the re-shaped result (if
153 // reshaping was needed) and the original shape results. 182 // reshaping was needed) and the original shape results.
154 RefPtr<ShapeResult> line_result = ShapeResult::Create(font_, 0, direction); 183 RefPtr<ShapeResult> line_result = ShapeResult::Create(font_, 0, direction);
155 unsigned max_length = std::numeric_limits<unsigned>::max(); 184 unsigned max_length = std::numeric_limits<unsigned>::max();
156 if (line_start_result) 185 if (line_start_result)
157 line_start_result->CopyRange(0, max_length, line_result.Get()); 186 line_start_result->CopyRange(0, max_length, line_result.Get());
158 if (last_safe > first_safe) 187 if (last_safe > first_safe)
159 result_->CopyRange(first_safe, last_safe, line_result.Get()); 188 result_->CopyRange(first_safe, last_safe, line_result.Get());
160 if (line_end_result) 189 if (line_end_result)
161 line_end_result->CopyRange(last_safe, max_length, line_result.Get()); 190 line_end_result->CopyRange(last_safe, max_length, line_result.Get());
162 191
192 DCHECK_GT(break_opportunity, start);
193 DCHECK_EQ(std::min(break_opportunity, range_end) - start,
194 line_result->NumCharacters());
195
163 *break_offset = break_opportunity; 196 *break_offset = break_opportunity;
164 return line_result.Release(); 197 return line_result.Release();
165 } 198 }
166 199
167 } // namespace blink 200 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698