OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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.h" | 5 #include "ui/gfx/render_text.h" |
6 | 6 |
7 #include <limits.h> | 7 #include <limits.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <climits> | 10 #include <climits> |
11 | 11 |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/i18n/break_iterator.h" | 13 #include "base/i18n/break_iterator.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
18 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
19 #include "build/build_config.h" | 19 #include "build/build_config.h" |
20 #include "third_party/icu/source/common/unicode/rbbi.h" | 20 #include "third_party/icu/source/common/unicode/rbbi.h" |
21 #include "third_party/icu/source/common/unicode/utf16.h" | 21 #include "third_party/icu/source/common/unicode/utf16.h" |
22 #include "third_party/skia/include/core/SkDrawLooper.h" | 22 #include "third_party/skia/include/core/SkDrawLooper.h" |
| 23 #include "third_party/skia/include/core/SkFontStyle.h" |
23 #include "third_party/skia/include/core/SkTypeface.h" | 24 #include "third_party/skia/include/core/SkTypeface.h" |
24 #include "third_party/skia/include/effects/SkGradientShader.h" | 25 #include "third_party/skia/include/effects/SkGradientShader.h" |
25 #include "ui/gfx/canvas.h" | 26 #include "ui/gfx/canvas.h" |
26 #include "ui/gfx/geometry/insets.h" | 27 #include "ui/gfx/geometry/insets.h" |
27 #include "ui/gfx/geometry/safe_integer_conversions.h" | 28 #include "ui/gfx/geometry/safe_integer_conversions.h" |
28 #include "ui/gfx/platform_font.h" | 29 #include "ui/gfx/platform_font.h" |
29 #include "ui/gfx/render_text_harfbuzz.h" | 30 #include "ui/gfx/render_text_harfbuzz.h" |
30 #include "ui/gfx/scoped_canvas.h" | 31 #include "ui/gfx/scoped_canvas.h" |
31 #include "ui/gfx/skia_util.h" | 32 #include "ui/gfx/skia_util.h" |
32 #include "ui/gfx/switches.h" | 33 #include "ui/gfx/switches.h" |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 | 360 |
360 if (clipped) | 361 if (clipped) |
361 canvas_->Restore(); | 362 canvas_->Restore(); |
362 | 363 |
363 x += pieces_[i].first; | 364 x += pieces_[i].first; |
364 } | 365 } |
365 } | 366 } |
366 | 367 |
367 StyleIterator::StyleIterator(const BreakList<SkColor>& colors, | 368 StyleIterator::StyleIterator(const BreakList<SkColor>& colors, |
368 const BreakList<BaselineStyle>& baselines, | 369 const BreakList<BaselineStyle>& baselines, |
| 370 const BreakList<Font::Weight>& weights, |
369 const std::vector<BreakList<bool>>& styles) | 371 const std::vector<BreakList<bool>>& styles) |
370 : colors_(colors), baselines_(baselines), styles_(styles) { | 372 : colors_(colors), |
| 373 baselines_(baselines), |
| 374 weights_(weights), |
| 375 styles_(styles) { |
371 color_ = colors_.breaks().begin(); | 376 color_ = colors_.breaks().begin(); |
372 baseline_ = baselines_.breaks().begin(); | 377 baseline_ = baselines_.breaks().begin(); |
| 378 weight_ = weights_.breaks().begin(); |
373 for (size_t i = 0; i < styles_.size(); ++i) | 379 for (size_t i = 0; i < styles_.size(); ++i) |
374 style_.push_back(styles_[i].breaks().begin()); | 380 style_.push_back(styles_[i].breaks().begin()); |
375 } | 381 } |
376 | 382 |
377 StyleIterator::~StyleIterator() {} | 383 StyleIterator::~StyleIterator() {} |
378 | 384 |
379 Range StyleIterator::GetRange() const { | 385 Range StyleIterator::GetRange() const { |
380 Range range(colors_.GetRange(color_)); | 386 Range range(colors_.GetRange(color_)); |
381 range = range.Intersect(baselines_.GetRange(baseline_)); | 387 range = range.Intersect(baselines_.GetRange(baseline_)); |
| 388 range = range.Intersect(weights_.GetRange(weight_)); |
382 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) | 389 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) |
383 range = range.Intersect(styles_[i].GetRange(style_[i])); | 390 range = range.Intersect(styles_[i].GetRange(style_[i])); |
384 return range; | 391 return range; |
385 } | 392 } |
386 | 393 |
387 void StyleIterator::UpdatePosition(size_t position) { | 394 void StyleIterator::UpdatePosition(size_t position) { |
388 color_ = colors_.GetBreak(position); | 395 color_ = colors_.GetBreak(position); |
389 baseline_ = baselines_.GetBreak(position); | 396 baseline_ = baselines_.GetBreak(position); |
| 397 weight_ = weights_.GetBreak(position); |
390 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) | 398 for (size_t i = 0; i < NUM_TEXT_STYLES; ++i) |
391 style_[i] = styles_[i].GetBreak(position); | 399 style_[i] = styles_[i].GetBreak(position); |
392 } | 400 } |
393 | 401 |
394 LineSegment::LineSegment() : run(0) {} | 402 LineSegment::LineSegment() : run(0) {} |
395 | 403 |
396 LineSegment::~LineSegment() {} | 404 LineSegment::~LineSegment() {} |
397 | 405 |
398 Line::Line() : preceding_heights(0), baseline(0) {} | 406 Line::Line() : preceding_heights(0), baseline(0) {} |
399 | 407 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 std::unique_ptr<RenderText> render_text = CreateInstanceOfSameType(); | 447 std::unique_ptr<RenderText> render_text = CreateInstanceOfSameType(); |
440 // |SetText()| must be called before styles are set. | 448 // |SetText()| must be called before styles are set. |
441 render_text->SetText(text); | 449 render_text->SetText(text); |
442 render_text->SetFontList(font_list_); | 450 render_text->SetFontList(font_list_); |
443 render_text->SetDirectionalityMode(directionality_mode_); | 451 render_text->SetDirectionalityMode(directionality_mode_); |
444 render_text->SetCursorEnabled(cursor_enabled_); | 452 render_text->SetCursorEnabled(cursor_enabled_); |
445 render_text->set_truncate_length(truncate_length_); | 453 render_text->set_truncate_length(truncate_length_); |
446 render_text->styles_ = styles_; | 454 render_text->styles_ = styles_; |
447 render_text->baselines_ = baselines_; | 455 render_text->baselines_ = baselines_; |
448 render_text->colors_ = colors_; | 456 render_text->colors_ = colors_; |
| 457 render_text->weights_ = weights_; |
449 return render_text; | 458 return render_text; |
450 } | 459 } |
451 | 460 |
452 void RenderText::SetText(const base::string16& text) { | 461 void RenderText::SetText(const base::string16& text) { |
453 DCHECK(!composition_range_.IsValid()); | 462 DCHECK(!composition_range_.IsValid()); |
454 if (text_ == text) | 463 if (text_ == text) |
455 return; | 464 return; |
456 text_ = text; | 465 text_ = text; |
457 UpdateStyleLengths(); | 466 UpdateStyleLengths(); |
458 | 467 |
459 // Clear style ranges as they might break new text graphemes and apply | 468 // Clear style ranges as they might break new text graphemes and apply |
460 // the first style to the whole text instead. | 469 // the first style to the whole text instead. |
461 colors_.SetValue(colors_.breaks().begin()->second); | 470 colors_.SetValue(colors_.breaks().begin()->second); |
462 baselines_.SetValue(baselines_.breaks().begin()->second); | 471 baselines_.SetValue(baselines_.breaks().begin()->second); |
| 472 weights_.SetValue(weights_.breaks().begin()->second); |
463 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) | 473 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) |
464 styles_[style].SetValue(styles_[style].breaks().begin()->second); | 474 styles_[style].SetValue(styles_[style].breaks().begin()->second); |
465 cached_bounds_and_offset_valid_ = false; | 475 cached_bounds_and_offset_valid_ = false; |
466 | 476 |
467 // Reset selection model. SetText should always followed by SetSelectionModel | 477 // Reset selection model. SetText should always followed by SetSelectionModel |
468 // or SetCursorPosition in upper layer. | 478 // or SetCursorPosition in upper layer. |
469 SetSelectionModel(SelectionModel()); | 479 SetSelectionModel(SelectionModel()); |
470 | 480 |
471 // Invalidate the cached text direction if it depends on the text contents. | 481 // Invalidate the cached text direction if it depends on the text contents. |
472 if (directionality_mode_ == DIRECTIONALITY_FROM_TEXT) | 482 if (directionality_mode_ == DIRECTIONALITY_FROM_TEXT) |
(...skipping 15 matching lines...) Expand all Loading... |
488 if (horizontal_alignment_ != alignment) { | 498 if (horizontal_alignment_ != alignment) { |
489 horizontal_alignment_ = alignment; | 499 horizontal_alignment_ = alignment; |
490 display_offset_ = Vector2d(); | 500 display_offset_ = Vector2d(); |
491 cached_bounds_and_offset_valid_ = false; | 501 cached_bounds_and_offset_valid_ = false; |
492 } | 502 } |
493 } | 503 } |
494 | 504 |
495 void RenderText::SetFontList(const FontList& font_list) { | 505 void RenderText::SetFontList(const FontList& font_list) { |
496 font_list_ = font_list; | 506 font_list_ = font_list; |
497 const int font_style = font_list.GetFontStyle(); | 507 const int font_style = font_list.GetFontStyle(); |
498 SetStyle(BOLD, (font_style & gfx::Font::BOLD) != 0); | 508 weights_.SetValue(font_list.GetFontWeight()); |
499 SetStyle(ITALIC, (font_style & gfx::Font::ITALIC) != 0); | 509 styles_[ITALIC].SetValue((font_style & Font::ITALIC) != 0); |
500 SetStyle(UNDERLINE, (font_style & gfx::Font::UNDERLINE) != 0); | 510 styles_[UNDERLINE].SetValue((font_style & Font::UNDERLINE) != 0); |
501 baseline_ = kInvalidBaseline; | 511 baseline_ = kInvalidBaseline; |
502 cached_bounds_and_offset_valid_ = false; | 512 cached_bounds_and_offset_valid_ = false; |
503 OnLayoutTextAttributeChanged(false); | 513 OnLayoutTextAttributeChanged(false); |
504 } | 514 } |
505 | 515 |
506 void RenderText::SetCursorEnabled(bool cursor_enabled) { | 516 void RenderText::SetCursorEnabled(bool cursor_enabled) { |
507 cursor_enabled_ = cursor_enabled; | 517 cursor_enabled_ = cursor_enabled; |
508 cached_bounds_and_offset_valid_ = false; | 518 cached_bounds_and_offset_valid_ = false; |
509 } | 519 } |
510 | 520 |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
759 const size_t end = IsValidCursorIndex(range.end()) ? range.end() : | 769 const size_t end = IsValidCursorIndex(range.end()) ? range.end() : |
760 IndexOfAdjacentGrapheme(range.end(), CURSOR_FORWARD); | 770 IndexOfAdjacentGrapheme(range.end(), CURSOR_FORWARD); |
761 styles_[style].ApplyValue(value, Range(start, end)); | 771 styles_[style].ApplyValue(value, Range(start, end)); |
762 | 772 |
763 cached_bounds_and_offset_valid_ = false; | 773 cached_bounds_and_offset_valid_ = false; |
764 // TODO(oshima|msw): Not all style change requires layout changes. | 774 // TODO(oshima|msw): Not all style change requires layout changes. |
765 // Consider optimizing based on the type of change. | 775 // Consider optimizing based on the type of change. |
766 OnLayoutTextAttributeChanged(false); | 776 OnLayoutTextAttributeChanged(false); |
767 } | 777 } |
768 | 778 |
| 779 void RenderText::SetWeight(Font::Weight weight) { |
| 780 weights_.SetValue(weight); |
| 781 |
| 782 cached_bounds_and_offset_valid_ = false; |
| 783 OnLayoutTextAttributeChanged(false); |
| 784 } |
| 785 |
| 786 void RenderText::ApplyWeight(Font::Weight weight, const Range& range) { |
| 787 weights_.ApplyValue(weight, range); |
| 788 |
| 789 cached_bounds_and_offset_valid_ = false; |
| 790 OnLayoutTextAttributeChanged(false); |
| 791 } |
| 792 |
769 bool RenderText::GetStyle(TextStyle style) const { | 793 bool RenderText::GetStyle(TextStyle style) const { |
770 return (styles_[style].breaks().size() == 1) && | 794 return (styles_[style].breaks().size() == 1) && |
771 styles_[style].breaks().front().second; | 795 styles_[style].breaks().front().second; |
772 } | 796 } |
773 | 797 |
774 void RenderText::SetDirectionalityMode(DirectionalityMode mode) { | 798 void RenderText::SetDirectionalityMode(DirectionalityMode mode) { |
775 if (mode == directionality_mode_) | 799 if (mode == directionality_mode_) |
776 return; | 800 return; |
777 | 801 |
778 directionality_mode_ = mode; | 802 directionality_mode_ = mode; |
779 text_direction_ = base::i18n::UNKNOWN_DIRECTION; | 803 text_direction_ = base::i18n::UNKNOWN_DIRECTION; |
780 cached_bounds_and_offset_valid_ = false; | 804 cached_bounds_and_offset_valid_ = false; |
781 OnLayoutTextAttributeChanged(false); | 805 OnLayoutTextAttributeChanged(false); |
782 } | 806 } |
783 | 807 |
784 base::i18n::TextDirection RenderText::GetDisplayTextDirection() { | 808 base::i18n::TextDirection RenderText::GetDisplayTextDirection() { |
785 return GetTextDirection(GetDisplayText()); | 809 return GetTextDirection(GetDisplayText()); |
786 } | 810 } |
787 | 811 |
788 VisualCursorDirection RenderText::GetVisualDirectionOfLogicalEnd() { | 812 VisualCursorDirection RenderText::GetVisualDirectionOfLogicalEnd() { |
789 return GetDisplayTextDirection() == base::i18n::LEFT_TO_RIGHT ? | 813 return GetDisplayTextDirection() == base::i18n::LEFT_TO_RIGHT ? |
790 CURSOR_RIGHT : CURSOR_LEFT; | 814 CURSOR_RIGHT : CURSOR_LEFT; |
791 } | 815 } |
792 | 816 |
793 SizeF RenderText::GetStringSizeF() { | 817 SizeF RenderText::GetStringSizeF() { |
794 return gfx::SizeF(GetStringSize()); | 818 return SizeF(GetStringSize()); |
795 } | 819 } |
796 | 820 |
797 float RenderText::GetContentWidthF() { | 821 float RenderText::GetContentWidthF() { |
798 const float string_size = GetStringSizeF().width(); | 822 const float string_size = GetStringSizeF().width(); |
799 // The cursor is drawn one pixel beyond the int-enclosed text bounds. | 823 // The cursor is drawn one pixel beyond the int-enclosed text bounds. |
800 return cursor_enabled_ ? std::ceil(string_size) + 1 : string_size; | 824 return cursor_enabled_ ? std::ceil(string_size) + 1 : string_size; |
801 } | 825 } |
802 | 826 |
803 int RenderText::GetContentWidth() { | 827 int RenderText::GetContentWidth() { |
804 return ToCeiledInt(GetContentWidthF()); | 828 return ToCeiledInt(GetContentWidthF()); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
990 cursor_enabled_(true), | 1014 cursor_enabled_(true), |
991 cursor_visible_(false), | 1015 cursor_visible_(false), |
992 insert_mode_(true), | 1016 insert_mode_(true), |
993 cursor_color_(kDefaultColor), | 1017 cursor_color_(kDefaultColor), |
994 selection_color_(kDefaultColor), | 1018 selection_color_(kDefaultColor), |
995 selection_background_focused_color_(kDefaultSelectionBackgroundColor), | 1019 selection_background_focused_color_(kDefaultSelectionBackgroundColor), |
996 focused_(false), | 1020 focused_(false), |
997 composition_range_(Range::InvalidRange()), | 1021 composition_range_(Range::InvalidRange()), |
998 colors_(kDefaultColor), | 1022 colors_(kDefaultColor), |
999 baselines_(NORMAL_BASELINE), | 1023 baselines_(NORMAL_BASELINE), |
| 1024 weights_(Font::Weight::NORMAL), |
1000 styles_(NUM_TEXT_STYLES), | 1025 styles_(NUM_TEXT_STYLES), |
1001 composition_and_selection_styles_applied_(false), | 1026 composition_and_selection_styles_applied_(false), |
1002 obscured_(false), | 1027 obscured_(false), |
1003 obscured_reveal_index_(-1), | 1028 obscured_reveal_index_(-1), |
1004 truncate_length_(0), | 1029 truncate_length_(0), |
1005 elide_behavior_(NO_ELIDE), | 1030 elide_behavior_(NO_ELIDE), |
1006 text_elided_(false), | 1031 text_elided_(false), |
1007 min_line_height_(0), | 1032 min_line_height_(0), |
1008 multiline_(false), | 1033 multiline_(false), |
1009 max_lines_(0), | 1034 max_lines_(0), |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1301 ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index; | 1326 ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index; |
1302 CHECK_GE(i, 0); | 1327 CHECK_GE(i, 0); |
1303 // Clamp indices to the length of the given layout or display text. | 1328 // Clamp indices to the length of the given layout or display text. |
1304 return std::min<size_t>(given_text.length(), i); | 1329 return std::min<size_t>(given_text.length(), i); |
1305 } | 1330 } |
1306 | 1331 |
1307 void RenderText::UpdateStyleLengths() { | 1332 void RenderText::UpdateStyleLengths() { |
1308 const size_t text_length = text_.length(); | 1333 const size_t text_length = text_.length(); |
1309 colors_.SetMax(text_length); | 1334 colors_.SetMax(text_length); |
1310 baselines_.SetMax(text_length); | 1335 baselines_.SetMax(text_length); |
| 1336 weights_.SetMax(text_length); |
1311 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) | 1337 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) |
1312 styles_[style].SetMax(text_length); | 1338 styles_[style].SetMax(text_length); |
1313 } | 1339 } |
1314 | 1340 |
1315 // static | 1341 // static |
1316 bool RenderText::RangeContainsCaret(const Range& range, | 1342 bool RenderText::RangeContainsCaret(const Range& range, |
1317 size_t caret_pos, | 1343 size_t caret_pos, |
1318 LogicalCursorDirection caret_affinity) { | 1344 LogicalCursorDirection caret_affinity) { |
1319 // NB: exploits unsigned wraparound (WG14/N1124 section 6.2.5 paragraph 9). | 1345 // NB: exploits unsigned wraparound (WG14/N1124 section 6.2.5 paragraph 9). |
1320 size_t adjacent = (caret_affinity == CURSOR_BACKWARD) ? | 1346 size_t adjacent = (caret_affinity == CURSOR_BACKWARD) ? |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1453 new_text += base::i18n::kRightToLeftMark; | 1479 new_text += base::i18n::kRightToLeftMark; |
1454 } | 1480 } |
1455 render_text->SetText(new_text); | 1481 render_text->SetText(new_text); |
1456 } | 1482 } |
1457 | 1483 |
1458 // Restore styles and baselines without breaking multi-character graphemes. | 1484 // Restore styles and baselines without breaking multi-character graphemes. |
1459 render_text->styles_ = styles_; | 1485 render_text->styles_ = styles_; |
1460 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) | 1486 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style) |
1461 RestoreBreakList(render_text.get(), &render_text->styles_[style]); | 1487 RestoreBreakList(render_text.get(), &render_text->styles_[style]); |
1462 RestoreBreakList(render_text.get(), &render_text->baselines_); | 1488 RestoreBreakList(render_text.get(), &render_text->baselines_); |
| 1489 render_text->weights_ = weights_; |
| 1490 RestoreBreakList(render_text.get(), &render_text->weights_); |
1463 | 1491 |
1464 // We check the width of the whole desired string at once to ensure we | 1492 // We check the width of the whole desired string at once to ensure we |
1465 // handle kerning/ligatures/etc. correctly. | 1493 // handle kerning/ligatures/etc. correctly. |
1466 const float guess_width = render_text->GetContentWidthF(); | 1494 const float guess_width = render_text->GetContentWidthF(); |
1467 if (guess_width == available_width) | 1495 if (guess_width == available_width) |
1468 break; | 1496 break; |
1469 if (guess_width > available_width) { | 1497 if (guess_width > available_width) { |
1470 hi = guess - 1; | 1498 hi = guess - 1; |
1471 // Move back on the loop terminating condition when the guess is too wide. | 1499 // Move back on the loop terminating condition when the guess is too wide. |
1472 if (hi < lo) | 1500 if (hi < lo) |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1559 | 1587 |
1560 SetDisplayOffset(display_offset_.x() + delta_x); | 1588 SetDisplayOffset(display_offset_.x() + delta_x); |
1561 } | 1589 } |
1562 | 1590 |
1563 void RenderText::DrawSelection(Canvas* canvas) { | 1591 void RenderText::DrawSelection(Canvas* canvas) { |
1564 for (const Rect& s : GetSubstringBounds(selection())) | 1592 for (const Rect& s : GetSubstringBounds(selection())) |
1565 canvas->FillRect(s, selection_background_focused_color_); | 1593 canvas->FillRect(s, selection_background_focused_color_); |
1566 } | 1594 } |
1567 | 1595 |
1568 } // namespace gfx | 1596 } // namespace gfx |
OLD | NEW |