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

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

Issue 1015533016: Move allow_character_break property to RenderText. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: test fix 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
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 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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| if word_wrap_behavior is TRUNCATE_LONG_WORDS.
msw 2015/03/26 19:36:29 nit: "smaller than |*next_char| for certain word w
Jun Mukai 2015/03/26 22:47:38 Done.
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(word_wrap_behavior_ == IGNORE_LONG_WORDS ||
msw 2015/03/26 19:36:30 nit: maybe just DCHECK_NE WRAP_LONG_WORDS?
Jun Mukai 2015/03/26 22:47:38 Done.
333 word_wrap_behavior_ == TRUNCATE_LONG_WORDS);
334 *next_char = i;
335 if (!truncated)
336 *end_char = *next_char;
337 return true;
338 }
325 word = next_word++; 339 word = next_word++;
326 word_width = 0; 340 word_width = 0;
327 } 341 }
328 342
329 Range glyph_range; 343 Range glyph_range;
330 run.GetClusterAt(i, &char_range, &glyph_range); 344 run.GetClusterAt(i, &char_range, &glyph_range);
331 DCHECK_LT(0U, char_range.length()); 345 DCHECK_LT(0U, char_range.length());
332 346
333 SkScalar char_width = ((glyph_range.end() >= run.glyph_count) 347 SkScalar char_width = ((glyph_range.end() >= run.glyph_count)
334 ? SkFloatToScalar(run.width) 348 ? SkFloatToScalar(run.width)
335 : run.positions[glyph_range.end()].x()) - 349 : run.positions[glyph_range.end()].x()) -
336 run.positions[glyph_range.start()].x(); 350 run.positions[glyph_range.start()].x();
337 351
338 *width += char_width; 352 *width += char_width;
339 word_width += char_width; 353 word_width += char_width;
340 354
355 // TODO(mukai): implement ELIDE_LONG_WORDS.
341 if (*width > available_width) { 356 if (*width > available_width) {
342 if (line_x_ != 0 || word_width < *width) { 357 if (line_x_ != 0 || word_width < *width) {
343 // Roll back one word. 358 // Roll back one word.
344 *width -= word_width; 359 *width -= word_width;
345 *next_char = std::max(word->first, start_char); 360 *next_char = std::max(word->first, start_char);
346 } else if (char_width < *width) { 361 *end_char = *next_char;
347 // Roll back one character. 362 return true;
348 *width -= char_width; 363 } else if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS) {
349 *next_char = i; 364 *end_char = i;
msw 2015/03/26 19:36:30 Shouldn't end_char be set as soon as the width exc
Jun Mukai 2015/03/26 22:47:38 You are right, "!truncated" is necessary in the co
msw 2015/03/26 23:05:54 Hmm, if we only set "*end_char = i;" if (*width <=
Jun Mukai 2015/03/27 00:31:58 Aagh, I see. Sorry for my poor understanding, now
350 } else { 365 truncated = true;
351 // Continue from the next character. 366 } else if (word_wrap_behavior_ == WRAP_LONG_WORDS) {
352 *next_char = i + char_range.length(); 367 if (char_width < *width) {
368 // Roll back one character.
369 *width -= char_width;
370 *next_char = i;
371 } else {
372 // Continue from the next character.
373 *next_char = i + char_range.length();
374 }
375 *end_char = *next_char;
376 return true;
353 } 377 }
354 return true;
355 } 378 }
356 } 379 }
357 380
358 *next_char = run.range.end(); 381 *next_char = run.range.end();
382 if (!truncated)
383 *end_char = *next_char;
359 return false; 384 return false;
360 } 385 }
361 386
362 // RTL runs are broken in logical order but displayed in visual order. To find 387 // 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) 388 // 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. 389 // |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]}. 390 // e.g. {[5, 10], [10, 40]} will become {[35, 40], [5, 35]}.
366 void UpdateRTLSegmentRanges() { 391 void UpdateRTLSegmentRanges() {
367 if (rtl_segments_.empty()) 392 if (rtl_segments_.empty())
368 return; 393 return;
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 UpdateRTLSegmentRanges(); 466 UpdateRTLSegmentRanges();
442 } 467 }
443 text_x_ += SkFloatToScalar(width); 468 text_x_ += SkFloatToScalar(width);
444 line_x_ += SkFloatToScalar(width); 469 line_x_ += SkFloatToScalar(width);
445 } 470 }
446 471
447 const SkScalar max_width_; 472 const SkScalar max_width_;
448 const int min_baseline_; 473 const int min_baseline_;
449 const float min_height_; 474 const float min_height_;
450 const bool multiline_; 475 const bool multiline_;
476 const WordWrapBehavior word_wrap_behavior_;
451 const base::string16& text_; 477 const base::string16& text_;
452 const BreakList<size_t>* const words_; 478 const BreakList<size_t>* const words_;
453 const internal::TextRunList& run_list_; 479 const internal::TextRunList& run_list_;
454 480
455 // Stores the resulting lines. 481 // Stores the resulting lines.
456 std::vector<internal::Line> lines_; 482 std::vector<internal::Line> lines_;
457 483
458 // Text space and line space x coordinates of the next segment to be added. 484 // Text space and line space x coordinates of the next segment to be added.
459 SkScalar text_x_; 485 SkScalar text_x_;
460 SkScalar line_x_; 486 SkScalar line_x_;
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after
990 if (lines().empty()) { 1016 if (lines().empty()) {
991 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. 1017 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
992 tracked_objects::ScopedTracker tracking_profile2( 1018 tracked_objects::ScopedTracker tracking_profile2(
993 FROM_HERE_WITH_EXPLICIT_FUNCTION( 1019 FROM_HERE_WITH_EXPLICIT_FUNCTION(
994 "431326 RenderTextHarfBuzz::EnsureLayout2")); 1020 "431326 RenderTextHarfBuzz::EnsureLayout2"));
995 1021
996 internal::TextRunList* run_list = GetRunList(); 1022 internal::TextRunList* run_list = GetRunList();
997 HarfBuzzLineBreaker line_breaker( 1023 HarfBuzzLineBreaker line_breaker(
998 display_rect().width(), font_list().GetBaseline(), 1024 display_rect().width(), font_list().GetBaseline(),
999 std::max(font_list().GetHeight(), min_line_height()), multiline(), 1025 std::max(font_list().GetHeight(), min_line_height()), multiline(),
1000 GetDisplayText(), multiline() ? &GetLineBreaks() : nullptr, *run_list); 1026 word_wrap_behavior(), GetDisplayText(),
1027 multiline() ? &GetLineBreaks() : nullptr, *run_list);
1001 1028
1002 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. 1029 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
1003 tracked_objects::ScopedTracker tracking_profile3( 1030 tracked_objects::ScopedTracker tracking_profile3(
1004 FROM_HERE_WITH_EXPLICIT_FUNCTION( 1031 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1005 "431326 RenderTextHarfBuzz::EnsureLayout3")); 1032 "431326 RenderTextHarfBuzz::EnsureLayout3"));
1006 1033
1007 for (size_t i = 0; i < run_list->size(); ++i) 1034 for (size_t i = 0; i < run_list->size(); ++i)
1008 line_breaker.AddRun(i); 1035 line_breaker.AddRun(i);
1009 std::vector<internal::Line> lines; 1036 std::vector<internal::Line> lines;
1010 line_breaker.Finalize(&lines, &total_size_); 1037 line_breaker.Finalize(&lines, &total_size_);
(...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after
1525 DCHECK(!update_layout_run_list_); 1552 DCHECK(!update_layout_run_list_);
1526 DCHECK(!update_display_run_list_); 1553 DCHECK(!update_display_run_list_);
1527 return text_elided() ? display_run_list_.get() : &layout_run_list_; 1554 return text_elided() ? display_run_list_.get() : &layout_run_list_;
1528 } 1555 }
1529 1556
1530 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { 1557 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const {
1531 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); 1558 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList();
1532 } 1559 }
1533 1560
1534 } // namespace gfx 1561 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698