Chromium Code Reviews| 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 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 115 LayoutUnit start_position = SnapStart(start_position_float, direction); | 115 LayoutUnit start_position = SnapStart(start_position_float, direction); |
| 116 | 116 |
| 117 // Find a candidate break opportunity by identifying the last offset before | 117 // Find a candidate break opportunity by identifying the last offset before |
| 118 // exceeding the available space and the determine the closest valid break | 118 // exceeding the available space and the determine the closest valid break |
| 119 // preceding the candidate. | 119 // preceding the candidate. |
| 120 LayoutUnit end_position = SnapEnd(start_position_float, direction) + | 120 LayoutUnit end_position = SnapEnd(start_position_float, direction) + |
| 121 FlipRtl(available_space, direction); | 121 FlipRtl(available_space, direction); |
| 122 DCHECK_GE(FlipRtl(end_position - start_position, direction), LayoutUnit(0)); | 122 DCHECK_GE(FlipRtl(end_position - start_position, direction), LayoutUnit(0)); |
| 123 unsigned candidate_break = | 123 unsigned candidate_break = |
| 124 result_->OffsetForPosition(end_position, false) + range_start; | 124 result_->OffsetForPosition(end_position, false) + range_start; |
| 125 | |
| 126 if (candidate_break >= range_end) { | |
|
eae
2017/06/12 16:51:37
When would this happen?
kojii
2017/06/12 16:54:34
"==" happens when end_position >= result->Width().
| |
| 127 // The |result_| does not have glyphs to fill the available space, | |
| 128 // and thus unable to compute. Return the result up to range_end. | |
| 129 DCHECK_EQ(candidate_break, range_end); | |
| 130 *break_offset = range_end; | |
| 131 return ShapeToEnd(start, start_position, range_end); | |
| 132 } | |
| 133 | |
| 125 // candidate_break should be >= start, but rounding errors can chime in when | 134 // candidate_break should be >= start, but rounding errors can chime in when |
| 126 // comparing floats. See ShapeLineZeroAvailableWidth on Linux/Mac. | 135 // comparing floats. See ShapeLineZeroAvailableWidth on Linux/Mac. |
| 127 candidate_break = std::max(candidate_break, start); | 136 candidate_break = std::max(candidate_break, start); |
| 128 unsigned break_opportunity = | 137 unsigned break_opportunity = |
| 129 break_iterator_->PreviousBreakOpportunity(candidate_break, start); | 138 break_iterator_->PreviousBreakOpportunity(candidate_break, start); |
| 130 if (break_opportunity <= start) { | 139 if (break_opportunity <= start) { |
| 131 break_opportunity = break_iterator_->NextBreakOpportunity( | 140 break_opportunity = break_iterator_->NextBreakOpportunity( |
| 132 std::max(candidate_break, start + 1)); | 141 std::max(candidate_break, start + 1)); |
| 142 // |range_end| may not be a break opportunity, but this function cannot | |
| 143 // measure beyond it. | |
| 144 break_opportunity = std::min(break_opportunity, range_end); | |
| 133 } | 145 } |
| 134 DCHECK_GT(break_opportunity, start); | 146 DCHECK_GT(break_opportunity, start); |
| 135 | 147 |
| 136 // If the start offset is not at a safe-to-break boundary the content between | 148 // If the start offset is not at a safe-to-break boundary the content between |
| 137 // the start and the next safe-to-break boundary needs to be reshaped and the | 149 // the start and the next safe-to-break boundary needs to be reshaped and the |
| 138 // available space adjusted to take the reshaping into account. | 150 // available space adjusted to take the reshaping into account. |
| 139 RefPtr<ShapeResult> line_start_result; | 151 RefPtr<ShapeResult> line_start_result; |
| 140 unsigned first_safe = | 152 unsigned first_safe = |
| 141 NextSafeToBreakBefore(shaper_->GetText(), shaper_->TextLength(), start); | 153 NextSafeToBreakBefore(shaper_->GetText(), shaper_->TextLength(), start); |
| 142 DCHECK_GE(first_safe, start); | 154 DCHECK_GE(first_safe, start); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 160 // offset. If the resulting width exceeds the available space the | 172 // offset. If the resulting width exceeds the available space the |
| 161 // preceding boundary is tried until the available space is sufficient. | 173 // preceding boundary is tried until the available space is sufficient. |
| 162 unsigned previous_safe = std::max( | 174 unsigned previous_safe = std::max( |
| 163 PreviousSafeToBreakAfter(shaper_->GetText(), start, break_opportunity), | 175 PreviousSafeToBreakAfter(shaper_->GetText(), start, break_opportunity), |
| 164 start); | 176 start); |
| 165 DCHECK_LE(previous_safe, break_opportunity); | 177 DCHECK_LE(previous_safe, break_opportunity); |
| 166 if (previous_safe != break_opportunity) { | 178 if (previous_safe != break_opportunity) { |
| 167 LayoutUnit safe_position = SnapStart( | 179 LayoutUnit safe_position = SnapStart( |
| 168 result_->PositionForOffset(previous_safe - range_start), direction); | 180 result_->PositionForOffset(previous_safe - range_start), direction); |
| 169 while (break_opportunity > previous_safe && previous_safe >= start) { | 181 while (break_opportunity > previous_safe && previous_safe >= start) { |
| 182 DCHECK_LE(break_opportunity, range_end); | |
| 170 line_end_result = | 183 line_end_result = |
| 171 shaper_->Shape(font_, direction, previous_safe, | 184 shaper_->Shape(font_, direction, previous_safe, break_opportunity); |
| 172 std::min(break_opportunity, range_end)); | |
| 173 if (line_end_result->SnappedWidth() <= | 185 if (line_end_result->SnappedWidth() <= |
| 174 FlipRtl(end_position - safe_position, direction)) | 186 FlipRtl(end_position - safe_position, direction)) |
| 175 break; | 187 break; |
| 176 // Doesn't fit after the reshape. Try previous break opportunity, or | 188 // Doesn't fit after the reshape. Try previous break opportunity, or |
| 177 // overflow if there were none. | 189 // overflow if there were none. |
| 178 unsigned previous_break_opportunity = | 190 unsigned previous_break_opportunity = |
| 179 break_iterator_->PreviousBreakOpportunity(break_opportunity - 1, | 191 break_iterator_->PreviousBreakOpportunity(break_opportunity - 1, |
| 180 start); | 192 start); |
| 181 if (previous_break_opportunity <= start) | 193 if (previous_break_opportunity <= start) |
| 182 break; | 194 break; |
| 183 break_opportunity = previous_break_opportunity; | 195 break_opportunity = previous_break_opportunity; |
| 184 line_end_result = nullptr; | 196 line_end_result = nullptr; |
| 185 } | 197 } |
| 186 } | 198 } |
| 187 | 199 |
| 188 if (break_opportunity > start) { | 200 if (break_opportunity > start) { |
| 189 last_safe = previous_safe; | 201 last_safe = previous_safe; |
| 190 break; | 202 break; |
| 191 } | 203 } |
| 192 | 204 |
| 193 // No suitable break opportunity, not exceeding the available space, | 205 // No suitable break opportunity, not exceeding the available space, |
| 194 // found. Choose the next valid one even though it will overflow. | 206 // found. Choose the next valid one even though it will overflow. |
| 195 break_opportunity = break_iterator_->NextBreakOpportunity(candidate_break); | 207 break_opportunity = break_iterator_->NextBreakOpportunity(candidate_break); |
| 208 // |range_end| may not be a break opportunity, but this function cannot | |
| 209 // measure beyond it. | |
| 210 break_opportunity = std::min(break_opportunity, range_end); | |
| 196 } | 211 } |
| 197 | 212 |
| 198 // Create shape results for the line by copying from the re-shaped result (if | 213 // Create shape results for the line by copying from the re-shaped result (if |
| 199 // reshaping was needed) and the original shape results. | 214 // reshaping was needed) and the original shape results. |
| 200 RefPtr<ShapeResult> line_result = ShapeResult::Create(font_, 0, direction); | 215 RefPtr<ShapeResult> line_result = ShapeResult::Create(font_, 0, direction); |
| 201 unsigned max_length = std::numeric_limits<unsigned>::max(); | 216 unsigned max_length = std::numeric_limits<unsigned>::max(); |
| 202 if (line_start_result) | 217 if (line_start_result) |
| 203 line_start_result->CopyRange(0, max_length, line_result.Get()); | 218 line_start_result->CopyRange(0, max_length, line_result.Get()); |
| 204 if (last_safe > first_safe) | 219 if (last_safe > first_safe) |
| 205 result_->CopyRange(first_safe, last_safe, line_result.Get()); | 220 result_->CopyRange(first_safe, last_safe, line_result.Get()); |
| 206 if (line_end_result) | 221 if (line_end_result) |
| 207 line_end_result->CopyRange(last_safe, max_length, line_result.Get()); | 222 line_end_result->CopyRange(last_safe, max_length, line_result.Get()); |
| 208 | 223 |
| 209 DCHECK_GT(break_opportunity, start); | 224 DCHECK_GT(break_opportunity, start); |
| 210 DCHECK_EQ(std::min(break_opportunity, range_end) - start, | 225 DCHECK_EQ(std::min(break_opportunity, range_end) - start, |
| 211 line_result->NumCharacters()); | 226 line_result->NumCharacters()); |
| 212 | 227 |
| 213 *break_offset = break_opportunity; | 228 *break_offset = break_opportunity; |
| 214 return line_result.Release(); | 229 return line_result.Release(); |
| 215 } | 230 } |
| 216 | 231 |
| 232 // Shape from the specified offset to the end of the ShapeResult. | |
| 233 // If |start| is safe-to-break, this copies the subset of the result. | |
| 234 PassRefPtr<ShapeResult> ShapingLineBreaker::ShapeToEnd( | |
| 235 unsigned start, | |
| 236 LayoutUnit start_position, | |
| 237 unsigned range_end) { | |
| 238 unsigned first_safe = | |
| 239 NextSafeToBreakBefore(shaper_->GetText(), shaper_->TextLength(), start); | |
| 240 DCHECK_GE(first_safe, start); | |
| 241 | |
| 242 RefPtr<ShapeResult> line_result; | |
| 243 TextDirection direction = result_->Direction(); | |
| 244 if (first_safe == start) { | |
| 245 // If |start| is safe-to-break, reshape is not needed. | |
| 246 line_result = ShapeResult::Create(font_, 0, direction); | |
| 247 result_->CopyRange(start, range_end, line_result.Get()); | |
| 248 } else if (first_safe < range_end) { | |
| 249 // Otherwise reshape to the first safe, then copy the rest. | |
| 250 line_result = shaper_->Shape(font_, direction, start, first_safe); | |
| 251 result_->CopyRange(first_safe, range_end, line_result.Get()); | |
| 252 } else { | |
| 253 // If no safe-to-break in the ragne, reshape the whole range. | |
| 254 line_result = shaper_->Shape(font_, direction, start, range_end); | |
| 255 } | |
| 256 return line_result.Release(); | |
| 257 } | |
| 258 | |
| 217 } // namespace blink | 259 } // namespace blink |
| OLD | NEW |