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

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: line width for truncated words 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 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| 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 SkScalar truncated_width = 0;
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 (word_wrap_behavior_ != TRUNCATE_LONG_WORDS)
335 *end_char = *next_char;
336 else
337 *width = truncated_width;
338 return true;
339 }
325 word = next_word++; 340 word = next_word++;
326 word_width = 0; 341 word_width = 0;
327 } 342 }
328 343
329 Range glyph_range; 344 Range glyph_range;
330 run.GetClusterAt(i, &char_range, &glyph_range); 345 run.GetClusterAt(i, &char_range, &glyph_range);
331 DCHECK_LT(0U, char_range.length()); 346 DCHECK_LT(0U, char_range.length());
332 347
333 SkScalar char_width = ((glyph_range.end() >= run.glyph_count) 348 SkScalar char_width = ((glyph_range.end() >= run.glyph_count)
334 ? SkFloatToScalar(run.width) 349 ? SkFloatToScalar(run.width)
335 : run.positions[glyph_range.end()].x()) - 350 : run.positions[glyph_range.end()].x()) -
336 run.positions[glyph_range.start()].x(); 351 run.positions[glyph_range.start()].x();
337 352
338 *width += char_width; 353 *width += char_width;
339 word_width += char_width; 354 word_width += char_width;
340 355
356 // TODO(mukai): implement ELIDE_LONG_WORDS.
341 if (*width > available_width) { 357 if (*width > available_width) {
342 if (line_x_ != 0 || word_width < *width) { 358 if (line_x_ != 0 || word_width < *width) {
343 // Roll back one word. 359 // Roll back one word.
344 *width -= word_width; 360 *width -= word_width;
345 *next_char = std::max(word->first, start_char); 361 *next_char = std::max(word->first, start_char);
346 } else if (char_width < *width) { 362 *end_char = *next_char;
347 // Roll back one character. 363 return true;
348 *width -= char_width; 364 } else if (word_wrap_behavior_ == WRAP_LONG_WORDS) {
349 *next_char = i; 365 if (char_width < *width) {
350 } else { 366 // Roll back one character.
351 // Continue from the next character. 367 *width -= char_width;
352 *next_char = i + char_range.length(); 368 *next_char = i;
369 } else {
370 // Continue from the next character.
371 *next_char = i + char_range.length();
372 }
373 *end_char = *next_char;
374 return true;
353 } 375 }
354 return true; 376 } else {
377 *end_char = char_range.end();
378 truncated_width = *width;
355 } 379 }
356 } 380 }
357 381
358 *next_char = run.range.end(); 382 if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS)
383 *width = truncated_width;
384 *end_char = *next_char = run.range.end();
359 return false; 385 return false;
360 } 386 }
361 387
362 // RTL runs are broken in logical order but displayed in visual order. To find 388 // 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) 389 // 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. 390 // |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]}. 391 // e.g. {[5, 10], [10, 40]} will become {[35, 40], [5, 35]}.
366 void UpdateRTLSegmentRanges() { 392 void UpdateRTLSegmentRanges() {
367 if (rtl_segments_.empty()) 393 if (rtl_segments_.empty())
368 return; 394 return;
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 UpdateRTLSegmentRanges(); 467 UpdateRTLSegmentRanges();
442 } 468 }
443 text_x_ += SkFloatToScalar(width); 469 text_x_ += SkFloatToScalar(width);
444 line_x_ += SkFloatToScalar(width); 470 line_x_ += SkFloatToScalar(width);
445 } 471 }
446 472
447 const SkScalar max_width_; 473 const SkScalar max_width_;
448 const int min_baseline_; 474 const int min_baseline_;
449 const float min_height_; 475 const float min_height_;
450 const bool multiline_; 476 const bool multiline_;
477 const WordWrapBehavior word_wrap_behavior_;
451 const base::string16& text_; 478 const base::string16& text_;
452 const BreakList<size_t>* const words_; 479 const BreakList<size_t>* const words_;
453 const internal::TextRunList& run_list_; 480 const internal::TextRunList& run_list_;
454 481
455 // Stores the resulting lines. 482 // Stores the resulting lines.
456 std::vector<internal::Line> lines_; 483 std::vector<internal::Line> lines_;
457 484
458 // Text space and line space x coordinates of the next segment to be added. 485 // Text space and line space x coordinates of the next segment to be added.
459 SkScalar text_x_; 486 SkScalar text_x_;
460 SkScalar line_x_; 487 SkScalar line_x_;
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after
990 if (lines().empty()) { 1017 if (lines().empty()) {
991 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. 1018 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
992 tracked_objects::ScopedTracker tracking_profile2( 1019 tracked_objects::ScopedTracker tracking_profile2(
993 FROM_HERE_WITH_EXPLICIT_FUNCTION( 1020 FROM_HERE_WITH_EXPLICIT_FUNCTION(
994 "431326 RenderTextHarfBuzz::EnsureLayout2")); 1021 "431326 RenderTextHarfBuzz::EnsureLayout2"));
995 1022
996 internal::TextRunList* run_list = GetRunList(); 1023 internal::TextRunList* run_list = GetRunList();
997 HarfBuzzLineBreaker line_breaker( 1024 HarfBuzzLineBreaker line_breaker(
998 display_rect().width(), font_list().GetBaseline(), 1025 display_rect().width(), font_list().GetBaseline(),
999 std::max(font_list().GetHeight(), min_line_height()), multiline(), 1026 std::max(font_list().GetHeight(), min_line_height()), multiline(),
1000 GetDisplayText(), multiline() ? &GetLineBreaks() : nullptr, *run_list); 1027 word_wrap_behavior(), GetDisplayText(),
1028 multiline() ? &GetLineBreaks() : nullptr, *run_list);
1001 1029
1002 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. 1030 // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
1003 tracked_objects::ScopedTracker tracking_profile3( 1031 tracked_objects::ScopedTracker tracking_profile3(
1004 FROM_HERE_WITH_EXPLICIT_FUNCTION( 1032 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1005 "431326 RenderTextHarfBuzz::EnsureLayout3")); 1033 "431326 RenderTextHarfBuzz::EnsureLayout3"));
1006 1034
1007 for (size_t i = 0; i < run_list->size(); ++i) 1035 for (size_t i = 0; i < run_list->size(); ++i)
1008 line_breaker.AddRun(i); 1036 line_breaker.AddRun(i);
1009 std::vector<internal::Line> lines; 1037 std::vector<internal::Line> lines;
1010 line_breaker.Finalize(&lines, &total_size_); 1038 line_breaker.Finalize(&lines, &total_size_);
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after
1528 DCHECK(!update_layout_run_list_); 1556 DCHECK(!update_layout_run_list_);
1529 DCHECK(!update_display_run_list_); 1557 DCHECK(!update_display_run_list_);
1530 return text_elided() ? display_run_list_.get() : &layout_run_list_; 1558 return text_elided() ? display_run_list_.get() : &layout_run_list_;
1531 } 1559 }
1532 1560
1533 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const { 1561 const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const {
1534 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList(); 1562 return const_cast<RenderTextHarfBuzz*>(this)->GetRunList();
1535 } 1563 }
1536 1564
1537 } // namespace gfx 1565 } // 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