OLD | NEW |
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" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 // HarfBuzzHarfBuzz safe to break info when available. | 46 // HarfBuzzHarfBuzz safe to break info when available. |
47 for (; offset < end; offset++) { | 47 for (; offset < end; offset++) { |
48 if (text[offset] == kSpaceCharacter) | 48 if (text[offset] == kSpaceCharacter) |
49 break; | 49 break; |
50 } | 50 } |
51 return offset; | 51 return offset; |
52 } | 52 } |
53 | 53 |
54 } // namespace | 54 } // namespace |
55 | 55 |
56 // TODO(eae); Should take a const LazyLineBreakIterator& but that requires the | |
57 // LazyLineBreakIterator::isBreakable method to be updated to be const. | |
58 unsigned ShapingLineBreaker::PreviousBreakOpportunity( | |
59 LazyLineBreakIterator* break_iterator, | |
60 unsigned start, | |
61 unsigned offset) { | |
62 DCHECK(break_iterator); | |
63 unsigned pos = std::min(start + offset, shaper_->TextLength()); | |
64 for (; pos > start; pos--) { | |
65 int next_break = 0; | |
66 if (break_iterator->IsBreakable(pos, next_break, break_type_)) | |
67 return pos; | |
68 } | |
69 return start; | |
70 } | |
71 | |
72 unsigned ShapingLineBreaker::NextBreakOpportunity( | |
73 LazyLineBreakIterator* break_iterator, | |
74 unsigned offset) { | |
75 DCHECK(break_iterator); | |
76 int next_break = 0; | |
77 break_iterator->IsBreakable(offset, next_break, break_type_); | |
78 return next_break; | |
79 } | |
80 | |
81 // Shapes a line of text by finding a valid and appropriate break opportunity | 56 // Shapes a line of text by finding a valid and appropriate break opportunity |
82 // based on the shaping results for the entire paragraph. Re-shapes the start | 57 // based on the shaping results for the entire paragraph. Re-shapes the start |
83 // and end of the line as needed. | 58 // and end of the line as needed. |
84 // | 59 // |
85 // Definitions: | 60 // Definitions: |
86 // Candidate break opportunity: Ideal point to break, disregarding line | 61 // Candidate break opportunity: Ideal point to break, disregarding line |
87 // breaking rules. May be in the middle of a word | 62 // breaking rules. May be in the middle of a word |
88 // or inside a ligature. | 63 // or inside a ligature. |
89 // Valid break opportunity: A point where a break is allowed according to | 64 // Valid break opportunity: A point where a break is allowed according to |
90 // the relevant breaking rules. | 65 // the relevant breaking rules. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 if (first_safe != start) { | 99 if (first_safe != start) { |
125 LayoutUnit original_width = | 100 LayoutUnit original_width = |
126 result_->SnappedEndPositionForOffset(first_safe) - start_position; | 101 result_->SnappedEndPositionForOffset(first_safe) - start_position; |
127 line_start_result = shaper_->Shape(font_, direction, start, first_safe); | 102 line_start_result = shaper_->Shape(font_, direction, start, first_safe); |
128 available_space += line_start_result->SnappedWidth() - original_width; | 103 available_space += line_start_result->SnappedWidth() - original_width; |
129 } | 104 } |
130 | 105 |
131 // Find a candidate break opportunity by identifying the last offset before | 106 // Find a candidate break opportunity by identifying the last offset before |
132 // exceeding the available space and the determine the closest valid break | 107 // exceeding the available space and the determine the closest valid break |
133 // preceding the candidate. | 108 // preceding the candidate. |
134 LazyLineBreakIterator break_iterator(text_, locale_); | 109 LazyLineBreakIterator break_iterator(text_, locale_, break_type_); |
135 LayoutUnit end_position = start_position + available_space; | 110 LayoutUnit end_position = start_position + available_space; |
136 unsigned candidate_break = result_->OffsetForPosition(end_position, false); | 111 unsigned candidate_break = result_->OffsetForPosition(end_position, false); |
137 unsigned break_opportunity = | 112 unsigned break_opportunity = |
138 PreviousBreakOpportunity(&break_iterator, start, candidate_break); | 113 break_iterator.PreviousBreakOpportunity(candidate_break, start); |
139 if (break_opportunity <= start) { | 114 if (break_opportunity <= start) { |
140 break_opportunity = NextBreakOpportunity(&break_iterator, candidate_break); | 115 break_opportunity = break_iterator.NextBreakOpportunity(candidate_break); |
141 } | 116 } |
142 | 117 |
143 RefPtr<ShapeResult> line_end_result; | 118 RefPtr<ShapeResult> line_end_result; |
144 unsigned last_safe = break_opportunity; | 119 unsigned last_safe = break_opportunity; |
145 while (break_opportunity > start) { | 120 while (break_opportunity > start) { |
146 // If the previous valid break opportunity is not at a safe-to-break | 121 // If the previous valid break opportunity is not at a safe-to-break |
147 // boundary reshape between the safe-to-break offset and the valid break | 122 // boundary reshape between the safe-to-break offset and the valid break |
148 // offset. If the resulting width exceeds the available space the | 123 // offset. If the resulting width exceeds the available space the |
149 // preceding boundary is tried until the available space is sufficient. | 124 // preceding boundary is tried until the available space is sufficient. |
150 unsigned previous_safe = std::max( | 125 unsigned previous_safe = std::max( |
151 PreviousSafeToBreakAfter(shaper_->GetText(), start, break_opportunity), | 126 PreviousSafeToBreakAfter(shaper_->GetText(), start, break_opportunity), |
152 start); | 127 start); |
153 if (previous_safe != break_opportunity) { | 128 if (previous_safe != break_opportunity) { |
154 LayoutUnit safe_position = | 129 LayoutUnit safe_position = |
155 result_->SnappedStartPositionForOffset(previous_safe); | 130 result_->SnappedStartPositionForOffset(previous_safe); |
156 while (break_opportunity > previous_safe && previous_safe > start) { | 131 while (break_opportunity > previous_safe && previous_safe > start) { |
157 line_end_result = | 132 line_end_result = |
158 shaper_->Shape(font_, direction, previous_safe, break_opportunity); | 133 shaper_->Shape(font_, direction, previous_safe, break_opportunity); |
159 if (safe_position + line_end_result->SnappedWidth() <= end_position) | 134 if (safe_position + line_end_result->SnappedWidth() <= end_position) |
160 break; | 135 break; |
161 line_end_result = nullptr; | 136 line_end_result = nullptr; |
162 break_opportunity = PreviousBreakOpportunity(&break_iterator, start, | 137 break_opportunity = break_iterator.PreviousBreakOpportunity( |
163 break_opportunity - 1); | 138 break_opportunity - 1, start); |
164 } | 139 } |
165 } | 140 } |
166 | 141 |
167 if (break_opportunity > start) { | 142 if (break_opportunity > start) { |
168 last_safe = previous_safe; | 143 last_safe = previous_safe; |
169 break; | 144 break; |
170 } | 145 } |
171 | 146 |
172 // No suitable break opportunity, not exceeding the available space, | 147 // No suitable break opportunity, not exceeding the available space, |
173 // found. Choose the next valid one even though it will overflow. | 148 // found. Choose the next valid one even though it will overflow. |
174 break_opportunity = NextBreakOpportunity(&break_iterator, candidate_break); | 149 break_opportunity = break_iterator.NextBreakOpportunity(candidate_break); |
175 } | 150 } |
176 | 151 |
177 // Create shape results for the line by copying from the re-shaped result (if | 152 // Create shape results for the line by copying from the re-shaped result (if |
178 // reshaping was needed) and the original shape results. | 153 // reshaping was needed) and the original shape results. |
179 RefPtr<ShapeResult> line_result = ShapeResult::Create(font_, 0, direction); | 154 RefPtr<ShapeResult> line_result = ShapeResult::Create(font_, 0, direction); |
180 unsigned max_length = std::numeric_limits<unsigned>::max(); | 155 unsigned max_length = std::numeric_limits<unsigned>::max(); |
181 if (line_start_result) | 156 if (line_start_result) |
182 line_start_result->CopyRange(0, max_length, line_result.Get()); | 157 line_start_result->CopyRange(0, max_length, line_result.Get()); |
183 if (last_safe > first_safe) | 158 if (last_safe > first_safe) |
184 result_->CopyRange(first_safe, last_safe, line_result.Get()); | 159 result_->CopyRange(first_safe, last_safe, line_result.Get()); |
185 if (line_end_result) | 160 if (line_end_result) |
186 line_end_result->CopyRange(last_safe, max_length, line_result.Get()); | 161 line_end_result->CopyRange(last_safe, max_length, line_result.Get()); |
187 | 162 |
188 *break_offset = break_opportunity; | 163 *break_offset = break_opportunity; |
189 return line_result.Release(); | 164 return line_result.Release(); |
190 } | 165 } |
191 | 166 |
192 } // namespace blink | 167 } // namespace blink |
OLD | NEW |