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

Unified 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: Rebase 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/render_text_harfbuzz.cc
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
index 32a9e554f60b47127cef9d426aef71a9f410adfa..0d72cb28a21bf77e1866f5a56ee76e1c11b134d1 100644
--- a/ui/gfx/render_text_harfbuzz.cc
+++ b/ui/gfx/render_text_harfbuzz.cc
@@ -90,15 +90,12 @@ size_t FindRunBreakingCharacter(const base::string16& text,
return run_break;
}
-// If the given scripts match, returns the one that isn't USCRIPT_COMMON or
-// USCRIPT_INHERITED, i.e. the more specific one. Otherwise returns
-// USCRIPT_INVALID_CODE.
+// If the given scripts match, returns the one that isn't USCRIPT_INHERITED,
+// i.e. the more specific one. Otherwise returns USCRIPT_INVALID_CODE.
UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) {
- if (first == second ||
- (second > USCRIPT_INVALID_CODE && second <= USCRIPT_INHERITED)) {
+ if (first == second || second == USCRIPT_INHERITED)
return first;
- }
- if (first > USCRIPT_INVALID_CODE && first <= USCRIPT_INHERITED)
+ if (first == USCRIPT_INHERITED)
return second;
return USCRIPT_INVALID_CODE;
}
@@ -167,6 +164,11 @@ int ScriptInterval(const base::string16& text,
while (char_iterator.Advance()) {
ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size);
+ // Special handling to merge white space into the previous run.
+ if (u_isUWhiteSpace(char_iterator.get())) {
Jun Mukai 2015/04/28 01:57:36 I am not so sure about other whitespace variations
xdai1 2015/04/29 18:23:27 I added a test case for fullwidth space in RenderT
+ scripts[0] = *script;
+ scripts_size = 1U;
+ }
if (scripts_size == 0U)
return char_iterator.array_pos();
*script = scripts[0];
@@ -239,7 +241,8 @@ class HarfBuzzLineBreaker {
text_x_(0),
line_x_(0),
max_descent_(0),
- max_ascent_(0) {
+ max_ascent_(0),
+ next_word_start_pos_(0) {
DCHECK_EQ(multiline_, (words_ != nullptr));
AdvanceLine();
}
@@ -248,6 +251,15 @@ class HarfBuzzLineBreaker {
void AddRun(int run_index) {
const internal::TextRunHarfBuzz* run = run_list_.runs()[run_index];
base::char16 first_char = text_[run->range.start()];
+
+ if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS && words_) {
+ // If the run has been processed, skip it.
+ size_t current_word_start_pos =
+ words_->GetBreak(run->range.start())->first;
+ if (current_word_start_pos < next_word_start_pos_)
+ return;
+ }
+
if (multiline_ && first_char == '\n') {
AdvanceLine();
} else if (multiline_ && (line_x_ + SkFloatToScalar(run->width)) >
@@ -317,8 +329,12 @@ class HarfBuzzLineBreaker {
SkScalar available_width = max_width_ - line_x_;
BreakList<size_t>::const_iterator word = words_->GetBreak(start_char);
BreakList<size_t>::const_iterator next_word = word + 1;
- // Width from |std::max(word->first, start_char)| to the current character.
- SkScalar word_width = 0;
+ next_word_start_pos_ =
+ (next_word == words_->breaks().end()) ? text_.size() : next_word->first;
+
+ // Glyph width of text_[word->first, start_char - 1].
+ SkScalar word_width =
+ start_char == 0 ? 0 : GetGlyphWidth(word->first, start_char - 1);
Jun Mukai 2015/04/28 01:57:36 I think you don't have to add a method like 'GetGl
xdai1 2015/04/29 18:23:27 Done.
*width = 0;
Range char_range;
@@ -328,16 +344,10 @@ class HarfBuzzLineBreaker {
// the word boundary right after |i|. Advance both |word| and |next_word|
// when |i| reaches |next_word|.
if (next_word != words_->breaks().end() && i >= next_word->first) {
- if (*width > available_width) {
- DCHECK_NE(WRAP_LONG_WORDS, word_wrap_behavior_);
- *next_char = i;
- if (word_wrap_behavior_ != TRUNCATE_LONG_WORDS)
- *end_char = *next_char;
- else
- *width = truncated_width;
- return true;
- }
word = next_word++;
+ next_word_start_pos_ = (next_word == words_->breaks().end())
+ ? text_.size()
+ : next_word->first;
word_width = 0;
}
@@ -355,7 +365,8 @@ class HarfBuzzLineBreaker {
// TODO(mukai): implement ELIDE_LONG_WORDS.
if (*width > available_width) {
- if (line_x_ != 0 || word_width < *width) {
+ if ((line_x_ != 0 && word_width <= *width) ||
+ (line_x_ == 0 && word_width < *width)) {
Jun Mukai 2015/04/28 01:57:36 I don't get these conditions. If line_x_ is 0 (i.
xdai1 2015/04/29 18:23:27 For example, "I am a student", suppose the line wi
// Roll back one word.
*width -= word_width;
*next_char = std::max(word->first, start_char);
@@ -372,6 +383,10 @@ class HarfBuzzLineBreaker {
}
*end_char = *next_char;
return true;
+ } else if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS) {
+ *width = truncated_width;
+ *next_char = next_word_start_pos_;
+ return true;
}
} else {
*end_char = char_range.end();
@@ -470,6 +485,65 @@ class HarfBuzzLineBreaker {
line_x_ += SkFloatToScalar(width);
}
+ // Returns the index for the run that contains text_[pos] using binary search.
+ size_t GetRunIndexAt(size_t pos) const {
+ pos = (pos < text_.size()) ? pos : text_.size() - 1;
+ size_t low = 0, high = run_list_.size() - 1;
+ while (low <= high) {
+ size_t mid = low + (high - low) / 2;
+ if (run_list_.runs()[mid]->range.start() <= pos &&
+ run_list_.runs()[mid]->range.end() > pos)
+ return mid;
+ else if (run_list_.runs()[mid]->range.start() > pos)
+ high = mid - 1;
+ else
+ low = mid + 1;
+ }
+ return 0;
+ }
+
+ // Returns the glyph width for |text_| between [start_pos, end_pos].
+ SkScalar GetGlyphWidth(size_t start_pos, size_t end_pos) const {
+ end_pos = (end_pos < text_.size()) ? end_pos : text_.size() - 1;
+ if (start_pos > end_pos)
+ return 0;
+
+ // Finding the runs that containing |start_char| and |end_char|.
+ size_t start_run_idx = GetRunIndexAt(start_pos);
+ size_t end_run_idx = GetRunIndexAt(end_pos);
+ const internal::TextRunHarfBuzz* start_run =
+ run_list_.runs()[start_run_idx];
+ const internal::TextRunHarfBuzz* end_run = run_list_.runs()[end_run_idx];
+
+ SkScalar width = 0;
+ for (size_t i = start_run_idx; i <= end_run_idx; ++i) {
+ width += run_list_.runs()[i]->width;
+ }
+
+ Range char_range;
+ Range glyph_range;
+ for (size_t pos = start_run->range.start(); pos < start_pos; ++pos) {
+ start_run->GetClusterAt(pos, &char_range, &glyph_range);
+ SkScalar char_width =
+ ((glyph_range.end() >= start_run->glyph_count)
+ ? SkFloatToScalar(start_run->width)
+ : start_run->positions[glyph_range.end()].x()) -
+ start_run->positions[glyph_range.start()].x();
+ width -= char_width;
+ }
+
+ for (size_t pos = end_pos + 1; pos < end_run->range.end(); ++pos) {
+ end_run->GetClusterAt(pos, &char_range, &glyph_range);
+ SkScalar char_width = ((glyph_range.end() >= end_run->glyph_count)
+ ? SkFloatToScalar(end_run->width)
+ : end_run->positions[glyph_range.end()].x()) -
+ end_run->positions[glyph_range.start()].x();
+ width -= char_width;
+ }
+
+ return width;
+ }
+
const SkScalar max_width_;
const int min_baseline_;
const float min_height_;
@@ -489,6 +563,9 @@ class HarfBuzzLineBreaker {
float max_descent_;
float max_ascent_;
+ // Stores the start position of next word that need to be processed.
+ size_t next_word_start_pos_;
+
// Size of the multiline text, not including the currently processed line.
SizeF total_size_;
« 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