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

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: Address Mukai's comments. Created 5 years, 7 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 size_t length, 155 size_t length,
159 UScriptCode* script) { 156 UScriptCode* script) {
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()) {
Jun Mukai 2015/04/29 21:09:07 Hm, why not just doing if (u_isUWhiteSpace(char_it
xdai1 2015/05/05 18:27:49 As I said in the previous comment to msw@, this is
169 ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size); 166 ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size);
167 // Special handling to merge white space into the previous run.
168 if (u_isUWhiteSpace(char_iterator.get())) {
169 scripts[0] = *script;
170 scripts_size = 1U;
171 }
170 if (scripts_size == 0U) 172 if (scripts_size == 0U)
171 return char_iterator.array_pos(); 173 return char_iterator.array_pos();
172 *script = scripts[0]; 174 *script = scripts[0];
173 } 175 }
174 176
175 return length; 177 return length;
176 } 178 }
177 179
178 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built without 180 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built without
179 // hb-icu. See http://crbug.com/356929 181 // hb-icu. See http://crbug.com/356929
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 min_baseline_(min_baseline), 234 min_baseline_(min_baseline),
233 min_height_(min_height), 235 min_height_(min_height),
234 multiline_(multiline), 236 multiline_(multiline),
235 word_wrap_behavior_(word_wrap_behavior), 237 word_wrap_behavior_(word_wrap_behavior),
236 text_(text), 238 text_(text),
237 words_(words), 239 words_(words),
238 run_list_(run_list), 240 run_list_(run_list),
239 text_x_(0), 241 text_x_(0),
240 line_x_(0), 242 line_x_(0),
241 max_descent_(0), 243 max_descent_(0),
242 max_ascent_(0) { 244 max_ascent_(0),
245 next_word_start_pos_(0),
246 word_width_(0) {
243 DCHECK_EQ(multiline_, (words_ != nullptr)); 247 DCHECK_EQ(multiline_, (words_ != nullptr));
244 AdvanceLine(); 248 AdvanceLine();
245 } 249 }
246 250
247 // Breaks the run at given |run_index| into Line structs. 251 // Breaks the run at given |run_index| into Line structs.
248 void AddRun(int run_index) { 252 void AddRun(int run_index) {
249 const internal::TextRunHarfBuzz* run = run_list_.runs()[run_index]; 253 const internal::TextRunHarfBuzz* run = run_list_.runs()[run_index];
250 base::char16 first_char = text_[run->range.start()]; 254 base::char16 first_char = text_[run->range.start()];
255
256 if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS && words_) {
257 // If the run has been processed, skip it.
258 size_t current_word_start_pos =
259 words_->GetBreak(run->range.start())->first;
260 if (current_word_start_pos < next_word_start_pos_)
261 return;
262 }
263
251 if (multiline_ && first_char == '\n') { 264 if (multiline_ && first_char == '\n') {
252 AdvanceLine(); 265 AdvanceLine();
253 } else if (multiline_ && (line_x_ + SkFloatToScalar(run->width)) > 266 } else if (multiline_ && (line_x_ + SkFloatToScalar(run->width)) >
254 max_width_) { 267 max_width_) {
255 BreakRun(run_index); 268 BreakRun(run_index);
256 } else { 269 } else {
257 AddSegment(run_index, run->range, run->width); 270 AddSegment(run_index, run->range, run->width);
258 } 271 }
259 } 272 }
260 273
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 bool BreakRunAtWidth(const internal::TextRunHarfBuzz& run, 323 bool BreakRunAtWidth(const internal::TextRunHarfBuzz& run,
311 size_t start_char, 324 size_t start_char,
312 SkScalar* width, 325 SkScalar* width,
313 size_t* end_char, 326 size_t* end_char,
314 size_t* next_char) { 327 size_t* next_char) {
315 DCHECK(words_); 328 DCHECK(words_);
316 DCHECK(run.range.Contains(Range(start_char, start_char + 1))); 329 DCHECK(run.range.Contains(Range(start_char, start_char + 1)));
317 SkScalar available_width = max_width_ - line_x_; 330 SkScalar available_width = max_width_ - line_x_;
318 BreakList<size_t>::const_iterator word = words_->GetBreak(start_char); 331 BreakList<size_t>::const_iterator word = words_->GetBreak(start_char);
319 BreakList<size_t>::const_iterator next_word = word + 1; 332 BreakList<size_t>::const_iterator next_word = word + 1;
320 // Width from |std::max(word->first, start_char)| to the current character. 333 next_word_start_pos_ =
Jun Mukai 2015/04/29 21:09:07 Probably word_end_pos_ would be a better name?
xdai1 2015/05/05 18:27:49 Done.
321 SkScalar word_width = 0; 334 (next_word == words_->breaks().end()) ? text_.size() : next_word->first;
322 *width = 0; 335 *width = 0;
323 336
324 Range char_range; 337 Range char_range;
325 SkScalar truncated_width = 0; 338 SkScalar truncated_width = 0;
326 for (size_t i = start_char; i < run.range.end(); i += char_range.length()) { 339 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 340 // |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| 341 // the word boundary right after |i|. Advance both |word| and |next_word|
329 // when |i| reaches |next_word|. 342 // when |i| reaches |next_word|.
330 if (next_word != words_->breaks().end() && i >= next_word->first) { 343 if (next_word != words_->breaks().end() && i >= next_word->first) {
331 if (*width > available_width) {
Jun Mukai 2015/04/29 21:09:07 I am not sure if removing this block works correct
xdai1 2015/05/05 18:27:49 In third run it won't come inside this inner if be
Jun Mukai 2015/05/06 17:38:52 For line 387, the behavior has to be TRUNCATE_LONG
xdai1 2015/05/06 20:23:44 In this case when it comes to "b", it will return
Jun Mukai 2015/05/06 20:47:55 No, "b " and "ccc" must be in a single run, they a
332 DCHECK_NE(WRAP_LONG_WORDS, word_wrap_behavior_);
333 *next_char = i;
334 if (word_wrap_behavior_ != TRUNCATE_LONG_WORDS)
335 *end_char = *next_char;
336 else
337 *width = truncated_width;
338 return true;
339 }
340 word = next_word++; 344 word = next_word++;
341 word_width = 0; 345 next_word_start_pos_ = (next_word == words_->breaks().end())
346 ? text_.size()
347 : next_word->first;
348 word_width_ = 0;
342 } 349 }
343 350
344 Range glyph_range; 351 Range glyph_range;
345 run.GetClusterAt(i, &char_range, &glyph_range); 352 run.GetClusterAt(i, &char_range, &glyph_range);
346 DCHECK_LT(0U, char_range.length()); 353 DCHECK_LT(0U, char_range.length());
347 354
348 SkScalar char_width = ((glyph_range.end() >= run.glyph_count) 355 SkScalar char_width = ((glyph_range.end() >= run.glyph_count)
349 ? SkFloatToScalar(run.width) 356 ? SkFloatToScalar(run.width)
350 : run.positions[glyph_range.end()].x()) - 357 : run.positions[glyph_range.end()].x()) -
351 run.positions[glyph_range.start()].x(); 358 run.positions[glyph_range.start()].x();
352 359
353 *width += char_width; 360 *width += char_width;
354 word_width += char_width; 361 word_width_ += char_width;
355 362
356 // TODO(mukai): implement ELIDE_LONG_WORDS. 363 // TODO(mukai): implement ELIDE_LONG_WORDS.
357 if (*width > available_width) { 364 if (*width > available_width) {
358 if (line_x_ != 0 || word_width < *width) { 365 if ((line_x_ != 0 && word_width_ <= *width) ||
366 (line_x_ == 0 && word_width_ < *width)) {
359 // Roll back one word. 367 // Roll back one word.
360 *width -= word_width; 368 *width -= word_width_;
361 *next_char = std::max(word->first, start_char); 369 *next_char = std::max(word->first, start_char);
362 *end_char = *next_char; 370 *end_char = *next_char;
371 word_width_ = 0;
363 return true; 372 return true;
364 } else if (word_wrap_behavior_ == WRAP_LONG_WORDS) { 373 } else if (word_wrap_behavior_ == WRAP_LONG_WORDS) {
365 if (char_width < *width) { 374 if (char_width < *width) {
366 // Roll back one character. 375 // Roll back one character.
367 *width -= char_width; 376 *width -= char_width;
368 *next_char = i; 377 *next_char = i;
369 } else { 378 } else {
370 // Continue from the next character. 379 // Continue from the next character.
371 *next_char = i + char_range.length(); 380 *next_char = i + char_range.length();
372 } 381 }
373 *end_char = *next_char; 382 *end_char = *next_char;
374 return true; 383 return true;
384 } else if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS) {
385 *width = truncated_width;
386 *next_char = next_word_start_pos_;
387 return true;
375 } 388 }
376 } else { 389 } else {
377 *end_char = char_range.end(); 390 *end_char = char_range.end();
378 truncated_width = *width; 391 truncated_width = *width;
379 } 392 }
380 } 393 }
381 394
382 if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS) 395 if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS)
383 *width = truncated_width; 396 *width = truncated_width;
384 *end_char = *next_char = run.range.end(); 397 *end_char = *next_char = run.range.end();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_)); 429 line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_));
417 line->baseline = 430 line->baseline =
418 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_)); 431 std::max(min_baseline_, SkScalarRoundToInt(max_ascent_));
419 line->preceding_heights = std::ceil(total_size_.height()); 432 line->preceding_heights = std::ceil(total_size_.height());
420 total_size_.set_height(total_size_.height() + line->size.height()); 433 total_size_.set_height(total_size_.height() + line->size.height());
421 total_size_.set_width(std::max(total_size_.width(), line->size.width())); 434 total_size_.set_width(std::max(total_size_.width(), line->size.width()));
422 } 435 }
423 max_descent_ = 0; 436 max_descent_ = 0;
424 max_ascent_ = 0; 437 max_ascent_ = 0;
425 line_x_ = 0; 438 line_x_ = 0;
439 word_width_ = 0;
426 lines_.push_back(internal::Line()); 440 lines_.push_back(internal::Line());
427 } 441 }
428 442
429 // Adds a new segment with the given properties to |lines_.back()|. 443 // Adds a new segment with the given properties to |lines_.back()|.
430 void AddSegment(int run_index, Range char_range, float width) { 444 void AddSegment(int run_index, Range char_range, float width) {
431 if (char_range.is_empty()) { 445 if (char_range.is_empty()) {
432 DCHECK_EQ(0, width); 446 DCHECK_EQ(0, width);
433 return; 447 return;
434 } 448 }
435 const internal::TextRunHarfBuzz& run = *(run_list_.runs()[run_index]); 449 const internal::TextRunHarfBuzz& run = *(run_list_.runs()[run_index]);
(...skipping 25 matching lines...) Expand all
461 if (run.is_rtl) { 475 if (run.is_rtl) {
462 rtl_segments_.push_back( 476 rtl_segments_.push_back(
463 SegmentHandle(lines_.size() - 1, line->segments.size() - 1)); 477 SegmentHandle(lines_.size() - 1, line->segments.size() - 1));
464 // If this is the last segment of an RTL run, reprocess the text-space x 478 // If this is the last segment of an RTL run, reprocess the text-space x
465 // ranges of all segments from the run. 479 // ranges of all segments from the run.
466 if (char_range.end() == run.range.end()) 480 if (char_range.end() == run.range.end())
467 UpdateRTLSegmentRanges(); 481 UpdateRTLSegmentRanges();
468 } 482 }
469 text_x_ += SkFloatToScalar(width); 483 text_x_ += SkFloatToScalar(width);
470 line_x_ += SkFloatToScalar(width); 484 line_x_ += SkFloatToScalar(width);
485
486 // Calculate |word_width_|.
487 if (words_) {
488 BreakList<size_t>::const_iterator current_word =
489 (char_range.start() == 0) ? words_->breaks().begin()
490 : words_->GetBreak(char_range.end() - 1);
491 BreakList<size_t>::const_iterator next_word =
492 (char_range.end() == text_.size())
493 ? words_->breaks().end()
494 : words_->GetBreak(char_range.end());
495 if (word_width_ == 0 && current_word == next_word) {
496 Range tmp_range;
497 Range glyph_range;
498 for (size_t pos = current_word->first; pos < char_range.end(); ++pos) {
499 run.GetClusterAt(pos, &tmp_range, &glyph_range);
500 SkScalar char_width = ((glyph_range.end() >= run.glyph_count)
501 ? SkFloatToScalar(run.width)
502 : run.positions[glyph_range.end()].x()) -
503 run.positions[glyph_range.start()].x();
504 word_width_ += char_width;
505 }
506 } else if (current_word != next_word) {
507 word_width_ = 0;
508 }
509 }
471 } 510 }
472 511
473 const SkScalar max_width_; 512 const SkScalar max_width_;
474 const int min_baseline_; 513 const int min_baseline_;
475 const float min_height_; 514 const float min_height_;
476 const bool multiline_; 515 const bool multiline_;
477 const WordWrapBehavior word_wrap_behavior_; 516 const WordWrapBehavior word_wrap_behavior_;
478 const base::string16& text_; 517 const base::string16& text_;
479 const BreakList<size_t>* const words_; 518 const BreakList<size_t>* const words_;
480 const internal::TextRunList& run_list_; 519 const internal::TextRunList& run_list_;
481 520
482 // Stores the resulting lines. 521 // Stores the resulting lines.
483 std::vector<internal::Line> lines_; 522 std::vector<internal::Line> lines_;
484 523
485 // Text space and line space x coordinates of the next segment to be added. 524 // Text space and line space x coordinates of the next segment to be added.
486 SkScalar text_x_; 525 SkScalar text_x_;
487 SkScalar line_x_; 526 SkScalar line_x_;
488 527
489 float max_descent_; 528 float max_descent_;
490 float max_ascent_; 529 float max_ascent_;
491 530
531 // Stores the start position of next word that need to be processed.
532 size_t next_word_start_pos_;
533 // Stores the glyph width between the current position and the start position
534 // of the current word. If the current position is pointing to the first
535 // character of the current word, |word_width_| is set to 0.
536 SkScalar word_width_;
537
492 // Size of the multiline text, not including the currently processed line. 538 // Size of the multiline text, not including the currently processed line.
493 SizeF total_size_; 539 SizeF total_size_;
494 540
495 // The current RTL run segments, to be applied by |UpdateRTLSegmentRanges()|. 541 // The current RTL run segments, to be applied by |UpdateRTLSegmentRanges()|.
496 std::vector<SegmentHandle> rtl_segments_; 542 std::vector<SegmentHandle> rtl_segments_;
497 543
498 DISALLOW_COPY_AND_ASSIGN(HarfBuzzLineBreaker); 544 DISALLOW_COPY_AND_ASSIGN(HarfBuzzLineBreaker);
499 }; 545 };
500 546
501 // Function object for case insensitive string comparison. 547 // Function object for case insensitive string comparison.
(...skipping 977 matching lines...) Expand 10 before | Expand all | Expand 10 after
1479 DCHECK(!update_layout_run_list_); 1525 DCHECK(!update_layout_run_list_);
1480 DCHECK(!update_display_run_list_); 1526 DCHECK(!update_display_run_list_);
1481 return text_elided() ? display_run_list_.get() : &layout_run_list_; 1527 return text_elided() ? display_run_list_.get() : &layout_run_list_;
1482 } 1528 }
1483 1529
1484 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { 1530 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const {
1485 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); 1531 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList();
1486 } 1532 }
1487 1533
1488 } // namespace gfx 1534 } // 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