| 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> |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 return new RenderTextMac; | 427 return new RenderTextMac; |
| 428 #endif // defined(OS_MACOSX) | 428 #endif // defined(OS_MACOSX) |
| 429 return new RenderTextHarfBuzz; | 429 return new RenderTextHarfBuzz; |
| 430 } | 430 } |
| 431 | 431 |
| 432 // static | 432 // static |
| 433 RenderText* RenderText::CreateInstanceForEditing() { | 433 RenderText* RenderText::CreateInstanceForEditing() { |
| 434 return new RenderTextHarfBuzz; | 434 return new RenderTextHarfBuzz; |
| 435 } | 435 } |
| 436 | 436 |
| 437 std::unique_ptr<RenderText> RenderText::CreateInstanceOfSameStyle( |
| 438 const base::string16& text) const { |
| 439 std::unique_ptr<RenderText> render_text = CreateInstanceOfSameType(); |
| 440 // |SetText()| must be called before styles are set. |
| 441 render_text->directionality_mode_ = directionality_mode_; |
| 442 render_text->cursor_enabled_ = cursor_enabled_; |
| 443 render_text->set_truncate_length(truncate_length_); |
| 444 render_text->font_list_ = font_list_; |
| 445 render_text->text_ = text; |
| 446 render_text->styles_ = styles_; |
| 447 render_text->baselines_ = baselines_; |
| 448 render_text->colors_ = colors_; |
| 449 render_text->multiline_ = multiline_; |
| 450 render_text->SetDisplayRect(display_rect_); |
| 451 render_text->OnTextAttributeChanged(); |
| 452 return render_text; |
| 453 } |
| 454 |
| 437 void RenderText::SetText(const base::string16& text) { | 455 void RenderText::SetText(const base::string16& text) { |
| 438 DCHECK(!composition_range_.IsValid()); | 456 DCHECK(!composition_range_.IsValid()); |
| 439 if (text_ == text) | 457 if (text_ == text) |
| 440 return; | 458 return; |
| 441 text_ = text; | 459 text_ = text; |
| 442 UpdateStyleLengths(); | 460 UpdateStyleLengths(); |
| 443 | 461 |
| 444 // Clear style ranges as they might break new text graphemes and apply | 462 // Clear style ranges as they might break new text graphemes and apply |
| 445 // the first style to the whole text instead. | 463 // the first style to the whole text instead. |
| 446 colors_.SetValue(colors_.breaks().begin()->second); | 464 colors_.SetValue(colors_.breaks().begin()->second); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 | 536 |
| 519 void RenderText::SetMultiline(bool multiline) { | 537 void RenderText::SetMultiline(bool multiline) { |
| 520 if (multiline != multiline_) { | 538 if (multiline != multiline_) { |
| 521 multiline_ = multiline; | 539 multiline_ = multiline; |
| 522 cached_bounds_and_offset_valid_ = false; | 540 cached_bounds_and_offset_valid_ = false; |
| 523 lines_.clear(); | 541 lines_.clear(); |
| 524 OnTextAttributeChanged(); | 542 OnTextAttributeChanged(); |
| 525 } | 543 } |
| 526 } | 544 } |
| 527 | 545 |
| 546 void RenderText::SetMaxLines(size_t max_lines) { |
| 547 max_lines_ = max_lines; |
| 548 OnDisplayTextAttributeChanged(); |
| 549 } |
| 550 |
| 551 size_t RenderText::GetNumLines() { |
| 552 return lines_.size(); |
| 553 } |
| 554 |
| 528 void RenderText::SetWordWrapBehavior(WordWrapBehavior behavior) { | 555 void RenderText::SetWordWrapBehavior(WordWrapBehavior behavior) { |
| 529 if (word_wrap_behavior_ == behavior) | 556 if (word_wrap_behavior_ == behavior) |
| 530 return; | 557 return; |
| 531 word_wrap_behavior_ = behavior; | 558 word_wrap_behavior_ = behavior; |
| 532 if (multiline_) { | 559 if (multiline_) { |
| 533 cached_bounds_and_offset_valid_ = false; | 560 cached_bounds_and_offset_valid_ = false; |
| 534 lines_.clear(); | 561 lines_.clear(); |
| 535 OnTextAttributeChanged(); | 562 OnTextAttributeChanged(); |
| 536 } | 563 } |
| 537 } | 564 } |
| (...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 975 baselines_(NORMAL_BASELINE), | 1002 baselines_(NORMAL_BASELINE), |
| 976 styles_(NUM_TEXT_STYLES), | 1003 styles_(NUM_TEXT_STYLES), |
| 977 composition_and_selection_styles_applied_(false), | 1004 composition_and_selection_styles_applied_(false), |
| 978 obscured_(false), | 1005 obscured_(false), |
| 979 obscured_reveal_index_(-1), | 1006 obscured_reveal_index_(-1), |
| 980 truncate_length_(0), | 1007 truncate_length_(0), |
| 981 elide_behavior_(NO_ELIDE), | 1008 elide_behavior_(NO_ELIDE), |
| 982 text_elided_(false), | 1009 text_elided_(false), |
| 983 min_line_height_(0), | 1010 min_line_height_(0), |
| 984 multiline_(false), | 1011 multiline_(false), |
| 1012 max_lines_(0), |
| 985 word_wrap_behavior_(IGNORE_LONG_WORDS), | 1013 word_wrap_behavior_(IGNORE_LONG_WORDS), |
| 986 replace_newline_chars_with_symbols_(true), | 1014 replace_newline_chars_with_symbols_(true), |
| 987 subpixel_rendering_suppressed_(false), | 1015 subpixel_rendering_suppressed_(false), |
| 988 clip_to_display_rect_(true), | 1016 clip_to_display_rect_(true), |
| 989 baseline_(kInvalidBaseline), | 1017 baseline_(kInvalidBaseline), |
| 990 cached_bounds_and_offset_valid_(false) { | 1018 cached_bounds_and_offset_valid_(false) {} |
| 991 } | |
| 992 | 1019 |
| 993 SelectionModel RenderText::GetAdjacentSelectionModel( | 1020 SelectionModel RenderText::GetAdjacentSelectionModel( |
| 994 const SelectionModel& current, | 1021 const SelectionModel& current, |
| 995 BreakType break_type, | 1022 BreakType break_type, |
| 996 VisualCursorDirection direction) { | 1023 VisualCursorDirection direction) { |
| 997 EnsureLayout(); | 1024 EnsureLayout(); |
| 998 | 1025 |
| 999 if (break_type == LINE_BREAK || text().empty()) | 1026 if (break_type == LINE_BREAK || text().empty()) |
| 1000 return EdgeSelectionModel(direction); | 1027 return EdgeSelectionModel(direction); |
| 1001 if (break_type == CHARACTER_BREAK) | 1028 if (break_type == CHARACTER_BREAK) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1014 void RenderText::SetSelectionModel(const SelectionModel& model) { | 1041 void RenderText::SetSelectionModel(const SelectionModel& model) { |
| 1015 DCHECK_LE(model.selection().GetMax(), text().length()); | 1042 DCHECK_LE(model.selection().GetMax(), text().length()); |
| 1016 selection_model_ = model; | 1043 selection_model_ = model; |
| 1017 cached_bounds_and_offset_valid_ = false; | 1044 cached_bounds_and_offset_valid_ = false; |
| 1018 } | 1045 } |
| 1019 | 1046 |
| 1020 void RenderText::OnTextColorChanged() { | 1047 void RenderText::OnTextColorChanged() { |
| 1021 } | 1048 } |
| 1022 | 1049 |
| 1023 void RenderText::UpdateDisplayText(float text_width) { | 1050 void RenderText::UpdateDisplayText(float text_width) { |
| 1024 // TODO(oshima): Consider support eliding for multi-line text. | 1051 // TODO(krb): Consider other elision modes for multiline. |
| 1025 // This requires max_line support first. | 1052 if ((multiline_ && (!max_lines_ || elide_behavior() != ELIDE_TAIL)) || |
| 1026 if (multiline_ || | 1053 elide_behavior() == NO_ELIDE || elide_behavior() == FADE_TAIL || |
| 1027 elide_behavior() == NO_ELIDE || | 1054 (text_width > 0 && text_width < display_rect_.width()) || |
| 1028 elide_behavior() == FADE_TAIL || | |
| 1029 text_width < display_rect_.width() || | |
| 1030 layout_text_.empty()) { | 1055 layout_text_.empty()) { |
| 1031 text_elided_ = false; | 1056 text_elided_ = false; |
| 1032 display_text_.clear(); | 1057 display_text_.clear(); |
| 1033 return; | 1058 return; |
| 1034 } | 1059 } |
| 1035 | 1060 |
| 1036 // This doesn't trim styles so ellipsis may get rendered as a different | 1061 if (!multiline_) { |
| 1037 // style than the preceding text. See crbug.com/327850. | 1062 // This doesn't trim styles so ellipsis may get rendered as a different |
| 1038 display_text_.assign(Elide(layout_text_, | 1063 // style than the preceding text. See crbug.com/327850. |
| 1039 text_width, | 1064 display_text_.assign(Elide(layout_text_, text_width, |
| 1040 static_cast<float>(display_rect_.width()), | 1065 static_cast<float>(display_rect_.width()), |
| 1041 elide_behavior_)); | 1066 elide_behavior_)); |
| 1067 } else { |
| 1068 bool was_elided = text_elided_; |
| 1069 text_elided_ = false; |
| 1070 display_text_.clear(); |
| 1042 | 1071 |
| 1072 std::unique_ptr<RenderText> render_text( |
| 1073 CreateInstanceOfSameStyle(layout_text_)); |
| 1074 //render_text->SetMultiline(true); |
| 1075 //render_text->SetDisplayRect(display_rect_); |
| 1076 // Have it arrange words on |lines_|. |
| 1077 //render_text->OnLayoutTextAttributeChanged(false); |
| 1078 render_text->EnsureLayout(); |
| 1079 |
| 1080 if (render_text->lines_.size() > max_lines_) { |
| 1081 size_t start_of_elision = render_text->lines_[max_lines_ - 1] |
| 1082 .segments.front() |
| 1083 .char_range.start(); |
| 1084 base::string16 text_to_elide = layout_text_.substr(start_of_elision); |
| 1085 display_text_.assign(layout_text_.substr(0, start_of_elision) + |
| 1086 Elide(text_to_elide, 0, |
| 1087 static_cast<float>(display_rect_.width()), |
| 1088 ELIDE_TAIL)); |
| 1089 // Have GetLineBreaks() re-calculate. |
| 1090 line_breaks_.SetMax(0); |
| 1091 } else { |
| 1092 // If elision changed, re-calculate. |
| 1093 if (was_elided) |
| 1094 line_breaks_.SetMax(0); |
| 1095 // Initial state above is fine. |
| 1096 return; |
| 1097 } |
| 1098 } |
| 1043 text_elided_ = display_text_ != layout_text_; | 1099 text_elided_ = display_text_ != layout_text_; |
| 1044 if (!text_elided_) | 1100 if (!text_elided_) |
| 1045 display_text_.clear(); | 1101 display_text_.clear(); |
| 1046 } | 1102 } |
| 1047 | 1103 |
| 1048 const BreakList<size_t>& RenderText::GetLineBreaks() { | 1104 const BreakList<size_t>& RenderText::GetLineBreaks() { |
| 1049 if (line_breaks_.max() != 0) | 1105 if (line_breaks_.max() != 0) |
| 1050 return line_breaks_; | 1106 return line_breaks_; |
| 1051 | 1107 |
| 1052 const base::string16& layout_text = GetDisplayText(); | 1108 const base::string16& layout_text = GetDisplayText(); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 if (available_width <= 0 || text.empty()) | 1400 if (available_width <= 0 || text.empty()) |
| 1345 return base::string16(); | 1401 return base::string16(); |
| 1346 if (behavior == ELIDE_EMAIL) | 1402 if (behavior == ELIDE_EMAIL) |
| 1347 return ElideEmail(text, available_width); | 1403 return ElideEmail(text, available_width); |
| 1348 if (text_width > 0 && text_width < available_width) | 1404 if (text_width > 0 && text_width < available_width) |
| 1349 return text; | 1405 return text; |
| 1350 | 1406 |
| 1351 TRACE_EVENT0("ui", "RenderText::Elide"); | 1407 TRACE_EVENT0("ui", "RenderText::Elide"); |
| 1352 | 1408 |
| 1353 // Create a RenderText copy with attributes that affect the rendering width. | 1409 // Create a RenderText copy with attributes that affect the rendering width. |
| 1354 std::unique_ptr<RenderText> render_text = CreateInstanceOfSameType(); | 1410 bool orig_multiline = multiline_; |
| 1355 render_text->SetFontList(font_list_); | 1411 multiline_ = false; |
| 1356 render_text->SetDirectionalityMode(directionality_mode_); | 1412 std::unique_ptr<RenderText> render_text = CreateInstanceOfSameStyle(text); |
| 1357 render_text->SetCursorEnabled(cursor_enabled_); | 1413 multiline_ = orig_multiline; |
| 1358 render_text->set_truncate_length(truncate_length_); | |
| 1359 render_text->styles_ = styles_; | |
| 1360 render_text->baselines_ = baselines_; | |
| 1361 render_text->colors_ = colors_; | |
| 1362 if (text_width == 0) { | 1414 if (text_width == 0) { |
| 1363 render_text->SetText(text); | |
| 1364 text_width = render_text->GetContentWidthF(); | 1415 text_width = render_text->GetContentWidthF(); |
| 1365 } | 1416 } |
| 1366 if (text_width <= available_width) | 1417 if (text_width <= available_width) |
| 1367 return text; | 1418 return text; |
| 1368 | 1419 |
| 1369 const base::string16 ellipsis = base::string16(kEllipsisUTF16); | 1420 const base::string16 ellipsis = base::string16(kEllipsisUTF16); |
| 1370 const bool insert_ellipsis = (behavior != TRUNCATE); | 1421 const bool insert_ellipsis = (behavior != TRUNCATE); |
| 1371 const bool elide_in_middle = (behavior == ELIDE_MIDDLE); | 1422 const bool elide_in_middle = (behavior == ELIDE_MIDDLE); |
| 1372 const bool elide_at_beginning = (behavior == ELIDE_HEAD); | 1423 const bool elide_at_beginning = (behavior == ELIDE_HEAD); |
| 1373 | 1424 |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1515 | 1566 |
| 1516 SetDisplayOffset(display_offset_.x() + delta_x); | 1567 SetDisplayOffset(display_offset_.x() + delta_x); |
| 1517 } | 1568 } |
| 1518 | 1569 |
| 1519 void RenderText::DrawSelection(Canvas* canvas) { | 1570 void RenderText::DrawSelection(Canvas* canvas) { |
| 1520 for (const Rect& s : GetSubstringBounds(selection())) | 1571 for (const Rect& s : GetSubstringBounds(selection())) |
| 1521 canvas->FillRect(s, selection_background_focused_color_); | 1572 canvas->FillRect(s, selection_background_focused_color_); |
| 1522 } | 1573 } |
| 1523 | 1574 |
| 1524 } // namespace gfx | 1575 } // namespace gfx |
| OLD | NEW |