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 |