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

Side by Side Diff: ui/gfx/render_text_harfbuzz.cc

Issue 1070223004: Stop combining text runs which are connected by 'COMMON' blocks. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make sure multiline breaker behavior is correct. Created 5 years, 8 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
« no previous file with comments | « ui/gfx/render_text_harfbuzz.h ('k') | ui/gfx/render_text_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 const bool block_break = current_block != first_block && 83 const bool block_break = current_block != first_block &&
84 (first_block_unusual || IsUnusualBlockCode(current_block)); 84 (first_block_unusual || IsUnusualBlockCode(current_block));
85 if (block_break || current_char == '\n' || 85 if (block_break || current_char == '\n' ||
86 first_bracket != IsBracket(current_char)) { 86 first_bracket != IsBracket(current_char)) {
87 return run_start + iter.array_pos(); 87 return run_start + iter.array_pos();
88 } 88 }
89 } 89 }
90 return run_break; 90 return run_break;
91 } 91 }
92 92
93 // If the given scripts match, returns the one that isn't USCRIPT_COMMON or 93 // If the given scripts match, returns the one that isn't USCRIPT_INHERITED,
94 // USCRIPT_INHERITED, i.e. the more specific one. Otherwise returns 94 // i.e. the more specific one. Otherwise returns USCRIPT_INVALID_CODE.
95 // USCRIPT_INVALID_CODE.
96 UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) { 95 UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) {
97 if (first == second || 96 if (first == second || second == USCRIPT_INHERITED)
98 (second > USCRIPT_INVALID_CODE && second <= USCRIPT_INHERITED)) {
99 return first; 97 return first;
100 } 98 if (first == USCRIPT_INHERITED)
101 if (first > USCRIPT_INVALID_CODE && first <= USCRIPT_INHERITED)
102 return second; 99 return second;
103 return USCRIPT_INVALID_CODE; 100 return USCRIPT_INVALID_CODE;
104 } 101 }
105 102
106 // Writes the script and the script extensions of the character with the 103 // Writes the script and the script extensions of the character with the
107 // Unicode |codepoint|. Returns the number of written scripts. 104 // Unicode |codepoint|. Returns the number of written scripts.
108 int GetScriptExtensions(UChar32 codepoint, UScriptCode* scripts) { 105 int GetScriptExtensions(UChar32 codepoint, UScriptCode* scripts) {
109 UErrorCode icu_error = U_ZERO_ERROR; 106 UErrorCode icu_error = U_ZERO_ERROR;
110 // ICU documentation incorrectly states that the result of 107 // ICU documentation incorrectly states that the result of
111 // |uscript_getScriptExtensions| will contain the regular script property. 108 // |uscript_getScriptExtensions| will contain the regular script property.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 DCHECK_GT(length, 0U); 157 DCHECK_GT(length, 0U);
161 158
162 UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE }; 159 UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE };
163 160
164 base::i18n::UTF16CharIterator char_iterator(text.c_str() + start, length); 161 base::i18n::UTF16CharIterator char_iterator(text.c_str() + start, length);
165 size_t scripts_size = GetScriptExtensions(char_iterator.get(), scripts); 162 size_t scripts_size = GetScriptExtensions(char_iterator.get(), scripts);
166 *script = scripts[0]; 163 *script = scripts[0];
167 164
168 while (char_iterator.Advance()) { 165 while (char_iterator.Advance()) {
169 ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size); 166 ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size);
167 // Special handling for white space. White space should be merged into the
msw 2015/04/23 00:00:38 nit: "Special handling to merge white space into t
xdai1 2015/04/23 22:59:42 Done.
168 // previous run.
169 if (u_isUWhiteSpace(char_iterator.get())) {
msw 2015/04/23 00:00:38 Just "continue;" instead of faking out |scripts| a
xdai1 2015/04/23 22:59:42 Actually this is depending on how we want to break
170 scripts[0] = *script;
171 scripts_size = 1U;
172 }
170 if (scripts_size == 0U) 173 if (scripts_size == 0U)
171 return char_iterator.array_pos(); 174 return char_iterator.array_pos();
172 *script = scripts[0]; 175 *script = scripts[0];
173 } 176 }
174 177
175 return length; 178 return length;
176 } 179 }
177 180
178 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built without 181 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built without
179 // hb-icu. See http://crbug.com/356929 182 // hb-icu. See http://crbug.com/356929
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 size_t start_char, 314 size_t start_char,
312 SkScalar* width, 315 SkScalar* width,
313 size_t* end_char, 316 size_t* end_char,
314 size_t* next_char) { 317 size_t* next_char) {
315 DCHECK(words_); 318 DCHECK(words_);
316 DCHECK(run.range.Contains(Range(start_char, start_char + 1))); 319 DCHECK(run.range.Contains(Range(start_char, start_char + 1)));
317 SkScalar available_width = max_width_ - line_x_; 320 SkScalar available_width = max_width_ - line_x_;
318 BreakList<size_t>::const_iterator word = words_->GetBreak(start_char); 321 BreakList<size_t>::const_iterator word = words_->GetBreak(start_char);
319 BreakList<size_t>::const_iterator next_word = word + 1; 322 BreakList<size_t>::const_iterator next_word = word + 1;
320 // Width from |std::max(word->first, start_char)| to the current character. 323 // Width from |std::max(word->first, start_char)| to the current character.
321 SkScalar word_width = 0; 324 SkScalar word_width =
msw 2015/04/23 00:00:38 Is this necessary for the run breaking change? Can
xdai1 2015/04/23 22:59:42 Yes, it has to be modified as described in the CL
325 start_char == 0 ? 0 : GetGlyphWidth(word->first, start_char - 1);
322 *width = 0; 326 *width = 0;
323 327
324 Range char_range; 328 Range char_range;
325 SkScalar truncated_width = 0; 329 SkScalar truncated_width = 0;
326 for (size_t i = start_char; i < run.range.end(); i += char_range.length()) { 330 for (size_t i = start_char; i < run.range.end(); i += char_range.length()) {
327 // |word| holds the word boundary at or before |i|, and |next_word| holds 331 // |word| holds the word boundary at or before |i|, and |next_word| holds
328 // the word boundary right after |i|. Advance both |word| and |next_word| 332 // the word boundary right after |i|. Advance both |word| and |next_word|
329 // when |i| reaches |next_word|. 333 // when |i| reaches |next_word|.
330 if (next_word != words_->breaks().end() && i >= next_word->first) { 334 if (next_word != words_->breaks().end() && i >= next_word->first) {
331 if (*width > available_width) { 335 if (*width > available_width) {
(...skipping 16 matching lines...) Expand all
348 SkScalar char_width = ((glyph_range.end() >= run.glyph_count) 352 SkScalar char_width = ((glyph_range.end() >= run.glyph_count)
349 ? SkFloatToScalar(run.width) 353 ? SkFloatToScalar(run.width)
350 : run.positions[glyph_range.end()].x()) - 354 : run.positions[glyph_range.end()].x()) -
351 run.positions[glyph_range.start()].x(); 355 run.positions[glyph_range.start()].x();
352 356
353 *width += char_width; 357 *width += char_width;
354 word_width += char_width; 358 word_width += char_width;
355 359
356 // TODO(mukai): implement ELIDE_LONG_WORDS. 360 // TODO(mukai): implement ELIDE_LONG_WORDS.
357 if (*width > available_width) { 361 if (*width > available_width) {
358 if (line_x_ != 0 || word_width < *width) { 362 if ((line_x_ != 0 && word_width <= *width) ||
363 (line_x_ == 0 && word_width < *width)) {
359 // Roll back one word. 364 // Roll back one word.
360 *width -= word_width; 365 *width -= word_width;
361 *next_char = std::max(word->first, start_char); 366 *next_char = std::max(word->first, start_char);
362 *end_char = *next_char; 367 *end_char = *next_char;
363 return true; 368 return true;
364 } else if (word_wrap_behavior_ == WRAP_LONG_WORDS) { 369 } else if (word_wrap_behavior_ == WRAP_LONG_WORDS) {
365 if (char_width < *width) { 370 if (char_width < *width) {
366 // Roll back one character. 371 // Roll back one character.
367 *width -= char_width; 372 *width -= char_width;
368 *next_char = i; 373 *next_char = i;
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 SegmentHandle(lines_.size() - 1, line->segments.size() - 1)); 468 SegmentHandle(lines_.size() - 1, line->segments.size() - 1));
464 // If this is the last segment of an RTL run, reprocess the text-space x 469 // If this is the last segment of an RTL run, reprocess the text-space x
465 // ranges of all segments from the run. 470 // ranges of all segments from the run.
466 if (char_range.end() == run.range.end()) 471 if (char_range.end() == run.range.end())
467 UpdateRTLSegmentRanges(); 472 UpdateRTLSegmentRanges();
468 } 473 }
469 text_x_ += SkFloatToScalar(width); 474 text_x_ += SkFloatToScalar(width);
470 line_x_ += SkFloatToScalar(width); 475 line_x_ += SkFloatToScalar(width);
471 } 476 }
472 477
478 // Returns the index for the run that contains text_[pos] using binary search.
479 size_t GetRunIndexAt(size_t pos) const {
480 pos = (pos < text_.size()) ? pos : text_.size() - 1;
481 size_t low = 0, high = run_list_.size() - 1;
482 while (low <= high) {
483 size_t mid = low + (high - low) / 2;
484 if (run_list_.runs()[mid]->range.start() <= pos &&
485 run_list_.runs()[mid]->range.end() > pos)
486 return mid;
487 else if (run_list_.runs()[mid]->range.start() > pos)
488 high = mid - 1;
489 else
490 low = mid + 1;
491 }
492 return 0;
493 }
494
495 // Returns the glyph width for |text_| between [start_pos, end_pos].
496 SkScalar GetGlyphWidth(size_t start_pos, size_t end_pos) const {
497 end_pos = (end_pos < text_.size()) ? end_pos : text_.size() - 1;
498 if (start_pos > end_pos)
499 return 0;
500
501 // Finding the runs that containing |start_char| and |end_char|.
502 size_t start_run_idx = GetRunIndexAt(start_pos);
503 size_t end_run_idx = GetRunIndexAt(end_pos);
504 const internal::TextRunHarfBuzz* start_run =
505 run_list_.runs()[start_run_idx];
506 const internal::TextRunHarfBuzz* end_run = run_list_.runs()[end_run_idx];
507
508 SkScalar width = 0;
509 for (size_t i = start_run_idx; i <= end_run_idx; ++i) {
510 width += run_list_.runs()[i]->width;
511 }
512
513 Range char_range;
514 Range glyph_range;
515 for (size_t pos = start_run->range.start(); pos < start_pos; ++pos) {
516 start_run->GetClusterAt(pos, &char_range, &glyph_range);
517 SkScalar char_width =
518 ((glyph_range.end() >= start_run->glyph_count)
519 ? SkFloatToScalar(start_run->width)
520 : start_run->positions[glyph_range.end()].x()) -
521 start_run->positions[glyph_range.start()].x();
522 width -= char_width;
523 }
524
525 for (size_t pos = end_pos + 1; pos < end_run->range.end(); ++pos) {
526 end_run->GetClusterAt(pos, &char_range, &glyph_range);
527 SkScalar char_width = ((glyph_range.end() >= end_run->glyph_count)
528 ? SkFloatToScalar(end_run->width)
529 : end_run->positions[glyph_range.end()].x()) -
530 end_run->positions[glyph_range.start()].x();
531 width -= char_width;
532 }
533
534 return width;
535 }
536
473 const SkScalar max_width_; 537 const SkScalar max_width_;
474 const int min_baseline_; 538 const int min_baseline_;
475 const float min_height_; 539 const float min_height_;
476 const bool multiline_; 540 const bool multiline_;
477 const WordWrapBehavior word_wrap_behavior_; 541 const WordWrapBehavior word_wrap_behavior_;
478 const base::string16& text_; 542 const base::string16& text_;
479 const BreakList<size_t>* const words_; 543 const BreakList<size_t>* const words_;
480 const internal::TextRunList& run_list_; 544 const internal::TextRunList& run_list_;
481 545
482 // Stores the resulting lines. 546 // Stores the resulting lines.
(...skipping 996 matching lines...) Expand 10 before | Expand all | Expand 10 after
1479 DCHECK(!update_layout_run_list_); 1543 DCHECK(!update_layout_run_list_);
1480 DCHECK(!update_display_run_list_); 1544 DCHECK(!update_display_run_list_);
1481 return text_elided() ? display_run_list_.get() : &layout_run_list_; 1545 return text_elided() ? display_run_list_.get() : &layout_run_list_;
1482 } 1546 }
1483 1547
1484 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { 1548 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const {
1485 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); 1549 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList();
1486 } 1550 }
1487 1551
1488 } // namespace gfx 1552 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_harfbuzz.h ('k') | ui/gfx/render_text_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698