| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "ui/gfx/render_text_harfbuzz.h" | 5 #include "ui/gfx/render_text_harfbuzz.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/i18n/bidi_line_iterator.h" | 10 #include "base/i18n/bidi_line_iterator.h" |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 // the given runs. |min_baseline| and |min_height| are the minimum baseline and | 217 // the given runs. |min_baseline| and |min_height| are the minimum baseline and |
| 218 // height for each line. | 218 // height for each line. |
| 219 // TODO(ckocagil): Expose the interface of this class in the header and test | 219 // TODO(ckocagil): Expose the interface of this class in the header and test |
| 220 // this class directly. | 220 // this class directly. |
| 221 class HarfBuzzLineBreaker { | 221 class HarfBuzzLineBreaker { |
| 222 public: | 222 public: |
| 223 HarfBuzzLineBreaker(size_t max_width, | 223 HarfBuzzLineBreaker(size_t max_width, |
| 224 int min_baseline, | 224 int min_baseline, |
| 225 float min_height, | 225 float min_height, |
| 226 bool multiline, | 226 bool multiline, |
| 227 WordWrapBehavior word_wrap_behavior, |
| 227 const base::string16& text, | 228 const base::string16& text, |
| 228 const BreakList<size_t>* words, | 229 const BreakList<size_t>* words, |
| 229 const internal::TextRunList& run_list) | 230 const internal::TextRunList& run_list) |
| 230 : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)), | 231 : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)), |
| 231 min_baseline_(min_baseline), | 232 min_baseline_(min_baseline), |
| 232 min_height_(min_height), | 233 min_height_(min_height), |
| 233 multiline_(multiline), | 234 multiline_(multiline), |
| 235 word_wrap_behavior_(word_wrap_behavior), |
| 234 text_(text), | 236 text_(text), |
| 235 words_(words), | 237 words_(words), |
| 236 run_list_(run_list), | 238 run_list_(run_list), |
| 237 text_x_(0), | 239 text_x_(0), |
| 238 line_x_(0), | 240 line_x_(0), |
| 239 max_descent_(0), | 241 max_descent_(0), |
| 240 max_ascent_(0) { | 242 max_ascent_(0) { |
| 241 DCHECK_EQ(multiline_, (words_ != nullptr)); | 243 DCHECK_EQ(multiline_, (words_ != nullptr)); |
| 242 AdvanceLine(); | 244 AdvanceLine(); |
| 243 } | 245 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 // them. Adds a new Line to the back of |lines_| whenever a new segment can't | 280 // them. Adds a new Line to the back of |lines_| whenever a new segment can't |
| 279 // be added without the Line's width exceeding |max_width_|. | 281 // be added without the Line's width exceeding |max_width_|. |
| 280 void BreakRun(int run_index) { | 282 void BreakRun(int run_index) { |
| 281 const internal::TextRunHarfBuzz& run = *(run_list_.runs()[run_index]); | 283 const internal::TextRunHarfBuzz& run = *(run_list_.runs()[run_index]); |
| 282 SkScalar width = 0; | 284 SkScalar width = 0; |
| 283 size_t next_char = run.range.start(); | 285 size_t next_char = run.range.start(); |
| 284 | 286 |
| 285 // Break the run until it fits the current line. | 287 // Break the run until it fits the current line. |
| 286 while (next_char < run.range.end()) { | 288 while (next_char < run.range.end()) { |
| 287 const size_t current_char = next_char; | 289 const size_t current_char = next_char; |
| 290 size_t end_char = next_char; |
| 288 const bool skip_line = | 291 const bool skip_line = |
| 289 BreakRunAtWidth(run, current_char, &width, &next_char); | 292 BreakRunAtWidth(run, current_char, &width, &end_char, &next_char); |
| 290 AddSegment(run_index, Range(current_char, next_char), | 293 AddSegment(run_index, Range(current_char, end_char), |
| 291 SkScalarToFloat(width)); | 294 SkScalarToFloat(width)); |
| 292 if (skip_line) | 295 if (skip_line) |
| 293 AdvanceLine(); | 296 AdvanceLine(); |
| 294 } | 297 } |
| 295 } | 298 } |
| 296 | 299 |
| 297 // Starting from |start_char|, finds a suitable line break position at or | 300 // Starting from |start_char|, finds a suitable line break position at or |
| 298 // before available width using word break. If the current position is at the | 301 // before available width using word break. If the current position is at the |
| 299 // beginning of a line, this function will not roll back to |start_char| and | 302 // beginning of a line, this function will not roll back to |start_char| and |
| 300 // |*next_char| will be greater than |start_char| (to avoid constructing empty | 303 // |*next_char| will be greater than |start_char| (to avoid constructing empty |
| 301 // lines). | 304 // lines). It stores the end of the segment range to |end_char|, which can be |
| 305 // smaller than |*next_char| for certain word wrapping behavior. |
| 302 // Returns whether to skip the line before |*next_char|. | 306 // Returns whether to skip the line before |*next_char|. |
| 303 // TODO(ckocagil): We might have to reshape after breaking at ligatures. | 307 // TODO(ckocagil): We might have to reshape after breaking at ligatures. |
| 304 // See whether resolving the TODO above resolves this too. | 308 // See whether resolving the TODO above resolves this too. |
| 305 // TODO(ckocagil): Do not reserve width for whitespace at the end of lines. | 309 // TODO(ckocagil): Do not reserve width for whitespace at the end of lines. |
| 306 bool BreakRunAtWidth(const internal::TextRunHarfBuzz& run, | 310 bool BreakRunAtWidth(const internal::TextRunHarfBuzz& run, |
| 307 size_t start_char, | 311 size_t start_char, |
| 308 SkScalar* width, | 312 SkScalar* width, |
| 313 size_t* end_char, |
| 309 size_t* next_char) { | 314 size_t* next_char) { |
| 310 DCHECK(words_); | 315 DCHECK(words_); |
| 311 DCHECK(run.range.Contains(Range(start_char, start_char + 1))); | 316 DCHECK(run.range.Contains(Range(start_char, start_char + 1))); |
| 312 SkScalar available_width = max_width_ - line_x_; | 317 SkScalar available_width = max_width_ - line_x_; |
| 313 BreakList<size_t>::const_iterator word = words_->GetBreak(start_char); | 318 BreakList<size_t>::const_iterator word = words_->GetBreak(start_char); |
| 314 BreakList<size_t>::const_iterator next_word = word + 1; | 319 BreakList<size_t>::const_iterator next_word = word + 1; |
| 315 // Width from |std::max(word->first, start_char)| to the current character. | 320 // Width from |std::max(word->first, start_char)| to the current character. |
| 316 SkScalar word_width = 0; | 321 SkScalar word_width = 0; |
| 317 *width = 0; | 322 *width = 0; |
| 318 | 323 |
| 319 Range char_range; | 324 Range char_range; |
| 325 bool truncated = false; |
| 320 for (size_t i = start_char; i < run.range.end(); i += char_range.length()) { | 326 for (size_t i = start_char; i < run.range.end(); i += char_range.length()) { |
| 321 // |word| holds the word boundary at or before |i|, and |next_word| holds | 327 // |word| holds the word boundary at or before |i|, and |next_word| holds |
| 322 // the word boundary right after |i|. Advance both |word| and |next_word| | 328 // the word boundary right after |i|. Advance both |word| and |next_word| |
| 323 // when |i| reaches |next_word|. | 329 // when |i| reaches |next_word|. |
| 324 if (next_word != words_->breaks().end() && i >= next_word->first) { | 330 if (next_word != words_->breaks().end() && i >= next_word->first) { |
| 331 if (*width > available_width) { |
| 332 DCHECK_NE(WRAP_LONG_WORDS, word_wrap_behavior_); |
| 333 *next_char = i; |
| 334 if (!truncated) |
| 335 *end_char = *next_char; |
| 336 return true; |
| 337 } |
| 325 word = next_word++; | 338 word = next_word++; |
| 326 word_width = 0; | 339 word_width = 0; |
| 327 } | 340 } |
| 328 | 341 |
| 329 Range glyph_range; | 342 Range glyph_range; |
| 330 run.GetClusterAt(i, &char_range, &glyph_range); | 343 run.GetClusterAt(i, &char_range, &glyph_range); |
| 331 DCHECK_LT(0U, char_range.length()); | 344 DCHECK_LT(0U, char_range.length()); |
| 332 | 345 |
| 333 SkScalar char_width = ((glyph_range.end() >= run.glyph_count) | 346 SkScalar char_width = ((glyph_range.end() >= run.glyph_count) |
| 334 ? SkFloatToScalar(run.width) | 347 ? SkFloatToScalar(run.width) |
| 335 : run.positions[glyph_range.end()].x()) - | 348 : run.positions[glyph_range.end()].x()) - |
| 336 run.positions[glyph_range.start()].x(); | 349 run.positions[glyph_range.start()].x(); |
| 337 | 350 |
| 338 *width += char_width; | 351 *width += char_width; |
| 339 word_width += char_width; | 352 word_width += char_width; |
| 340 | 353 |
| 354 // TODO(mukai): implement ELIDE_LONG_WORDS. |
| 341 if (*width > available_width) { | 355 if (*width > available_width) { |
| 342 if (line_x_ != 0 || word_width < *width) { | 356 if (line_x_ != 0 || word_width < *width) { |
| 343 // Roll back one word. | 357 // Roll back one word. |
| 344 *width -= word_width; | 358 *width -= word_width; |
| 345 *next_char = std::max(word->first, start_char); | 359 *next_char = std::max(word->first, start_char); |
| 346 } else if (char_width < *width) { | 360 *end_char = *next_char; |
| 347 // Roll back one character. | 361 return true; |
| 348 *width -= char_width; | 362 } else if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS && !truncated) { |
| 349 *next_char = i; | 363 *end_char = i; |
| 350 } else { | 364 truncated = true; |
| 351 // Continue from the next character. | 365 } else if (word_wrap_behavior_ == WRAP_LONG_WORDS) { |
| 352 *next_char = i + char_range.length(); | 366 if (char_width < *width) { |
| 367 // Roll back one character. |
| 368 *width -= char_width; |
| 369 *next_char = i; |
| 370 } else { |
| 371 // Continue from the next character. |
| 372 *next_char = i + char_range.length(); |
| 373 } |
| 374 *end_char = *next_char; |
| 375 return true; |
| 353 } | 376 } |
| 354 return true; | |
| 355 } | 377 } |
| 356 } | 378 } |
| 357 | 379 |
| 358 *next_char = run.range.end(); | 380 *next_char = run.range.end(); |
| 381 if (!truncated) |
| 382 *end_char = *next_char; |
| 359 return false; | 383 return false; |
| 360 } | 384 } |
| 361 | 385 |
| 362 // RTL runs are broken in logical order but displayed in visual order. To find | 386 // RTL runs are broken in logical order but displayed in visual order. To find |
| 363 // the text-space coordinate (where it would fall in a single-line text) | 387 // the text-space coordinate (where it would fall in a single-line text) |
| 364 // |x_range| of RTL segments, segment widths are applied in reverse order. | 388 // |x_range| of RTL segments, segment widths are applied in reverse order. |
| 365 // e.g. {[5, 10], [10, 40]} will become {[35, 40], [5, 35]}. | 389 // e.g. {[5, 10], [10, 40]} will become {[35, 40], [5, 35]}. |
| 366 void UpdateRTLSegmentRanges() { | 390 void UpdateRTLSegmentRanges() { |
| 367 if (rtl_segments_.empty()) | 391 if (rtl_segments_.empty()) |
| 368 return; | 392 return; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 UpdateRTLSegmentRanges(); | 465 UpdateRTLSegmentRanges(); |
| 442 } | 466 } |
| 443 text_x_ += SkFloatToScalar(width); | 467 text_x_ += SkFloatToScalar(width); |
| 444 line_x_ += SkFloatToScalar(width); | 468 line_x_ += SkFloatToScalar(width); |
| 445 } | 469 } |
| 446 | 470 |
| 447 const SkScalar max_width_; | 471 const SkScalar max_width_; |
| 448 const int min_baseline_; | 472 const int min_baseline_; |
| 449 const float min_height_; | 473 const float min_height_; |
| 450 const bool multiline_; | 474 const bool multiline_; |
| 475 const WordWrapBehavior word_wrap_behavior_; |
| 451 const base::string16& text_; | 476 const base::string16& text_; |
| 452 const BreakList<size_t>* const words_; | 477 const BreakList<size_t>* const words_; |
| 453 const internal::TextRunList& run_list_; | 478 const internal::TextRunList& run_list_; |
| 454 | 479 |
| 455 // Stores the resulting lines. | 480 // Stores the resulting lines. |
| 456 std::vector<internal::Line> lines_; | 481 std::vector<internal::Line> lines_; |
| 457 | 482 |
| 458 // Text space and line space x coordinates of the next segment to be added. | 483 // Text space and line space x coordinates of the next segment to be added. |
| 459 SkScalar text_x_; | 484 SkScalar text_x_; |
| 460 SkScalar line_x_; | 485 SkScalar line_x_; |
| (...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 990 if (lines().empty()) { | 1015 if (lines().empty()) { |
| 991 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 1016 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 992 tracked_objects::ScopedTracker tracking_profile2( | 1017 tracked_objects::ScopedTracker tracking_profile2( |
| 993 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 1018 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 994 "431326 RenderTextHarfBuzz::EnsureLayout2")); | 1019 "431326 RenderTextHarfBuzz::EnsureLayout2")); |
| 995 | 1020 |
| 996 internal::TextRunList* run_list = GetRunList(); | 1021 internal::TextRunList* run_list = GetRunList(); |
| 997 HarfBuzzLineBreaker line_breaker( | 1022 HarfBuzzLineBreaker line_breaker( |
| 998 display_rect().width(), font_list().GetBaseline(), | 1023 display_rect().width(), font_list().GetBaseline(), |
| 999 std::max(font_list().GetHeight(), min_line_height()), multiline(), | 1024 std::max(font_list().GetHeight(), min_line_height()), multiline(), |
| 1000 GetDisplayText(), multiline() ? &GetLineBreaks() : nullptr, *run_list); | 1025 word_wrap_behavior(), GetDisplayText(), |
| 1026 multiline() ? &GetLineBreaks() : nullptr, *run_list); |
| 1001 | 1027 |
| 1002 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. | 1028 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. |
| 1003 tracked_objects::ScopedTracker tracking_profile3( | 1029 tracked_objects::ScopedTracker tracking_profile3( |
| 1004 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 1030 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 1005 "431326 RenderTextHarfBuzz::EnsureLayout3")); | 1031 "431326 RenderTextHarfBuzz::EnsureLayout3")); |
| 1006 | 1032 |
| 1007 for (size_t i = 0; i < run_list->size(); ++i) | 1033 for (size_t i = 0; i < run_list->size(); ++i) |
| 1008 line_breaker.AddRun(i); | 1034 line_breaker.AddRun(i); |
| 1009 std::vector<internal::Line> lines; | 1035 std::vector<internal::Line> lines; |
| 1010 line_breaker.Finalize(&lines, &total_size_); | 1036 line_breaker.Finalize(&lines, &total_size_); |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1525 DCHECK(!update_layout_run_list_); | 1551 DCHECK(!update_layout_run_list_); |
| 1526 DCHECK(!update_display_run_list_); | 1552 DCHECK(!update_display_run_list_); |
| 1527 return text_elided() ? display_run_list_.get() : &layout_run_list_; | 1553 return text_elided() ? display_run_list_.get() : &layout_run_list_; |
| 1528 } | 1554 } |
| 1529 | 1555 |
| 1530 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { | 1556 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { |
| 1531 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); | 1557 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); |
| 1532 } | 1558 } |
| 1533 | 1559 |
| 1534 } // namespace gfx | 1560 } // namespace gfx |
| OLD | NEW |